From: Joanne Koong <joannelkoong@gmail.com>
To: miklos@szeredi.hu
Cc: djwong@kernel.org, brauner@kernel.org,
linux-fsdevel@vger.kernel.org, linux-xfs@vger.kernel.org,
bernd.schubert@fastmail.fm, kernel-team@meta.com
Subject: [PATCH v1 7/8] fuse: use iomap for writeback
Date: Fri, 6 Jun 2025 16:38:02 -0700 [thread overview]
Message-ID: <20250606233803.1421259-8-joannelkoong@gmail.com> (raw)
In-Reply-To: <20250606233803.1421259-1-joannelkoong@gmail.com>
Use iomap for dirty folio writeback in ->writepages().
This allows for granular dirty writeback of large folios.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
fs/fuse/file.c | 114 ++++++++++++++++++++++++++++---------------------
1 file changed, 66 insertions(+), 48 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index a0118b501880..31842ee1ce0e 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1835,7 +1835,7 @@ static void fuse_writepage_finish(struct fuse_writepage_args *wpa)
* scope of the fi->lock alleviates xarray lock
* contention and noticeably improves performance.
*/
- folio_end_writeback(ap->folios[i]);
+ iomap_finish_folio_write(inode, ap->folios[i], 1);
dec_wb_stat(&bdi->wb, WB_WRITEBACK);
wb_writeout_inc(&bdi->wb);
}
@@ -2022,19 +2022,20 @@ static void fuse_writepage_add_to_bucket(struct fuse_conn *fc,
}
static void fuse_writepage_args_page_fill(struct fuse_writepage_args *wpa, struct folio *folio,
- uint32_t folio_index)
+ uint32_t folio_index, loff_t offset, unsigned len)
{
struct inode *inode = folio->mapping->host;
struct fuse_args_pages *ap = &wpa->ia.ap;
ap->folios[folio_index] = folio;
- ap->descs[folio_index].offset = 0;
- ap->descs[folio_index].length = folio_size(folio);
+ ap->descs[folio_index].offset = offset;
+ ap->descs[folio_index].length = len;
inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
}
static struct fuse_writepage_args *fuse_writepage_args_setup(struct folio *folio,
+ size_t offset,
struct fuse_file *ff)
{
struct inode *inode = folio->mapping->host;
@@ -2047,7 +2048,7 @@ static struct fuse_writepage_args *fuse_writepage_args_setup(struct folio *folio
return NULL;
fuse_writepage_add_to_bucket(fc, wpa);
- fuse_write_args_fill(&wpa->ia, ff, folio_pos(folio), 0);
+ fuse_write_args_fill(&wpa->ia, ff, folio_pos(folio) + offset, 0);
wpa->ia.write.in.write_flags |= FUSE_WRITE_CACHE;
wpa->inode = inode;
wpa->ia.ff = ff;
@@ -2103,7 +2104,7 @@ struct fuse_fill_wb_data {
struct fuse_file *ff;
struct inode *inode;
unsigned int max_folios;
- unsigned int nr_pages;
+ unsigned int nr_bytes;
};
static bool fuse_pages_realloc(struct fuse_fill_wb_data *data)
@@ -2145,21 +2146,28 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
}
static bool fuse_writepage_need_send(struct fuse_conn *fc, struct folio *folio,
+ loff_t offset, unsigned len,
struct fuse_args_pages *ap,
struct fuse_fill_wb_data *data)
{
+ struct folio *prev_folio;
+ struct fuse_folio_desc prev_desc;
+
WARN_ON(!ap->num_folios);
/* Reached max pages */
- if (data->nr_pages + folio_nr_pages(folio) > fc->max_pages)
+ if ((data->nr_bytes + len) / PAGE_SIZE > fc->max_pages)
return true;
/* Reached max write bytes */
- if ((data->nr_pages * PAGE_SIZE) + folio_size(folio) > fc->max_write)
+ if (data->nr_bytes + len > fc->max_write)
return true;
/* Discontinuity */
- if (folio_next_index(ap->folios[ap->num_folios - 1]) != folio_index(folio))
+ prev_folio = ap->folios[ap->num_folios - 1];
+ prev_desc = ap->descs[ap->num_folios - 1];
+ if ((folio_pos(prev_folio) + prev_desc.offset + prev_desc.length) !=
+ folio_pos(folio) + offset)
return true;
/* Need to grow the pages array? If so, did the expansion fail? */
@@ -2169,85 +2177,95 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, struct folio *folio,
return false;
}
-static int fuse_writepages_fill(struct folio *folio,
- struct writeback_control *wbc, void *_data)
+static int fuse_iomap_writeback_folio(struct iomap_writepage_ctx *wpc,
+ struct folio *folio, struct inode *inode,
+ loff_t offset, unsigned len)
{
- struct fuse_fill_wb_data *data = _data;
+ struct fuse_fill_wb_data *data = wpc->private;
struct fuse_writepage_args *wpa = data->wpa;
struct fuse_args_pages *ap = &wpa->ia.ap;
- struct inode *inode = data->inode;
- struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_conn *fc = get_fuse_conn(inode);
- int err;
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ /* len will always be page aligned */
+ WARN_ON_ONCE(len & (PAGE_SIZE - 1));
if (!data->ff) {
- err = -EIO;
data->ff = fuse_write_file_get(fi);
if (!data->ff)
- goto out_unlock;
+ return -EIO;
}
- if (wpa && fuse_writepage_need_send(fc, folio, ap, data)) {
+ iomap_start_folio_write(inode, folio, 1);
+
+ if (wpa && fuse_writepage_need_send(fc, folio, offset, len, ap, data)) {
fuse_writepages_send(data);
data->wpa = NULL;
- data->nr_pages = 0;
+ data->nr_bytes = 0;
}
if (data->wpa == NULL) {
- err = -ENOMEM;
- wpa = fuse_writepage_args_setup(folio, data->ff);
+ wpa = fuse_writepage_args_setup(folio, offset, data->ff);
if (!wpa)
- goto out_unlock;
+ return -ENOMEM;
fuse_file_get(wpa->ia.ff);
data->max_folios = 1;
ap = &wpa->ia.ap;
}
- folio_start_writeback(folio);
- fuse_writepage_args_page_fill(wpa, folio, ap->num_folios);
- data->nr_pages += folio_nr_pages(folio);
+ fuse_writepage_args_page_fill(wpa, folio, ap->num_folios,
+ offset, len);
+ data->nr_bytes += len;
- err = 0;
ap->num_folios++;
if (!data->wpa)
data->wpa = wpa;
-out_unlock:
- folio_unlock(folio);
- return err;
+ return 0;
+}
+
+static int fuse_iomap_submit_ioend(struct iomap_writepage_ctx *wpc, int error)
+{
+ struct fuse_fill_wb_data *data = wpc->private;
+ WARN_ON_ONCE(!data);
+
+ if (data->wpa) {
+ WARN_ON(!data->wpa->ia.ap.num_folios);
+ fuse_writepages_send(data);
+ }
+
+ if (data->ff)
+ fuse_file_put(data->ff, false);
+
+ return error;
}
+static const struct iomap_writeback_ops fuse_writeback_ops = {
+ .writeback_folio = fuse_iomap_writeback_folio,
+ .submit_ioend = fuse_iomap_submit_ioend,
+};
+
static int fuse_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
struct inode *inode = mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_fill_wb_data data;
- int err;
+ struct fuse_fill_wb_data data = {
+ .inode = inode,
+ };
+ struct iomap_writepage_ctx wpc = {
+ .iomap.type = IOMAP_IN_MEM,
+ .private = &data,
+ };
- err = -EIO;
if (fuse_is_bad(inode))
- goto out;
+ return -EIO;
if (wbc->sync_mode == WB_SYNC_NONE &&
fc->num_background >= fc->congestion_threshold)
return 0;
- data.inode = inode;
- data.wpa = NULL;
- data.ff = NULL;
- data.nr_pages = 0;
-
- err = write_cache_pages(mapping, wbc, fuse_writepages_fill, &data);
- if (data.wpa) {
- WARN_ON(!data.wpa->ia.ap.num_folios);
- fuse_writepages_send(&data);
- }
- if (data.ff)
- fuse_file_put(data.ff, false);
-
-out:
- return err;
+ return iomap_writepages(mapping, wbc, &wpc, &fuse_writeback_ops);
}
static int fuse_launder_folio(struct folio *folio)
--
2.47.1
next prev parent reply other threads:[~2025-06-06 23:42 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-06 23:37 [PATCH v1 0/8] fuse: use iomap for buffered writes + writeback Joanne Koong
2025-06-06 23:37 ` [PATCH v1 1/8] iomap: move buffered io bio logic into separate file Joanne Koong
2025-06-08 19:17 ` Anuj gupta
2025-06-09 4:44 ` Christoph Hellwig
2025-06-09 20:01 ` Joanne Koong
2025-06-06 23:37 ` [PATCH v1 2/8] iomap: add IOMAP_IN_MEM iomap type Joanne Koong
2025-06-09 4:45 ` Christoph Hellwig
2025-06-09 21:45 ` Joanne Koong
2025-06-10 3:39 ` Christoph Hellwig
2025-06-10 13:27 ` Christoph Hellwig
2025-06-10 20:13 ` Joanne Koong
2025-06-11 4:04 ` Christoph Hellwig
2025-06-11 6:00 ` Joanne Koong
2025-06-11 6:08 ` Christoph Hellwig
2025-06-11 18:33 ` Joanne Koong
2025-06-11 18:50 ` Darrick J. Wong
2025-06-11 23:08 ` Joanne Koong
2025-06-12 4:42 ` Christoph Hellwig
2025-06-09 16:24 ` Darrick J. Wong
2025-06-09 21:28 ` Joanne Koong
2025-06-12 3:53 ` Darrick J. Wong
2025-06-06 23:37 ` [PATCH v1 3/8] iomap: add buffered write support for IOMAP_IN_MEM iomaps Joanne Koong
2025-06-09 4:56 ` Christoph Hellwig
2025-06-09 22:45 ` Joanne Koong
2025-06-10 3:44 ` Christoph Hellwig
2025-06-09 16:38 ` Darrick J. Wong
2025-06-09 22:03 ` Joanne Koong
2025-06-12 3:54 ` Darrick J. Wong
2025-06-06 23:37 ` [PATCH v1 4/8] iomap: add writepages " Joanne Koong
2025-06-09 5:32 ` Christoph Hellwig
2025-06-09 16:57 ` Darrick J. Wong
2025-06-10 3:49 ` Christoph Hellwig
2025-06-12 3:56 ` Darrick J. Wong
2025-06-09 23:15 ` Joanne Koong
2025-06-10 3:58 ` Christoph Hellwig
2025-06-10 18:23 ` Joanne Koong
2025-06-10 18:58 ` Joanne Koong
2025-06-11 4:01 ` Christoph Hellwig
2025-06-06 23:38 ` [PATCH v1 5/8] iomap: add iomap_writeback_dirty_folio() Joanne Koong
2025-06-09 4:51 ` Christoph Hellwig
2025-06-09 17:14 ` Darrick J. Wong
2025-06-09 23:54 ` Joanne Koong
2025-06-10 3:59 ` Christoph Hellwig
2025-06-11 4:34 ` Matthew Wilcox
2025-06-18 4:47 ` does fuse need ->launder_folios, was: " Christoph Hellwig
2025-06-18 12:17 ` Jeff Layton
2025-06-20 18:15 ` Matthew Wilcox
2025-06-25 5:26 ` Joanne Koong
2025-06-25 6:26 ` Christoph Hellwig
2025-06-25 16:44 ` Joanne Koong
2025-07-01 5:41 ` Darrick J. Wong
2025-07-02 21:36 ` Joanne Koong
2025-07-02 21:47 ` Joanne Koong
2025-07-01 6:23 ` Miklos Szeredi
2025-06-09 23:30 ` Joanne Koong
2025-06-10 4:03 ` Christoph Hellwig
2025-06-06 23:38 ` [PATCH v1 6/8] fuse: use iomap for buffered writes Joanne Koong
2025-06-06 23:38 ` Joanne Koong [this message]
2025-06-08 19:20 ` [PATCH v1 7/8] fuse: use iomap for writeback Anuj gupta
2025-06-06 23:38 ` [PATCH v1 8/8] fuse: use iomap for folio laundering Joanne Koong
2025-06-08 19:12 ` [PATCH v1 0/8] fuse: use iomap for buffered writes + writeback Anuj gupta
2025-06-09 19:59 ` Joanne Koong
2025-06-14 14:22 ` Anuj gupta
2025-06-09 4:40 ` Christoph Hellwig
2025-06-09 12:38 ` Anuj gupta
2025-06-09 19:47 ` Joanne Koong
2025-06-10 4:04 ` Christoph Hellwig
2025-06-10 0:47 ` Dave Chinner
2025-06-10 4:06 ` Christoph Hellwig
2025-06-10 20:33 ` Joanne Koong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250606233803.1421259-8-joannelkoong@gmail.com \
--to=joannelkoong@gmail.com \
--cc=bernd.schubert@fastmail.fm \
--cc=brauner@kernel.org \
--cc=djwong@kernel.org \
--cc=kernel-team@meta.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=miklos@szeredi.hu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).