On Mon, Sep 25, 2023 at 11:51:33AM +0200, Christoph Hellwig wrote: > A szybot reproducer that does write I/O while truncating the size of a > block device can end up in clean_bdev_aliases, which tries to clean the > bdev aliases that it uses. This is because iomap_to_bh automatically > sets the BH_New flag when outside of i_size. For block devices updates > to i_size are racy and we can hit this case in a tiny race window, > leading to the eventual clean_bdev_aliases call. Fix this by erroring > out of > i_size I/O on block devices. > > Reported-by: syzbot+1fa947e7f09e136925b8@xxxxxxxxxxxxxxxxxxxxxxxxx > Signed-off-by: Christoph Hellwig <hch@xxxxxx> > Tested-by: syzbot+1fa947e7f09e136925b8@xxxxxxxxxxxxxxxxxxxxxxxxx > --- > fs/buffer.c | 11 ++++++++++- > 1 file changed, 10 insertions(+), 1 deletion(-) > > diff --git a/fs/buffer.c b/fs/buffer.c > index a6785cd07081cb..12e9a71c693d74 100644 > --- a/fs/buffer.c > +++ b/fs/buffer.c > @@ -2058,8 +2058,17 @@ iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh, > fallthrough; > case IOMAP_MAPPED: > if ((iomap->flags & IOMAP_F_NEW) || > - offset >= i_size_read(inode)) > + offset >= i_size_read(inode)) { > + /* > + * This can happen if truncating the block device races > + * with the check in the caller as i_size updates on > + * block devices aren't synchronized by i_rwsem for > + * block devices. Why /are/ bdevs special like this (not holding i_rwsem during a truncate) anyway? Is it because we require the sysadmin to coordinate device shrink vs. running programs? --D > + */ > + if (S_ISBLK(inode->i_mode)) > + return -EIO; > set_buffer_new(bh); > + } > bh->b_blocknr = (iomap->addr + offset - iomap->offset) >> > inode->i_blkbits; > set_buffer_mapped(bh); > -- > 2.39.2 >