]> www.infradead.org Git - users/hch/block.git/commitdiff
block: don't take part_tbl_mutex inside of open_mutex
authorChristoph Hellwig <hch@lst.de>
Wed, 19 Jan 2022 07:39:24 +0000 (08:39 +0100)
committerChristoph Hellwig <hch@lst.de>
Wed, 19 Jan 2022 15:19:57 +0000 (16:19 +0100)
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 <hch@lst.de>
block/bdev.c
drivers/block/loop.c
include/linux/genhd.h

index 5fb7a672bd4a711c733f3a4ee6727c68774a37b2..2f1f47c891c99960cac855fc36fb7f1b4c649168 100644 (file)
@@ -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)
index 392eedafe67c8dad67c789a7f074e9fcd4190e83..998d08a18414b394214cc382a24f1fa364ab2130 100644 (file)
@@ -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)
index b85b4c0121bf1207b44ffaa00166f6c4216d9c49..fbed18c7a5b703e904ecf65012460b67b2447f9f 100644 (file)
@@ -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 */