From: Zheng Bin <zhengbi...@huawei.com>

commit f4bd34b139a3fa2808c4205f12714c65e1548c6c upstream.

When a filesystem is mounted on a loop device and on a loop ioctl
LOOP_SET_STATUS64, because of kill_bdev, buffer_head mappings are getting
destroyed.
kill_bdev
  truncate_inode_pages
    truncate_inode_pages_range
      do_invalidatepage
        block_invalidatepage
          discard_buffer  -->clear BH_Mapped flag

sb_bread
  __bread_gfp
  bh = __getblk_gfp
  -->discard_buffer clear BH_Mapped flag
  __bread_slow
    submit_bh
      submit_bh_wbc
        BUG_ON(!buffer_mapped(bh))  --> hit this BUG_ON

Fixes: 5db470e229e2 ("loop: drop caches if offset or block_size are changed")
Signed-off-by: Zheng Bin <zhengbi...@huawei.com>
Reviewed-by: Christoph Hellwig <h...@lst.de>
Reviewed-by: Bart Van Assche <bvanass...@acm.org>
Signed-off-by: Jens Axboe <ax...@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 drivers/block/loop.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index c1341c86bcded..728681a20b7f4 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1238,7 +1238,7 @@ loop_set_status(struct loop_device *lo, const struct 
loop_info64 *info)
        if (lo->lo_offset != info->lo_offset ||
            lo->lo_sizelimit != info->lo_sizelimit) {
                sync_blockdev(lo->lo_device);
-               kill_bdev(lo->lo_device);
+               invalidate_bdev(lo->lo_device);
        }
 
        /* I/O need to be drained during transfer transition */
@@ -1512,12 +1512,12 @@ static int loop_set_block_size(struct loop_device *lo, 
unsigned long arg)
 
        if (lo->lo_queue->limits.logical_block_size != arg) {
                sync_blockdev(lo->lo_device);
-               kill_bdev(lo->lo_device);
+               invalidate_bdev(lo->lo_device);
        }
 
        blk_mq_freeze_queue(lo->lo_queue);
 
-       /* kill_bdev should have truncated all the pages */
+       /* invalidate_bdev should have truncated all the pages */
        if (lo->lo_queue->limits.logical_block_size != arg &&
                        lo->lo_device->bd_inode->i_mapping->nrpages) {
                err = -EAGAIN;
-- 
2.25.1

Reply via email to