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/proc.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/proc.c')
-rw-r--r-- | fs/nfs/proc.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 5a8b9407ee9..0b507bf0f33 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -425,14 +425,15 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | |||
425 | } | 425 | } |
426 | 426 | ||
427 | static int | 427 | static int |
428 | nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | 428 | nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path, |
429 | struct iattr *sattr, struct nfs_fh *fhandle, | 429 | struct iattr *sattr) |
430 | struct nfs_fattr *fattr) | ||
431 | { | 430 | { |
431 | struct nfs_fh fhandle; | ||
432 | struct nfs_fattr fattr; | ||
432 | struct nfs_symlinkargs arg = { | 433 | struct nfs_symlinkargs arg = { |
433 | .fromfh = NFS_FH(dir), | 434 | .fromfh = NFS_FH(dir), |
434 | .fromname = name->name, | 435 | .fromname = dentry->d_name.name, |
435 | .fromlen = name->len, | 436 | .fromlen = dentry->d_name.len, |
436 | .topath = path->name, | 437 | .topath = path->name, |
437 | .tolen = path->len, | 438 | .tolen = path->len, |
438 | .sattr = sattr | 439 | .sattr = sattr |
@@ -445,11 +446,23 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
445 | 446 | ||
446 | if (path->len > NFS2_MAXPATHLEN) | 447 | if (path->len > NFS2_MAXPATHLEN) |
447 | return -ENAMETOOLONG; | 448 | return -ENAMETOOLONG; |
448 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); | 449 | |
449 | nfs_fattr_init(fattr); | 450 | dprintk("NFS call symlink %s -> %s\n", dentry->d_name.name, |
450 | fhandle->size = 0; | 451 | path->name); |
451 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 452 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
452 | nfs_mark_for_revalidate(dir); | 453 | nfs_mark_for_revalidate(dir); |
454 | |||
455 | /* | ||
456 | * V2 SYMLINK requests don't return any attributes. Setting the | ||
457 | * filehandle size to zero indicates to nfs_instantiate that it | ||
458 | * should fill in the data with a LOOKUP call on the wire. | ||
459 | */ | ||
460 | if (status == 0) { | ||
461 | nfs_fattr_init(&fattr); | ||
462 | fhandle.size = 0; | ||
463 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
464 | } | ||
465 | |||
453 | dprintk("NFS reply symlink: %d\n", status); | 466 | dprintk("NFS reply symlink: %d\n", status); |
454 | return status; | 467 | return status; |
455 | } | 468 | } |