aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2006-08-22 20:06:22 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:24:52 -0400
commit4f390c152bc87165da4b1f5b7d870b46fb106d4e (patch)
tree643b5d12f76bd7d3688380fbaf69f607a34a06bf
parentd3db90e270791b21cd00d3c094884bffa907cc9e (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>
-rw-r--r--fs/nfs/dir.c16
-rw-r--r--fs/nfs/nfs3proc.c26
-rw-r--r--fs/nfs/nfs4proc.c31
-rw-r--r--fs/nfs/proc.c29
-rw-r--r--include/linux/nfs_xdr.h5
5 files changed, 59 insertions, 48 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;
1164out_err:
1165 d_drop(dentry);
1166 return error;
1167} 1164}
1168 1165
1169/* 1166/*
@@ -1448,8 +1445,6 @@ static int
1448nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 1445nfs_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;
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 9e8258ece6fd..d85ac427c326 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -544,23 +544,23 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
544} 544}
545 545
546static int 546static int
547nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, 547nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
548 struct iattr *sattr, struct nfs_fh *fhandle, 548 struct iattr *sattr)
549 struct nfs_fattr *fattr)
550{ 549{
551 struct nfs_fattr dir_attr; 550 struct nfs_fh fhandle;
551 struct nfs_fattr fattr, dir_attr;
552 struct nfs3_symlinkargs arg = { 552 struct nfs3_symlinkargs arg = {
553 .fromfh = NFS_FH(dir), 553 .fromfh = NFS_FH(dir),
554 .fromname = name->name, 554 .fromname = dentry->d_name.name,
555 .fromlen = name->len, 555 .fromlen = dentry->d_name.len,
556 .topath = path->name, 556 .topath = path->name,
557 .tolen = path->len, 557 .tolen = path->len,
558 .sattr = sattr 558 .sattr = sattr
559 }; 559 };
560 struct nfs3_diropres res = { 560 struct nfs3_diropres res = {
561 .dir_attr = &dir_attr, 561 .dir_attr = &dir_attr,
562 .fh = fhandle, 562 .fh = &fhandle,
563 .fattr = fattr 563 .fattr = &fattr
564 }; 564 };
565 struct rpc_message msg = { 565 struct rpc_message msg = {
566 .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], 566 .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK],
@@ -571,11 +571,17 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
571 571
572 if (path->len > NFS3_MAXPATHLEN) 572 if (path->len > NFS3_MAXPATHLEN)
573 return -ENAMETOOLONG; 573 return -ENAMETOOLONG;
574 dprintk("NFS call symlink %s -> %s\n", name->name, path->name); 574
575 dprintk("NFS call symlink %s -> %s\n", dentry->d_name.name,
576 path->name);
575 nfs_fattr_init(&dir_attr); 577 nfs_fattr_init(&dir_attr);
576 nfs_fattr_init(fattr); 578 nfs_fattr_init(&fattr);
577 status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); 579 status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
578 nfs_post_op_update_inode(dir, &dir_attr); 580 nfs_post_op_update_inode(dir, &dir_attr);
581 if (status != 0)
582 goto out;
583 status = nfs_instantiate(dentry, &fhandle, &fattr);
584out:
579 dprintk("NFS reply symlink: %d\n", status); 585 dprintk("NFS reply symlink: %d\n", status);
580 return status; 586 return status;
581} 587}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index a825547e8214..2d18eac6bee5 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2084,24 +2084,24 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
2084 return err; 2084 return err;
2085} 2085}
2086 2086
2087static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, 2087static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
2088 struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, 2088 struct qstr *path, struct iattr *sattr)
2089 struct nfs_fattr *fattr)
2090{ 2089{
2091 struct nfs_server *server = NFS_SERVER(dir); 2090 struct nfs_server *server = NFS_SERVER(dir);
2092 struct nfs_fattr dir_fattr; 2091 struct nfs_fh fhandle;
2092 struct nfs_fattr fattr, dir_fattr;
2093 struct nfs4_create_arg arg = { 2093 struct nfs4_create_arg arg = {
2094 .dir_fh = NFS_FH(dir), 2094 .dir_fh = NFS_FH(dir),
2095 .server = server, 2095 .server = server,
2096 .name = name, 2096 .name = &dentry->d_name,
2097 .attrs = sattr, 2097 .attrs = sattr,
2098 .ftype = NF4LNK, 2098 .ftype = NF4LNK,
2099 .bitmask = server->attr_bitmask, 2099 .bitmask = server->attr_bitmask,
2100 }; 2100 };
2101 struct nfs4_create_res res = { 2101 struct nfs4_create_res res = {
2102 .server = server, 2102 .server = server,
2103 .fh = fhandle, 2103 .fh = &fhandle,
2104 .fattr = fattr, 2104 .fattr = &fattr,
2105 .dir_fattr = &dir_fattr, 2105 .dir_fattr = &dir_fattr,
2106 }; 2106 };
2107 struct rpc_message msg = { 2107 struct rpc_message msg = {
@@ -2113,27 +2113,28 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
2113 2113
2114 if (path->len > NFS4_MAXPATHLEN) 2114 if (path->len > NFS4_MAXPATHLEN)
2115 return -ENAMETOOLONG; 2115 return -ENAMETOOLONG;
2116
2116 arg.u.symlink = path; 2117 arg.u.symlink = path;
2117 nfs_fattr_init(fattr); 2118 nfs_fattr_init(&fattr);
2118 nfs_fattr_init(&dir_fattr); 2119 nfs_fattr_init(&dir_fattr);
2119 2120
2120 status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); 2121 status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
2121 if (!status) 2122 if (!status) {
2122 update_changeattr(dir, &res.dir_cinfo); 2123 update_changeattr(dir, &res.dir_cinfo);
2123 nfs_post_op_update_inode(dir, res.dir_fattr); 2124 nfs_post_op_update_inode(dir, res.dir_fattr);
2125 status = nfs_instantiate(dentry, &fhandle, &fattr);
2126 }
2124 return status; 2127 return status;
2125} 2128}
2126 2129
2127static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, 2130static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
2128 struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, 2131 struct qstr *path, struct iattr *sattr)
2129 struct nfs_fattr *fattr)
2130{ 2132{
2131 struct nfs4_exception exception = { }; 2133 struct nfs4_exception exception = { };
2132 int err; 2134 int err;
2133 do { 2135 do {
2134 err = nfs4_handle_exception(NFS_SERVER(dir), 2136 err = nfs4_handle_exception(NFS_SERVER(dir),
2135 _nfs4_proc_symlink(dir, name, path, sattr, 2137 _nfs4_proc_symlink(dir, dentry, path, sattr),
2136 fhandle, fattr),
2137 &exception); 2138 &exception);
2138 } while (exception.retry); 2139 } while (exception.retry);
2139 return err; 2140 return err;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 5a8b9407ee9a..0b507bf0f330 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
427static int 427static int
428nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, 428nfs_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}
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 0f33e621892f..ddf5d75e97a2 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -793,9 +793,8 @@ struct nfs_rpc_ops {
793 int (*rename) (struct inode *, struct qstr *, 793 int (*rename) (struct inode *, struct qstr *,
794 struct inode *, struct qstr *); 794 struct inode *, struct qstr *);
795 int (*link) (struct inode *, struct inode *, struct qstr *); 795 int (*link) (struct inode *, struct inode *, struct qstr *);
796 int (*symlink) (struct inode *, struct qstr *, struct qstr *, 796 int (*symlink) (struct inode *, struct dentry *, struct qstr *,
797 struct iattr *, struct nfs_fh *, 797 struct iattr *);
798 struct nfs_fattr *);
799 int (*mkdir) (struct inode *, struct dentry *, struct iattr *); 798 int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
800 int (*rmdir) (struct inode *, struct qstr *); 799 int (*rmdir) (struct inode *, struct qstr *);
801 int (*readdir) (struct dentry *, struct rpc_cred *, 800 int (*readdir) (struct dentry *, struct rpc_cred *,