Skip to content

Commit e5cfefa

Browse files
YuKuai-huaweiaxboe
authored andcommitted
block: fix scan partition for exclusively open device again
As explained in commit 36369f4 ("block: Do not reread partition table on exclusively open device"), reread partition on the device that is exclusively opened by someone else is problematic. This patch will make sure partition scan will only be proceed if current thread open the device exclusively, or the device is not opened exclusively, and in the later case, other scanners and exclusive openers will be blocked temporarily until partition scan is done. Fixes: 10c70d9 ("block: remove the bd_openers checks in blk_drop_partitions") Cc: <[email protected]> Suggested-by: Jan Kara <[email protected]> Signed-off-by: Yu Kuai <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 0f77b29 commit e5cfefa

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

block/genhd.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ EXPORT_SYMBOL_GPL(disk_uevent);
359359
int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
360360
{
361361
struct block_device *bdev;
362+
int ret = 0;
362363

363364
if (disk->flags & (GENHD_FL_NO_PART | GENHD_FL_HIDDEN))
364365
return -EINVAL;
@@ -368,11 +369,27 @@ int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
368369
return -EBUSY;
369370

370371
set_bit(GD_NEED_PART_SCAN, &disk->state);
371-
bdev = blkdev_get_by_dev(disk_devt(disk), mode, NULL);
372+
/*
373+
* If the device is opened exclusively by current thread already, it's
374+
* safe to scan partitons, otherwise, use bd_prepare_to_claim() to
375+
* synchronize with other exclusive openers and other partition
376+
* scanners.
377+
*/
378+
if (!(mode & FMODE_EXCL)) {
379+
ret = bd_prepare_to_claim(disk->part0, disk_scan_partitions);
380+
if (ret)
381+
return ret;
382+
}
383+
384+
bdev = blkdev_get_by_dev(disk_devt(disk), mode & ~FMODE_EXCL, NULL);
372385
if (IS_ERR(bdev))
373-
return PTR_ERR(bdev);
374-
blkdev_put(bdev, mode);
375-
return 0;
386+
ret = PTR_ERR(bdev);
387+
else
388+
blkdev_put(bdev, mode);
389+
390+
if (!(mode & FMODE_EXCL))
391+
bd_abort_claiming(disk->part0, disk_scan_partitions);
392+
return ret;
376393
}
377394

378395
/**
@@ -494,6 +511,11 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
494511
if (ret)
495512
goto out_unregister_bdi;
496513

514+
/* Make sure the first partition scan will be proceed */
515+
if (get_capacity(disk) && !(disk->flags & GENHD_FL_NO_PART) &&
516+
!test_bit(GD_SUPPRESS_PART_SCAN, &disk->state))
517+
set_bit(GD_NEED_PART_SCAN, &disk->state);
518+
497519
bdev_add(disk->part0, ddev->devt);
498520
if (get_capacity(disk))
499521
disk_scan_partitions(disk, FMODE_READ);

block/ioctl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
528528
return -EACCES;
529529
if (bdev_is_partition(bdev))
530530
return -EINVAL;
531-
return disk_scan_partitions(bdev->bd_disk, mode & ~FMODE_EXCL);
531+
return disk_scan_partitions(bdev->bd_disk, mode);
532532
case BLKTRACESTART:
533533
case BLKTRACESTOP:
534534
case BLKTRACETEARDOWN:

0 commit comments

Comments
 (0)