[PATCH 1/5] block: add flag for add_disk() completion notation

Luis Chamberlain
2021-07-20T18:22:01Z

Often drivers may have complex setups where it is not
clear if their disk completed their respective *add_disk*()
call. They either have to invent a setting or, they
incorrectly use GENHD_FL_UP. Using GENHD_FL_UP however is
used internally so we know when we can add / remove
partitions safely. We can easily fail along the way
prior to add_disk() completing and still have
GENHD_FL_UP set, so it would not be correct in that case
to call del_gendisk() on the disk.

Provide a new flag then which allows us to check if
*add_disk*() completed, and conversely just make
del_gendisk() check for this for drivers so that
they can safely call del_gendisk() and we'll figure
it out if it is safe for you to call this.

Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
block/genhd.c | 8 ++++++++
include/linux/genhd.h | 11 ++++++++++-
2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/block/genhd.c b/block/genhd.c
index af4d2ab4a633..a858eed05e55 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -539,6 +539,8 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,

disk_add_events(disk);
blk_integrity_add(disk);
+
+ disk->flags |= GENHD_FL_DISK_ADDED;
}

void device_add_disk(struct device *parent, struct gendisk *disk,
@@ -569,6 +571,9 @@ EXPORT_SYMBOL(device_add_disk_no_queue_reg);
* with put_disk(), which should be called after del_gendisk(), if
* __device_add_disk() was used.
*
+ * Drivers can safely call this even if they are not sure if the respective
+ * __device_add_disk() call succeeded.
+ *
* Drivers exist which depend on the release of the gendisk to be synchronous,
* it should not be deferred.
*
@@ -578,6 +583,9 @@ void del_gendisk(struct gendisk *disk)
{
might_sleep();

+ if (!blk_disk_added(disk))
+ return;
+
if (WARN_ON_ONCE(!disk->queue))
return;

diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 13b34177cc85..2470c8b56599 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -56,6 +56,10 @@ struct partition_meta_info {
* Must not be set for devices which are removed entirely when the
* media is removed.
*
+ * ``GENHD_FL_DISK_ADDED`` (0x0002): used to clarify that the
+ * respective add_disk*() call completed successfully, so that
+ * we know we can safely process del_gendisk() on the disk.
+ *
* ``GENHD_FL_CD`` (0x0008): the block device is a CD-ROM-style
* device.
* Affects responses to the ``CDROM_GET_CAPABILITY`` ioctl.
@@ -94,7 +98,7 @@ struct partition_meta_info {
* Used for multipath devices.
*/
#define GENHD_FL_REMOVABLE 0x0001
-/* 2 is unused (used to be GENHD_FL_DRIVERFS) */
+#define GENHD_FL_DISK_ADDED 0x0002
/* 4 is unused (used to be GENHD_FL_MEDIA_CHANGE_NOTIFY) */
#define GENHD_FL_CD 0x0008
#define GENHD_FL_UP 0x0010
@@ -189,6 +193,11 @@ struct gendisk {
#define disk_to_cdi(disk) NULL
#endif

+static inline bool blk_disk_added(struct gendisk *disk)
+{
+ return disk && (disk->flags & GENHD_FL_DISK_ADDED);
+}
+
static inline int disk_max_parts(struct gendisk *disk)
{
if (disk->flags & GENHD_FL_EXT_DEVT)
--
2.27.0