Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iomap: fix invalid folio access when i_blkbits differs from I/O granularity

Commit aa35dd5cbc06 ("iomap: fix invalid folio access after
folio_end_read()") partially addressed invalid folio access for folios
without an ifs attached, but it did not handle the case where
1 << inode->i_blkbits matches the folio size but is different from the
granularity used for the IO, which means IO can be submitted for less
than the full folio for the !ifs case.

In this case, the condition:

if (*bytes_submitted == folio_len)
ctx->cur_folio = NULL;

in iomap_read_folio_iter() will not invalidate ctx->cur_folio, and
iomap_read_end() will still be called on the folio even though the IO
helper owns it and will finish the read on it.

Fix this by unconditionally invalidating ctx->cur_folio for the !ifs
case.

Reported-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Tested-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Link: https://lore.kernel.org/linux-fsdevel/b3dfe271-4e3d-4922-b618-e73731242bca@wdc.com/
Fixes: b2f35ac4146d ("iomap: add caller-provided callbacks for read and readahead")
Cc: stable@vger.kernel.org
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Link: https://patch.msgid.link/20260317203935.830549-1-joannelkoong@gmail.com
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Joanne Koong and committed by
Christian Brauner
bd71fb3f c465f559

+10 -5
+10 -5
fs/iomap/buffered-io.c
··· 514 514 loff_t length = iomap_length(iter); 515 515 struct folio *folio = ctx->cur_folio; 516 516 size_t folio_len = folio_size(folio); 517 + struct iomap_folio_state *ifs; 517 518 size_t poff, plen; 518 519 loff_t pos_diff; 519 520 int ret; ··· 526 525 return iomap_iter_advance(iter, length); 527 526 } 528 527 529 - ifs_alloc(iter->inode, folio, iter->flags); 528 + ifs = ifs_alloc(iter->inode, folio, iter->flags); 530 529 531 530 length = min_t(loff_t, length, folio_len - offset_in_folio(folio, pos)); 532 531 while (length) { ··· 561 560 562 561 *bytes_submitted += plen; 563 562 /* 564 - * If the entire folio has been read in by the IO 565 - * helper, then the helper owns the folio and will end 566 - * the read on it. 563 + * Hand off folio ownership to the IO helper when: 564 + * 1) The entire folio has been submitted for IO, or 565 + * 2) There is no ifs attached to the folio 566 + * 567 + * Case (2) occurs when 1 << i_blkbits matches the folio 568 + * size but the underlying filesystem or block device 569 + * uses a smaller granularity for IO. 567 570 */ 568 - if (*bytes_submitted == folio_len) 571 + if (*bytes_submitted == folio_len || !ifs) 569 572 ctx->cur_folio = NULL; 570 573 } 571 574