diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-09-29 17:41:33 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-10-09 17:19:22 -0400 |
commit | fab728e156b3cbfe31f05d6e7cdebe3d5eaff878 (patch) | |
tree | 4a0a9ab57867e33342119e61d52c16d0c9eb7a32 /fs/nfs/dir.c | |
parent | 4b841736bc16b320bcdb1e8ece585b3ced9a8811 (diff) |
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/dir.c')
-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: | |||
1174 | int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | 1174 | int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, |
1175 | struct nfs_fattr *fattr) | 1175 | struct nfs_fattr *fattr) |
1176 | { | 1176 | { |
1177 | struct dentry *parent = dget_parent(dentry); | ||
1178 | struct inode *dir = parent->d_inode; | ||
1177 | struct inode *inode; | 1179 | struct inode *inode; |
1178 | int error = -EACCES; | 1180 | int error = -EACCES; |
1179 | 1181 | ||
1182 | d_drop(dentry); | ||
1183 | |||
1180 | /* We may have been initialized further down */ | 1184 | /* We may have been initialized further down */ |
1181 | if (dentry->d_inode) | 1185 | if (dentry->d_inode) |
1182 | return 0; | 1186 | goto out; |
1183 | if (fhandle->size == 0) { | 1187 | if (fhandle->size == 0) { |
1184 | struct inode *dir = dentry->d_parent->d_inode; | ||
1185 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1188 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
1186 | if (error) | 1189 | if (error) |
1187 | return error; | 1190 | goto out_error; |
1188 | } | 1191 | } |
1189 | if (!(fattr->valid & NFS_ATTR_FATTR)) { | 1192 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
1190 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 1193 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
1191 | error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); | 1194 | error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); |
1192 | if (error < 0) | 1195 | if (error < 0) |
1193 | return error; | 1196 | goto out_error; |
1194 | } | 1197 | } |
1195 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); | 1198 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
1196 | error = PTR_ERR(inode); | 1199 | error = PTR_ERR(inode); |
1197 | if (IS_ERR(inode)) | 1200 | if (IS_ERR(inode)) |
1198 | return error; | 1201 | goto out_error; |
1199 | d_instantiate(dentry, inode); | 1202 | d_add(dentry, inode); |
1200 | if (d_unhashed(dentry)) | 1203 | out: |
1201 | d_rehash(dentry); | 1204 | dput(parent); |
1202 | return 0; | 1205 | return 0; |
1206 | out_error: | ||
1207 | nfs_mark_for_revalidate(dir); | ||
1208 | dput(parent); | ||
1209 | return error; | ||
1203 | } | 1210 | } |
1204 | 1211 | ||
1205 | /* | 1212 | /* |