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>
This commit is contained in:

committed by
Trond Myklebust

parent
d3db90e270
commit
4f390c152b
16
fs/nfs/dir.c
16
fs/nfs/dir.c
@@ -1147,23 +1147,20 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
|
||||
if (error)
|
||||
goto out_err;
|
||||
return 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)
|
||||
goto out_err;
|
||||
return error;
|
||||
}
|
||||
inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
|
||||
error = PTR_ERR(inode);
|
||||
if (IS_ERR(inode))
|
||||
goto out_err;
|
||||
return error;
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
out_err:
|
||||
d_drop(dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1448,8 +1445,6 @@ static int
|
||||
nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
|
||||
{
|
||||
struct iattr attr;
|
||||
struct nfs_fattr sym_attr;
|
||||
struct nfs_fh sym_fh;
|
||||
struct qstr qsymname;
|
||||
int error;
|
||||
|
||||
@@ -1473,12 +1468,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||
|
||||
lock_kernel();
|
||||
nfs_begin_data_update(dir);
|
||||
error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
|
||||
&attr, &sym_fh, &sym_attr);
|
||||
error = NFS_PROTO(dir)->symlink(dir, dentry, &qsymname, &attr);
|
||||
nfs_end_data_update(dir);
|
||||
if (!error)
|
||||
error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
|
||||
else
|
||||
d_drop(dentry);
|
||||
unlock_kernel();
|
||||
return error;
|
||||
|
Reference in New Issue
Block a user