Merge tag 'block-6.3-2023-03-03' of git://git.kernel.dk/linux
[sfrench/cifs-2.6.git] / block / genhd.c
index 093ef292e98f7f913e96878065485cb182f7250b..3ee5577e15860ceb1221c609160cc6b5f56158f1 100644 (file)
@@ -356,9 +356,10 @@ void disk_uevent(struct gendisk *disk, enum kobject_action action)
 }
 EXPORT_SYMBOL_GPL(disk_uevent);
 
-int disk_scan_partitions(struct gendisk *disk, fmode_t mode, void *owner)
+int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
 {
        struct block_device *bdev;
+       int ret = 0;
 
        if (disk->flags & (GENHD_FL_NO_PART | GENHD_FL_HIDDEN))
                return -EINVAL;
@@ -366,16 +367,29 @@ int disk_scan_partitions(struct gendisk *disk, fmode_t mode, void *owner)
                return -EINVAL;
        if (disk->open_partitions)
                return -EBUSY;
-       /* Someone else has bdev exclusively open? */
-       if (disk->part0->bd_holder && disk->part0->bd_holder != owner)
-               return -EBUSY;
 
        set_bit(GD_NEED_PART_SCAN, &disk->state);
-       bdev = blkdev_get_by_dev(disk_devt(disk), mode, NULL);
+       /*
+        * If the device is opened exclusively by current thread already, it's
+        * safe to scan partitons, otherwise, use bd_prepare_to_claim() to
+        * synchronize with other exclusive openers and other partition
+        * scanners.
+        */
+       if (!(mode & FMODE_EXCL)) {
+               ret = bd_prepare_to_claim(disk->part0, disk_scan_partitions);
+               if (ret)
+                       return ret;
+       }
+
+       bdev = blkdev_get_by_dev(disk_devt(disk), mode & ~FMODE_EXCL, NULL);
        if (IS_ERR(bdev))
-               return PTR_ERR(bdev);
-       blkdev_put(bdev, mode);
-       return 0;
+               ret =  PTR_ERR(bdev);
+       else
+               blkdev_put(bdev, mode);
+
+       if (!(mode & FMODE_EXCL))
+               bd_abort_claiming(disk->part0, disk_scan_partitions);
+       return ret;
 }
 
 /**
@@ -497,9 +511,14 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
                if (ret)
                        goto out_unregister_bdi;
 
+               /* Make sure the first partition scan will be proceed */
+               if (get_capacity(disk) && !(disk->flags & GENHD_FL_NO_PART) &&
+                   !test_bit(GD_SUPPRESS_PART_SCAN, &disk->state))
+                       set_bit(GD_NEED_PART_SCAN, &disk->state);
+
                bdev_add(disk->part0, ddev->devt);
                if (get_capacity(disk))
-                       disk_scan_partitions(disk, FMODE_READ, NULL);
+                       disk_scan_partitions(disk, FMODE_READ);
 
                /*
                 * Announce the disk and partitions after all partitions are
@@ -1200,7 +1219,7 @@ struct class block_class = {
        .dev_uevent     = block_uevent,
 };
 
-static char *block_devnode(struct device *dev, umode_t *mode,
+static char *block_devnode(const struct device *dev, umode_t *mode,
                           kuid_t *uid, kgid_t *gid)
 {
        struct gendisk *disk = dev_to_disk(dev);