[PATCH v2 10/16] iomap: make iomap_read_folio_ctx->folio_owned internal

Joanne Koong
2025-09-08T18:52:32Z

struct iomap_read_folio_ctx will be made a public interface when
read/readahead takes in caller-provided callbacks.

To make the interface simpler for end users, keep track of the folio
ownership state internally instead of exposing it in struct
iomap_read_folio_ctx.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
---
fs/iomap/buffered-io.c | 39 +++++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 50de09426c96..d38459740180 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -365,12 +365,6 @@ static void iomap_read_end_io(struct bio *bio)

struct iomap_read_folio_ctx {
struct folio *cur_folio;
- /*
- * Is the folio owned by this readpage context, or by some
- * external IO helper? Either way, the owner of the folio is
- * responsible for unlocking it when the read completes.
- */
- bool folio_owned;
void *private;
struct readahead_control *rac;
};
@@ -399,7 +393,6 @@ static void iomap_read_folio_range_bio_async(const struct iomap_iter *iter,
sector_t sector;
struct bio *bio = ctx->private;

- ctx->folio_owned = true;
iomap_start_folio_read(folio, plen);

sector = iomap_sector(iomap, pos);
@@ -432,7 +425,7 @@ static void iomap_read_folio_range_bio_async(const struct iomap_iter *iter,
}

static int iomap_read_folio_iter(struct iomap_iter *iter,
- struct iomap_read_folio_ctx *ctx)
+ struct iomap_read_folio_ctx *ctx, bool *cur_folio_owned)
{
const struct iomap *iomap = &iter->iomap;
loff_t pos = iter->pos;
@@ -465,6 +458,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
folio_zero_range(folio, poff, plen);
iomap_set_range_uptodate(folio, poff, plen);
} else {
+ *cur_folio_owned = true;
iomap_read_folio_range_bio_async(iter, ctx, pos, plen);
}

@@ -487,16 +481,22 @@ int iomap_read_folio(struct folio *folio, const struct iomap_ops *ops)
struct iomap_read_folio_ctx ctx = {
.cur_folio = folio,
};
+ /*
+ * If an external IO helper takes ownership of the folio,
+ * it is responsible for unlocking it when the read completes.
+ */
+ bool cur_folio_owned = false;
int ret;

trace_iomap_readpage(iter.inode, 1);

while ((ret = iomap_iter(&iter, ops)) > 0)
- iter.status = iomap_read_folio_iter(&iter, &ctx);
+ iter.status = iomap_read_folio_iter(&iter, &ctx,
+ &cur_folio_owned);

iomap_submit_read_bio(&ctx);

- if (!ctx.folio_owned)
+ if (!cur_folio_owned)
folio_unlock(folio);

return ret;
@@ -504,12 +504,13 @@ int iomap_read_folio(struct folio *folio, const struct iomap_ops *ops)
EXPORT_SYMBOL_GPL(iomap_read_folio);

static int iomap_readahead_iter(struct iomap_iter *iter,
- struct iomap_read_folio_ctx *ctx)
+ struct iomap_read_folio_ctx *ctx,
+ bool *cur_folio_owned)
{
int ret;

while (iomap_length(iter)) {
- if (ctx->cur_folio && !ctx->folio_owned)
+ if (ctx->cur_folio && !*cur_folio_owned)
folio_unlock(ctx->cur_folio);
ctx->cur_folio = readahead_folio(ctx->rac);
/*
@@ -518,8 +519,8 @@ static int iomap_readahead_iter(struct iomap_iter *iter,
*/
if (WARN_ON_ONCE(!ctx->cur_folio))
return -EINVAL;
- ctx->folio_owned = false;
- ret = iomap_read_folio_iter(iter, ctx);
+ *cur_folio_owned = false;
+ ret = iomap_read_folio_iter(iter, ctx, cur_folio_owned);
if (ret)
return ret;
}
@@ -552,15 +553,21 @@ void iomap_readahead(struct readahead_control *rac, const struct iomap_ops *ops)
struct iomap_read_folio_ctx ctx = {
.rac = rac,
};
+ /*
+ * If an external IO helper takes ownership of the folio,
+ * it is responsible for unlocking it when the read completes.
+ */
+ bool cur_folio_owned = false;

trace_iomap_readahead(rac->mapping->host, readahead_count(rac));

while (iomap_iter(&iter, ops) > 0)
- iter.status = iomap_readahead_iter(&iter, &ctx);
+ iter.status = iomap_readahead_iter(&iter, &ctx,
+ &cur_folio_owned);

iomap_submit_read_bio(&ctx);

- if (ctx.cur_folio && !ctx.folio_owned)
+ if (ctx.cur_folio && !cur_folio_owned)
folio_unlock(ctx.cur_folio);
}
EXPORT_SYMBOL_GPL(iomap_readahead);
--
2.47.3