mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
nfsd/nfsd3_proc_readdir: fix buffer count and page pointers
After this commitf875a79
nfsd: allow nfsv3 readdir request to be larger. nfsv3 readdir request size can be larger than PAGE_SIZE. So if the directory been read is large enough, we can use multiple pages in rq_respages. Update buffer count and page pointers like we do in readdirplus to make this happen. Now listing a directory within 3000 files will panic because we are counting in a wrong way and would write on random page. Fixes:f875a79
"nfsd: allow nfsv3 readdir request to be larger" Signed-off-by: Murphy Zhou <jencce.kernel@gmail.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
d58431eacb
commit
3c86794ac0
2 changed files with 24 additions and 4 deletions
|
@ -442,7 +442,9 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
||||||
struct nfsd3_readdirargs *argp = rqstp->rq_argp;
|
struct nfsd3_readdirargs *argp = rqstp->rq_argp;
|
||||||
struct nfsd3_readdirres *resp = rqstp->rq_resp;
|
struct nfsd3_readdirres *resp = rqstp->rq_resp;
|
||||||
__be32 nfserr;
|
__be32 nfserr;
|
||||||
int count;
|
int count = 0;
|
||||||
|
struct page **p;
|
||||||
|
caddr_t page_addr = NULL;
|
||||||
|
|
||||||
dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
|
dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
|
||||||
SVCFH_fmt(&argp->fh),
|
SVCFH_fmt(&argp->fh),
|
||||||
|
@ -462,7 +464,18 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
||||||
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
|
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
|
||||||
&resp->common, nfs3svc_encode_entry);
|
&resp->common, nfs3svc_encode_entry);
|
||||||
memcpy(resp->verf, argp->verf, 8);
|
memcpy(resp->verf, argp->verf, 8);
|
||||||
resp->count = resp->buffer - argp->buffer;
|
count = 0;
|
||||||
|
for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
|
||||||
|
page_addr = page_address(*p);
|
||||||
|
|
||||||
|
if (((caddr_t)resp->buffer >= page_addr) &&
|
||||||
|
((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
|
||||||
|
count += (caddr_t)resp->buffer - page_addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
resp->count = count >> 2;
|
||||||
if (resp->offset) {
|
if (resp->offset) {
|
||||||
loff_t offset = argp->cookie;
|
loff_t offset = argp->cookie;
|
||||||
|
|
||||||
|
|
|
@ -573,6 +573,7 @@ int
|
||||||
nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
|
nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
|
||||||
{
|
{
|
||||||
struct nfsd3_readdirargs *args = rqstp->rq_argp;
|
struct nfsd3_readdirargs *args = rqstp->rq_argp;
|
||||||
|
int len;
|
||||||
u32 max_blocksize = svc_max_payload(rqstp);
|
u32 max_blocksize = svc_max_payload(rqstp);
|
||||||
|
|
||||||
p = decode_fh(p, &args->fh);
|
p = decode_fh(p, &args->fh);
|
||||||
|
@ -582,8 +583,14 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
|
||||||
args->verf = p; p += 2;
|
args->verf = p; p += 2;
|
||||||
args->dircount = ~0;
|
args->dircount = ~0;
|
||||||
args->count = ntohl(*p++);
|
args->count = ntohl(*p++);
|
||||||
args->count = min_t(u32, args->count, max_blocksize);
|
len = args->count = min_t(u32, args->count, max_blocksize);
|
||||||
args->buffer = page_address(*(rqstp->rq_next_page++));
|
|
||||||
|
while (len > 0) {
|
||||||
|
struct page *p = *(rqstp->rq_next_page++);
|
||||||
|
if (!args->buffer)
|
||||||
|
args->buffer = page_address(p);
|
||||||
|
len -= PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
return xdr_argsize_check(rqstp, p);
|
return xdr_argsize_check(rqstp, p);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue