The BLKRRPART ioctl used to report errors such as EIO before we changed the blkdev_reread_part() logic. Lets add a flag and capture the errors returned by bdev_disk_changed() when the flag is set. Setting this flag for the BLKRRPART path when we want the errors to be reported when rereading partitions on the disk. Link: https://lore.kernel.org/all/20240320015134.GA14267@xxxxxx/ Suggested-by: Christoph Hellwig <hch@xxxxxx> Tested: Tested by simulating failure to the block device and will propose a new test to blktests. Fixes: 4601b4b130de ("block: reopen the device in blkdev_reread_part") Reported-by: Saranya Muruganandam <saranyamohan@xxxxxxxxxx> Signed-off-by: Saranya Muruganandam <saranyamohan@xxxxxxxxxx> Change-Id: Idf3d97390ed78061556f8468d10d6cab24ae20b1 --- block/bdev.c | 31 +++++++++++++++++++++---------- block/ioctl.c | 3 ++- include/linux/blkdev.h | 3 +++ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 77fa77cd29bee..71478f8865546 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -632,6 +632,14 @@ static void blkdev_flush_mapping(struct block_device *bdev) bdev_write_inode(bdev); } +static void blkdev_put_whole(struct block_device *bdev) +{ + if (atomic_dec_and_test(&bdev->bd_openers)) + blkdev_flush_mapping(bdev); + if (bdev->bd_disk->fops->release) + bdev->bd_disk->fops->release(bdev->bd_disk); +} + static int blkdev_get_whole(struct block_device *bdev, blk_mode_t mode) { struct gendisk *disk = bdev->bd_disk; @@ -650,18 +658,21 @@ static int blkdev_get_whole(struct block_device *bdev, blk_mode_t mode) if (!atomic_read(&bdev->bd_openers)) set_init_blocksize(bdev); - if (test_bit(GD_NEED_PART_SCAN, &disk->state)) - bdev_disk_changed(disk, false); atomic_inc(&bdev->bd_openers); - return 0; -} -static void blkdev_put_whole(struct block_device *bdev) -{ - if (atomic_dec_and_test(&bdev->bd_openers)) - blkdev_flush_mapping(bdev); - if (bdev->bd_disk->fops->release) - bdev->bd_disk->fops->release(bdev->bd_disk); + if (test_bit(GD_NEED_PART_SCAN, &disk->state)) { + /* + * Only return scanning errors if we are called from contexts + * that explicitly want them, e.g. the BLKRRPART ioctl. + */ + ret = bdev_disk_changed(disk, false); + if (ret && (mode & BLK_OPEN_STRICT_SCAN)) { + blkdev_put_whole(bdev); + return ret; + } + } + + return 0; } static int blkdev_get_part(struct block_device *part, blk_mode_t mode) diff --git a/block/ioctl.c b/block/ioctl.c index aa46f3761c3ed..e8d72d9f327fd 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -557,7 +557,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, blk_mode_t mode, return -EACCES; if (bdev_is_partition(bdev)) return -EINVAL; - return disk_scan_partitions(bdev->bd_disk, mode); + return disk_scan_partitions(bdev->bd_disk, + mode | BLK_OPEN_STRICT_SCAN); case BLKTRACESTART: case BLKTRACESTOP: case BLKTRACETEARDOWN: diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 01983eece8f2a..d0104dc839b0d 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -151,6 +151,9 @@ struct access_rules_head { int max_rules; }; +/* return partition scanning errors */ +#define BLK_OPEN_STRICT_SCAN ((__force blk_mode_t)(1 << 5)) + struct gendisk { /* * major/first_minor/minors should not be set by any new driver, the -- 2.44.0.478.gd926399ef9-goog