Currently the iomap buffered read path tries to build up read context (i.e. bios for the typical block based case) over multiple iomaps as long as the sector matches. This does not take into account files that can map to multiple different devices. While this could be fixed by a bdev check in iomap_bio_read_folio_range, the building up of I/O over iomaps actually was a problem for the not yet merged ext2 iomap port, as that does want to send out I/O at the end of an indirect block mapped range.
So instead of adding more checks move over to a model where a bio only spans a single iomap. File systems can still create iomap that span more than an extent if they want to build larger I/O. Reported-by: Kelu Ye <[email protected]> Reported-by: Yifan Zhao <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> --- fs/iomap/buffered-io.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 8d4806dc46d4..7449cfd995d5 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -524,6 +524,14 @@ static void iomap_read_end(struct folio *folio, size_t bytes_submitted) } } +static void iomap_read_submit(struct iomap_iter *iter, + struct iomap_read_folio_ctx *ctx) +{ + if (ctx->read_ctx && ctx->ops->submit_read) + ctx->ops->submit_read(iter, ctx); + ctx->read_ctx = NULL; +} + static int iomap_read_folio_iter(struct iomap_iter *iter, struct iomap_read_folio_ctx *ctx, size_t *bytes_submitted) { @@ -642,12 +650,11 @@ void iomap_read_folio(const struct iomap_ops *ops, fsverity_readahead(ctx->vi, folio->index, folio_nr_pages(folio)); - while ((ret = iomap_iter(&iter, ops)) > 0) + while ((ret = iomap_iter(&iter, ops)) > 0) { iter.status = iomap_read_folio_iter(&iter, ctx, &bytes_submitted); - - if (ctx->read_ctx && ctx->ops->submit_read) - ctx->ops->submit_read(&iter, ctx); + iomap_read_submit(&iter, ctx); + } if (ctx->cur_folio) iomap_read_end(ctx->cur_folio, bytes_submitted); @@ -718,12 +725,11 @@ void iomap_readahead(const struct iomap_ops *ops, fsverity_readahead(ctx->vi, readahead_index(rac), readahead_count(rac)); - while (iomap_iter(&iter, ops) > 0) + while (iomap_iter(&iter, ops) > 0) { iter.status = iomap_readahead_iter(&iter, ctx, &cur_bytes_submitted); - - if (ctx->read_ctx && ctx->ops->submit_read) - ctx->ops->submit_read(&iter, ctx); + iomap_read_submit(&iter, ctx); + } if (ctx->cur_folio) iomap_read_end(ctx->cur_folio, cur_bytes_submitted); -- 2.53.0
