summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2026-07-22 15:42:18 +0200
committerChristian Brauner <brauner@kernel.org>2026-07-31 12:28:47 +0200
commitfb770bb6fedffd1ce530e43d174518d2de3ea763 (patch)
tree1ddd46139ee876ce93edee45e83d51efe2b8052b
parent9dd2ac120e493ccd3ca554279c567fad149d6c5b (diff)
parent881a27082e4d7faf21ad6960a3c6a0b6c5abc78d (diff)
Merge patch series "iomap/fuse: add helper to keep uptodate bitmap in sync"
Joanne Koong <joannelkoong@gmail.com> says: iomap/fuse: add helper to keep uptodate bitmap in sync Filesystems that use iomap normally mark folios uptodate through the iomap read/write paths, which keep iomap's internal uptodate bitmap in sync. However, some filesystems need to write data directly into the page cache outside of those paths (eg fuse, which may need to write server-pushed data straight into the page cache for servicing notify stores). These filesystems need a way to mark a folio uptodate that also updates the iomap bitmap so they're kept in sync. This series adds iomap_folio_mark_uptodate() for filesystems to do that and updates the relevant fuse call paths to use this. This is needed before fuse can enable large folios. Patch 1 ("fuse: don't clear folio uptodate on writethrough errors") was originally submitted to the fuse tree [1] but patch 3 ("fuse: use iomap helper to mark folio uptodate") has a dependency on it, so to make cross-coordination between trees easier, patch 1 is now part of this series and submitted to the vfs tree. [1] https://lore.kernel.org/fuse-devel/20260624205201.842714-1-joannelkoong@gmail.com/ * patches from https://patch.msgid.link/20260707220450.1200943-1-joannelkoong@gmail.com: fuse: use iomap helper to mark folio uptodate iomap: add helper to mark folio uptodate fuse: don't clear folio uptodate on writethrough errors Link: https://patch.msgid.link/20260707220450.1200943-1-joannelkoong@gmail.com Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
-rw-r--r--fs/fuse/file.c20
-rw-r--r--fs/fuse/notify.c4
-rw-r--r--fs/iomap/buffered-io.c6
-rw-r--r--include/linux/iomap.h1
4 files changed, 12 insertions, 19 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index e052a0d44dee..ea4a15a7635a 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1227,8 +1227,7 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
struct file *file = iocb->ki_filp;
struct fuse_file *ff = file->private_data;
struct fuse_mount *fm = ff->fm;
- unsigned int offset, i;
- bool short_write;
+ unsigned int i;
int err;
for (i = 0; i < ap->num_folios; i++)
@@ -1243,24 +1242,9 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
if (!err && ia->write.out.size > count)
err = -EIO;
- short_write = ia->write.out.size < count;
- offset = ap->descs[0].offset;
- count = ia->write.out.size;
for (i = 0; i < ap->num_folios; i++) {
struct folio *folio = ap->folios[i];
- if (err) {
- folio_clear_uptodate(folio);
- } else {
- if (count >= folio_size(folio) - offset)
- count -= folio_size(folio) - offset;
- else {
- if (short_write)
- folio_clear_uptodate(folio);
- count = 0;
- }
- offset = 0;
- }
if (ia->write.folio_locked && (i == ap->num_folios - 1))
folio_unlock(folio);
folio_put(folio);
@@ -1335,7 +1319,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
/* If we copied full folio, mark it uptodate */
if (tmp == folio_size(folio))
- folio_mark_uptodate(folio);
+ iomap_folio_mark_uptodate(folio);
if (folio_test_uptodate(folio)) {
folio_unlock(folio);
diff --git a/fs/fuse/notify.c b/fs/fuse/notify.c
index 29578104ae6c..1ba763705d91 100644
--- a/fs/fuse/notify.c
+++ b/fs/fuse/notify.c
@@ -2,6 +2,8 @@
#include "dev.h"
#include "fuse_i.h"
+
+#include <linux/iomap.h>
#include <linux/pagemap.h>
static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size,
@@ -192,7 +194,7 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
if (!folio_test_uptodate(folio) && !err && folio_offset == 0 &&
(nr_bytes == folio_size(folio) || file_size == end)) {
folio_zero_segment(folio, nr_bytes, folio_size(folio));
- folio_mark_uptodate(folio);
+ iomap_folio_mark_uptodate(folio);
}
folio_unlock(folio);
folio_put(folio);
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 27bc2455a98d..f6040199d114 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -105,6 +105,12 @@ static void iomap_set_range_uptodate(struct folio *folio, size_t off,
folio_mark_uptodate(folio);
}
+void iomap_folio_mark_uptodate(struct folio *folio)
+{
+ iomap_set_range_uptodate(folio, 0, folio_size(folio));
+}
+EXPORT_SYMBOL_GPL(iomap_folio_mark_uptodate);
+
/*
* Find the next dirty block in the folio. end_blk is inclusive.
* If no dirty block is found, this will return end_blk + 1.
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 3582ed1fe236..21e73cb9c51e 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -365,6 +365,7 @@ struct folio *iomap_get_folio(struct iomap_iter *iter, loff_t pos, size_t len);
bool iomap_release_folio(struct folio *folio, gfp_t gfp_flags);
void iomap_invalidate_folio(struct folio *folio, size_t offset, size_t len);
bool iomap_dirty_folio(struct address_space *mapping, struct folio *folio);
+void iomap_folio_mark_uptodate(struct folio *folio);
int iomap_file_unshare(struct inode *inode, loff_t pos, loff_t len,
const struct iomap_ops *ops,
const struct iomap_write_ops *write_ops);