Skip to content

Commit 394244b

Browse files
joannekoongMiklos Szeredi
authored andcommitted
fuse: support copying large folios
Currently, all folios associated with fuse are one page size. As part of the work to enable large folios, this commit adds support for copying to/from folios larger than one page size. Signed-off-by: Joanne Koong <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Reviewed-by: Bernd Schubert <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent f092229 commit 394244b

File tree

2 files changed

+49
-50
lines changed

2 files changed

+49
-50
lines changed

fs/fuse/dev.c

Lines changed: 48 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -956,10 +956,10 @@ static int fuse_check_folio(struct folio *folio)
956956
* folio that was originally in @pagep will lose a reference and the new
957957
* folio returned in @pagep will carry a reference.
958958
*/
959-
static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
959+
static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliop)
960960
{
961961
int err;
962-
struct folio *oldfolio = page_folio(*pagep);
962+
struct folio *oldfolio = *foliop;
963963
struct folio *newfolio;
964964
struct pipe_buffer *buf = cs->pipebufs;
965965

@@ -980,7 +980,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
980980
cs->pipebufs++;
981981
cs->nr_segs--;
982982

983-
if (cs->len != PAGE_SIZE)
983+
if (cs->len != folio_size(oldfolio))
984984
goto out_fallback;
985985

986986
if (!pipe_buf_try_steal(cs->pipe, buf))
@@ -1026,7 +1026,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
10261026
if (test_bit(FR_ABORTED, &cs->req->flags))
10271027
err = -ENOENT;
10281028
else
1029-
*pagep = &newfolio->page;
1029+
*foliop = newfolio;
10301030
spin_unlock(&cs->req->waitq.lock);
10311031

10321032
if (err) {
@@ -1059,26 +1059,26 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
10591059
goto out_put_old;
10601060
}
10611061

1062-
static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
1063-
unsigned offset, unsigned count)
1062+
static int fuse_ref_folio(struct fuse_copy_state *cs, struct folio *folio,
1063+
unsigned offset, unsigned count)
10641064
{
10651065
struct pipe_buffer *buf;
10661066
int err;
10671067

10681068
if (cs->nr_segs >= cs->pipe->max_usage)
10691069
return -EIO;
10701070

1071-
get_page(page);
1071+
folio_get(folio);
10721072
err = unlock_request(cs->req);
10731073
if (err) {
1074-
put_page(page);
1074+
folio_put(folio);
10751075
return err;
10761076
}
10771077

10781078
fuse_copy_finish(cs);
10791079

10801080
buf = cs->pipebufs;
1081-
buf->page = page;
1081+
buf->page = &folio->page;
10821082
buf->offset = offset;
10831083
buf->len = count;
10841084

@@ -1090,20 +1090,24 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
10901090
}
10911091

10921092
/*
1093-
* Copy a page in the request to/from the userspace buffer. Must be
1093+
* Copy a folio in the request to/from the userspace buffer. Must be
10941094
* done atomically
10951095
*/
1096-
static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
1097-
unsigned offset, unsigned count, int zeroing)
1096+
static int fuse_copy_folio(struct fuse_copy_state *cs, struct folio **foliop,
1097+
unsigned offset, unsigned count, int zeroing)
10981098
{
10991099
int err;
1100-
struct page *page = *pagep;
1100+
struct folio *folio = *foliop;
1101+
size_t size;
11011102

1102-
if (page && zeroing && count < PAGE_SIZE)
1103-
clear_highpage(page);
1103+
if (folio) {
1104+
size = folio_size(folio);
1105+
if (zeroing && count < size)
1106+
folio_zero_range(folio, 0, size);
1107+
}
11041108

11051109
while (count) {
1106-
if (cs->write && cs->pipebufs && page) {
1110+
if (cs->write && cs->pipebufs && folio) {
11071111
/*
11081112
* Can't control lifetime of pipe buffers, so always
11091113
* copy user pages.
@@ -1113,12 +1117,12 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
11131117
if (err)
11141118
return err;
11151119
} else {
1116-
return fuse_ref_page(cs, page, offset, count);
1120+
return fuse_ref_folio(cs, folio, offset, count);
11171121
}
11181122
} else if (!cs->len) {
1119-
if (cs->move_pages && page &&
1120-
offset == 0 && count == PAGE_SIZE) {
1121-
err = fuse_try_move_page(cs, pagep);
1123+
if (cs->move_folios && folio &&
1124+
offset == 0 && count == size) {
1125+
err = fuse_try_move_folio(cs, foliop);
11221126
if (err <= 0)
11231127
return err;
11241128
} else {
@@ -1127,22 +1131,30 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
11271131
return err;
11281132
}
11291133
}
1130-
if (page) {
1131-
void *mapaddr = kmap_local_page(page);
1132-
void *buf = mapaddr + offset;
1133-
offset += fuse_copy_do(cs, &buf, &count);
1134+
if (folio) {
1135+
void *mapaddr = kmap_local_folio(folio, offset);
1136+
void *buf = mapaddr;
1137+
unsigned int copy = count;
1138+
unsigned int bytes_copied;
1139+
1140+
if (folio_test_highmem(folio) && count > PAGE_SIZE - offset_in_page(offset))
1141+
copy = PAGE_SIZE - offset_in_page(offset);
1142+
1143+
bytes_copied = fuse_copy_do(cs, &buf, &copy);
11341144
kunmap_local(mapaddr);
1145+
offset += bytes_copied;
1146+
count -= bytes_copied;
11351147
} else
11361148
offset += fuse_copy_do(cs, NULL, &count);
11371149
}
1138-
if (page && !cs->write)
1139-
flush_dcache_page(page);
1150+
if (folio && !cs->write)
1151+
flush_dcache_folio(folio);
11401152
return 0;
11411153
}
11421154

1143-
/* Copy pages in the request to/from userspace buffer */
1144-
static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
1145-
int zeroing)
1155+
/* Copy folios in the request to/from userspace buffer */
1156+
static int fuse_copy_folios(struct fuse_copy_state *cs, unsigned nbytes,
1157+
int zeroing)
11461158
{
11471159
unsigned i;
11481160
struct fuse_req *req = cs->req;
@@ -1152,23 +1164,12 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
11521164
int err;
11531165
unsigned int offset = ap->descs[i].offset;
11541166
unsigned int count = min(nbytes, ap->descs[i].length);
1155-
struct page *orig, *pagep;
11561167

1157-
orig = pagep = &ap->folios[i]->page;
1158-
1159-
err = fuse_copy_page(cs, &pagep, offset, count, zeroing);
1168+
err = fuse_copy_folio(cs, &ap->folios[i], offset, count, zeroing);
11601169
if (err)
11611170
return err;
11621171

11631172
nbytes -= count;
1164-
1165-
/*
1166-
* fuse_copy_page may have moved a page from a pipe instead of
1167-
* copying into our given page, so update the folios if it was
1168-
* replaced.
1169-
*/
1170-
if (pagep != orig)
1171-
ap->folios[i] = page_folio(pagep);
11721173
}
11731174
return 0;
11741175
}
@@ -1198,7 +1199,7 @@ int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs,
11981199
for (i = 0; !err && i < numargs; i++) {
11991200
struct fuse_arg *arg = &args[i];
12001201
if (i == numargs - 1 && argpages)
1201-
err = fuse_copy_pages(cs, arg->size, zeroing);
1202+
err = fuse_copy_folios(cs, arg->size, zeroing);
12021203
else
12031204
err = fuse_copy_one(cs, arg->value, arg->size);
12041205
}
@@ -1787,17 +1788,15 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
17871788
num = outarg.size;
17881789
while (num) {
17891790
struct folio *folio;
1790-
struct page *page;
17911791
unsigned int this_num;
17921792

17931793
folio = filemap_grab_folio(mapping, index);
17941794
err = PTR_ERR(folio);
17951795
if (IS_ERR(folio))
17961796
goto out_iput;
17971797

1798-
page = &folio->page;
17991798
this_num = min_t(unsigned, num, folio_size(folio) - offset);
1800-
err = fuse_copy_page(cs, &page, offset, this_num, 0);
1799+
err = fuse_copy_folio(cs, &folio, offset, this_num, 0);
18011800
if (!folio_test_uptodate(folio) && !err && offset == 0 &&
18021801
(this_num == folio_size(folio) || file_size == end)) {
18031802
folio_zero_segment(folio, this_num, folio_size(folio));
@@ -2038,8 +2037,8 @@ static int fuse_notify_inc_epoch(struct fuse_conn *fc)
20382037
static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
20392038
unsigned int size, struct fuse_copy_state *cs)
20402039
{
2041-
/* Don't try to move pages (yet) */
2042-
cs->move_pages = false;
2040+
/* Don't try to move folios (yet) */
2041+
cs->move_folios = false;
20432042

20442043
switch (code) {
20452044
case FUSE_NOTIFY_POLL:
@@ -2190,7 +2189,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
21902189
spin_unlock(&fpq->lock);
21912190
cs->req = req;
21922191
if (!req->args->page_replace)
2193-
cs->move_pages = false;
2192+
cs->move_folios = false;
21942193

21952194
if (oh.error)
21962195
err = nbytes != sizeof(oh) ? -EINVAL : 0;
@@ -2308,7 +2307,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
23082307
cs.pipe = pipe;
23092308

23102309
if (flags & SPLICE_F_MOVE)
2311-
cs.move_pages = true;
2310+
cs.move_folios = true;
23122311

23132312
ret = fuse_dev_do_write(fud, &cs, len);
23142313

fs/fuse/fuse_dev_i.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct fuse_copy_state {
3030
unsigned int len;
3131
unsigned int offset;
3232
bool write:1;
33-
bool move_pages:1;
33+
bool move_folios:1;
3434
bool is_uring:1;
3535
struct {
3636
unsigned int copied_sz; /* copied size into the user buffer */

0 commit comments

Comments
 (0)