Re: [PATCH 3/8] block: remove the racy bd_inode->i_mapping->nrpages asserts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux