From 44d6f78756560e95903de239e10f8a40a6eae444 Mon Sep 17 00:00:00 2001 From: Hidehiro Kawai Date: Mon, 27 Oct 2008 22:51:46 -0400 Subject: ext3: fix a bug accessing freed memory in ext3_abort Vegard Nossum reported a bug which accesses freed memory (found via kmemcheck). When journal has been aborted, ext3_put_super() calls ext3_abort() after freeing the journal_t object, and then ext3_abort() accesses it. This patch fix it. Signed-off-by: Hidehiro Kawai Acked-by: Jan Kara Signed-off-by: "Theodore Ts'o" --- fs/ext3/super.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 18eaa78ecb4e..e5717a4fae67 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -281,7 +281,8 @@ void ext3_abort (struct super_block * sb, const char * function, EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; sb->s_flags |= MS_RDONLY; EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; - journal_abort(EXT3_SB(sb)->s_journal, -EIO); + if (EXT3_SB(sb)->s_journal) + journal_abort(EXT3_SB(sb)->s_journal, -EIO); } void ext3_warning (struct super_block * sb, const char * function, @@ -390,11 +391,14 @@ static void ext3_put_super (struct super_block * sb) { struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; - int i; + int i, err; ext3_xattr_put_super(sb); - if (journal_destroy(sbi->s_journal) < 0) + err = journal_destroy(sbi->s_journal); + sbi->s_journal = NULL; + if (err < 0) ext3_abort(sb, __func__, "Couldn't clean up the journal"); + if (!(sb->s_flags & MS_RDONLY)) { EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); es->s_state = cpu_to_le16(sbi->s_mount_state); -- cgit v1.2.2 From ef2cabf7c6d838eb0ee2b4fb8ef84f7c06ce16d9 Mon Sep 17 00:00:00 2001 From: Hidehiro Kawai Date: Mon, 27 Oct 2008 22:53:05 -0400 Subject: ext4: fix a bug accessing freed memory in ext4_abort Vegard Nossum reported a bug which accesses freed memory (found via kmemcheck). When journal has been aborted, ext4_put_super() calls ext4_abort() after freeing the journal_t object, and then ext4_abort() accesses it. This patch fix it. Signed-off-by: Hidehiro Kawai Acked-by: Jan Kara Signed-off-by: "Theodore Ts'o" --- fs/ext4/super.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/ext4/super.c b/fs/ext4/super.c index bdddea14e782..994859df010e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -333,7 +333,8 @@ void ext4_abort(struct super_block *sb, const char *function, EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; sb->s_flags |= MS_RDONLY; EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; - jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); + if (EXT4_SB(sb)->s_journal) + jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); } void ext4_warning(struct super_block *sb, const char *function, @@ -442,14 +443,16 @@ static void ext4_put_super(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; - int i; + int i, err; ext4_mb_release(sb); ext4_ext_release(sb); ext4_xattr_put_super(sb); - if (jbd2_journal_destroy(sbi->s_journal) < 0) - ext4_abort(sb, __func__, "Couldn't clean up the journal"); + err = jbd2_journal_destroy(sbi->s_journal); sbi->s_journal = NULL; + if (err < 0) + ext4_abort(sb, __func__, "Couldn't clean up the journal"); + if (!(sb->s_flags & MS_RDONLY)) { EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); es->s_state = cpu_to_le16(sbi->s_mount_state); -- cgit v1.2.2 From 6c20ec850360bc6e5c66a787f0523a80450d65ab Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 28 Oct 2008 21:08:20 -0400 Subject: jbd2: Call the commit callback before the transaction could get dropped The transaction can potentially get dropped if there are no buffers that need to be written. Make sure we call the commit callback before potentially deciding to drop the transaction. Also avoid dereferencing the commit_transaction pointer in the marker for the same reason. This patch fixes the bug reported by Eric Paris at: http://bugzilla.kernel.org/show_bug.cgi?id=11838 Signed-off-by: "Theodore Ts'o" Acked-by: Eric Sandeen Tested-by: Eric Paris --- fs/jbd2/commit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 8b119e16aa36..ebc667bc54a8 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -974,6 +974,9 @@ restart_loop: journal->j_committing_transaction = NULL; spin_unlock(&journal->j_state_lock); + if (journal->j_commit_callback) + journal->j_commit_callback(journal, commit_transaction); + if (commit_transaction->t_checkpoint_list == NULL && commit_transaction->t_checkpoint_io_list == NULL) { __jbd2_journal_drop_transaction(journal, commit_transaction); @@ -995,11 +998,8 @@ restart_loop: } spin_unlock(&journal->j_list_lock); - if (journal->j_commit_callback) - journal->j_commit_callback(journal, commit_transaction); - trace_mark(jbd2_end_commit, "dev %s transaction %d head %d", - journal->j_devname, commit_transaction->t_tid, + journal->j_devname, journal->j_commit_sequence, journal->j_tail_sequence); jbd_debug(1, "JBD: commit %d complete, head %d\n", journal->j_commit_sequence, journal->j_tail_sequence); -- cgit v1.2.2 From 8c3bf8a01c005385e9be0bc992e10abfb355278c Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 28 Oct 2008 00:08:12 -0400 Subject: merge ext4_claim_free_blocks & ext4_has_free_blocks Mingming pointed out that ext4_claim_free_blocks & ext4_has_free_blocks are largely cut & pasted; they can be collapsed/merged as follows. Signed-off-by: Eric Sandeen Reviewed-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/balloc.c | 57 ++++++++++++++++---------------------------------------- fs/ext4/ext4.h | 3 +-- 2 files changed, 17 insertions(+), 43 deletions(-) (limited to 'fs') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index b9821be709bd..e28203ec45bd 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -589,8 +589,15 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, return; } -int ext4_claim_free_blocks(struct ext4_sb_info *sbi, - s64 nblocks) +/** + * ext4_has_free_blocks() + * @sbi: in-core super block structure. + * @nblocks: number of needed blocks + * + * Check if filesystem has nblocks free & available for allocation. + * On success return 1, return 0 on failure. + */ +int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) { s64 free_blocks, dirty_blocks; s64 root_blocks = 0; @@ -620,53 +627,21 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi, */ if (free_blocks < ((root_blocks + nblocks) + dirty_blocks)) /* we don't have free space */ - return -ENOSPC; + return 0; - /* Add the blocks to nblocks */ - percpu_counter_add(dbc, nblocks); - return 0; + return 1; } -/** - * ext4_has_free_blocks() - * @sbi: in-core super block structure. - * @nblocks: number of neeed blocks - * - * Check if filesystem has free blocks available for allocation. - * Return the number of blocks avaible for allocation for this request - * On success, return nblocks - */ -ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, +int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) { - s64 free_blocks, dirty_blocks; - s64 root_blocks = 0; - struct percpu_counter *fbc = &sbi->s_freeblocks_counter; - struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; - - free_blocks = percpu_counter_read_positive(fbc); - dirty_blocks = percpu_counter_read_positive(dbc); - - if (!capable(CAP_SYS_RESOURCE) && - sbi->s_resuid != current->fsuid && - (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) - root_blocks = ext4_r_blocks_count(sbi->s_es); - - if (free_blocks - (nblocks + root_blocks + dirty_blocks) < - EXT4_FREEBLOCKS_WATERMARK) { - free_blocks = percpu_counter_sum(fbc); - dirty_blocks = percpu_counter_sum(dbc); - } - if (free_blocks <= (root_blocks + dirty_blocks)) - /* we don't have free space */ + if (ext4_has_free_blocks(sbi, nblocks)) { + percpu_counter_add(&sbi->s_dirtyblocks_counter, nblocks); return 0; - - if (free_blocks - (root_blocks + dirty_blocks) < nblocks) - return free_blocks - (root_blocks + dirty_blocks); - return nblocks; + } else + return -ENOSPC; } - /** * ext4_should_retry_alloc() * @sb: super block diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4880cc3e6727..b0537c827024 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1003,8 +1003,7 @@ extern ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, ext4_lblk_t iblock, ext4_fsblk_t goal, unsigned long *count, int *errp); extern int ext4_claim_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); -extern ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, - s64 nblocks); +extern int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks); extern void ext4_free_blocks(handle_t *handle, struct inode *inode, ext4_fsblk_t block, unsigned long count, int metadata); extern void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, -- cgit v1.2.2 From a996031c87e093017c0763326a08896a3a4817f4 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 28 Oct 2008 00:08:17 -0400 Subject: delay capable() check in ext4_has_free_blocks() As reported by Eric Paris, the capable() check in ext4_has_free_blocks() sometimes causes SELinux denials. We can rearrange the logic so that we only try to use the root-reserved blocks when necessary, and even then we can move the capable() test to last, to avoid the check most of the time. Signed-off-by: Eric Sandeen Reviewed-by: Mingming Cao Signed-off-by: "Theodore Ts'o" --- fs/ext4/balloc.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index e28203ec45bd..d2003cdc36aa 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -599,18 +599,13 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, */ int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) { - s64 free_blocks, dirty_blocks; - s64 root_blocks = 0; + s64 free_blocks, dirty_blocks, root_blocks; struct percpu_counter *fbc = &sbi->s_freeblocks_counter; struct percpu_counter *dbc = &sbi->s_dirtyblocks_counter; free_blocks = percpu_counter_read_positive(fbc); dirty_blocks = percpu_counter_read_positive(dbc); - - if (!capable(CAP_SYS_RESOURCE) && - sbi->s_resuid != current->fsuid && - (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) - root_blocks = ext4_r_blocks_count(sbi->s_es); + root_blocks = ext4_r_blocks_count(sbi->s_es); if (free_blocks - (nblocks + root_blocks + dirty_blocks) < EXT4_FREEBLOCKS_WATERMARK) { @@ -623,13 +618,20 @@ int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks) } } /* Check whether we have space after - * accounting for current dirty blocks + * accounting for current dirty blocks & root reserved blocks. */ - if (free_blocks < ((root_blocks + nblocks) + dirty_blocks)) - /* we don't have free space */ - return 0; + if (free_blocks >= ((root_blocks + nblocks) + dirty_blocks)) + return 1; - return 1; + /* Hm, nope. Are (enough) root reserved blocks available? */ + if (sbi->s_resuid == current->fsuid || + ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) || + capable(CAP_SYS_RESOURCE)) { + if (free_blocks >= (nblocks + dirty_blocks)) + return 1; + } + + return 0; } int ext4_claim_free_blocks(struct ext4_sb_info *sbi, -- cgit v1.2.2 From ae05f269400533cbb32bfba131ab528d78dffd16 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 28 Oct 2008 15:21:40 -0400 Subject: NFS: Convert nfs_attr_generation_counter into an atomic_long The most important property we need from nfs_attr_generation_counter is monotonicity, which is not guaranteed by the current system of smp memory barriers. We should convert it to an atomic_long_t, and drop the memory barriers. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index dc52793ff8f8..d22eb383e1cf 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -908,21 +908,16 @@ static int nfs_size_need_update(const struct inode *inode, const struct nfs_fatt return nfs_size_to_loff_t(fattr->size) > i_size_read(inode); } -static unsigned long nfs_attr_generation_counter; +static atomic_long_t nfs_attr_generation_counter; static unsigned long nfs_read_attr_generation_counter(void) { - smp_rmb(); - return nfs_attr_generation_counter; + return atomic_long_read(&nfs_attr_generation_counter); } unsigned long nfs_inc_attr_generation_counter(void) { - unsigned long ret; - smp_rmb(); - ret = ++nfs_attr_generation_counter; - smp_wmb(); - return ret; + return atomic_long_inc_return(&nfs_attr_generation_counter); } void nfs_fattr_init(struct nfs_fattr *fattr) -- cgit v1.2.2 From 4e02ed4b4a2fae34aae766a5bb93ae235f60adb8 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 29 Oct 2008 14:00:55 -0700 Subject: fs: remove prepare_write/commit_write Nothing uses prepare_write or commit_write. Remove them from the tree completely. [akpm@linux-foundation.org: schedule simple_prepare_write() for unexporting] Signed-off-by: Nick Piggin Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/inode.c | 2 +- fs/libfs.c | 2 +- fs/ocfs2/file.c | 3 +-- fs/splice.c | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 19eafbe3c379..2b2eec1283bf 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -175,7 +175,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, if (rw == WRITE) { /* - * FIXME: blockdev_direct_IO() doesn't use ->prepare_write(), + * FIXME: blockdev_direct_IO() doesn't use ->write_begin(), * so we need to update the ->mmu_private to block boundary. * * But we must fill the remaining area or hole by nul for diff --git a/fs/libfs.c b/fs/libfs.c index 74688598bcf7..e960a8321902 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -814,7 +814,7 @@ EXPORT_SYMBOL(simple_getattr); EXPORT_SYMBOL(simple_link); EXPORT_SYMBOL(simple_lookup); EXPORT_SYMBOL(simple_pin_fs); -EXPORT_SYMBOL(simple_prepare_write); +EXPORT_UNUSED_SYMBOL(simple_prepare_write); EXPORT_SYMBOL(simple_readpage); EXPORT_SYMBOL(simple_release_fs); EXPORT_SYMBOL(simple_rename); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 8d3225a78073..7efe937a415f 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -679,8 +679,7 @@ leave: /* Some parts of this taken from generic_cont_expand, which turned out * to be too fragile to do exactly what we need without us having to - * worry about recursive locking in ->prepare_write() and - * ->commit_write(). */ + * worry about recursive locking in ->write_begin() and ->write_end(). */ static int ocfs2_write_zero_page(struct inode *inode, u64 size) { diff --git a/fs/splice.c b/fs/splice.c index a1e701c27156..1abab5cee4ba 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -731,8 +731,8 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, }; /* - * The actor worker might be calling ->prepare_write and - * ->commit_write. Most of the time, these expect i_mutex to + * The actor worker might be calling ->write_begin and + * ->write_end. Most of the time, these expect i_mutex to * be held. Since this may result in an ABBA deadlock with * pipe->inode, we have to order lock acquiry here. */ -- cgit v1.2.2 From 87b811c3f96559e466403e22b1fa99d472571625 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Wed, 29 Oct 2008 14:01:08 -0700 Subject: ecryptfs: fix memory corruption when storing crypto info in xattrs When ecryptfs allocates space to write crypto headers into, before copying it out to file headers or to xattrs, it looks at the value of crypt_stat->num_header_bytes_at_front to determine how much space it needs. This is also used as the file offset to the actual encrypted data, so for xattr-stored crypto info, the value was zero. So, we kzalloc'd 0 bytes, and then ran off to write to that memory. (Which returned as ZERO_SIZE_PTR, so we explode quickly). The right answer is to always allocate a page to write into; the current code won't ever write more than that (this is enforced by the (PAGE_CACHE_SIZE - offset) length in the call to ecryptfs_generate_key_packet_set). To be explicit about this, we now send in a "max" parameter, rather than magically using PAGE_CACHE_SIZE there. Also, since the pointer we pass down the callchain eventually gets the virt_to_page() treatment, we should be using a alloc_page variant, not kzalloc (see also 7fcba054373d5dfc43d26e243a5c9b92069972ee) Signed-off-by: Eric Sandeen Acked-by: Michael Halcrow Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ecryptfs/crypto.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 06db79d05c12..6046239465a1 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1251,6 +1251,7 @@ struct kmem_cache *ecryptfs_header_cache_2; /** * ecryptfs_write_headers_virt * @page_virt: The virtual address to write the headers to + * @max: The size of memory allocated at page_virt * @size: Set to the number of bytes written by this function * @crypt_stat: The cryptographic context * @ecryptfs_dentry: The eCryptfs dentry @@ -1278,7 +1279,8 @@ struct kmem_cache *ecryptfs_header_cache_2; * * Returns zero on success */ -static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, +static int ecryptfs_write_headers_virt(char *page_virt, size_t max, + size_t *size, struct ecryptfs_crypt_stat *crypt_stat, struct dentry *ecryptfs_dentry) { @@ -1296,7 +1298,7 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, offset += written; rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat, ecryptfs_dentry, &written, - PAGE_CACHE_SIZE - offset); + max - offset); if (rc) ecryptfs_printk(KERN_WARNING, "Error generating key packet " "set; rc = [%d]\n", rc); @@ -1368,14 +1370,14 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) goto out; } /* Released in this function */ - virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL); + virt = (char *)get_zeroed_page(GFP_KERNEL); if (!virt) { printk(KERN_ERR "%s: Out of memory\n", __func__); rc = -ENOMEM; goto out; } - rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat, - ecryptfs_dentry); + rc = ecryptfs_write_headers_virt(virt, PAGE_CACHE_SIZE, &size, + crypt_stat, ecryptfs_dentry); if (unlikely(rc)) { printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n", __func__, rc); @@ -1393,8 +1395,7 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) goto out_free; } out_free: - memset(virt, 0, crypt_stat->num_header_bytes_at_front); - kfree(virt); + free_page((unsigned long)virt); out: return rc; } -- cgit v1.2.2 From e74481e23283fb080d4591c258de20785cc3b6c3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 29 Oct 2008 14:01:10 -0700 Subject: fs: remove excess kernel-doc Delete excess kernel-doc notation in fs/ subdirectory: Warning(linux-2.6.27-git10//fs/jbd/transaction.c:886): Excess function parameter or struct member 'credits' description in 'journal_get_undo_access' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/jbd/transaction.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index d15cd6e7251e..60d4c32c8808 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -860,7 +860,6 @@ out: * int journal_get_undo_access() - Notify intent to modify metadata with non-rewindable consequences * @handle: transaction * @bh: buffer to undo - * @credits: store the number of taken credits here (if not NULL) * * Sometimes there is a need to distinguish between metadata which has * been committed to disk and that which has not. The ext3fs code uses -- cgit v1.2.2 From 8d7c4203c681a3ec359eccff4e53bc8c0ccf403b Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 30 Oct 2008 13:48:33 -0400 Subject: nfsd: fix failure to set eof in readdir in some situations Before 14f7dd632011bb89c035722edd6ea0d90ca6b078 "[PATCH] Copy XFS readdir hack into nfsd code", readdir_cd->err was reset to eof before each call to vfs_readdir; afterwards, it is set only once. Similarly, c002a6c7977320f95b5edede5ce4e0eeecf291ff "[PATCH] Optimise NFS readdir hack slightly", can cause us to exit without nfserr_eof set. Fix this. This ensures the "eof" bit is set when needed in readdir replies. (The particular case I saw was an nfsv4 readdir of an empty directory, which returned with no entries (the protocol requires "." and ".." to be filtered out), but with eof unset.) Cc: David Woodhouse Cc: Al Viro Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 0bc56f6d9276..848a03e83a42 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1912,6 +1912,7 @@ static int nfsd_buffered_readdir(struct file *file, filldir_t func, de = (struct buffered_dirent *)((char *)de + reclen); } offset = vfs_llseek(file, 0, SEEK_CUR); + cdp->err = nfserr_eof; if (!buf.full) break; } -- cgit v1.2.2 From d7dc61d0a70371b1c6557ea8ffbc60fff94c8168 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 23 Oct 2008 00:50:35 -0400 Subject: NLM: Set address family before calling nlm_host_rebooted() The nlm_host_rebooted() function uses nlm_cmp_addr() to find an nsm_handle that matches the rebooted peer. In order for this to work, the passed-in address must have a proper address family. This fixes a post-2.6.28 regression introduced by commit 781b61a6, which added AF_INET6 support to nlm_cmp_addr(). Before that commit, nlm_cmp_addr() didn't care about the address family; it compared only the sin_addr.s_addr field for equality. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/svc4proc.c | 1 + fs/lockd/svcproc.c | 1 + 2 files changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 014f6ce48172..4dfdcbc6bf68 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -434,6 +434,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, * reclaim all locks we hold on this server. */ memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = argp->addr; nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state); diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 548b0bb2b84d..3ca89e2a9381 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -466,6 +466,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, * reclaim all locks we hold on this server. */ memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = argp->addr; nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state); -- cgit v1.2.2 From 233e70f4228e78eb2f80dc6650f65d3ae3dbf17c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 31 Oct 2008 23:28:30 +0000 Subject: saner FASYNC handling on file close As it is, all instances of ->release() for files that have ->fasync() need to remember to evict file from fasync lists; forgetting that creates a hole and we actually have a bunch that *does* forget. So let's keep our lives simple - let __fput() check FASYNC in file->f_flags and call ->fasync() there if it's been set. And lose that crap in ->release() instances - leaving it there is still valid, but we don't have to bother anymore. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/file_table.c | 4 ++++ fs/fuse/dev.c | 1 - fs/inotify_user.c | 3 --- fs/pipe.c | 3 --- 4 files changed, 4 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/file_table.c b/fs/file_table.c index efc06faede6c..5ad0eca6eea2 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -269,6 +269,10 @@ void __fput(struct file *file) eventpoll_release(file); locks_remove_flock(file); + if (unlikely(file->f_flags & FASYNC)) { + if (file->f_op && file->f_op->fasync) + file->f_op->fasync(-1, file, 0); + } if (file->f_op && file->f_op->release) file->f_op->release(inode, file); security_file_free(file); diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 87250b6a8682..b72361479be2 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1056,7 +1056,6 @@ static int fuse_dev_release(struct inode *inode, struct file *file) end_requests(fc, &fc->pending); end_requests(fc, &fc->processing); spin_unlock(&fc->lock); - fasync_helper(-1, file, 0, &fc->fasync); fuse_conn_put(fc); } diff --git a/fs/inotify_user.c b/fs/inotify_user.c index d85c7d931cdf..d367e9b92862 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -537,9 +537,6 @@ static int inotify_release(struct inode *ignored, struct file *file) inotify_dev_event_dequeue(dev); mutex_unlock(&dev->ev_mutex); - if (file->f_flags & FASYNC) - inotify_fasync(-1, file, 0); - /* free this device: the put matching the get in inotify_init() */ put_inotify_dev(dev); diff --git a/fs/pipe.c b/fs/pipe.c index fcba6542b8d0..7aea8b89baac 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -717,14 +717,12 @@ pipe_rdwr_fasync(int fd, struct file *filp, int on) static int pipe_read_release(struct inode *inode, struct file *filp) { - pipe_read_fasync(-1, filp, 0); return pipe_release(inode, 1, 0); } static int pipe_write_release(struct inode *inode, struct file *filp) { - pipe_write_fasync(-1, filp, 0); return pipe_release(inode, 0, 1); } @@ -733,7 +731,6 @@ pipe_rdwr_release(struct inode *inode, struct file *filp) { int decr, decw; - pipe_rdwr_fasync(-1, filp, 0); decr = (filp->f_mode & FMODE_READ) != 0; decw = (filp->f_mode & FMODE_WRITE) != 0; return pipe_release(inode, decr, decw); -- cgit v1.2.2