]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fuse: use iomap for read_folio
authorJoanne Koong <joannelkoong@gmail.com>
Fri, 26 Sep 2025 00:26:07 +0000 (17:26 -0700)
committerChristian Brauner <brauner@kernel.org>
Wed, 5 Nov 2025 11:57:23 +0000 (12:57 +0100)
Read folio data into the page cache using iomap. This gives us granular
uptodate tracking for large folios, which optimizes how much data needs
to be read in. If some portions of the folio are already uptodate (eg
through a prior write), we only need to read in the non-uptodate
portions.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/fuse/file.c

index f1ef77a0be05bbee8991a0b1bdf61644e58b6c50..0e4f8734fe9d874a5ed5ad0907bebf51c8eca864 100644 (file)
@@ -834,23 +834,69 @@ static int fuse_do_readfolio(struct file *file, struct folio *folio,
        return 0;
 }
 
+static int fuse_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
+                           unsigned int flags, struct iomap *iomap,
+                           struct iomap *srcmap)
+{
+       iomap->type = IOMAP_MAPPED;
+       iomap->length = length;
+       iomap->offset = offset;
+       return 0;
+}
+
+static const struct iomap_ops fuse_iomap_ops = {
+       .iomap_begin    = fuse_iomap_begin,
+};
+
+struct fuse_fill_read_data {
+       struct file *file;
+};
+
+static int fuse_iomap_read_folio_range_async(const struct iomap_iter *iter,
+                                            struct iomap_read_folio_ctx *ctx,
+                                            size_t len)
+{
+       struct fuse_fill_read_data *data = ctx->read_ctx;
+       struct folio *folio = ctx->cur_folio;
+       loff_t pos =  iter->pos;
+       size_t off = offset_in_folio(folio, pos);
+       struct file *file = data->file;
+       int ret;
+
+       /*
+        *  for non-readahead read requests, do reads synchronously since
+        *  it's not guaranteed that the server can handle out-of-order reads
+        */
+       ret = fuse_do_readfolio(file, folio, off, len);
+       iomap_finish_folio_read(folio, off, len, ret);
+       return ret;
+}
+
+static const struct iomap_read_ops fuse_iomap_read_ops = {
+       .read_folio_range = fuse_iomap_read_folio_range_async,
+};
+
 static int fuse_read_folio(struct file *file, struct folio *folio)
 {
        struct inode *inode = folio->mapping->host;
-       int err;
+       struct fuse_fill_read_data data = {
+               .file = file,
+       };
+       struct iomap_read_folio_ctx ctx = {
+               .cur_folio = folio,
+               .ops = &fuse_iomap_read_ops,
+               .read_ctx = &data,
 
-       err = -EIO;
-       if (fuse_is_bad(inode))
-               goto out;
+       };
 
-       err = fuse_do_readfolio(file, folio, 0, folio_size(folio));
-       if (!err)
-               folio_mark_uptodate(folio);
+       if (fuse_is_bad(inode)) {
+               folio_unlock(folio);
+               return -EIO;
+       }
 
+       iomap_read_folio(&fuse_iomap_ops, &ctx);
        fuse_invalidate_atime(inode);
- out:
-       folio_unlock(folio);
-       return err;
+       return 0;
 }
 
 static int fuse_iomap_read_folio_range(const struct iomap_iter *iter,
@@ -1397,20 +1443,6 @@ static const struct iomap_write_ops fuse_iomap_write_ops = {
        .read_folio_range = fuse_iomap_read_folio_range,
 };
 
-static int fuse_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
-                           unsigned int flags, struct iomap *iomap,
-                           struct iomap *srcmap)
-{
-       iomap->type = IOMAP_MAPPED;
-       iomap->length = length;
-       iomap->offset = offset;
-       return 0;
-}
-
-static const struct iomap_ops fuse_iomap_ops = {
-       .iomap_begin    = fuse_iomap_begin,
-};
-
 static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct file *file = iocb->ki_filp;