aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-12-14 16:38:46 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-12-14 17:45:11 -0500
commit1f018458b30b0d5c535c94e577aa0acbb92e1395 (patch)
tree5eda746d742869a4441ce4032e8ca1b60e4eca07
parenteed9935745cc44071043ec8c4cde64c820b5c601 (diff)
NFS: Fix calls to drop_nlink()
It is almost always wrong for NFS to call drop_nlink() after removing a file. What we really want is to mark the inode's attributes for revalidation, and we want to ensure that the VFS drops it if we're reasonably sure that this is the final unlink(). Do the former using the usual cache validity flags, and the latter by testing if inode->i_nlink == 1, and clearing it in that case. This also fixes the following warning reported by Neil Brown and Jeff Layton (among others). [634155.004438] WARNING: at /home/abuild/rpmbuild/BUILD/kernel-desktop-3.5.0/lin [634155.004442] Hardware name: Latitude E6510 [634155.004577] crc_itu_t crc32c_intel snd_hwdep snd_pcm snd_timer snd soundcor [634155.004609] Pid: 13402, comm: bash Tainted: G W 3.5.0-36-desktop # [634155.004611] Call Trace: [634155.004630] [<ffffffff8100444a>] dump_trace+0xaa/0x2b0 [634155.004641] [<ffffffff815a23dc>] dump_stack+0x69/0x6f [634155.004653] [<ffffffff81041a0b>] warn_slowpath_common+0x7b/0xc0 [634155.004662] [<ffffffff811832e4>] drop_nlink+0x34/0x40 [634155.004687] [<ffffffffa05bb6c3>] nfs_dentry_iput+0x33/0x70 [nfs] [634155.004714] [<ffffffff8118049e>] dput+0x12e/0x230 [634155.004726] [<ffffffff8116b230>] __fput+0x170/0x230 [634155.004735] [<ffffffff81167c0f>] filp_close+0x5f/0x90 [634155.004743] [<ffffffff81167cd7>] sys_close+0x97/0x100 [634155.004754] [<ffffffff815c3b39>] system_call_fastpath+0x16/0x1b [634155.004767] [<00007f2a73a0d110>] 0x7f2a73a0d10f Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: stable@vger.kernel.org [3.3+]
-rw-r--r--fs/nfs/dir.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index ce8cb926526b..a46a74654488 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1155,11 +1155,14 @@ static int nfs_dentry_delete(const struct dentry *dentry)
1155 1155
1156} 1156}
1157 1157
1158/* Ensure that we revalidate inode->i_nlink */
1158static void nfs_drop_nlink(struct inode *inode) 1159static void nfs_drop_nlink(struct inode *inode)
1159{ 1160{
1160 spin_lock(&inode->i_lock); 1161 spin_lock(&inode->i_lock);
1161 if (inode->i_nlink > 0) 1162 /* drop the inode if we're reasonably sure this is the last link */
1162 drop_nlink(inode); 1163 if (inode->i_nlink == 1)
1164 clear_nlink(inode);
1165 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
1163 spin_unlock(&inode->i_lock); 1166 spin_unlock(&inode->i_lock);
1164} 1167}
1165 1168
@@ -1174,8 +1177,8 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
1174 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; 1177 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
1175 1178
1176 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { 1179 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
1177 drop_nlink(inode);
1178 nfs_complete_unlink(dentry, inode); 1180 nfs_complete_unlink(dentry, inode);
1181 nfs_drop_nlink(inode);
1179 } 1182 }
1180 iput(inode); 1183 iput(inode);
1181} 1184}
@@ -1646,10 +1649,8 @@ static int nfs_safe_remove(struct dentry *dentry)
1646 if (inode != NULL) { 1649 if (inode != NULL) {
1647 NFS_PROTO(inode)->return_delegation(inode); 1650 NFS_PROTO(inode)->return_delegation(inode);
1648 error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); 1651 error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
1649 /* The VFS may want to delete this inode */
1650 if (error == 0) 1652 if (error == 0)
1651 nfs_drop_nlink(inode); 1653 nfs_drop_nlink(inode);
1652 nfs_mark_for_revalidate(inode);
1653 } else 1654 } else
1654 error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); 1655 error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
1655 if (error == -ENOENT) 1656 if (error == -ENOENT)