iomap: keep large chunks from defeating the bio cap

For integrity I/O a bio must not grow beyond max_integrity_io_size()
because the integrity buffer is a single allocation of at most 2 MiB.
Writeback and buffered reads check that before adding to a bio:

        bio->bi_iter.bi_size > iomap_max_bio_size(iomap) - len

The subtraction is done in size_t and wraps if len alone is above the
limit. The check then never fires and the bio grows until it runs out
of bio_vecs.

That's easy to hit. The limit is also capped by the maximum segment size
which is 64 KiB for SCSI hosts that don't set it, such as lpfc and
qla2xxx, and XFS uses folios of up to 2 MiB. Writeback of a preallocated
300 MiB file then builds a single bio that needs 4.7 MiB of PI with 512
byte sectors and 8 byte tuples. That's more than kmalloc() can do, so
bio_integrity_alloc_buf() falls back to a 2 MiB mempool element and
generating the PI writes 2.7 MiB past its end.

Check the length on its own first. A chunk above the limit still gets a
bio of its own which is never larger than a folio.

Fixes: 0b10a37052 ("iomap: support T10 protection information")
Cc: stable@vger.kernel.org # v7.1+
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Link: https://patch.msgid.link/20261029-work-iomap-ai-fixes-v1-2-7eda63bc1b13@kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Josef Bacik 2026-10-29 11:34:49 +01:00 committed by Christian Brauner
parent a4193b4af3
commit eb8ab8c23e
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
3 changed files with 11 additions and 3 deletions

View File

@ -109,7 +109,7 @@ int iomap_bio_read_folio_range(const struct iomap_iter *iter,
if (!bio ||
bio_end_sector(bio) != iomap_sector(&iter->iomap, iter->pos) ||
bio->bi_iter.bi_size > iomap_max_bio_size(&iter->iomap) - plen ||
!iomap_bio_has_room(&iter->iomap, bio, plen) ||
!bio_add_folio(bio, folio, plen, offset_in_folio(folio, iter->pos)))
iomap_read_alloc_bio(iter, ctx, plen);
return 0;

View File

@ -17,6 +17,15 @@ static inline size_t iomap_max_bio_size(const struct iomap *iomap)
return BIO_MAX_SIZE;
}
/* Can @len more bytes go into @bio? */
static inline bool iomap_bio_has_room(const struct iomap *iomap,
const struct bio *bio, size_t len)
{
size_t max_size = iomap_max_bio_size(iomap);
return len <= max_size && bio->bi_iter.bi_size <= max_size - len;
}
u32 iomap_finish_ioend_buffered_read(struct iomap_ioend *ioend);
u32 iomap_finish_ioend_direct(struct iomap_ioend *ioend);

View File

@ -133,8 +133,7 @@ static bool iomap_can_add_to_ioend(struct iomap_writepage_ctx *wpc, loff_t pos,
{
struct iomap_ioend *ioend = wpc->wb_ctx;
if (ioend->io_bio.bi_iter.bi_size >
iomap_max_bio_size(&wpc->iomap) - map_len)
if (!iomap_bio_has_room(&wpc->iomap, &ioend->io_bio, map_len))
return false;
if (ioend_flags & IOMAP_IOEND_BOUNDARY)
return false;