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

[ Upstream commit f4bd34b139a3fa2808c4205f12714c65e1548c6c ]

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: Sasha Levin <sas...@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 drivers/block/loop.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index da693e6a834e5..418bb4621255a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1289,7 +1289,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 */
@@ -1320,7 +1320,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) {
-               /* kill_bdev should have truncated all the pages */
+               /* invalidate_bdev should have truncated all the pages */
                if (lo->lo_device->bd_inode->i_mapping->nrpages) {
                        err = -EAGAIN;
                        pr_warn("%s: loop%d (%s) has still dirty pages 
(nrpages=%lu)\n",
@@ -1565,11 +1565,11 @@ static int loop_set_block_size(struct loop_device *lo, 
unsigned long arg)
                return 0;
 
        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_device->bd_inode->i_mapping->nrpages) {
                err = -EAGAIN;
                pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n",
-- 
2.25.1

Reply via email to