aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs3xdr.c
diff options
context:
space:
mode:
authorMurphy Zhou <jencce.kernel@gmail.com>2019-04-04 14:57:11 +0800
committerJ. Bruce Fields <bfields@redhat.com>2019-04-05 19:57:24 -0400
commit3c86794ac0e6582eea7733619d58ea150198502f (patch)
tree097ea6e5d63a6fc920c1c0b30f7de874f148b4cf /fs/nfsd/nfs3xdr.c
parentsunrpc: don't mark uninitialised items as VALID. (diff)
downloadlinux-dev-3c86794ac0e6582eea7733619d58ea150198502f.tar.xz
linux-dev-3c86794ac0e6582eea7733619d58ea150198502f.zip
nfsd/nfsd3_proc_readdir: fix buffer count and page pointers
After this commit f875a79 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>
Diffstat (limited to '')
-rw-r--r--fs/nfsd/nfs3xdr.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 93fea246f676..8d789124ed3c 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -573,6 +573,7 @@ int
nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
{
struct nfsd3_readdirargs *args = rqstp->rq_argp;
+ int len;
u32 max_blocksize = svc_max_payload(rqstp);
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->dircount = ~0;
args->count = ntohl(*p++);
- args->count = min_t(u32, args->count, max_blocksize);
- args->buffer = page_address(*(rqstp->rq_next_page++));
+ len = args->count = min_t(u32, args->count, max_blocksize);
+
+ 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);
}