From b896fa85e0ee4f09ba4be48a3f405fc82c38afb4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Apr 2021 08:22:52 +0200 Subject: dasd: use bdev_disk_changed instead of blk_drop_partitions Use the more general interface - the behavior is the same except that now a change uevent is sent, which is the right thing to do when the device becomes unusable. Signed-off-by: Christoph Hellwig Acked-by: Stefan Haberland Link: https://lore.kernel.org/r/20210406062303.811835-2-hch@lst.de Signed-off-by: Jens Axboe --- block/partitions/core.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'block/partitions') diff --git a/block/partitions/core.c b/block/partitions/core.c index 1a7558917c47..22a0dab17ed3 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -544,10 +544,6 @@ int blk_drop_partitions(struct block_device *bdev) return 0; } -#ifdef CONFIG_S390 -/* for historic reasons in the DASD driver */ -EXPORT_SYMBOL_GPL(blk_drop_partitions); -#endif static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev, struct parsed_partitions *state, int p) -- cgit v1.2.3 From 473338be3aaea117a7133720305f240eb7f68951 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Apr 2021 08:22:54 +0200 Subject: block: move more syncing and invalidation to delete_partition Move the calls to fsync_bdev and __invalidate_device from del_gendisk to delete_partition. For the other two callers that check that there are no openers for the delete partitions(s) the callouts are a no-op as no file system can be mounted, but this keeps all the cleanup in one place. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20210406062303.811835-4-hch@lst.de Signed-off-by: Jens Axboe --- block/genhd.c | 5 +---- block/partitions/core.c | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'block/partitions') diff --git a/block/genhd.c b/block/genhd.c index 9b121b1f7998..15f99da4543f 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -686,11 +686,8 @@ void del_gendisk(struct gendisk *disk) /* invalidate stuff */ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); - while ((part = disk_part_iter_next(&piter))) { - fsync_bdev(part); - __invalidate_device(part, true); + while ((part = disk_part_iter_next(&piter))) delete_partition(part); - } disk_part_iter_exit(&piter); fsync_bdev(disk->part0); diff --git a/block/partitions/core.c b/block/partitions/core.c index 22a0dab17ed3..8c1735292940 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -287,6 +287,9 @@ struct device_type part_type = { */ void delete_partition(struct block_device *part) { + fsync_bdev(part); + __invalidate_device(part, true); + xa_erase(&part->bd_disk->part_tbl, part->bd_partno); kobject_put(part->bd_holder_dir); device_del(&part->bd_device); @@ -468,9 +471,6 @@ int bdev_del_partition(struct block_device *bdev, int partno) if (part->bd_openers) goto out_unlock; - sync_blockdev(part); - invalidate_bdev(part); - delete_partition(part); ret = 0; out_unlock: -- cgit v1.2.3 From d3c4a43d9291279c28b26757351a6ab72c110753 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Apr 2021 08:22:55 +0200 Subject: block: refactor blk_drop_partitions Move the busy check and disk-wide sync into the only caller, so that the remainder can be shared with del_gendisk. Also pass the gendisk instead of the bdev as that is all that is needed. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20210406062303.811835-5-hch@lst.de Signed-off-by: Jens Axboe --- block/blk.h | 1 - block/genhd.c | 11 +---------- block/partitions/core.c | 14 +++----------- fs/block_dev.c | 8 +++++--- include/linux/genhd.h | 2 +- 5 files changed, 10 insertions(+), 26 deletions(-) (limited to 'block/partitions') diff --git a/block/blk.h b/block/blk.h index 8f4337c5a9e6..8b3591aee0a5 100644 --- a/block/blk.h +++ b/block/blk.h @@ -349,7 +349,6 @@ char *disk_name(struct gendisk *hd, int partno, char *buf); #define ADDPART_FLAG_NONE 0 #define ADDPART_FLAG_RAID 1 #define ADDPART_FLAG_WHOLEDISK 2 -void delete_partition(struct block_device *part); int bdev_add_partition(struct block_device *bdev, int partno, sector_t start, sector_t length); int bdev_del_partition(struct block_device *bdev, int partno); diff --git a/block/genhd.c b/block/genhd.c index 15f99da4543f..8303ec67fd70 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -667,9 +667,6 @@ EXPORT_SYMBOL(device_add_disk_no_queue_reg); */ void del_gendisk(struct gendisk *disk) { - struct disk_part_iter piter; - struct block_device *part; - might_sleep(); if (WARN_ON_ONCE(!disk->queue)) @@ -683,13 +680,7 @@ void del_gendisk(struct gendisk *disk) * disk is marked as dead (GENHD_FL_UP cleared). */ down_write(&bdev_lookup_sem); - - /* invalidate stuff */ - disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); - while ((part = disk_part_iter_next(&piter))) - delete_partition(part); - disk_part_iter_exit(&piter); - + blk_drop_partitions(disk); fsync_bdev(disk->part0); __invalidate_device(disk->part0, true); diff --git a/block/partitions/core.c b/block/partitions/core.c index 8c1735292940..536f7c5bb0b6 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -285,7 +285,7 @@ struct device_type part_type = { * Must be called either with bd_mutex held, before a disk can be opened or * after all disk users are gone. */ -void delete_partition(struct block_device *part) +static void delete_partition(struct block_device *part) { fsync_bdev(part); __invalidate_device(part, true); @@ -526,23 +526,15 @@ static bool disk_unlock_native_capacity(struct gendisk *disk) } } -int blk_drop_partitions(struct block_device *bdev) +void blk_drop_partitions(struct gendisk *disk) { struct disk_part_iter piter; struct block_device *part; - if (bdev->bd_part_count) - return -EBUSY; - - sync_blockdev(bdev); - invalidate_bdev(bdev); - - disk_part_iter_init(&piter, bdev->bd_disk, DISK_PITER_INCL_EMPTY); + disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); while ((part = disk_part_iter_next(&piter))) delete_partition(part); disk_part_iter_exit(&piter); - - return 0; } static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev, diff --git a/fs/block_dev.c b/fs/block_dev.c index 92ed7d5df677..594a1bee9dd9 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1243,9 +1243,11 @@ int bdev_disk_changed(struct block_device *bdev, bool invalidate) clear_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); rescan: - ret = blk_drop_partitions(bdev); - if (ret) - return ret; + if (bdev->bd_part_count) + return -EBUSY; + sync_blockdev(bdev); + invalidate_bdev(bdev); + blk_drop_partitions(disk); /* * Historically we only set the capacity to zero for devices that diff --git a/include/linux/genhd.h b/include/linux/genhd.h index f364619092cc..16178a935c40 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -273,7 +273,7 @@ static inline sector_t get_capacity(struct gendisk *disk) int bdev_disk_changed(struct block_device *bdev, bool invalidate); int blk_add_partitions(struct gendisk *disk, struct block_device *bdev); -int blk_drop_partitions(struct block_device *bdev); +void blk_drop_partitions(struct gendisk *disk); extern struct gendisk *__alloc_disk_node(int minors, int node_id); extern void put_disk(struct gendisk *disk); -- cgit v1.2.3 From c76f48eb5c084b1e15c931ae8cc1826cd771d70d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Apr 2021 08:22:56 +0200 Subject: block: take bd_mutex around delete_partitions in del_gendisk There is nothing preventing an ioctl from trying do delete partition concurrenly with del_gendisk, so take open_mutex to serialize against that. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20210406062303.811835-6-hch@lst.de Signed-off-by: Jens Axboe --- block/genhd.c | 4 ++++ block/partitions/core.c | 2 ++ 2 files changed, 6 insertions(+) (limited to 'block/partitions') diff --git a/block/genhd.c b/block/genhd.c index 8303ec67fd70..e3f3c2321773 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -680,7 +680,11 @@ void del_gendisk(struct gendisk *disk) * disk is marked as dead (GENHD_FL_UP cleared). */ down_write(&bdev_lookup_sem); + + mutex_lock(&disk->part0->bd_mutex); blk_drop_partitions(disk); + mutex_unlock(&disk->part0->bd_mutex); + fsync_bdev(disk->part0); __invalidate_device(disk->part0, true); diff --git a/block/partitions/core.c b/block/partitions/core.c index 536f7c5bb0b6..9fbaec466b51 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -531,6 +531,8 @@ void blk_drop_partitions(struct gendisk *disk) struct disk_part_iter piter; struct block_device *part; + lockdep_assert_held(&disk->part0->bd_mutex); + disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); while ((part = disk_part_iter_next(&piter))) delete_partition(part); -- cgit v1.2.3 From 6c4541a8bb94a1cccca55ee53c866eb72bf279cf Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Apr 2021 08:22:57 +0200 Subject: block: simplify partition removal Always look up the first available entry instead of the complicated stateful traversal. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20210406062303.811835-7-hch@lst.de Signed-off-by: Jens Axboe --- block/partitions/core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'block/partitions') diff --git a/block/partitions/core.c b/block/partitions/core.c index 9fbaec466b51..927144d4e59d 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -528,15 +528,17 @@ static bool disk_unlock_native_capacity(struct gendisk *disk) void blk_drop_partitions(struct gendisk *disk) { - struct disk_part_iter piter; struct block_device *part; + unsigned long idx; lockdep_assert_held(&disk->part0->bd_mutex); - disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); - while ((part = disk_part_iter_next(&piter))) + xa_for_each_start(&disk->part_tbl, idx, part, 1) { + if (!bdgrab(part)) + continue; delete_partition(part); - disk_part_iter_exit(&piter); + bdput(part); + } } static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev, -- cgit v1.2.3 From e30691237bc1e055c55b0fe256ed7fc1a4ee1122 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Apr 2021 08:22:58 +0200 Subject: block: simplify partition_overlaps Just use xa_for_each to iterate over the partitions as there is no need to grab a reference to each partition. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20210406062303.811835-8-hch@lst.de Signed-off-by: Jens Axboe --- block/partitions/core.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'block/partitions') diff --git a/block/partitions/core.c b/block/partitions/core.c index 927144d4e59d..0f8454b93c6e 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -420,21 +420,21 @@ out_put: static bool partition_overlaps(struct gendisk *disk, sector_t start, sector_t length, int skip_partno) { - struct disk_part_iter piter; struct block_device *part; bool overlap = false; + unsigned long idx; - disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); - while ((part = disk_part_iter_next(&piter))) { - if (part->bd_partno == skip_partno || - start >= part->bd_start_sect + bdev_nr_sectors(part) || - start + length <= part->bd_start_sect) - continue; - overlap = true; - break; + rcu_read_lock(); + xa_for_each_start(&disk->part_tbl, idx, part, 1) { + if (part->bd_partno != skip_partno && + start < part->bd_start_sect + bdev_nr_sectors(part) && + start + length > part->bd_start_sect) { + overlap = true; + break; + } } + rcu_read_unlock(); - disk_part_iter_exit(&piter); return overlap; } -- cgit v1.2.3