[PATCH] fuse: when copying a folio delay the mark dirty until the end

From: Horst Birthelmer

Date: Mon Mar 16 2026 - 11:33:52 EST


From: Horst Birthelmer <hbirthelmer@xxxxxxx>

Doing set_page_dirty_lock() for every page is inefficient
for large folios.
When copying a folio (and with large folios enabled,
this can be many pages) we can delay the marking dirty
and flush_dcache_page() until the whole folio is handled
and do it once per folio instead of once per page.

Signed-off-by: Horst Birthelmer <hbirthelmer@xxxxxxx>
---
Currently when doing a folio copy
flush_dcache_page(cs->pg) and set_page_dirty_lock(cs->pg)
are called for every page.

We can do this at the end for the whole folio.
---
fs/fuse/dev.c | 9 +++++++--
fs/fuse/fuse_dev_i.h | 1 +
2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 0b0241f47170d4640f0b8f3cae8be1f78944a456..ae96a48f898e883b4e96147f3b27398261c5e844 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -855,7 +855,7 @@ void fuse_copy_finish(struct fuse_copy_state *cs)
buf->len = PAGE_SIZE - cs->len;
cs->currbuf = NULL;
} else if (cs->pg) {
- if (cs->write) {
+ if (cs->write && !cs->copy_folio) {
flush_dcache_page(cs->pg);
set_page_dirty_lock(cs->pg);
}
@@ -1126,6 +1126,7 @@ static int fuse_copy_folio(struct fuse_copy_state *cs, struct folio **foliop,
folio_zero_range(folio, 0, size);
}

+ cs->copy_folio = true;
while (count) {
if (cs->write && cs->pipebufs && folio) {
/*
@@ -1167,8 +1168,12 @@ static int fuse_copy_folio(struct fuse_copy_state *cs, struct folio **foliop,
} else
offset += fuse_copy_do(cs, NULL, &count);
}
- if (folio && !cs->write)
+ if (folio) {
flush_dcache_folio(folio);
+ if (cs->write)
+ folio_mark_dirty_lock(folio);
+ }
+ cs->copy_folio = false;
return 0;
}

diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h
index 134bf44aff0d39ae8d5d47cf1518efcf2f1cfc23..4a433d902266d573ad1c19adbdd573440e2a77b2 100644
--- a/fs/fuse/fuse_dev_i.h
+++ b/fs/fuse/fuse_dev_i.h
@@ -33,6 +33,7 @@ struct fuse_copy_state {
unsigned int offset;
bool write:1;
bool move_folios:1;
+ bool copy_folio:1;
bool is_uring:1;
struct {
unsigned int copied_sz; /* copied size into the user buffer */

---
base-commit: f338e77383789c0cae23ca3d48adcc5e9e137e3c
change-id: 20260316-mark-dirty-per-folio-be87b6b4bf56

Best regards,
--
Horst Birthelmer <hbirthelmer@xxxxxxx>