]>
Commit | Line | Data |
---|---|---|
52761858 SL |
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 |