aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-10-15 18:17:53 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-10-19 17:19:16 -0400
commit565277f63c616e11c37309a1e98c052d18ebbb55 (patch)
tree60fdddc5a1c97df696392e47ead71d33d39e487f /fs/nfs/nfs4proc.c
parent61e930a904966cc37e0a3404276f0b73037e57ca (diff)
NFS: Fix a race in sillyrename
lookup() and sillyrename() can race one another because the sillyrename() completion cannot take the parent directory's inode->i_mutex since the latter may be held by whoever is calling dput(). We therefore have little option but to add extra locking to ensure that nfs_lookup() and nfs_atomic_open() do not race with the sillyrename completion. If somebody has looked up the sillyrenamed file in the meantime, we just transfer the sillydelete information to the new dentry. Please refer to the bug-report at http://bugzilla.linux-nfs.org/show_bug.cgi?id=150 Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index cb99fd90a9ac..2cb3b8b71ee7 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1372,6 +1372,7 @@ out_close:
1372struct dentry * 1372struct dentry *
1373nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 1373nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1374{ 1374{
1375 struct dentry *parent;
1375 struct path path = { 1376 struct path path = {
1376 .mnt = nd->mnt, 1377 .mnt = nd->mnt,
1377 .dentry = dentry, 1378 .dentry = dentry,
@@ -1394,6 +1395,9 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1394 cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); 1395 cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
1395 if (IS_ERR(cred)) 1396 if (IS_ERR(cred))
1396 return (struct dentry *)cred; 1397 return (struct dentry *)cred;
1398 parent = dentry->d_parent;
1399 /* Protect against concurrent sillydeletes */
1400 nfs_block_sillyrename(parent);
1397 state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); 1401 state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
1398 put_rpccred(cred); 1402 put_rpccred(cred);
1399 if (IS_ERR(state)) { 1403 if (IS_ERR(state)) {
@@ -1401,12 +1405,14 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1401 d_add(dentry, NULL); 1405 d_add(dentry, NULL);
1402 nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 1406 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1403 } 1407 }
1408 nfs_unblock_sillyrename(parent);
1404 return (struct dentry *)state; 1409 return (struct dentry *)state;
1405 } 1410 }
1406 res = d_add_unique(dentry, igrab(state->inode)); 1411 res = d_add_unique(dentry, igrab(state->inode));
1407 if (res != NULL) 1412 if (res != NULL)
1408 path.dentry = res; 1413 path.dentry = res;
1409 nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); 1414 nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
1415 nfs_unblock_sillyrename(parent);
1410 nfs4_intent_set_file(nd, &path, state); 1416 nfs4_intent_set_file(nd, &path, state);
1411 return res; 1417 return res;
1412} 1418}