]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.15/nfsd_splice_actor-handle-compound-pages.patch
Fixes for 5.15
[thirdparty/kernel/stable-queue.git] / queue-5.15 / nfsd_splice_actor-handle-compound-pages.patch
1 From 39db3090791509dadb896ad8a1d1cebefed7c733 Mon Sep 17 00:00:00 2001
2 From: Sasha Levin <sashal@kernel.org>
3 Date: Sat, 10 Sep 2022 22:14:02 +0100
4 Subject: nfsd_splice_actor(): handle compound pages
5
6 From: Al Viro <viro@zeniv.linux.org.uk>
7
8 [ Upstream commit bfbfb6182ad1d7d184b16f25165faad879147f79 ]
9
10 pipe_buffer might refer to a compound page (and contain more than a PAGE_SIZE
11 worth of data). Theoretically it had been possible since way back, but
12 nfsd_splice_actor() hadn't run into that until copy_page_to_iter() change.
13 Fortunately, the only thing that changes for compound pages is that we
14 need to stuff each relevant subpage in and convert the offset into offset
15 in the first subpage.
16
17 Acked-by: Chuck Lever <chuck.lever@oracle.com>
18 Tested-by: Benjamin Coddington <bcodding@redhat.com>
19 Fixes: f0f6b614f83d "copy_page_to_iter(): don't split high-order page in case of ITER_PIPE"
20 Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
21 Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
22 ---
23 fs/nfsd/vfs.c | 13 +++++++++----
24 1 file changed, 9 insertions(+), 4 deletions(-)
25
26 diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
27 index ad689215b1f37..343af6341e5e1 100644
28 --- a/fs/nfsd/vfs.c
29 +++ b/fs/nfsd/vfs.c
30 @@ -846,10 +846,15 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
31 struct splice_desc *sd)
32 {
33 struct svc_rqst *rqstp = sd->u.data;
34 -
35 - svc_rqst_replace_page(rqstp, buf->page);
36 - if (rqstp->rq_res.page_len == 0)
37 - rqstp->rq_res.page_base = buf->offset;
38 + struct page *page = buf->page; // may be a compound one
39 + unsigned offset = buf->offset;
40 + int i;
41 +
42 + page += offset / PAGE_SIZE;
43 + for (i = sd->len; i > 0; i -= PAGE_SIZE)
44 + svc_rqst_replace_page(rqstp, page++);
45 + if (rqstp->rq_res.page_len == 0) // first call
46 + rqstp->rq_res.page_base = offset % PAGE_SIZE;
47 rqstp->rq_res.page_len += sd->len;
48 return sd->len;
49 }
50 --
51 2.43.0
52