diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2006-08-22 20:06:22 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-09-22 23:24:52 -0400 |
commit | 4f390c152bc87165da4b1f5b7d870b46fb106d4e (patch) | |
tree | 643b5d12f76bd7d3688380fbaf69f607a34a06bf /fs/nfs/dir.c | |
parent | d3db90e270791b21cd00d3c094884bffa907cc9e (diff) |
NFS: Fix double d_drop in nfs_instantiate() error path
If the LOOKUP or GETATTR in nfs_instantiate fail, nfs_instantiate will do a
d_drop before returning. But some callers already do a d_drop in the case
of an error return. Make certain we do only one d_drop in all error paths.
This issue was introduced because over time, the symlink proc API diverged
slightly from the create/mkdir/mknod proc API. To prevent other coding
mistakes of this type, change the symlink proc API to be more like
create/mkdir/mknod and move the nfs_instantiate call into the symlink proc
routines so it is used in exactly the same way for create, mkdir, mknod,
and symlink.
Test plan:
Connectathon, all versions of NFS.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 16 |
1 files changed, 4 insertions, 12 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 084e8cb41c84..affd3ae52e55 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1147,23 +1147,20 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | |||
1147 | struct inode *dir = dentry->d_parent->d_inode; | 1147 | struct inode *dir = dentry->d_parent->d_inode; |
1148 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1148 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
1149 | if (error) | 1149 | if (error) |
1150 | goto out_err; | 1150 | return error; |
1151 | } | 1151 | } |
1152 | if (!(fattr->valid & NFS_ATTR_FATTR)) { | 1152 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
1153 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 1153 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
1154 | error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); | 1154 | error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); |
1155 | if (error < 0) | 1155 | if (error < 0) |
1156 | goto out_err; | 1156 | return error; |
1157 | } | 1157 | } |
1158 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); | 1158 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
1159 | error = PTR_ERR(inode); | 1159 | error = PTR_ERR(inode); |
1160 | if (IS_ERR(inode)) | 1160 | if (IS_ERR(inode)) |
1161 | goto out_err; | 1161 | return error; |
1162 | d_instantiate(dentry, inode); | 1162 | d_instantiate(dentry, inode); |
1163 | return 0; | 1163 | return 0; |
1164 | out_err: | ||
1165 | d_drop(dentry); | ||
1166 | return error; | ||
1167 | } | 1164 | } |
1168 | 1165 | ||
1169 | /* | 1166 | /* |
@@ -1448,8 +1445,6 @@ static int | |||
1448 | nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 1445 | nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) |
1449 | { | 1446 | { |
1450 | struct iattr attr; | 1447 | struct iattr attr; |
1451 | struct nfs_fattr sym_attr; | ||
1452 | struct nfs_fh sym_fh; | ||
1453 | struct qstr qsymname; | 1448 | struct qstr qsymname; |
1454 | int error; | 1449 | int error; |
1455 | 1450 | ||
@@ -1473,12 +1468,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name); | |||
1473 | 1468 | ||
1474 | lock_kernel(); | 1469 | lock_kernel(); |
1475 | nfs_begin_data_update(dir); | 1470 | nfs_begin_data_update(dir); |
1476 | error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname, | 1471 | error = NFS_PROTO(dir)->symlink(dir, dentry, &qsymname, &attr); |
1477 | &attr, &sym_fh, &sym_attr); | ||
1478 | nfs_end_data_update(dir); | 1472 | nfs_end_data_update(dir); |
1479 | if (!error) | 1473 | if (!error) |
1480 | error = nfs_instantiate(dentry, &sym_fh, &sym_attr); | ||
1481 | else | ||
1482 | d_drop(dentry); | 1474 | d_drop(dentry); |
1483 | unlock_kernel(); | 1475 | unlock_kernel(); |
1484 | return error; | 1476 | return error; |