Skip to content

Commit bd71fb3

Browse files
joannekoongbrauner
authored andcommitted
iomap: fix invalid folio access when i_blkbits differs from I/O granularity
Commit aa35dd5 ("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 <[email protected]> Tested-by: Johannes Thumshirn <[email protected]> Link: https://lore.kernel.org/linux-fsdevel/[email protected]/ Fixes: b2f35ac ("iomap: add caller-provided callbacks for read and readahead") Cc: [email protected] Signed-off-by: Joanne Koong <[email protected]> Link: https://patch.msgid.link/[email protected] Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent c465f55 commit bd71fb3

1 file changed

Lines changed: 10 additions & 5 deletions

File tree

fs/iomap/buffered-io.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
514514
loff_t length = iomap_length(iter);
515515
struct folio *folio = ctx->cur_folio;
516516
size_t folio_len = folio_size(folio);
517+
struct iomap_folio_state *ifs;
517518
size_t poff, plen;
518519
loff_t pos_diff;
519520
int ret;
@@ -525,7 +526,7 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
525526
return iomap_iter_advance(iter, length);
526527
}
527528

528-
ifs_alloc(iter->inode, folio, iter->flags);
529+
ifs = ifs_alloc(iter->inode, folio, iter->flags);
529530

530531
length = min_t(loff_t, length, folio_len - offset_in_folio(folio, pos));
531532
while (length) {
@@ -560,11 +561,15 @@ static int iomap_read_folio_iter(struct iomap_iter *iter,
560561

561562
*bytes_submitted += plen;
562563
/*
563-
* If the entire folio has been read in by the IO
564-
* helper, then the helper owns the folio and will end
565-
* the read on it.
564+
* Hand off folio ownership to the IO helper when:
565+
* 1) The entire folio has been submitted for IO, or
566+
* 2) There is no ifs attached to the folio
567+
*
568+
* Case (2) occurs when 1 << i_blkbits matches the folio
569+
* size but the underlying filesystem or block device
570+
* uses a smaller granularity for IO.
566571
*/
567-
if (*bytes_submitted == folio_len)
572+
if (*bytes_submitted == folio_len || !ifs)
568573
ctx->cur_folio = NULL;
569574
}
570575

0 commit comments

Comments
 (0)