I don't really like many of these helpers as they are rather confusing. Below is a patch ontop of your whole series that massages it into something I find much easier to follow. The big caveats are: - this moves the bdi link creation earlier, which is safe and probably preferable. (should go into a prep patch). - del_gendisk now needs to cope with not set up events and integrity kobject I also have a bunch of changes to del_gendisk which might require backporting, let me try to get those out ASAP. diff --git a/block/blk-integrity.c b/block/blk-integrity.c index e46f47f2dec9..3135adab2e7c 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -446,6 +446,8 @@ int blk_integrity_add(struct gendisk *disk) void blk_integrity_del(struct gendisk *disk) { + if (!disk->integrity_kobj.state_initialized) + return; kobject_uevent(&disk->integrity_kobj, KOBJ_REMOVE); kobject_del(&disk->integrity_kobj); kobject_put(&disk->integrity_kobj); diff --git a/block/disk-events.c b/block/disk-events.c index 0262784be34c..af7d7249eefa 100644 --- a/block/disk-events.c +++ b/block/disk-events.c @@ -458,7 +458,8 @@ void disk_del_events(struct gendisk *disk) disk_block_events(disk); mutex_lock(&disk_events_mutex); - list_del_init(&disk->ev->node); + if (!list_empty(&disk->ev->node)) + list_del_init(&disk->ev->node); mutex_unlock(&disk_events_mutex); } } diff --git a/block/genhd.c b/block/genhd.c index c6c9c196ff27..0c8c71d78536 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -390,68 +390,8 @@ static void disk_scan_partitions(struct gendisk *disk) blkdev_put(bdev, FMODE_READ); } -static void disk_announce(struct gendisk *disk) -{ - struct device *ddev = disk_to_dev(disk); - - /* announce the disk and partitions after all partitions are created */ - dev_set_uevent_suppress(ddev, 0); - disk_uevent(disk, KOBJ_ADD); -} - -static void unregister_disk_partitions(struct gendisk *disk) -{ - mutex_lock(&disk->open_mutex); - disk->flags &= ~GENHD_FL_UP; - blk_drop_partitions(disk); - mutex_unlock(&disk->open_mutex); - - fsync_bdev(disk->part0); - __invalidate_device(disk->part0, true); - - /* - * Unhash the bdev inode for this device so that it can't be looked - * up any more even if openers still hold references to it. - */ - remove_inode_hash(disk->part0->bd_inode); - - set_capacity(disk, 0); -} - -static void disk_invalidate(struct gendisk *disk) -{ - if (!(disk->flags & GENHD_FL_HIDDEN)) { - sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); - - /* - * Unregister bdi before releasing device numbers (as they can - * get reused and we'd get clashes in sysfs). - */ - bdi_unregister(disk->queue->backing_dev_info); - } - - blk_unregister_queue(disk); - - kobject_put(disk->part0->bd_holder_dir); - kobject_put(disk->slave_dir); - - part_stat_set_all(disk->part0, 0); - disk->part0->bd_stamp = 0; - if (!sysfs_deprecated) - sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); - pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); - device_del(disk_to_dev(disk)); -} - -static void unregister_disk(struct gendisk *disk) -{ - unregister_disk_partitions(disk); - disk_invalidate(disk); -} - -static int __must_check register_disk(struct device *parent, - struct gendisk *disk, - const struct attribute_group **groups) +static int register_disk(struct device *parent, struct gendisk *disk, + const struct attribute_group **groups) { struct device *ddev = disk_to_dev(disk); int err; @@ -498,20 +438,22 @@ static int __must_check register_disk(struct device *parent, if (disk->flags & GENHD_FL_HIDDEN) return 0; - disk_scan_partitions(disk); - disk_announce(disk); - if (disk->queue->backing_dev_info->dev) { err = sysfs_create_link(&ddev->kobj, - &disk->queue->backing_dev_info->dev->kobj, - "bdi"); + &disk->queue->backing_dev_info->dev->kobj, "bdi"); if (WARN_ON(err)) goto exit_del_block_depr; } + + disk_scan_partitions(disk); + + /* announce the disk and partitions after all partitions are created */ + dev_set_uevent_suppress(ddev, 0); + disk_uevent(disk, KOBJ_ADD); + return 0; exit_del_block_depr: - unregister_disk_partitions(disk); if (!sysfs_deprecated) sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); exit_del_device: @@ -614,6 +556,7 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, bdi_set_owner(bdi, dev); bdev_add(disk->part0, dev->devt); } + ret = register_disk(parent, disk, groups); if (ret) goto exit_unregister_bdi; @@ -628,13 +571,11 @@ static int __device_add_disk(struct device *parent, struct gendisk *disk, ret = blk_integrity_add(disk); if (ret) - goto exit_del_events; + goto exit_unregister_disk; return 0; -exit_del_events: - disk_del_events(disk); exit_unregister_disk: - unregister_disk(disk); + del_gendisk(disk); return ret; exit_unregister_bdi: @@ -691,7 +632,44 @@ void del_gendisk(struct gendisk *disk) blk_integrity_del(disk); disk_del_events(disk); - unregister_disk(disk); + + mutex_lock(&disk->open_mutex); + disk->flags &= ~GENHD_FL_UP; + blk_drop_partitions(disk); + mutex_unlock(&disk->open_mutex); + + fsync_bdev(disk->part0); + __invalidate_device(disk->part0, true); + + /* + * Unhash the bdev inode for this device so that it can't be looked + * up any more even if openers still hold references to it. + */ + remove_inode_hash(disk->part0->bd_inode); + + set_capacity(disk, 0); + + if (!(disk->flags & GENHD_FL_HIDDEN)) { + sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); + + /* + * Unregister bdi before releasing device numbers (as they can + * get reused and we'd get clashes in sysfs). + */ + bdi_unregister(disk->queue->backing_dev_info); + } + + blk_unregister_queue(disk); + + kobject_put(disk->part0->bd_holder_dir); + kobject_put(disk->slave_dir); + + part_stat_set_all(disk->part0, 0); + disk->part0->bd_stamp = 0; + if (!sysfs_deprecated) + sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); + pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); + device_del(disk_to_dev(disk)); } EXPORT_SYMBOL(del_gendisk);