From 1b1be9ea4e34ccede1e7cf9ff2b6317328a5b6ad Mon Sep 17 00:00:00 2001 From: Julian Sun Date: Thu, 15 Oct 2026 17:11:05 +0800 Subject: [PATCH] block: take the inode lock for buffered write fallback Commit c0e473a0d226 ("block: fix race between set_blocksize and read paths") added shared inode locking around ordinary buffered writes, but missed the direct-I/O fallback path. Move the lock into blkdev_buffered_write() so both paths serialize with set_blocksize(). Also correct the comment claiming that this path takes invalidate_lock; it only takes i_rwsem. Fixes: c0e473a0d226 ("block: fix race between set_blocksize and read paths") Signed-off-by: Julian Sun Link: https://patch.msgid.link/20261015091105.1315605-3-sunjunchao@bytedance.com Signed-off-by: Jens Axboe --- block/fops.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/block/fops.c b/block/fops.c index 07f4d7336a76..a1da6d428ca3 100644 --- a/block/fops.c +++ b/block/fops.c @@ -714,12 +714,22 @@ blkdev_direct_write(struct kiocb *iocb, struct iov_iter *from) static ssize_t blkdev_buffered_write(struct kiocb *iocb, struct iov_iter *from) { + struct inode *inode = bdev_file_inode(iocb->ki_filp); + ssize_t ret; + /* Buffered fallback waits for writeback, which NOWAIT cannot allow. */ if (iocb->ki_flags & IOCB_NOWAIT) return -EAGAIN; - return iomap_file_buffered_write(iocb, from, &blkdev_iomap_ops, NULL, - NULL); + /* + * Take i_rwsem to avoid racing with set_blocksize() changing + * i_blkbits/folio order and truncating the page cache. + */ + inode_lock_shared(inode); + ret = iomap_file_buffered_write(iocb, from, &blkdev_iomap_ops, NULL, + NULL); + inode_unlock_shared(inode); + return ret; } /* @@ -808,14 +818,7 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) need_sync = true; } } else { - /* - * Take i_rwsem and invalidate_lock to avoid racing with - * set_blocksize changing i_blkbits/folio order and punching - * out the pagecache. - */ - inode_lock_shared(bd_inode); ret = blkdev_buffered_write(iocb, from); - inode_unlock_shared(bd_inode); need_sync = true; }