aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-10-04 05:15:46 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-04 10:55:15 -0400
commit4452435948424e5322c2a2fefbdc2cf3732cc45d (patch)
treed2082c68d33298e85298852cafde7999ccca3364
parent5680c44632053a6c9464bca43083f01776d318da (diff)
[PATCH] knfsd: Replace two page lists in struct svc_rqst with one
We are planning to increase RPCSVC_MAXPAGES from about 8 to about 256. This means we need to be a bit careful about arrays of size RPCSVC_MAXPAGES. struct svc_rqst contains two such arrays. However the there are never more that RPCSVC_MAXPAGES pages in the two arrays together, so only one array is needed. The two arrays are for the pages holding the request, and the pages holding the reply. Instead of two arrays, we can simply keep an index into where the first reply page is. This patch also removes a number of small inline functions that probably server to obscure what is going on rather than clarify it, and opencode the needed functionality. Also remove the 'rq_restailpage' variable as it is *always* 0. i.e. if the response 'xdr' structure has a non-empty tail it is always in the same pages as the head. check counters are initilised and incr properly check for consistant usage of ++ etc maybe extra some inlines for common approach general review Signed-off-by: Neil Brown <neilb@suse.de> Cc: Magnus Maatta <novell@kiruna.se> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/nfsd/nfs2acl.c2
-rw-r--r--fs/nfsd/nfs3acl.c2
-rw-r--r--fs/nfsd/nfs3xdr.c23
-rw-r--r--fs/nfsd/nfs4xdr.c27
-rw-r--r--fs/nfsd/nfsxdr.c13
-rw-r--r--fs/nfsd/vfs.c16
-rw-r--r--include/linux/sunrpc/svc.h69
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c4
-rw-r--r--net/sunrpc/svc.c21
-rw-r--r--net/sunrpc/svcsock.c41
10 files changed, 77 insertions, 141 deletions
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index fe56b38364cc..71108da2e54e 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -241,7 +241,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
241 241
242 rqstp->rq_res.page_len = w; 242 rqstp->rq_res.page_len = w;
243 while (w > 0) { 243 while (w > 0) {
244 if (!svc_take_res_page(rqstp)) 244 if (!rqstp->rq_respages[rqstp->rq_resused++])
245 return 0; 245 return 0;
246 w -= PAGE_SIZE; 246 w -= PAGE_SIZE;
247 } 247 }
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 16e10c170aed..f813b054f4a1 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -185,7 +185,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
185 185
186 rqstp->rq_res.page_len = w; 186 rqstp->rq_res.page_len = w;
187 while (w > 0) { 187 while (w > 0) {
188 if (!svc_take_res_page(rqstp)) 188 if (!rqstp->rq_respages[rqstp->rq_resused++])
189 return 0; 189 return 0;
190 w -= PAGE_SIZE; 190 w -= PAGE_SIZE;
191 } 191 }
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 243d94b9653a..20ba728a4642 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -343,8 +343,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
343 /* set up the kvec */ 343 /* set up the kvec */
344 v=0; 344 v=0;
345 while (len > 0) { 345 while (len > 0) {
346 pn = rqstp->rq_resused; 346 pn = rqstp->rq_resused++;
347 svc_take_page(rqstp);
348 args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]); 347 args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
349 args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE; 348 args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
350 len -= args->vec[v].iov_len; 349 len -= args->vec[v].iov_len;
@@ -382,7 +381,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
382 while (len > args->vec[v].iov_len) { 381 while (len > args->vec[v].iov_len) {
383 len -= args->vec[v].iov_len; 382 len -= args->vec[v].iov_len;
384 v++; 383 v++;
385 args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]); 384 args->vec[v].iov_base = page_address(rqstp->rq_pages[v]);
386 args->vec[v].iov_len = PAGE_SIZE; 385 args->vec[v].iov_len = PAGE_SIZE;
387 } 386 }
388 args->vec[v].iov_len = len; 387 args->vec[v].iov_len = len;
@@ -446,11 +445,11 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
446 * This page appears in the rq_res.pages list, but as pages_len is always 445 * This page appears in the rq_res.pages list, but as pages_len is always
447 * 0, it won't get in the way 446 * 0, it won't get in the way
448 */ 447 */
449 svc_take_page(rqstp);
450 len = ntohl(*p++); 448 len = ntohl(*p++);
451 if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE) 449 if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
452 return 0; 450 return 0;
453 args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); 451 args->tname = new =
452 page_address(rqstp->rq_respages[rqstp->rq_resused++]);
454 args->tlen = len; 453 args->tlen = len;
455 /* first copy and check from the first page */ 454 /* first copy and check from the first page */
456 old = (char*)p; 455 old = (char*)p;
@@ -522,8 +521,8 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
522{ 521{
523 if (!(p = decode_fh(p, &args->fh))) 522 if (!(p = decode_fh(p, &args->fh)))
524 return 0; 523 return 0;
525 svc_take_page(rqstp); 524 args->buffer =
526 args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); 525 page_address(rqstp->rq_respages[rqstp->rq_resused++]);
527 526
528 return xdr_argsize_check(rqstp, p); 527 return xdr_argsize_check(rqstp, p);
529} 528}
@@ -554,8 +553,8 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
554 if (args->count > PAGE_SIZE) 553 if (args->count > PAGE_SIZE)
555 args->count = PAGE_SIZE; 554 args->count = PAGE_SIZE;
556 555
557 svc_take_page(rqstp); 556 args->buffer =
558 args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); 557 page_address(rqstp->rq_respages[rqstp->rq_resused++]);
559 558
560 return xdr_argsize_check(rqstp, p); 559 return xdr_argsize_check(rqstp, p);
561} 560}
@@ -578,8 +577,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
578 args->count = len; 577 args->count = len;
579 578
580 while (len > 0) { 579 while (len > 0) {
581 pn = rqstp->rq_resused; 580 pn = rqstp->rq_resused++;
582 svc_take_page(rqstp);
583 if (!args->buffer) 581 if (!args->buffer)
584 args->buffer = page_address(rqstp->rq_respages[pn]); 582 args->buffer = page_address(rqstp->rq_respages[pn]);
585 len -= PAGE_SIZE; 583 len -= PAGE_SIZE;
@@ -668,7 +666,6 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
668 rqstp->rq_res.page_len = resp->len; 666 rqstp->rq_res.page_len = resp->len;
669 if (resp->len & 3) { 667 if (resp->len & 3) {
670 /* need to pad the tail */ 668 /* need to pad the tail */
671 rqstp->rq_restailpage = 0;
672 rqstp->rq_res.tail[0].iov_base = p; 669 rqstp->rq_res.tail[0].iov_base = p;
673 *p = 0; 670 *p = 0;
674 rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); 671 rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -693,7 +690,6 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
693 rqstp->rq_res.page_len = resp->count; 690 rqstp->rq_res.page_len = resp->count;
694 if (resp->count & 3) { 691 if (resp->count & 3) {
695 /* need to pad the tail */ 692 /* need to pad the tail */
696 rqstp->rq_restailpage = 0;
697 rqstp->rq_res.tail[0].iov_base = p; 693 rqstp->rq_res.tail[0].iov_base = p;
698 *p = 0; 694 *p = 0;
699 rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3); 695 rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
@@ -768,7 +764,6 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
768 rqstp->rq_res.page_len = (resp->count) << 2; 764 rqstp->rq_res.page_len = (resp->count) << 2;
769 765
770 /* add the 'tail' to the end of the 'head' page - page 0. */ 766 /* add the 'tail' to the end of the 'head' page - page 0. */
771 rqstp->rq_restailpage = 0;
772 rqstp->rq_res.tail[0].iov_base = p; 767 rqstp->rq_res.tail[0].iov_base = p;
773 *p++ = 0; /* no more entries */ 768 *p++ = 0; /* no more entries */
774 *p++ = htonl(resp->common.err == nfserr_eof); 769 *p++ = htonl(resp->common.err == nfserr_eof);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5be00436b5b8..9f30c53ac0ed 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2039,7 +2039,8 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct n
2039} 2039}
2040 2040
2041static int 2041static int
2042nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read) 2042nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr,
2043 struct nfsd4_read *read)
2043{ 2044{
2044 u32 eof; 2045 u32 eof;
2045 int v, pn; 2046 int v, pn;
@@ -2061,10 +2062,11 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
2061 len = maxcount; 2062 len = maxcount;
2062 v = 0; 2063 v = 0;
2063 while (len > 0) { 2064 while (len > 0) {
2064 pn = resp->rqstp->rq_resused; 2065 pn = resp->rqstp->rq_resused++;
2065 svc_take_page(resp->rqstp); 2066 read->rd_iov[v].iov_base =
2066 read->rd_iov[v].iov_base = page_address(resp->rqstp->rq_respages[pn]); 2067 page_address(resp->rqstp->rq_respages[pn]);
2067 read->rd_iov[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE; 2068 read->rd_iov[v].iov_len =
2069 len < PAGE_SIZE ? len : PAGE_SIZE;
2068 v++; 2070 v++;
2069 len -= PAGE_SIZE; 2071 len -= PAGE_SIZE;
2070 } 2072 }
@@ -2078,7 +2080,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
2078 nfserr = nfserr_inval; 2080 nfserr = nfserr_inval;
2079 if (nfserr) 2081 if (nfserr)
2080 return nfserr; 2082 return nfserr;
2081 eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size); 2083 eof = (read->rd_offset + maxcount >=
2084 read->rd_fhp->fh_dentry->d_inode->i_size);
2082 2085
2083 WRITE32(eof); 2086 WRITE32(eof);
2084 WRITE32(maxcount); 2087 WRITE32(maxcount);
@@ -2088,7 +2091,6 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
2088 resp->xbuf->page_len = maxcount; 2091 resp->xbuf->page_len = maxcount;
2089 2092
2090 /* Use rest of head for padding and remaining ops: */ 2093 /* Use rest of head for padding and remaining ops: */
2091 resp->rqstp->rq_restailpage = 0;
2092 resp->xbuf->tail[0].iov_base = p; 2094 resp->xbuf->tail[0].iov_base = p;
2093 resp->xbuf->tail[0].iov_len = 0; 2095 resp->xbuf->tail[0].iov_len = 0;
2094 if (maxcount&3) { 2096 if (maxcount&3) {
@@ -2113,8 +2115,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
2113 if (resp->xbuf->page_len) 2115 if (resp->xbuf->page_len)
2114 return nfserr_resource; 2116 return nfserr_resource;
2115 2117
2116 svc_take_page(resp->rqstp); 2118 page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
2117 page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
2118 2119
2119 maxcount = PAGE_SIZE; 2120 maxcount = PAGE_SIZE;
2120 RESERVE_SPACE(4); 2121 RESERVE_SPACE(4);
@@ -2138,7 +2139,6 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
2138 resp->xbuf->page_len = maxcount; 2139 resp->xbuf->page_len = maxcount;
2139 2140
2140 /* Use rest of head for padding and remaining ops: */ 2141 /* Use rest of head for padding and remaining ops: */
2141 resp->rqstp->rq_restailpage = 0;
2142 resp->xbuf->tail[0].iov_base = p; 2142 resp->xbuf->tail[0].iov_base = p;
2143 resp->xbuf->tail[0].iov_len = 0; 2143 resp->xbuf->tail[0].iov_len = 0;
2144 if (maxcount&3) { 2144 if (maxcount&3) {
@@ -2189,8 +2189,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
2189 goto err_no_verf; 2189 goto err_no_verf;
2190 } 2190 }
2191 2191
2192 svc_take_page(resp->rqstp); 2192 page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
2193 page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
2194 readdir->common.err = 0; 2193 readdir->common.err = 0;
2195 readdir->buflen = maxcount; 2194 readdir->buflen = maxcount;
2196 readdir->buffer = page; 2195 readdir->buffer = page;
@@ -2215,10 +2214,10 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
2215 p = readdir->buffer; 2214 p = readdir->buffer;
2216 *p++ = 0; /* no more entries */ 2215 *p++ = 0; /* no more entries */
2217 *p++ = htonl(readdir->common.err == nfserr_eof); 2216 *p++ = htonl(readdir->common.err == nfserr_eof);
2218 resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]); 2217 resp->xbuf->page_len = ((char*)p) - (char*)page_address(
2218 resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
2219 2219
2220 /* Use rest of head for padding and remaining ops: */ 2220 /* Use rest of head for padding and remaining ops: */
2221 resp->rqstp->rq_restailpage = 0;
2222 resp->xbuf->tail[0].iov_base = tailbase; 2221 resp->xbuf->tail[0].iov_base = tailbase;
2223 resp->xbuf->tail[0].iov_len = 0; 2222 resp->xbuf->tail[0].iov_len = 0;
2224 resp->p = resp->xbuf->tail[0].iov_base; 2223 resp->p = resp->xbuf->tail[0].iov_base;
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 3f14a17eaa6e..ad2fba3c54f8 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -262,8 +262,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
262 */ 262 */
263 v=0; 263 v=0;
264 while (len > 0) { 264 while (len > 0) {
265 pn=rqstp->rq_resused; 265 pn = rqstp->rq_resused++;
266 svc_take_page(rqstp);
267 args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]); 266 args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
268 args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE; 267 args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
269 len -= args->vec[v].iov_len; 268 len -= args->vec[v].iov_len;
@@ -295,7 +294,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
295 while (len > args->vec[v].iov_len) { 294 while (len > args->vec[v].iov_len) {
296 len -= args->vec[v].iov_len; 295 len -= args->vec[v].iov_len;
297 v++; 296 v++;
298 args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]); 297 args->vec[v].iov_base = page_address(rqstp->rq_pages[v]);
299 args->vec[v].iov_len = PAGE_SIZE; 298 args->vec[v].iov_len = PAGE_SIZE;
300 } 299 }
301 args->vec[v].iov_len = len; 300 args->vec[v].iov_len = len;
@@ -333,8 +332,7 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinka
333{ 332{
334 if (!(p = decode_fh(p, &args->fh))) 333 if (!(p = decode_fh(p, &args->fh)))
335 return 0; 334 return 0;
336 svc_take_page(rqstp); 335 args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
337 args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
338 336
339 return xdr_argsize_check(rqstp, p); 337 return xdr_argsize_check(rqstp, p);
340} 338}
@@ -375,8 +373,7 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
375 if (args->count > PAGE_SIZE) 373 if (args->count > PAGE_SIZE)
376 args->count = PAGE_SIZE; 374 args->count = PAGE_SIZE;
377 375
378 svc_take_page(rqstp); 376 args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
379 args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
380 377
381 return xdr_argsize_check(rqstp, p); 378 return xdr_argsize_check(rqstp, p);
382} 379}
@@ -416,7 +413,6 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
416 rqstp->rq_res.page_len = resp->len; 413 rqstp->rq_res.page_len = resp->len;
417 if (resp->len & 3) { 414 if (resp->len & 3) {
418 /* need to pad the tail */ 415 /* need to pad the tail */
419 rqstp->rq_restailpage = 0;
420 rqstp->rq_res.tail[0].iov_base = p; 416 rqstp->rq_res.tail[0].iov_base = p;
421 *p = 0; 417 *p = 0;
422 rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); 418 rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -436,7 +432,6 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
436 rqstp->rq_res.page_len = resp->count; 432 rqstp->rq_res.page_len = resp->count;
437 if (resp->count & 3) { 433 if (resp->count & 3) {
438 /* need to pad the tail */ 434 /* need to pad the tail */
439 rqstp->rq_restailpage = 0;
440 rqstp->rq_res.tail[0].iov_base = p; 435 rqstp->rq_res.tail[0].iov_base = p;
441 *p = 0; 436 *p = 0;
442 rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3); 437 rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 443ebc52e382..bfd36e587ec5 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -791,22 +791,26 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
791{ 791{
792 unsigned long count = desc->count; 792 unsigned long count = desc->count;
793 struct svc_rqst *rqstp = desc->arg.data; 793 struct svc_rqst *rqstp = desc->arg.data;
794 struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
794 795
795 if (size > count) 796 if (size > count)
796 size = count; 797 size = count;
797 798
798 if (rqstp->rq_res.page_len == 0) { 799 if (rqstp->rq_res.page_len == 0) {
799 get_page(page); 800 get_page(page);
800 rqstp->rq_respages[rqstp->rq_resused++] = page; 801 put_page(*pp);
802 *pp = page;
803 rqstp->rq_resused++;
801 rqstp->rq_res.page_base = offset; 804 rqstp->rq_res.page_base = offset;
802 rqstp->rq_res.page_len = size; 805 rqstp->rq_res.page_len = size;
803 } else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) { 806 } else if (page != pp[-1]) {
804 get_page(page); 807 get_page(page);
805 rqstp->rq_respages[rqstp->rq_resused++] = page; 808 put_page(*pp);
809 *pp = page;
810 rqstp->rq_resused++;
806 rqstp->rq_res.page_len += size; 811 rqstp->rq_res.page_len += size;
807 } else { 812 } else
808 rqstp->rq_res.page_len += size; 813 rqstp->rq_res.page_len += size;
809 }
810 814
811 desc->count = count - size; 815 desc->count = count - size;
812 desc->written += size; 816 desc->written += size;
@@ -837,7 +841,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
837 file->f_ra = ra->p_ra; 841 file->f_ra = ra->p_ra;
838 842
839 if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { 843 if (file->f_op->sendfile && rqstp->rq_sendfile_ok) {
840 svc_pushback_unused_pages(rqstp); 844 rqstp->rq_resused = 1;
841 err = file->f_op->sendfile(file, &offset, *count, 845 err = file->f_op->sendfile(file, &offset, *count,
842 nfsd_read_actor, rqstp); 846 nfsd_read_actor, rqstp);
843 } else { 847 } else {
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 4ebcdf91f3b3..3669e91c43b8 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -170,7 +170,6 @@ static inline void svc_putu32(struct kvec *iov, __be32 val)
170/* 170/*
171 * The context of a single thread, including the request currently being 171 * The context of a single thread, including the request currently being
172 * processed. 172 * processed.
173 * NOTE: First two items must be prev/next.
174 */ 173 */
175struct svc_rqst { 174struct svc_rqst {
176 struct list_head rq_list; /* idle list */ 175 struct list_head rq_list; /* idle list */
@@ -189,12 +188,9 @@ struct svc_rqst {
189 188
190 struct xdr_buf rq_arg; 189 struct xdr_buf rq_arg;
191 struct xdr_buf rq_res; 190 struct xdr_buf rq_res;
192 struct page * rq_argpages[RPCSVC_MAXPAGES]; 191 struct page * rq_pages[RPCSVC_MAXPAGES];
193 struct page * rq_respages[RPCSVC_MAXPAGES]; 192 struct page * *rq_respages; /* points into rq_pages */
194 int rq_restailpage; 193 int rq_resused; /* number of pages used for result */
195 short rq_argused; /* pages used for argument */
196 short rq_arghi; /* pages available in argument page list */
197 short rq_resused; /* pages used for result */
198 194
199 __be32 rq_xid; /* transmission id */ 195 __be32 rq_xid; /* transmission id */
200 u32 rq_prog; /* program number */ 196 u32 rq_prog; /* program number */
@@ -255,63 +251,18 @@ xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p)
255 return vec->iov_len <= PAGE_SIZE; 251 return vec->iov_len <= PAGE_SIZE;
256} 252}
257 253
258static inline struct page * 254static inline void svc_free_res_pages(struct svc_rqst *rqstp)
259svc_take_res_page(struct svc_rqst *rqstp)
260{ 255{
261 if (rqstp->rq_arghi <= rqstp->rq_argused) 256 while (rqstp->rq_resused) {
262 return NULL; 257 struct page **pp = (rqstp->rq_respages +
263 rqstp->rq_arghi--; 258 --rqstp->rq_resused);
264 rqstp->rq_respages[rqstp->rq_resused] = 259 if (*pp) {
265 rqstp->rq_argpages[rqstp->rq_arghi]; 260 put_page(*pp);
266 return rqstp->rq_respages[rqstp->rq_resused++]; 261 *pp = NULL;
267}
268
269static inline void svc_take_page(struct svc_rqst *rqstp)
270{
271 if (rqstp->rq_arghi <= rqstp->rq_argused) {
272 WARN_ON(1);
273 return;
274 }
275 rqstp->rq_arghi--;
276 rqstp->rq_respages[rqstp->rq_resused] =
277 rqstp->rq_argpages[rqstp->rq_arghi];
278 rqstp->rq_resused++;
279}
280
281static inline void svc_pushback_allpages(struct svc_rqst *rqstp)
282{
283 while (rqstp->rq_resused) {
284 if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
285 continue;
286 rqstp->rq_argpages[rqstp->rq_arghi++] =
287 rqstp->rq_respages[rqstp->rq_resused];
288 rqstp->rq_respages[rqstp->rq_resused] = NULL;
289 }
290}
291
292static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp)
293{
294 while (rqstp->rq_resused &&
295 rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) {
296
297 if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) {
298 rqstp->rq_argpages[rqstp->rq_arghi++] =
299 rqstp->rq_respages[rqstp->rq_resused];
300 rqstp->rq_respages[rqstp->rq_resused] = NULL;
301 } 262 }
302 } 263 }
303} 264}
304 265
305static inline void svc_free_allpages(struct svc_rqst *rqstp)
306{
307 while (rqstp->rq_resused) {
308 if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
309 continue;
310 put_page(rqstp->rq_respages[rqstp->rq_resused]);
311 rqstp->rq_respages[rqstp->rq_resused] = NULL;
312 }
313}
314
315struct svc_deferred_req { 266struct svc_deferred_req {
316 u32 prot; /* protocol (UDP or TCP) */ 267 u32 prot; /* protocol (UDP or TCP) */
317 struct sockaddr_in addr; 268 struct sockaddr_in addr;
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 638c0b576203..558692d7e465 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1191,7 +1191,6 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
1191 resbuf->tail[0].iov_base = resbuf->head[0].iov_base 1191 resbuf->tail[0].iov_base = resbuf->head[0].iov_base
1192 + resbuf->head[0].iov_len; 1192 + resbuf->head[0].iov_len;
1193 resbuf->tail[0].iov_len = 0; 1193 resbuf->tail[0].iov_len = 0;
1194 rqstp->rq_restailpage = 0;
1195 resv = &resbuf->tail[0]; 1194 resv = &resbuf->tail[0];
1196 } else { 1195 } else {
1197 resv = &resbuf->tail[0]; 1196 resv = &resbuf->tail[0];
@@ -1240,7 +1239,7 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
1240 inpages = resbuf->pages; 1239 inpages = resbuf->pages;
1241 /* XXX: Would be better to write some xdr helper functions for 1240 /* XXX: Would be better to write some xdr helper functions for
1242 * nfs{2,3,4}xdr.c that place the data right, instead of copying: */ 1241 * nfs{2,3,4}xdr.c that place the data right, instead of copying: */
1243 if (resbuf->tail[0].iov_base && rqstp->rq_restailpage == 0) { 1242 if (resbuf->tail[0].iov_base) {
1244 BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base 1243 BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
1245 + PAGE_SIZE); 1244 + PAGE_SIZE);
1246 BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base); 1245 BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);
@@ -1258,7 +1257,6 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
1258 resbuf->tail[0].iov_base = resbuf->head[0].iov_base 1257 resbuf->tail[0].iov_base = resbuf->head[0].iov_base
1259 + resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE; 1258 + resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
1260 resbuf->tail[0].iov_len = 0; 1259 resbuf->tail[0].iov_len = 0;
1261 rqstp->rq_restailpage = 0;
1262 } 1260 }
1263 if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages)) 1261 if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
1264 return -ENOMEM; 1262 return -ENOMEM;
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index a99e67b164c1..f4a509a925b5 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -417,18 +417,15 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
417 if (size > RPCSVC_MAXPAYLOAD) 417 if (size > RPCSVC_MAXPAYLOAD)
418 size = RPCSVC_MAXPAYLOAD; 418 size = RPCSVC_MAXPAYLOAD;
419 pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE; 419 pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE;
420 rqstp->rq_argused = 0;
421 rqstp->rq_resused = 0;
422 arghi = 0; 420 arghi = 0;
423 BUG_ON(pages > RPCSVC_MAXPAGES); 421 BUG_ON(pages > RPCSVC_MAXPAGES);
424 while (pages) { 422 while (pages) {
425 struct page *p = alloc_page(GFP_KERNEL); 423 struct page *p = alloc_page(GFP_KERNEL);
426 if (!p) 424 if (!p)
427 break; 425 break;
428 rqstp->rq_argpages[arghi++] = p; 426 rqstp->rq_pages[arghi++] = p;
429 pages--; 427 pages--;
430 } 428 }
431 rqstp->rq_arghi = arghi;
432 return ! pages; 429 return ! pages;
433} 430}
434 431
@@ -438,14 +435,10 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
438static void 435static void
439svc_release_buffer(struct svc_rqst *rqstp) 436svc_release_buffer(struct svc_rqst *rqstp)
440{ 437{
441 while (rqstp->rq_arghi) 438 int i;
442 put_page(rqstp->rq_argpages[--rqstp->rq_arghi]); 439 for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
443 while (rqstp->rq_resused) { 440 if (rqstp->rq_pages[i])
444 if (rqstp->rq_respages[--rqstp->rq_resused] == NULL) 441 put_page(rqstp->rq_pages[i]);
445 continue;
446 put_page(rqstp->rq_respages[rqstp->rq_resused]);
447 }
448 rqstp->rq_argused = 0;
449} 442}
450 443
451/* 444/*
@@ -707,10 +700,10 @@ svc_process(struct svc_rqst *rqstp)
707 /* setup response xdr_buf. 700 /* setup response xdr_buf.
708 * Initially it has just one page 701 * Initially it has just one page
709 */ 702 */
710 svc_take_page(rqstp); /* must succeed */ 703 rqstp->rq_resused = 1;
711 resv->iov_base = page_address(rqstp->rq_respages[0]); 704 resv->iov_base = page_address(rqstp->rq_respages[0]);
712 resv->iov_len = 0; 705 resv->iov_len = 0;
713 rqstp->rq_res.pages = rqstp->rq_respages+1; 706 rqstp->rq_res.pages = rqstp->rq_respages + 1;
714 rqstp->rq_res.len = 0; 707 rqstp->rq_res.len = 0;
715 rqstp->rq_res.page_base = 0; 708 rqstp->rq_res.page_base = 0;
716 rqstp->rq_res.page_len = 0; 709 rqstp->rq_res.page_len = 0;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 4de8626e4f54..25096d53667a 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -313,7 +313,7 @@ svc_sock_release(struct svc_rqst *rqstp)
313 313
314 svc_release_skb(rqstp); 314 svc_release_skb(rqstp);
315 315
316 svc_free_allpages(rqstp); 316 svc_free_res_pages(rqstp);
317 rqstp->rq_res.page_len = 0; 317 rqstp->rq_res.page_len = 0;
318 rqstp->rq_res.page_base = 0; 318 rqstp->rq_res.page_base = 0;
319 319
@@ -412,7 +412,8 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
412 /* send head */ 412 /* send head */
413 if (slen == xdr->head[0].iov_len) 413 if (slen == xdr->head[0].iov_len)
414 flags = 0; 414 flags = 0;
415 len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags); 415 len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
416 xdr->head[0].iov_len, flags);
416 if (len != xdr->head[0].iov_len) 417 if (len != xdr->head[0].iov_len)
417 goto out; 418 goto out;
418 slen -= xdr->head[0].iov_len; 419 slen -= xdr->head[0].iov_len;
@@ -437,8 +438,9 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
437 } 438 }
438 /* send tail */ 439 /* send tail */
439 if (xdr->tail[0].iov_len) { 440 if (xdr->tail[0].iov_len) {
440 result = kernel_sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage], 441 result = kernel_sendpage(sock, rqstp->rq_respages[0],
441 ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1), 442 ((unsigned long)xdr->tail[0].iov_base)
443 & (PAGE_SIZE-1),
442 xdr->tail[0].iov_len, 0); 444 xdr->tail[0].iov_len, 0);
443 445
444 if (result > 0) 446 if (result > 0)
@@ -708,9 +710,11 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
708 if (len <= rqstp->rq_arg.head[0].iov_len) { 710 if (len <= rqstp->rq_arg.head[0].iov_len) {
709 rqstp->rq_arg.head[0].iov_len = len; 711 rqstp->rq_arg.head[0].iov_len = len;
710 rqstp->rq_arg.page_len = 0; 712 rqstp->rq_arg.page_len = 0;
713 rqstp->rq_respages = rqstp->rq_pages+1;
711 } else { 714 } else {
712 rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len; 715 rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
713 rqstp->rq_argused += (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE; 716 rqstp->rq_respages = rqstp->rq_pages + 1 +
717 (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
714 } 718 }
715 719
716 if (serv->sv_stats) 720 if (serv->sv_stats)
@@ -1053,11 +1057,12 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
1053 vlen = PAGE_SIZE; 1057 vlen = PAGE_SIZE;
1054 pnum = 1; 1058 pnum = 1;
1055 while (vlen < len) { 1059 while (vlen < len) {
1056 vec[pnum].iov_base = page_address(rqstp->rq_argpages[rqstp->rq_argused++]); 1060 vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]);
1057 vec[pnum].iov_len = PAGE_SIZE; 1061 vec[pnum].iov_len = PAGE_SIZE;
1058 pnum++; 1062 pnum++;
1059 vlen += PAGE_SIZE; 1063 vlen += PAGE_SIZE;
1060 } 1064 }
1065 rqstp->rq_respages = &rqstp->rq_pages[pnum];
1061 1066
1062 /* Now receive data */ 1067 /* Now receive data */
1063 len = svc_recvfrom(rqstp, vec, pnum, len); 1068 len = svc_recvfrom(rqstp, vec, pnum, len);
@@ -1209,7 +1214,7 @@ svc_recv(struct svc_rqst *rqstp, long timeout)
1209 struct svc_sock *svsk =NULL; 1214 struct svc_sock *svsk =NULL;
1210 struct svc_serv *serv = rqstp->rq_server; 1215 struct svc_serv *serv = rqstp->rq_server;
1211 struct svc_pool *pool = rqstp->rq_pool; 1216 struct svc_pool *pool = rqstp->rq_pool;
1212 int len; 1217 int len, i;
1213 int pages; 1218 int pages;
1214 struct xdr_buf *arg; 1219 struct xdr_buf *arg;
1215 DECLARE_WAITQUEUE(wait, current); 1220 DECLARE_WAITQUEUE(wait, current);
@@ -1226,27 +1231,22 @@ svc_recv(struct svc_rqst *rqstp, long timeout)
1226 "svc_recv: service %p, wait queue active!\n", 1231 "svc_recv: service %p, wait queue active!\n",
1227 rqstp); 1232 rqstp);
1228 1233
1229 /* Initialize the buffers */
1230 /* first reclaim pages that were moved to response list */
1231 svc_pushback_allpages(rqstp);
1232 1234
1233 /* now allocate needed pages. If we get a failure, sleep briefly */ 1235 /* now allocate needed pages. If we get a failure, sleep briefly */
1234 pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE; 1236 pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE;
1235 while (rqstp->rq_arghi < pages) { 1237 for (i=0; i < pages ; i++)
1236 struct page *p = alloc_page(GFP_KERNEL); 1238 while (rqstp->rq_pages[i] == NULL) {
1237 if (!p) { 1239 struct page *p = alloc_page(GFP_KERNEL);
1238 schedule_timeout_uninterruptible(msecs_to_jiffies(500)); 1240 if (!p)
1239 continue; 1241 schedule_timeout_uninterruptible(msecs_to_jiffies(500));
1242 rqstp->rq_pages[i] = p;
1240 } 1243 }
1241 rqstp->rq_argpages[rqstp->rq_arghi++] = p;
1242 }
1243 1244
1244 /* Make arg->head point to first page and arg->pages point to rest */ 1245 /* Make arg->head point to first page and arg->pages point to rest */
1245 arg = &rqstp->rq_arg; 1246 arg = &rqstp->rq_arg;
1246 arg->head[0].iov_base = page_address(rqstp->rq_argpages[0]); 1247 arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
1247 arg->head[0].iov_len = PAGE_SIZE; 1248 arg->head[0].iov_len = PAGE_SIZE;
1248 rqstp->rq_argused = 1; 1249 arg->pages = rqstp->rq_pages + 1;
1249 arg->pages = rqstp->rq_argpages + 1;
1250 arg->page_base = 0; 1250 arg->page_base = 0;
1251 /* save at least one page for response */ 1251 /* save at least one page for response */
1252 arg->page_len = (pages-2)*PAGE_SIZE; 1252 arg->page_len = (pages-2)*PAGE_SIZE;
@@ -1704,6 +1704,7 @@ static int svc_deferred_recv(struct svc_rqst *rqstp)
1704 rqstp->rq_prot = dr->prot; 1704 rqstp->rq_prot = dr->prot;
1705 rqstp->rq_addr = dr->addr; 1705 rqstp->rq_addr = dr->addr;
1706 rqstp->rq_daddr = dr->daddr; 1706 rqstp->rq_daddr = dr->daddr;
1707 rqstp->rq_respages = rqstp->rq_pages;
1707 return dr->argslen<<2; 1708 return dr->argslen<<2;
1708} 1709}
1709 1710