diff options
-rw-r--r-- | fs/nfsd/nfs2acl.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs3acl.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 23 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 27 | ||||
-rw-r--r-- | fs/nfsd/nfsxdr.c | 13 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 16 | ||||
-rw-r--r-- | include/linux/sunrpc/svc.h | 69 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 4 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 21 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 41 |
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 | ||
2041 | static int | 2041 | static int |
2042 | nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read) | 2042 | nfsd4_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 | */ |
175 | struct svc_rqst { | 174 | struct 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 | ||
258 | static inline struct page * | 254 | static inline void svc_free_res_pages(struct svc_rqst *rqstp) |
259 | svc_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 | |||
269 | static 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 | |||
281 | static 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 | |||
292 | static 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 | ||
305 | static 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 | |||
315 | struct svc_deferred_req { | 266 | struct 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) | |||
438 | static void | 435 | static void |
439 | svc_release_buffer(struct svc_rqst *rqstp) | 436 | svc_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 | ||