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 | |
| 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>
| -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 | /* |
