From 4d3e705f87e304a12c650c32ef6d41fbcdb75086 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 19 Jan 2022 08:39:24 +0100 Subject: [PATCH] block: don't take part_tbl_mutex inside of open_mutex Change the critical sections so that part_tbl_mutex never nests inside of open_mutex. The core block layer and dasd parts are easy, but the loop driver tries to drop from the ->release handler. Defer that rescan using a new GD_DROP_PARTITIONS flag that works similar to the GD_NEED_PART_SCAN flag used at open time. Signed-off-by: Christoph Hellwig --- block/bdev.c | 22 +++++++++++----------- drivers/block/loop.c | 11 +---------- include/linux/genhd.h | 1 + 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 5fb7a672bd4a..2f1f47c891c9 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -707,23 +707,17 @@ static int blkdev_get_whole(struct block_device *bdev, fmode_t mode) goto out_unlock; if (disk->fops->open) { ret = disk->fops->open(bdev, mode); - if (ret) { - /* avoid ghost partitions on a removed medium */ - if (ret == -ENOMEDIUM && - test_bit(GD_NEED_PART_SCAN, &disk->state)) - bdev_disk_changed(disk, true); + if (ret) goto out_unlock; - } } - - if (!bdev->bd_openers) + if (!bdev->bd_openers++) set_init_blocksize(bdev); - if (test_bit(GD_NEED_PART_SCAN, &disk->state)) - bdev_disk_changed(disk, false); - bdev->bd_openers++; ret = 0; out_unlock: mutex_unlock(&disk->open_mutex); + if (test_bit(GD_NEED_PART_SCAN, &disk->state) && + (ret == 0 || ret == -ENOMEDIUM)) + bdev_disk_changed(disk, ret == -ENOMEDIUM); return ret; } @@ -737,6 +731,12 @@ static void blkdev_put_whole(struct block_device *bdev, fmode_t mode) if (disk->fops->release) disk->fops->release(disk, mode); mutex_unlock(&disk->open_mutex); + + if (test_and_clear_bit(GD_DROP_PARTITIONS, &disk->state)) { + mutex_lock(&disk->part_tbl_mutex); + blk_drop_partitions(disk); + mutex_unlock(&disk->part_tbl_mutex); + } } static int blkdev_get_part(struct block_device *part, fmode_t mode) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 392eedafe67c..998d08a18414 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1145,16 +1145,7 @@ static void __loop_clr_fd(struct loop_device *lo) blk_mq_unfreeze_queue(lo->lo_queue); disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE); - - if (lo->lo_flags & LO_FLAGS_PARTSCAN) { - int err; - - err = bdev_disk_changed(lo->lo_disk, false); - if (err) - pr_warn("%s: partition scan of loop%d failed (rc=%d)\n", - __func__, lo->lo_number, err); - /* Device is gone, no point in returning error */ - } + set_bit(GD_DROP_PARTITIONS, &lo->lo_disk->state); lo->lo_flags = 0; if (!part_shift) diff --git a/include/linux/genhd.h b/include/linux/genhd.h index b85b4c0121bf..fbed18c7a5b7 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -111,6 +111,7 @@ struct gendisk { #define GD_READ_ONLY 1 #define GD_DEAD 2 #define GD_NATIVE_CAPACITY 3 +#define GD_DROP_PARTITIONS 4 struct mutex open_mutex; /* open/close mutex */ unsigned open_partitions; /* number of open partitions */ -- 2.50.1