From: Joanne Koong <joannelkoong@gmail.com>
To: brauner@kernel.org, miklos@szeredi.hu
Cc: hch@infradead.org, djwong@kernel.org,
hsiangkao@linux.alibaba.com, linux-block@vger.kernel.org,
gfs2@lists.linux.dev, linux-fsdevel@vger.kernel.org,
kernel-team@meta.com, linux-xfs@vger.kernel.org,
linux-doc@vger.kernel.org
Subject: [PATCH v2 12/16] iomap: add bias for async read requests
Date: Mon, 8 Sep 2025 11:51:18 -0700 [thread overview]
Message-ID: <20250908185122.3199171-13-joannelkoong@gmail.com> (raw)
In-Reply-To: <20250908185122.3199171-1-joannelkoong@gmail.com>
Non-block-based filesystems will be using iomap read/readahead. If they
handle reading in ranges asynchronously and fulfill those read requests
on an ongoing basis (instead of all together at the end), then there is
the possibility that the read on the folio may be prematurely ended if
earlier async requests complete before the later ones have been issued.
For example if there is a large folio and a readahead request for 16
pages in that folio, if doing readahead on those 16 pages is split into
4 async requests and the first request is sent off and then completed
before we have sent off the second request, then when the first request
calls iomap_finish_folio_read(), ifs->read_bytes_pending would be 0,
which would end the read and unlock the folio prematurely.
To mitigate this, a "bias" is added to ifs->read_bytes_pending before
the first range is forwarded to the caller and removed after the last
range has been forwarded.
iomap writeback does this with their async requests as well to prevent
prematurely ending writeback.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
fs/iomap/buffered-io.c | 43 ++++++++++++++++++++++++++++++++----------
1 file changed, 33 insertions(+), 10 deletions(-)
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 6fafe3b30563..f673e03f4ffb 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -329,8 +329,8 @@ void iomap_start_folio_read(struct folio *folio, size_t len)
}
EXPORT_SYMBOL_GPL(iomap_start_folio_read);
-void iomap_finish_folio_read(struct folio *folio, size_t off, size_t len,
- int error)
+static void __iomap_finish_folio_read(struct folio *folio, size_t off,
+ size_t len, int error, bool update_bitmap)
{
struct iomap_folio_state *ifs = folio->private;
bool uptodate = !error;
@@ -340,7 +340,7 @@ void iomap_finish_folio_read(struct folio *folio, size_t off, size_t len,
unsigned long flags;
spin_lock_irqsave(&ifs->state_lock, flags);
- if (!error)
+ if (!error && update_bitmap)
uptodate = ifs_set_range_uptodate(folio, ifs, off, len);
ifs->read_bytes_pending -= len;
finished = !ifs->read_bytes_pending;
@@ -350,6 +350,12 @@ void iomap_finish_folio_read(struct folio *folio, size_t off, size_t len,
if (finished)
folio_end_read(folio, uptodate);
}
+
+void iomap_finish_folio_read(struct folio *folio, size_t off, size_t len,
+ int error)
+{
+ return __iomap_finish_folio_read(folio, off, len, error, true);
+}
EXPORT_SYMBOL_GPL(iomap_finish_folio_read);
#ifdef CONFIG_BLOCK
@@ -434,9 +440,10 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
loff_t pos = iter->pos;
loff_t length = iomap_length(iter);
struct folio *folio = ctx->cur_folio;
+ struct iomap_folio_state *ifs;
size_t poff, plen;
loff_t count;
- int ret;
+ int ret = 0;
if (iomap->type == IOMAP_INLINE) {
ret = iomap_read_inline_data(iter, folio);
@@ -446,7 +453,14 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
}
/* zero post-eof blocks as the page may be mapped */
- ifs_alloc(iter->inode, folio, iter->flags);
+ ifs = ifs_alloc(iter->inode, folio, iter->flags);
+
+ /*
+ * Add a bias to ifs->read_bytes_pending so that a read is ended only
+ * after all the ranges have been read in.
+ */
+ if (ifs)
+ iomap_start_folio_read(folio, 1);
length = min_t(loff_t, length,
folio_size(folio) - offset_in_folio(folio, pos));
@@ -454,8 +468,10 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
iomap_adjust_read_range(iter->inode, folio, &pos,
length, &poff, &plen);
count = pos - iter->pos + plen;
- if (plen == 0)
- return iomap_iter_advance(iter, &count);
+ if (plen == 0) {
+ ret = iomap_iter_advance(iter, &count);
+ break;
+ }
if (iomap_block_needs_zeroing(iter, pos)) {
folio_zero_range(folio, poff, plen);
@@ -465,16 +481,23 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
ret = ctx->ops->read_folio_range(iter, ctx, pos,
plen);
if (ret)
- return ret;
+ break;
}
length -= count;
ret = iomap_iter_advance(iter, &count);
if (ret)
- return ret;
+ break;
pos = iter->pos;
}
- return 0;
+
+ if (ifs) {
+ __iomap_finish_folio_read(folio, 0, 1, ret, false);
+ /* __iomap_finish_folio_read takes care of any unlocking */
+ *cur_folio_owned = true;
+ }
+
+ return ret;
}
int iomap_read_folio(const struct iomap_ops *ops,
--
2.47.3
next prev parent reply other threads:[~2025-09-08 18:52 UTC|newest]
Thread overview: 60+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-08 18:51 [PATCH v2 00/16] fuse: use iomap for buffered reads + readahead Joanne Koong
2025-09-08 18:51 ` [PATCH v2 01/16] iomap: move async bio read logic into helper function Joanne Koong
2025-09-11 11:09 ` Christoph Hellwig
2025-09-12 16:01 ` Joanne Koong
2025-09-08 18:51 ` [PATCH v2 02/16] iomap: move read/readahead bio submission " Joanne Koong
2025-09-11 11:09 ` Christoph Hellwig
2025-09-08 18:51 ` [PATCH v2 03/16] iomap: rename cur_folio_in_bio to folio_owned Joanne Koong
2025-09-11 11:10 ` Christoph Hellwig
2025-09-08 18:51 ` [PATCH v2 04/16] iomap: store read/readahead bio generically Joanne Koong
2025-09-11 11:11 ` Christoph Hellwig
2025-09-12 16:10 ` Joanne Koong
2025-09-08 18:51 ` [PATCH v2 05/16] iomap: propagate iomap_read_folio() error to caller Joanne Koong
2025-09-11 11:13 ` Christoph Hellwig
2025-09-12 16:28 ` Joanne Koong
2025-09-15 16:05 ` Christoph Hellwig
2025-09-08 18:51 ` [PATCH v2 06/16] iomap: iterate over entire folio in iomap_readpage_iter() Joanne Koong
2025-09-11 11:15 ` Christoph Hellwig
2025-09-08 18:51 ` [PATCH v2 07/16] iomap: rename iomap_readpage_iter() to iomap_read_folio_iter() Joanne Koong
2025-09-11 11:16 ` Christoph Hellwig
2025-09-08 18:51 ` [PATCH v2 08/16] iomap: rename iomap_readpage_ctx struct to iomap_read_folio_ctx Joanne Koong
2025-09-11 11:16 ` Christoph Hellwig
2025-09-08 18:51 ` [PATCH v2 09/16] iomap: add public start/finish folio read helpers Joanne Koong
2025-09-11 11:16 ` Christoph Hellwig
2025-09-08 18:51 ` [PATCH v2 10/16] iomap: make iomap_read_folio_ctx->folio_owned internal Joanne Koong
2025-09-11 11:17 ` Christoph Hellwig
2025-09-08 18:51 ` [PATCH v2 11/16] iomap: add caller-provided callbacks for read and readahead Joanne Koong
2025-09-09 0:14 ` Gao Xiang
2025-09-09 0:40 ` Gao Xiang
2025-09-09 15:24 ` Joanne Koong
2025-09-09 23:21 ` Gao Xiang
2025-09-10 17:41 ` Joanne Koong
2025-09-11 11:19 ` Christoph Hellwig
2025-09-11 11:26 ` Christoph Hellwig
2025-09-12 17:36 ` Joanne Koong
2025-09-08 18:51 ` Joanne Koong [this message]
2025-09-11 11:31 ` [PATCH v2 12/16] iomap: add bias for async read requests Christoph Hellwig
2025-09-12 17:30 ` Joanne Koong
2025-09-15 16:05 ` Christoph Hellwig
2025-09-16 19:14 ` Joanne Koong
2025-09-19 15:04 ` Christoph Hellwig
2025-09-19 17:58 ` Joanne Koong
2025-09-08 18:51 ` [PATCH v2 13/16] iomap: move read/readahead logic out of CONFIG_BLOCK guard Joanne Koong
2025-09-09 2:14 ` Gao Xiang
2025-09-09 15:33 ` Joanne Koong
2025-09-10 4:59 ` Gao Xiang
2025-09-11 11:37 ` Christoph Hellwig
2025-09-11 12:29 ` Gao Xiang
2025-09-11 19:45 ` Joanne Koong
2025-09-12 0:06 ` Gao Xiang
2025-09-12 1:09 ` Gao Xiang
2025-09-12 1:10 ` Gao Xiang
2025-09-12 19:56 ` Joanne Koong
2025-09-12 20:09 ` Joanne Koong
2025-09-12 23:35 ` Gao Xiang
2025-09-12 23:20 ` Gao Xiang
2025-09-11 11:44 ` Christoph Hellwig
2025-09-16 23:23 ` Joanne Koong
2025-09-08 18:51 ` [PATCH v2 14/16] fuse: use iomap for read_folio Joanne Koong
2025-09-08 18:51 ` [PATCH v2 15/16] fuse: use iomap for readahead Joanne Koong
2025-09-08 18:51 ` [PATCH v2 16/16] fuse: remove fc->blkbits workaround for partial writes 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=20250908185122.3199171-13-joannelkoong@gmail.com \
--to=joannelkoong@gmail.com \
--cc=brauner@kernel.org \
--cc=djwong@kernel.org \
--cc=gfs2@lists.linux.dev \
--cc=hch@infradead.org \
--cc=hsiangkao@linux.alibaba.com \
--cc=kernel-team@meta.com \
--cc=linux-block@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--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).