aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2006-08-22 20:06:23 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:24:53 -0400
commit94a6d75320b3681e6e728b70e18bd186cb55e682 (patch)
tree0957071549d76ceb3857e419998818b11bce7269
parent873101b33776780d32610fc4c90c7358a5e98f51 (diff)
NFS: Use cached page as buffer for NFS symlink requests
Now that we have a copy of the symlink path in the page cache, we can pass a struct page down to the XDR routines instead of a string buffer. Test plan: Connectathon, all NFS versions. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/dir.c8
-rw-r--r--fs/nfs/nfs2xdr.c21
-rw-r--r--fs/nfs/nfs3proc.c14
-rw-r--r--fs/nfs/nfs3xdr.c7
-rw-r--r--fs/nfs/nfs4proc.c12
-rw-r--r--fs/nfs/nfs4xdr.c8
-rw-r--r--fs/nfs/proc.c14
-rw-r--r--include/linux/nfs_xdr.h17
8 files changed, 59 insertions, 42 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index b483e5d206cb..51328ae640dd 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1464,10 +1464,6 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
1464 char *kaddr; 1464 char *kaddr;
1465 struct iattr attr; 1465 struct iattr attr;
1466 unsigned int pathlen = strlen(symname); 1466 unsigned int pathlen = strlen(symname);
1467 struct qstr qsymname = {
1468 .name = symname,
1469 .len = pathlen,
1470 };
1471 int error; 1467 int error;
1472 1468
1473 dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, 1469 dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
@@ -1493,10 +1489,8 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
1493 memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); 1489 memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
1494 kunmap_atomic(kaddr, KM_USER0); 1490 kunmap_atomic(kaddr, KM_USER0);
1495 1491
1496 /* XXX: eventually this will pass in {page, pathlen},
1497 * instead of qsymname; need XDR changes for that */
1498 nfs_begin_data_update(dir); 1492 nfs_begin_data_update(dir);
1499 error = NFS_PROTO(dir)->symlink(dir, dentry, &qsymname, &attr); 1493 error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
1500 nfs_end_data_update(dir); 1494 nfs_end_data_update(dir);
1501 if (error != 0) { 1495 if (error != 0) {
1502 dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n", 1496 dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 67391eef6b93..b49501fc0a79 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -51,7 +51,7 @@
51#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) 51#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
52#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) 52#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
53#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) 53#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
54#define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz) 54#define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
55#define NFS_readdirargs_sz (NFS_fhandle_sz+2) 55#define NFS_readdirargs_sz (NFS_fhandle_sz+2)
56 56
57#define NFS_attrstat_sz (1+NFS_fattr_sz) 57#define NFS_attrstat_sz (1+NFS_fattr_sz)
@@ -351,11 +351,26 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
351static int 351static int
352nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) 352nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
353{ 353{
354 struct xdr_buf *sndbuf = &req->rq_snd_buf;
355 size_t pad;
356
354 p = xdr_encode_fhandle(p, args->fromfh); 357 p = xdr_encode_fhandle(p, args->fromfh);
355 p = xdr_encode_array(p, args->fromname, args->fromlen); 358 p = xdr_encode_array(p, args->fromname, args->fromlen);
356 p = xdr_encode_array(p, args->topath, args->tolen); 359 *p++ = htonl(args->pathlen);
360 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
361
362 xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
363
364 /*
365 * xdr_encode_pages may have added a few bytes to ensure the
366 * pathname ends on a 4-byte boundary. Start encoding the
367 * attributes after the pad bytes.
368 */
369 pad = sndbuf->tail->iov_len;
370 if (pad > 0)
371 p++;
357 p = xdr_encode_sattr(p, args->sattr); 372 p = xdr_encode_sattr(p, args->sattr);
358 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 373 sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
359 return 0; 374 return 0;
360} 375}
361 376
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index d85ac427c326..f8688eaa0001 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -544,8 +544,8 @@ 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 dentry *dentry, struct qstr *path, 547nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
548 struct iattr *sattr) 548 unsigned int len, struct iattr *sattr)
549{ 549{
550 struct nfs_fh fhandle; 550 struct nfs_fh fhandle;
551 struct nfs_fattr fattr, dir_attr; 551 struct nfs_fattr fattr, dir_attr;
@@ -553,8 +553,8 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
553 .fromfh = NFS_FH(dir), 553 .fromfh = NFS_FH(dir),
554 .fromname = dentry->d_name.name, 554 .fromname = dentry->d_name.name,
555 .fromlen = dentry->d_name.len, 555 .fromlen = dentry->d_name.len,
556 .topath = path->name, 556 .pages = &page,
557 .tolen = path->len, 557 .pathlen = len,
558 .sattr = sattr 558 .sattr = sattr
559 }; 559 };
560 struct nfs3_diropres res = { 560 struct nfs3_diropres res = {
@@ -569,11 +569,11 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
569 }; 569 };
570 int status; 570 int status;
571 571
572 if (path->len > NFS3_MAXPATHLEN) 572 if (len > NFS3_MAXPATHLEN)
573 return -ENAMETOOLONG; 573 return -ENAMETOOLONG;
574 574
575 dprintk("NFS call symlink %s -> %s\n", dentry->d_name.name, 575 dprintk("NFS call symlink %s\n", dentry->d_name.name);
576 path->name); 576
577 nfs_fattr_init(&dir_attr); 577 nfs_fattr_init(&dir_attr);
578 nfs_fattr_init(&fattr); 578 nfs_fattr_init(&fattr);
579 status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); 579 status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 0250269e9753..16556fa4effb 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -56,7 +56,7 @@
56#define NFS3_writeargs_sz (NFS3_fh_sz+5) 56#define NFS3_writeargs_sz (NFS3_fh_sz+5)
57#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 57#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
58#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) 58#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
59#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz) 59#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
60#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) 60#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
61#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) 61#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
62#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) 62#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
@@ -398,8 +398,11 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args
398 p = xdr_encode_fhandle(p, args->fromfh); 398 p = xdr_encode_fhandle(p, args->fromfh);
399 p = xdr_encode_array(p, args->fromname, args->fromlen); 399 p = xdr_encode_array(p, args->fromname, args->fromlen);
400 p = xdr_encode_sattr(p, args->sattr); 400 p = xdr_encode_sattr(p, args->sattr);
401 p = xdr_encode_array(p, args->topath, args->tolen); 401 *p++ = htonl(args->pathlen);
402 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 402 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
403
404 /* Copy the page */
405 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
403 return 0; 406 return 0;
404} 407}
405 408
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 2d18eac6bee5..7f60beb40df3 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2085,7 +2085,7 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n
2085} 2085}
2086 2086
2087static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, 2087static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
2088 struct qstr *path, struct iattr *sattr) 2088 struct page *page, unsigned int len, struct iattr *sattr)
2089{ 2089{
2090 struct nfs_server *server = NFS_SERVER(dir); 2090 struct nfs_server *server = NFS_SERVER(dir);
2091 struct nfs_fh fhandle; 2091 struct nfs_fh fhandle;
@@ -2111,10 +2111,11 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
2111 }; 2111 };
2112 int status; 2112 int status;
2113 2113
2114 if (path->len > NFS4_MAXPATHLEN) 2114 if (len > NFS4_MAXPATHLEN)
2115 return -ENAMETOOLONG; 2115 return -ENAMETOOLONG;
2116 2116
2117 arg.u.symlink = path; 2117 arg.u.symlink.pages = &page;
2118 arg.u.symlink.len = len;
2118 nfs_fattr_init(&fattr); 2119 nfs_fattr_init(&fattr);
2119 nfs_fattr_init(&dir_fattr); 2120 nfs_fattr_init(&dir_fattr);
2120 2121
@@ -2128,13 +2129,14 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
2128} 2129}
2129 2130
2130static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, 2131static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
2131 struct qstr *path, struct iattr *sattr) 2132 struct page *page, unsigned int len, struct iattr *sattr)
2132{ 2133{
2133 struct nfs4_exception exception = { }; 2134 struct nfs4_exception exception = { };
2134 int err; 2135 int err;
2135 do { 2136 do {
2136 err = nfs4_handle_exception(NFS_SERVER(dir), 2137 err = nfs4_handle_exception(NFS_SERVER(dir),
2137 _nfs4_proc_symlink(dir, dentry, path, sattr), 2138 _nfs4_proc_symlink(dir, dentry, page,
2139 len, sattr),
2138 &exception); 2140 &exception);
2139 } while (exception.retry); 2141 } while (exception.retry);
2140 return err; 2142 return err;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 99926067eca4..3dd413f52da1 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -128,7 +128,7 @@ static int nfs4_stat_to_errno(int);
128#define decode_link_maxsz (op_decode_hdr_maxsz + 5) 128#define decode_link_maxsz (op_decode_hdr_maxsz + 5)
129#define encode_symlink_maxsz (op_encode_hdr_maxsz + \ 129#define encode_symlink_maxsz (op_encode_hdr_maxsz + \
130 1 + nfs4_name_maxsz + \ 130 1 + nfs4_name_maxsz + \
131 nfs4_path_maxsz + \ 131 1 + \
132 nfs4_fattr_maxsz) 132 nfs4_fattr_maxsz)
133#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) 133#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
134#define encode_create_maxsz (op_encode_hdr_maxsz + \ 134#define encode_create_maxsz (op_encode_hdr_maxsz + \
@@ -673,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
673 673
674 switch (create->ftype) { 674 switch (create->ftype) {
675 case NF4LNK: 675 case NF4LNK:
676 RESERVE_SPACE(4 + create->u.symlink->len); 676 RESERVE_SPACE(4);
677 WRITE32(create->u.symlink->len); 677 WRITE32(create->u.symlink.len);
678 WRITEMEM(create->u.symlink->name, create->u.symlink->len); 678 xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
679 break; 679 break;
680 680
681 case NF4BLK: case NF4CHR: 681 case NF4BLK: case NF4CHR:
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 0b507bf0f330..630e50647bbb 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -425,8 +425,8 @@ 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 dentry *dentry, struct qstr *path, 428nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
429 struct iattr *sattr) 429 unsigned int len, struct iattr *sattr)
430{ 430{
431 struct nfs_fh fhandle; 431 struct nfs_fh fhandle;
432 struct nfs_fattr fattr; 432 struct nfs_fattr fattr;
@@ -434,8 +434,8 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
434 .fromfh = NFS_FH(dir), 434 .fromfh = NFS_FH(dir),
435 .fromname = dentry->d_name.name, 435 .fromname = dentry->d_name.name,
436 .fromlen = dentry->d_name.len, 436 .fromlen = dentry->d_name.len,
437 .topath = path->name, 437 .pages = &page,
438 .tolen = path->len, 438 .pathlen = len,
439 .sattr = sattr 439 .sattr = sattr
440 }; 440 };
441 struct rpc_message msg = { 441 struct rpc_message msg = {
@@ -444,11 +444,11 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
444 }; 444 };
445 int status; 445 int status;
446 446
447 if (path->len > NFS2_MAXPATHLEN) 447 if (len > NFS2_MAXPATHLEN)
448 return -ENAMETOOLONG; 448 return -ENAMETOOLONG;
449 449
450 dprintk("NFS call symlink %s -> %s\n", dentry->d_name.name, 450 dprintk("NFS call symlink %s\n", dentry->d_name.name);
451 path->name); 451
452 status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); 452 status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
453 nfs_mark_for_revalidate(dir); 453 nfs_mark_for_revalidate(dir);
454 454
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index ddf5d75e97a2..dc5397d9d23c 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -358,8 +358,8 @@ struct nfs_symlinkargs {
358 struct nfs_fh * fromfh; 358 struct nfs_fh * fromfh;
359 const char * fromname; 359 const char * fromname;
360 unsigned int fromlen; 360 unsigned int fromlen;
361 const char * topath; 361 struct page ** pages;
362 unsigned int tolen; 362 unsigned int pathlen;
363 struct iattr * sattr; 363 struct iattr * sattr;
364}; 364};
365 365
@@ -434,8 +434,8 @@ struct nfs3_symlinkargs {
434 struct nfs_fh * fromfh; 434 struct nfs_fh * fromfh;
435 const char * fromname; 435 const char * fromname;
436 unsigned int fromlen; 436 unsigned int fromlen;
437 const char * topath; 437 struct page ** pages;
438 unsigned int tolen; 438 unsigned int pathlen;
439 struct iattr * sattr; 439 struct iattr * sattr;
440}; 440};
441 441
@@ -533,7 +533,10 @@ struct nfs4_accessres {
533struct nfs4_create_arg { 533struct nfs4_create_arg {
534 u32 ftype; 534 u32 ftype;
535 union { 535 union {
536 struct qstr * symlink; /* NF4LNK */ 536 struct {
537 struct page ** pages;
538 unsigned int len;
539 } symlink; /* NF4LNK */
537 struct { 540 struct {
538 u32 specdata1; 541 u32 specdata1;
539 u32 specdata2; 542 u32 specdata2;
@@ -793,8 +796,8 @@ struct nfs_rpc_ops {
793 int (*rename) (struct inode *, struct qstr *, 796 int (*rename) (struct inode *, struct qstr *,
794 struct inode *, struct qstr *); 797 struct inode *, struct qstr *);
795 int (*link) (struct inode *, struct inode *, struct qstr *); 798 int (*link) (struct inode *, struct inode *, struct qstr *);
796 int (*symlink) (struct inode *, struct dentry *, struct qstr *, 799 int (*symlink) (struct inode *, struct dentry *, struct page *,
797 struct iattr *); 800 unsigned int, struct iattr *);
798 int (*mkdir) (struct inode *, struct dentry *, struct iattr *); 801 int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
799 int (*rmdir) (struct inode *, struct qstr *); 802 int (*rmdir) (struct inode *, struct qstr *);
800 int (*readdir) (struct dentry *, struct rpc_cred *, 803 int (*readdir) (struct dentry *, struct rpc_cred *,