This adds support in struct fuse_args_pages and fuse_copy_pages() for using folios instead of pages for transferring data. Both folios and pages must be supported right now in struct fuse_args_pages and fuse_copy_pages() until all request types have been converted to use folios. Once all have been converted, then struct fuse_args_pages and fuse_copy_pages() will only support folios. Right now in fuse, all folios are one page (large folios are not yet supported). As such, copying folio->page is sufficient for copying the entire folio in fuse_copy_pages(). No functional changes. Signed-off-by: Joanne Koong <joannelkoong@xxxxxxxxx> Reviewed-by: Josef Bacik <josef@xxxxxxxxxxxxxx> --- fs/fuse/dev.c | 40 ++++++++++++++++++++++++++++++++-------- fs/fuse/fuse_i.h | 22 +++++++++++++++++++--- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 5edad55750b0..9f860bd655a4 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1028,17 +1028,41 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, struct fuse_req *req = cs->req; struct fuse_args_pages *ap = container_of(req->args, typeof(*ap), args); + if (ap->uses_folios) { + for (i = 0; i < ap->num_folios && (nbytes || zeroing); i++) { + int err; + unsigned int offset = ap->folio_descs[i].offset; + unsigned int count = min(nbytes, ap->folio_descs[i].length); + struct page *orig, *pagep; - for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) { - int err; - unsigned int offset = ap->descs[i].offset; - unsigned int count = min(nbytes, ap->descs[i].length); + orig = pagep = &ap->folios[i]->page; - err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing); - if (err) - return err; + err = fuse_copy_page(cs, &pagep, offset, count, zeroing); + if (err) + return err; + + nbytes -= count; + + /* + * fuse_copy_page may have moved a page from a pipe + * instead of copying into our given page, so update + * the folios if it was replaced. + */ + if (pagep != orig) + ap->folios[i] = page_folio(pagep); + } + } else { + for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) { + int err; + unsigned int offset = ap->descs[i].offset; + unsigned int count = min(nbytes, ap->descs[i].length); - nbytes -= count; + err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing); + if (err) + return err; + + nbytes -= count; + } } return 0; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 671daa4d07ad..24a3da8400d1 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -291,6 +291,12 @@ struct fuse_page_desc { unsigned int offset; }; +/** FUSE folio descriptor */ +struct fuse_folio_desc { + unsigned int length; + unsigned int offset; +}; + struct fuse_args { uint64_t nodeid; uint32_t opcode; @@ -319,9 +325,19 @@ struct fuse_args { struct fuse_args_pages { struct fuse_args args; - struct page **pages; - struct fuse_page_desc *descs; - unsigned int num_pages; + union { + struct { + struct page **pages; + struct fuse_page_desc *descs; + unsigned int num_pages; + }; + struct { + struct folio **folios; + struct fuse_folio_desc *folio_descs; + unsigned int num_folios; + }; + }; + bool uses_folios; }; struct fuse_release_args { -- 2.43.5