Skip to content

Commit 4aa8cdd

Browse files
Christoph HellwigDarrick J. Wong
authored andcommitted
iomap: handle error conditions more gracefully in iomap_to_bh
iomap_to_bh currently BUG()s when the passed in block number is not in the iomap. For file systems that have proper synchronization this should never happen and so far hasn't in mainline, but for block devices size changes aren't fully synchronized against ongoing I/O. Instead of BUG()ing in this case, return -EIO to the caller, which already has proper error handling. While we're at it, also return -EIO for an unknown iomap state instead of returning garbage. Fixes: 487c607 ("block: use iomap for writes to block devices") Reported-by: syzbot+4a08ffdf3667b36650a1@syzkaller.appspotmail.com Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
1 parent 0bb80ec commit 4aa8cdd

File tree

1 file changed

+14
-11
lines changed

1 file changed

+14
-11
lines changed

fs/buffer.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,7 +2011,7 @@ void folio_zero_new_buffers(struct folio *folio, size_t from, size_t to)
20112011
}
20122012
EXPORT_SYMBOL(folio_zero_new_buffers);
20132013

2014-
static void
2014+
static int
20152015
iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
20162016
const struct iomap *iomap)
20172017
{
@@ -2025,7 +2025,8 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
20252025
* current block, then do not map the buffer and let the caller
20262026
* handle it.
20272027
*/
2028-
BUG_ON(offset >= iomap->offset + iomap->length);
2028+
if (offset >= iomap->offset + iomap->length)
2029+
return -EIO;
20292030

20302031
switch (iomap->type) {
20312032
case IOMAP_HOLE:
@@ -2037,15 +2038,15 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
20372038
if (!buffer_uptodate(bh) ||
20382039
(offset >= i_size_read(inode)))
20392040
set_buffer_new(bh);
2040-
break;
2041+
return 0;
20412042
case IOMAP_DELALLOC:
20422043
if (!buffer_uptodate(bh) ||
20432044
(offset >= i_size_read(inode)))
20442045
set_buffer_new(bh);
20452046
set_buffer_uptodate(bh);
20462047
set_buffer_mapped(bh);
20472048
set_buffer_delay(bh);
2048-
break;
2049+
return 0;
20492050
case IOMAP_UNWRITTEN:
20502051
/*
20512052
* For unwritten regions, we always need to ensure that regions
@@ -2062,7 +2063,10 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh,
20622063
bh->b_blocknr = (iomap->addr + offset - iomap->offset) >>
20632064
inode->i_blkbits;
20642065
set_buffer_mapped(bh);
2065-
break;
2066+
return 0;
2067+
default:
2068+
WARN_ON_ONCE(1);
2069+
return -EIO;
20662070
}
20672071
}
20682072

@@ -2103,13 +2107,12 @@ int __block_write_begin_int(struct folio *folio, loff_t pos, unsigned len,
21032107
clear_buffer_new(bh);
21042108
if (!buffer_mapped(bh)) {
21052109
WARN_ON(bh->b_size != blocksize);
2106-
if (get_block) {
2110+
if (get_block)
21072111
err = get_block(inode, block, bh, 1);
2108-
if (err)
2109-
break;
2110-
} else {
2111-
iomap_to_bh(inode, block, bh, iomap);
2112-
}
2112+
else
2113+
err = iomap_to_bh(inode, block, bh, iomap);
2114+
if (err)
2115+
break;
21132116

21142117
if (buffer_new(bh)) {
21152118
clean_bdev_bh_alias(bh);

0 commit comments

Comments
 (0)