diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-09-30 01:41:33 +0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-10-10 01:19:22 +0400 |
commit | fab728e156b3cbfe31f05d6e7cdebe3d5eaff878 (patch) | |
tree | 4a0a9ab57867e33342119e61d52c16d0c9eb7a32 | |
parent | 4b841736bc16b320bcdb1e8ece585b3ced9a8811 (diff) | |
download | linux-fab728e156b3cbfe31f05d6e7cdebe3d5eaff878.tar.xz |
NFS: Ensure nfs_instantiate() invalidates the parent dir on error
Also ensure that it drops the dentry in this case.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/dir.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e275a6eb0a7c..82395c511710 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1174,32 +1174,39 @@ out_renew: int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { + struct dentry *parent = dget_parent(dentry); + struct inode *dir = parent->d_inode; struct inode *inode; int error = -EACCES; + d_drop(dentry); + /* We may have been initialized further down */ if (dentry->d_inode) - return 0; + goto out; if (fhandle->size == 0) { - struct inode *dir = dentry->d_parent->d_inode; error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); if (error) - return error; + goto out_error; } if (!(fattr->valid & NFS_ATTR_FATTR)) { struct nfs_server *server = NFS_SB(dentry->d_sb); error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); if (error < 0) - return error; + goto out_error; } inode = nfs_fhget(dentry->d_sb, fhandle, fattr); error = PTR_ERR(inode); if (IS_ERR(inode)) - return error; - d_instantiate(dentry, inode); - if (d_unhashed(dentry)) - d_rehash(dentry); + goto out_error; + d_add(dentry, inode); +out: + dput(parent); return 0; +out_error: + nfs_mark_for_revalidate(dir); + dput(parent); + return error; } /* |