diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/buffer.c | 9 | ||||
-rw-r--r-- | fs/ecryptfs/file.c | 1 | ||||
-rw-r--r-- | fs/ecryptfs/inode.c | 9 | ||||
-rw-r--r-- | fs/ecryptfs/main.c | 10 | ||||
-rw-r--r-- | fs/ecryptfs/mmap.c | 44 | ||||
-rw-r--r-- | fs/ext3/xattr.c | 42 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 41 | ||||
-rw-r--r-- | fs/jfs/jfs_txnmgr.c | 3 | ||||
-rw-r--r-- | fs/libfs.c | 10 | ||||
-rw-r--r-- | fs/ncpfs/inode.c | 16 | ||||
-rw-r--r-- | fs/ncpfs/sock.c | 151 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 2 | ||||
-rw-r--r-- | fs/sysfs/file.c | 44 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 11 |
14 files changed, 267 insertions, 126 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index e8504b65176c..1d0852fa728b 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2365,6 +2365,10 @@ failed: } EXPORT_SYMBOL(nobh_prepare_write); +/* + * Make sure any changes to nobh_commit_write() are reflected in + * nobh_truncate_page(), since it doesn't call commit_write(). + */ int nobh_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { @@ -2466,6 +2470,11 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from) memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); + /* + * It would be more correct to call aops->commit_write() + * here, but this is more efficient. + */ + SetPageUptodate(page); set_page_dirty(page); } unlock_page(page); diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index bd969adf70d7..7a7d25d541e7 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -205,6 +205,7 @@ int ecryptfs_open_lower_file(struct file **lower_file, { int rc = 0; + flags |= O_LARGEFILE; dget(lower_dentry); mntget(lower_mnt); *lower_file = dentry_open(lower_dentry, lower_mnt, flags); diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 9fa7e0b27a96..e62f3fc7241e 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -168,9 +168,9 @@ static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file, goto out; } i_size_write(inode, 0); - ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, inode, - ecryptfs_dentry, - ECRYPTFS_LOWER_I_MUTEX_NOT_HELD); + rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, + inode, ecryptfs_dentry, + ECRYPTFS_LOWER_I_MUTEX_NOT_HELD); ecryptfs_inode_to_private(inode)->crypt_stat.flags |= ECRYPTFS_NEW_FILE; out: return rc; @@ -200,9 +200,6 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) inode = ecryptfs_dentry->d_inode; crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; lower_flags = ((O_CREAT | O_TRUNC) & O_ACCMODE) | O_RDWR; -#if BITS_PER_LONG != 32 - lower_flags |= O_LARGEFILE; -#endif lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); /* Corresponding fput() at end of this function */ if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt, diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 80044d196fe0..fc4a3a224641 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -484,18 +484,12 @@ static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) struct vfsmount *lower_mnt; memset(&nd, 0, sizeof(struct nameidata)); - rc = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); + rc = path_lookup(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd); if (rc) { ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n"); - goto out_free; + goto out; } lower_root = nd.dentry; - if (!lower_root->d_inode) { - ecryptfs_printk(KERN_WARNING, - "No directory to interpose on\n"); - rc = -ENOENT; - goto out_free; - } lower_mnt = nd.mnt; ecryptfs_set_superblock_lower(sb, lower_root->d_sb); sb->s_maxbytes = lower_root->d_sb->s_maxbytes; diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 3a6f65c3f14f..b731b09499cb 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -238,7 +238,6 @@ int ecryptfs_do_readpage(struct file *file, struct page *page, lower_page_data = kmap_atomic(lower_page, KM_USER1); memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE); kunmap_atomic(lower_page_data, KM_USER1); - flush_dcache_page(lower_page); kunmap_atomic(page_data, KM_USER0); flush_dcache_page(page); rc = 0; @@ -422,9 +421,11 @@ out: return rc; } -static void ecryptfs_release_lower_page(struct page *lower_page) +static +void ecryptfs_release_lower_page(struct page *lower_page, int page_locked) { - unlock_page(lower_page); + if (page_locked) + unlock_page(lower_page); page_cache_release(lower_page); } @@ -445,6 +446,7 @@ static int ecryptfs_write_inode_size_to_header(struct file *lower_file, const struct address_space_operations *lower_a_ops; u64 file_size; +retry: header_page = grab_cache_page(lower_inode->i_mapping, 0); if (!header_page) { ecryptfs_printk(KERN_ERR, "grab_cache_page for " @@ -454,6 +456,14 @@ static int ecryptfs_write_inode_size_to_header(struct file *lower_file, } lower_a_ops = lower_inode->i_mapping->a_ops; rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8); + if (rc) { + if (rc == AOP_TRUNCATED_PAGE) { + ecryptfs_release_lower_page(header_page, 0); + goto retry; + } else + ecryptfs_release_lower_page(header_page, 1); + goto out; + } file_size = (u64)i_size_read(inode); ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size); file_size = cpu_to_be64(file_size); @@ -465,7 +475,11 @@ static int ecryptfs_write_inode_size_to_header(struct file *lower_file, if (rc < 0) ecryptfs_printk(KERN_ERR, "Error commiting header page " "write\n"); - ecryptfs_release_lower_page(header_page); + if (rc == AOP_TRUNCATED_PAGE) { + ecryptfs_release_lower_page(header_page, 0); + goto retry; + } else + ecryptfs_release_lower_page(header_page, 1); lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; mark_inode_dirty_sync(inode); out: @@ -491,7 +505,8 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode, goto out; } lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); - if (!lower_dentry->d_inode->i_op->getxattr) { + if (!lower_dentry->d_inode->i_op->getxattr || + !lower_dentry->d_inode->i_op->setxattr) { printk(KERN_WARNING "No support for setting xattr in lower filesystem\n"); rc = -ENOSYS; @@ -553,6 +568,7 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, { int rc = 0; +retry: *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index); if (!(*lower_page)) { rc = -EINVAL; @@ -566,15 +582,18 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, byte_offset, region_bytes); if (rc) { - ecryptfs_printk(KERN_ERR, "prepare_write for " + if (rc == AOP_TRUNCATED_PAGE) { + ecryptfs_release_lower_page(*lower_page, 0); + goto retry; + } else { + ecryptfs_printk(KERN_ERR, "prepare_write for " "lower_page_index = [0x%.16x] failed; rc = " "[%d]\n", lower_page_index, rc); + ecryptfs_release_lower_page(*lower_page, 1); + (*lower_page) = NULL; + } } out: - if (rc && (*lower_page)) { - ecryptfs_release_lower_page(*lower_page); - (*lower_page) = NULL; - } return rc; } @@ -588,16 +607,19 @@ ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, struct file *lower_file, int byte_offset, int region_size) { + int page_locked = 1; int rc = 0; rc = lower_inode->i_mapping->a_ops->commit_write( lower_file, lower_page, byte_offset, region_size); + if (rc == AOP_TRUNCATED_PAGE) + page_locked = 0; if (rc < 0) { ecryptfs_printk(KERN_ERR, "Error committing write; rc = [%d]\n", rc); } else rc = 0; - ecryptfs_release_lower_page(lower_page); + ecryptfs_release_lower_page(lower_page, page_locked); return rc; } diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 99857a400f4b..12f7dda1232c 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -475,8 +475,15 @@ ext3_xattr_release_block(handle_t *handle, struct inode *inode, struct buffer_head *bh) { struct mb_cache_entry *ce = NULL; + int error = 0; ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev, bh->b_blocknr); + error = ext3_journal_get_write_access(handle, bh); + if (error) + goto out; + + lock_buffer(bh); + if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { ea_bdebug(bh, "refcount now=0; freeing"); if (ce) @@ -485,21 +492,20 @@ ext3_xattr_release_block(handle_t *handle, struct inode *inode, get_bh(bh); ext3_forget(handle, 1, inode, bh, bh->b_blocknr); } else { - if (ext3_journal_get_write_access(handle, bh) == 0) { - lock_buffer(bh); - BHDR(bh)->h_refcount = cpu_to_le32( + BHDR(bh)->h_refcount = cpu_to_le32( le32_to_cpu(BHDR(bh)->h_refcount) - 1); - ext3_journal_dirty_metadata(handle, bh); - if (IS_SYNC(inode)) - handle->h_sync = 1; - DQUOT_FREE_BLOCK(inode, 1); - unlock_buffer(bh); - ea_bdebug(bh, "refcount now=%d; releasing", - le32_to_cpu(BHDR(bh)->h_refcount)); - } + error = ext3_journal_dirty_metadata(handle, bh); + handle->h_sync = 1; + DQUOT_FREE_BLOCK(inode, 1); + ea_bdebug(bh, "refcount now=%d; releasing", + le32_to_cpu(BHDR(bh)->h_refcount)); if (ce) mb_cache_entry_release(ce); } + unlock_buffer(bh); +out: + ext3_std_error(inode->i_sb, error); + return; } struct ext3_xattr_info { @@ -675,7 +681,7 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, struct buffer_head *new_bh = NULL; struct ext3_xattr_search *s = &bs->s; struct mb_cache_entry *ce = NULL; - int error; + int error = 0; #define header(x) ((struct ext3_xattr_header *)(x)) @@ -684,16 +690,17 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, if (s->base) { ce = mb_cache_entry_get(ext3_xattr_cache, bs->bh->b_bdev, bs->bh->b_blocknr); + error = ext3_journal_get_write_access(handle, bs->bh); + if (error) + goto cleanup; + lock_buffer(bs->bh); + if (header(s->base)->h_refcount == cpu_to_le32(1)) { if (ce) { mb_cache_entry_free(ce); ce = NULL; } ea_bdebug(bs->bh, "modifying in-place"); - error = ext3_journal_get_write_access(handle, bs->bh); - if (error) - goto cleanup; - lock_buffer(bs->bh); error = ext3_xattr_set_entry(i, s); if (!error) { if (!IS_LAST_ENTRY(s->first)) @@ -713,6 +720,9 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, } else { int offset = (char *)s->here - bs->bh->b_data; + unlock_buffer(bs->bh); + journal_release_buffer(handle, bs->bh); + if (ce) { mb_cache_entry_release(ce); ce = NULL; diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index dc969c357aa1..e832e96095b3 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -475,8 +475,14 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, struct buffer_head *bh) { struct mb_cache_entry *ce = NULL; + int error = 0; ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr); + error = ext4_journal_get_write_access(handle, bh); + if (error) + goto out; + + lock_buffer(bh); if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { ea_bdebug(bh, "refcount now=0; freeing"); if (ce) @@ -485,21 +491,21 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, get_bh(bh); ext4_forget(handle, 1, inode, bh, bh->b_blocknr); } else { - if (ext4_journal_get_write_access(handle, bh) == 0) { - lock_buffer(bh); - BHDR(bh)->h_refcount = cpu_to_le32( + BHDR(bh)->h_refcount = cpu_to_le32( le32_to_cpu(BHDR(bh)->h_refcount) - 1); - ext4_journal_dirty_metadata(handle, bh); - if (IS_SYNC(inode)) - handle->h_sync = 1; - DQUOT_FREE_BLOCK(inode, 1); - unlock_buffer(bh); - ea_bdebug(bh, "refcount now=%d; releasing", - le32_to_cpu(BHDR(bh)->h_refcount)); - } + error = ext4_journal_dirty_metadata(handle, bh); + if (IS_SYNC(inode)) + handle->h_sync = 1; + DQUOT_FREE_BLOCK(inode, 1); + ea_bdebug(bh, "refcount now=%d; releasing", + le32_to_cpu(BHDR(bh)->h_refcount)); if (ce) mb_cache_entry_release(ce); } + unlock_buffer(bh); +out: + ext4_std_error(inode->i_sb, error); + return; } struct ext4_xattr_info { @@ -675,7 +681,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, struct buffer_head *new_bh = NULL; struct ext4_xattr_search *s = &bs->s; struct mb_cache_entry *ce = NULL; - int error; + int error = 0; #define header(x) ((struct ext4_xattr_header *)(x)) @@ -684,16 +690,17 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, if (s->base) { ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev, bs->bh->b_blocknr); + error = ext4_journal_get_write_access(handle, bs->bh); + if (error) + goto cleanup; + lock_buffer(bs->bh); + if (header(s->base)->h_refcount == cpu_to_le32(1)) { if (ce) { mb_cache_entry_free(ce); ce = NULL; } ea_bdebug(bs->bh, "modifying in-place"); - error = ext4_journal_get_write_access(handle, bs->bh); - if (error) - goto cleanup; - lock_buffer(bs->bh); error = ext4_xattr_set_entry(i, s); if (!error) { if (!IS_LAST_ENTRY(s->first)) @@ -713,6 +720,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, } else { int offset = (char *)s->here - bs->bh->b_data; + unlock_buffer(bs->bh); + jbd2_journal_release_buffer(handle, bs->bh); if (ce) { mb_cache_entry_release(ce); ce = NULL; diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 6988a1082f58..03893acbfda4 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1919,7 +1919,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, * header ? */ if (tlck->type & tlckTRUNCATE) { - pxd_t pxd; /* truncated extent of xad */ + /* This odd declaration suppresses a bogus gcc warning */ + pxd_t pxd = pxd; /* truncated extent of xad */ int twm; /* diff --git a/fs/libfs.c b/fs/libfs.c index cf79196535ec..d93842d3c0a0 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -190,6 +190,10 @@ const struct inode_operations simple_dir_inode_operations = { .lookup = simple_lookup, }; +static const struct super_operations simple_super_operations = { + .statfs = simple_statfs, +}; + /* * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that * will never be mountable) @@ -199,7 +203,6 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name, struct vfsmount *mnt) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); - static const struct super_operations default_ops = {.statfs = simple_statfs}; struct dentry *dentry; struct inode *root; struct qstr d_name = {.name = name, .len = strlen(name)}; @@ -212,7 +215,7 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name, s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = magic; - s->s_op = ops ? ops : &default_ops; + s->s_op = ops ? ops : &simple_super_operations; s->s_time_gran = 1; root = new_inode(s); if (!root) @@ -359,7 +362,6 @@ int simple_commit_write(struct file *file, struct page *page, int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files) { - static struct super_operations s_ops = {.statfs = simple_statfs}; struct inode *inode; struct dentry *root; struct dentry *dentry; @@ -368,7 +370,7 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files s->s_blocksize = PAGE_CACHE_SIZE; s->s_blocksize_bits = PAGE_CACHE_SHIFT; s->s_magic = magic; - s->s_op = &s_ops; + s->s_op = &simple_super_operations; s->s_time_gran = 1; inode = new_inode(s); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 14939ddf74f1..7285c94956c4 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -576,6 +576,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) server->packet = vmalloc(NCP_PACKET_SIZE); if (server->packet == NULL) goto out_nls; + server->txbuf = vmalloc(NCP_PACKET_SIZE); + if (server->txbuf == NULL) + goto out_packet; + server->rxbuf = vmalloc(NCP_PACKET_SIZE); + if (server->rxbuf == NULL) + goto out_txbuf; sock->sk->sk_data_ready = ncp_tcp_data_ready; sock->sk->sk_error_report = ncp_tcp_error_report; @@ -597,7 +603,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) error = ncp_connect(server); ncp_unlock_server(server); if (error < 0) - goto out_packet; + goto out_rxbuf; DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb)); error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */ @@ -666,8 +672,12 @@ out_disconnect: ncp_lock_server(server); ncp_disconnect(server); ncp_unlock_server(server); -out_packet: +out_rxbuf: ncp_stop_tasks(server); + vfree(server->rxbuf); +out_txbuf: + vfree(server->txbuf); +out_packet: vfree(server->packet); out_nls: #ifdef CONFIG_NCPFS_NLS @@ -723,6 +733,8 @@ static void ncp_put_super(struct super_block *sb) kfree(server->priv.data); kfree(server->auth.object_name); + vfree(server->rxbuf); + vfree(server->txbuf); vfree(server->packet); sb->s_fs_info = NULL; kfree(server); diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index e496d8b65e92..e37df8d5fe70 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -14,6 +14,7 @@ #include <linux/socket.h> #include <linux/fcntl.h> #include <linux/stat.h> +#include <linux/string.h> #include <asm/uaccess.h> #include <linux/in.h> #include <linux/net.h> @@ -55,10 +56,11 @@ static int _send(struct socket *sock, const void *buff, int len) struct ncp_request_reply { struct list_head req; wait_queue_head_t wq; - struct ncp_reply_header* reply_buf; + atomic_t refs; + unsigned char* reply_buf; size_t datalen; int result; - enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE } status; + enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status; struct kvec* tx_ciov; size_t tx_totallen; size_t tx_iovlen; @@ -67,6 +69,32 @@ struct ncp_request_reply { u_int32_t sign[6]; }; +static inline struct ncp_request_reply* ncp_alloc_req(void) +{ + struct ncp_request_reply *req; + + req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL); + if (!req) + return NULL; + + init_waitqueue_head(&req->wq); + atomic_set(&req->refs, (1)); + req->status = RQ_IDLE; + + return req; +} + +static void ncp_req_get(struct ncp_request_reply *req) +{ + atomic_inc(&req->refs); +} + +static void ncp_req_put(struct ncp_request_reply *req) +{ + if (atomic_dec_and_test(&req->refs)) + kfree(req); +} + void ncp_tcp_data_ready(struct sock *sk, int len) { struct ncp_server *server = sk->sk_user_data; @@ -101,14 +129,17 @@ void ncpdgram_timeout_call(unsigned long v) schedule_work(&server->timeout_tq); } -static inline void ncp_finish_request(struct ncp_request_reply *req, int result) +static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result) { req->result = result; + if (req->status != RQ_ABANDONED) + memcpy(req->reply_buf, server->rxbuf, req->datalen); req->status = RQ_DONE; wake_up_all(&req->wq); + ncp_req_put(req); } -static void __abort_ncp_connection(struct ncp_server *server, struct ncp_request_reply *aborted, int err) +static void __abort_ncp_connection(struct ncp_server *server) { struct ncp_request_reply *req; @@ -118,31 +149,19 @@ static void __abort_ncp_connection(struct ncp_server *server, struct ncp_request req = list_entry(server->tx.requests.next, struct ncp_request_reply, req); list_del_init(&req->req); - if (req == aborted) { - ncp_finish_request(req, err); - } else { - ncp_finish_request(req, -EIO); - } + ncp_finish_request(server, req, -EIO); } req = server->rcv.creq; if (req) { server->rcv.creq = NULL; - if (req == aborted) { - ncp_finish_request(req, err); - } else { - ncp_finish_request(req, -EIO); - } + ncp_finish_request(server, req, -EIO); server->rcv.ptr = NULL; server->rcv.state = 0; } req = server->tx.creq; if (req) { server->tx.creq = NULL; - if (req == aborted) { - ncp_finish_request(req, err); - } else { - ncp_finish_request(req, -EIO); - } + ncp_finish_request(server, req, -EIO); } } @@ -160,10 +179,12 @@ static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_req break; case RQ_QUEUED: list_del_init(&req->req); - ncp_finish_request(req, err); + ncp_finish_request(server, req, err); break; case RQ_INPROGRESS: - __abort_ncp_connection(server, req, err); + req->status = RQ_ABANDONED; + break; + case RQ_ABANDONED: break; } } @@ -177,7 +198,7 @@ static inline void ncp_abort_request(struct ncp_server *server, struct ncp_reque static inline void __ncptcp_abort(struct ncp_server *server) { - __abort_ncp_connection(server, NULL, 0); + __abort_ncp_connection(server); } static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req) @@ -294,6 +315,11 @@ static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_r static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req) { + /* we copy the data so that we do not depend on the caller + staying alive */ + memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len); + req->tx_iov[1].iov_base = server->txbuf; + if (server->ncp_sock->type == SOCK_STREAM) ncptcp_start_request(server, req); else @@ -308,6 +334,7 @@ static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply * printk(KERN_ERR "ncpfs: tcp: Server died\n"); return -EIO; } + ncp_req_get(req); if (server->tx.creq || server->rcv.creq) { req->status = RQ_QUEUED; list_add_tail(&req->req, &server->tx.requests); @@ -409,7 +436,7 @@ void ncpdgram_rcv_proc(struct work_struct *work) server->timeout_last = NCP_MAX_RPC_TIMEOUT; mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT); } else if (reply.type == NCP_REPLY) { - result = _recv(sock, (void*)req->reply_buf, req->datalen, MSG_DONTWAIT); + result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT); #ifdef CONFIG_NCPFS_PACKET_SIGNING if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) { if (result < 8 + 8) { @@ -419,7 +446,7 @@ void ncpdgram_rcv_proc(struct work_struct *work) result -= 8; hdrl = sock->sk->sk_family == AF_INET ? 8 : 6; - if (sign_verify_reply(server, ((char*)req->reply_buf) + hdrl, result - hdrl, cpu_to_le32(result), ((char*)req->reply_buf) + result)) { + if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) { printk(KERN_INFO "ncpfs: Signature violation\n"); result = -EIO; } @@ -428,7 +455,7 @@ void ncpdgram_rcv_proc(struct work_struct *work) #endif del_timer(&server->timeout_tm); server->rcv.creq = NULL; - ncp_finish_request(req, result); + ncp_finish_request(server, req, result); __ncp_next_request(server); mutex_unlock(&server->rcv.creq_mutex); continue; @@ -478,12 +505,6 @@ void ncpdgram_timeout_proc(struct work_struct *work) mutex_unlock(&server->rcv.creq_mutex); } -static inline void ncp_init_req(struct ncp_request_reply* req) -{ - init_waitqueue_head(&req->wq); - req->status = RQ_IDLE; -} - static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len) { int result; @@ -601,8 +622,8 @@ skipdata:; goto skipdata; } req->datalen = datalen - 8; - req->reply_buf->type = NCP_REPLY; - server->rcv.ptr = (unsigned char*)(req->reply_buf) + 2; + ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY; + server->rcv.ptr = server->rxbuf + 2; server->rcv.len = datalen - 10; server->rcv.state = 1; break; @@ -615,12 +636,12 @@ skipdata:; case 1: req = server->rcv.creq; if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) { - if (req->reply_buf->sequence != server->sequence) { + if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) { printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n"); __ncp_abort_request(server, req, -EIO); return -EIO; } - if ((req->reply_buf->conn_low | (req->reply_buf->conn_high << 8)) != server->connection) { + if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) { printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n"); __ncp_abort_request(server, req, -EIO); return -EIO; @@ -628,14 +649,14 @@ skipdata:; } #ifdef CONFIG_NCPFS_PACKET_SIGNING if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) { - if (sign_verify_reply(server, (unsigned char*)(req->reply_buf) + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) { + if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) { printk(KERN_ERR "ncpfs: tcp: Signature violation\n"); __ncp_abort_request(server, req, -EIO); return -EIO; } } #endif - ncp_finish_request(req, req->datalen); + ncp_finish_request(server, req, req->datalen); nextreq:; __ncp_next_request(server); case 2: @@ -645,7 +666,7 @@ skipdata:; server->rcv.state = 0; break; case 3: - ncp_finish_request(server->rcv.creq, -EIO); + ncp_finish_request(server, server->rcv.creq, -EIO); goto nextreq; case 5: info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len); @@ -675,28 +696,39 @@ void ncp_tcp_tx_proc(struct work_struct *work) } static int do_ncp_rpc_call(struct ncp_server *server, int size, - struct ncp_reply_header* reply_buf, int max_reply_size) + unsigned char* reply_buf, int max_reply_size) { int result; - struct ncp_request_reply req; - - ncp_init_req(&req); - req.reply_buf = reply_buf; - req.datalen = max_reply_size; - req.tx_iov[1].iov_base = server->packet; - req.tx_iov[1].iov_len = size; - req.tx_iovlen = 1; - req.tx_totallen = size; - req.tx_type = *(u_int16_t*)server->packet; - - result = ncp_add_request(server, &req); - if (result < 0) { - return result; - } - if (wait_event_interruptible(req.wq, req.status == RQ_DONE)) { - ncp_abort_request(server, &req, -EIO); + struct ncp_request_reply *req; + + req = ncp_alloc_req(); + if (!req) + return -ENOMEM; + + req->reply_buf = reply_buf; + req->datalen = max_reply_size; + req->tx_iov[1].iov_base = server->packet; + req->tx_iov[1].iov_len = size; + req->tx_iovlen = 1; + req->tx_totallen = size; + req->tx_type = *(u_int16_t*)server->packet; + + result = ncp_add_request(server, req); + if (result < 0) + goto out; + + if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) { + ncp_abort_request(server, req, -EINTR); + result = -EINTR; + goto out; } - return req.result; + + result = req->result; + +out: + ncp_req_put(req); + + return result; } /* @@ -751,11 +783,6 @@ static int ncp_do_request(struct ncp_server *server, int size, DDPRINTK("do_ncp_rpc_call returned %d\n", result); - if (result < 0) { - /* There was a problem with I/O, so the connections is - * no longer usable. */ - ncp_invalidate_conn(server); - } return result; } diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 8813990304fe..85a668680f82 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -431,6 +431,8 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent) new_parent_dentry = new_parent ? new_parent->dentry : sysfs_mount->mnt_sb->s_root; + if (old_parent_dentry->d_inode == new_parent_dentry->d_inode) + return 0; /* nothing to move */ again: mutex_lock(&old_parent_dentry->d_inode->i_mutex); if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) { diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 98b0910ad80c..8d4d839a9d88 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -502,6 +502,30 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) /** + * sysfs_add_file_to_group - add an attribute file to a pre-existing group. + * @kobj: object we're acting for. + * @attr: attribute descriptor. + * @group: group name. + */ +int sysfs_add_file_to_group(struct kobject *kobj, + const struct attribute *attr, const char *group) +{ + struct dentry *dir; + int error; + + dir = lookup_one_len(group, kobj->dentry, strlen(group)); + if (IS_ERR(dir)) + error = PTR_ERR(dir); + else { + error = sysfs_add_file(dir, attr, SYSFS_KOBJ_ATTR); + dput(dir); + } + return error; +} +EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); + + +/** * sysfs_update_file - update the modified timestamp on an object attribute. * @kobj: object we're acting for. * @attr: attribute descriptor. @@ -586,6 +610,26 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) } +/** + * sysfs_remove_file_from_group - remove an attribute file from a group. + * @kobj: object we're acting for. + * @attr: attribute descriptor. + * @group: group name. + */ +void sysfs_remove_file_from_group(struct kobject *kobj, + const struct attribute *attr, const char *group) +{ + struct dentry *dir; + + dir = lookup_one_len(group, kobj->dentry, strlen(group)); + if (!IS_ERR(dir)) { + sysfs_hash_and_remove(dir, attr->name); + dput(dir); + } +} +EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); + + EXPORT_SYMBOL_GPL(sysfs_create_file); EXPORT_SYMBOL_GPL(sysfs_remove_file); EXPORT_SYMBOL_GPL(sysfs_update_file); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index d976b0005549..a77c57e5a6d5 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -1,3 +1,14 @@ +struct sysfs_dirent { + atomic_t s_count; + struct list_head s_sibling; + struct list_head s_children; + void * s_element; + int s_type; + umode_t s_mode; + struct dentry * s_dentry; + struct iattr * s_iattr; + atomic_t s_event; +}; extern struct vfsmount * sysfs_mount; extern struct kmem_cache *sysfs_dir_cachep; |