summaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-09-29 23:41:33 +0200
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-10-09 23:19:22 +0200
commitfab728e156b3cbfe31f05d6e7cdebe3d5eaff878 (patch)
tree4a0a9ab57867e33342119e61d52c16d0c9eb7a32 /fs/nfs
parentNFS: Fix nfs_verify_change_attribute() (diff)
downloadlinux-fab728e156b3cbfe31f05d6e7cdebe3d5eaff878.tar.xz
linux-fab728e156b3cbfe31f05d6e7cdebe3d5eaff878.zip
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>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c23
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;
}
/*