On Thu 27-01-22 10:49:42, Christoph Hellwig wrote: > On Thu, Jan 27, 2022 at 10:47:37AM +0100, Jan Kara wrote: > > On Wed 26-01-22 16:50:35, Christoph Hellwig wrote: > > > Nothing prevents a file system or userspace opener of the block device > > > from redirtying the page right afte sync_blockdev returned. Fortunately > > > data in the page cache during a block device change is mostly harmless > > > anyway. > > > > > > Signed-off-by: Christoph Hellwig <hch@xxxxxx> > > > > My understanding was these warnings are there to tell userspace it is doing > > something wrong. Something like the warning we issue when DIO races with > > buffered IO... I'm not sure how useful they are but I don't see strong > > reason to remove them either... > > Well, it is not just a warning, but also fails the command. With some of > the reduced synchronization blktests loop/002 can hit them pretty reliably. I see. I guess another place where using mapping->invalidate_lock would be good to avoid these races... So maybe something like attached patch? Honza -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR
>From 3914760aa538f55012f41859857cfe75bdcfc6a2 Mon Sep 17 00:00:00 2001 From: Jan Kara <jack@xxxxxxx> 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 <jack@xxxxxxx> --- 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