Commit 6ed6decc authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] knfsd: nfsd4: fix corruption of returned data when using 64k pages

In v4 we grab an extra page just for the padding of returned data.  The
formula that the rpc server uses to allocate pages for the response doesn't
take into account this extra page.

Instead of adjusting those formulae, we adopt the same solution as v2 and v3,
and put the "tail" data in the same page as the "head" data.
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f0e2993e
......@@ -2084,27 +2084,20 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
WRITE32(eof);
WRITE32(maxcount);
ADJUST_ARGS();
resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
resp->xbuf->head[0].iov_len = (char*)p
- (char*)resp->xbuf->head[0].iov_base;
resp->xbuf->page_len = maxcount;
/* read zero bytes -> don't set up tail */
if(!maxcount)
return 0;
/* set up page for remaining responses */
svc_take_page(resp->rqstp);
resp->xbuf->tail[0].iov_base =
page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
resp->rqstp->rq_restailpage = resp->rqstp->rq_resused-1;
/* Use rest of head for padding and remaining ops: */
resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = p;
resp->xbuf->tail[0].iov_len = 0;
resp->p = resp->xbuf->tail[0].iov_base;
resp->end = resp->p + PAGE_SIZE/4;
if (maxcount&3) {
*(resp->p)++ = 0;
RESERVE_SPACE(4);
WRITE32(0);
resp->xbuf->tail[0].iov_base += maxcount&3;
resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
ADJUST_ARGS();
}
return 0;
}
......@@ -2141,21 +2134,20 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
WRITE32(maxcount);
ADJUST_ARGS();
resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
resp->xbuf->head[0].iov_len = (char*)p
- (char*)resp->xbuf->head[0].iov_base;
resp->xbuf->page_len = maxcount;
svc_take_page(resp->rqstp);
resp->xbuf->tail[0].iov_base =
page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
resp->rqstp->rq_restailpage = resp->rqstp->rq_resused-1;
/* Use rest of head for padding and remaining ops: */
resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = p;
resp->xbuf->tail[0].iov_len = 0;
resp->p = resp->xbuf->tail[0].iov_base;
resp->end = resp->p + PAGE_SIZE/4;
resp->xbuf->page_len = maxcount;
if (maxcount&3) {
*(resp->p)++ = 0;
RESERVE_SPACE(4);
WRITE32(0);
resp->xbuf->tail[0].iov_base += maxcount&3;
resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
ADJUST_ARGS();
}
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment