From 3914760aa538f55012f41859857cfe75bdcfc6a2 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 27 Jan 2022 12:43:26 +0100 Subject: [PATCH] loop: Protect loop device invalidation from racing page cache operations Grab bdev->i_mutex and bdev->i_mapping->invalidate_lock to protect operations invalidating loop device page cache from racing operations on the page cache. As a result we can drop some warnings. Signed-off-by: Jan Kara --- drivers/block/loop.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 01cbbfc4e9e2..170e3dc0d8a9 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1252,6 +1252,8 @@ 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) { size_changed = true; + inode_lock(lo->lo_device->bd_inode); + filemap_invalidate_lock(lo->lo_device->bd_inode->i_mapping); sync_blockdev(lo->lo_device); invalidate_bdev(lo->lo_device); } @@ -1259,15 +1261,6 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) /* I/O need to be drained during transfer transition */ blk_mq_freeze_queue(lo->lo_queue); - if (size_changed && lo->lo_device->bd_inode->i_mapping->nrpages) { - /* If any pages were dirtied after invalidate_bdev(), try again */ - err = -EAGAIN; - pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", - __func__, lo->lo_number, lo->lo_file_name, - lo->lo_device->bd_inode->i_mapping->nrpages); - goto out_unfreeze; - } - prev_lo_flags = lo->lo_flags; err = loop_set_status_from_info(lo, info); @@ -1285,6 +1278,8 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) loff_t new_size = get_size(lo->lo_offset, lo->lo_sizelimit, lo->lo_backing_file); loop_set_size(lo, new_size); + filemap_invalidate_unlock(lo->lo_device->bd_inode->i_mapping); + inode_unlock(lo->lo_device->bd_inode); } loop_config_discard(lo); @@ -1474,26 +1469,18 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg) if (lo->lo_queue->limits.logical_block_size == arg) return 0; + inode_lock(lo->lo_device->bd_inode); + filemap_invalidate_lock(lo->lo_device->bd_inode->i_mapping); sync_blockdev(lo->lo_device); invalidate_bdev(lo->lo_device); - blk_mq_freeze_queue(lo->lo_queue); - - /* 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", - __func__, lo->lo_number, lo->lo_file_name, - lo->lo_device->bd_inode->i_mapping->nrpages); - goto out_unfreeze; - } - blk_queue_logical_block_size(lo->lo_queue, arg); blk_queue_physical_block_size(lo->lo_queue, arg); blk_queue_io_min(lo->lo_queue, arg); loop_update_dio(lo); -out_unfreeze: blk_mq_unfreeze_queue(lo->lo_queue); + filemap_invalidate_unlock(lo->lo_device->bd_inode->i_mapping); + inode_unlock(lo->lo_device->bd_inode); return err; } -- 2.31.1