[PATCH v2 10/12] fuse: support large folios for direct io

Joanne Koong
2024-11-25T22:06:09Z

Add support for folios larger than one page size for direct io.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
---
fs/fuse/file.c | 34 ++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 590a3f2fa310..a907848f387a 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1482,7 +1482,8 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
return -ENOMEM;

while (nbytes < *nbytesp && nr_pages < max_pages) {
- unsigned nfolios, i;
+ unsigned npages;
+ unsigned i = 0;
size_t start;

ret = iov_iter_extract_pages(ii, &pages,
@@ -1494,19 +1495,28 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,

nbytes += ret;

- ret += start;
- /* Currently, all folios in FUSE are one page */
- nfolios = DIV_ROUND_UP(ret, PAGE_SIZE);
+ npages = DIV_ROUND_UP(ret + start, PAGE_SIZE);

- ap->descs[ap->num_folios].offset = start;
- fuse_folio_descs_length_init(ap->descs, ap->num_folios, nfolios);
- for (i = 0; i < nfolios; i++)
- ap->folios[i + ap->num_folios] = page_folio(pages[i]);
+ while (ret && i < npages) {
+ struct folio *folio;
+ unsigned int folio_offset;
+ unsigned int len;

- ap->num_folios += nfolios;
- ap->descs[ap->num_folios - 1].length -=
- (PAGE_SIZE - ret) & (PAGE_SIZE - 1);
- nr_pages += nfolios;
+ folio = page_folio(pages[i]);
+ folio_offset = ((size_t)folio_page_idx(folio, pages[i]) <<
+ PAGE_SHIFT) + start;
+ len = min_t(ssize_t, ret, folio_size(folio) - folio_offset);
+
+ ap->folios[ap->num_folios] = folio;
+ ap->descs[ap->num_folios].offset = folio_offset;
+ ap->descs[ap->num_folios].length = len;
+ ap->num_folios++;
+
+ ret -= len;
+ i += DIV_ROUND_UP(start + len, PAGE_SIZE);
+ start = 0;
+ }
+ nr_pages += npages;
}
kfree(pages);

--
2.43.5