aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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