dtoverlays: Add overlays for the IMX708 image sensor
[platform/kernel/linux-rpi.git] / block / genhd.c
index ab12ae6..6806518 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
+#include <linux/major.h>
 #include <linux/mutex.h>
 #include <linux/idr.h>
 #include <linux/log2.h>
@@ -323,7 +324,7 @@ int blk_alloc_ext_minor(void)
 {
        int idx;
 
-       idx = ida_alloc_range(&ext_devt_ida, 0, NR_EXT_DEVT, GFP_KERNEL);
+       idx = ida_alloc_range(&ext_devt_ida, 0, NR_EXT_DEVT - 1, GFP_KERNEL);
        if (idx == -ENOSPC)
                return -EBUSY;
        return idx;
@@ -420,6 +421,8 @@ int device_add_disk(struct device *parent, struct gendisk *disk,
                                DISK_MAX_PARTS);
                        disk->minors = DISK_MAX_PARTS;
                }
+               if (disk->first_minor + disk->minors > MINORMASK + 1)
+                       return -EINVAL;
        } else {
                if (WARN_ON(disk->minors))
                        return -EINVAL;
@@ -432,10 +435,6 @@ int device_add_disk(struct device *parent, struct gendisk *disk,
                disk->flags |= GENHD_FL_EXT_DEVT;
        }
 
-       ret = disk_alloc_events(disk);
-       if (ret)
-               goto out_free_ext_minor;
-
        /* delay uevents, until we scanned partition table */
        dev_set_uevent_suppress(ddev, 1);
 
@@ -446,7 +445,12 @@ int device_add_disk(struct device *parent, struct gendisk *disk,
                ddev->devt = MKDEV(disk->major, disk->first_minor);
        ret = device_add(ddev);
        if (ret)
-               goto out_disk_release_events;
+               goto out_free_ext_minor;
+
+       ret = disk_alloc_events(disk);
+       if (ret)
+               goto out_device_del;
+
        if (!sysfs_deprecated) {
                ret = sysfs_create_link(block_depr, &ddev->kobj,
                                        kobject_name(&ddev->kobj));
@@ -467,11 +471,15 @@ int device_add_disk(struct device *parent, struct gendisk *disk,
 
        disk->part0->bd_holder_dir =
                kobject_create_and_add("holders", &ddev->kobj);
-       if (!disk->part0->bd_holder_dir)
+       if (!disk->part0->bd_holder_dir) {
+               ret = -ENOMEM;
                goto out_del_integrity;
+       }
        disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
-       if (!disk->slave_dir)
+       if (!disk->slave_dir) {
+               ret = -ENOMEM;
                goto out_put_holder_dir;
+       }
 
        ret = bd_register_pending_holders(disk);
        if (ret < 0)
@@ -519,6 +527,7 @@ out_unregister_bdi:
                bdi_unregister(disk->bdi);
 out_unregister_queue:
        blk_unregister_queue(disk);
+       rq_qos_exit(disk->queue);
 out_put_slave_dir:
        kobject_put(disk->slave_dir);
 out_put_holder_dir:
@@ -530,8 +539,6 @@ out_del_block_link:
                sysfs_remove_link(block_depr, dev_name(ddev));
 out_device_del:
        device_del(ddev);
-out_disk_release_events:
-       disk_release_events(disk);
 out_free_ext_minor:
        if (disk->major == BLOCK_EXT_MAJOR)
                blk_free_ext_minor(disk->first_minor);
@@ -540,6 +547,20 @@ out_free_ext_minor:
 EXPORT_SYMBOL(device_add_disk);
 
 /**
+ * blk_mark_disk_dead - mark a disk as dead
+ * @disk: disk to mark as dead
+ *
+ * Mark as disk as dead (e.g. surprise removed) and don't accept any new I/O
+ * to this disk.
+ */
+void blk_mark_disk_dead(struct gendisk *disk)
+{
+       set_bit(GD_DEAD, &disk->state);
+       blk_queue_start_drain(disk->queue);
+}
+EXPORT_SYMBOL_GPL(blk_mark_disk_dead);
+
+/**
  * del_gendisk - remove the gendisk
  * @disk: the struct gendisk to remove
  *
@@ -1082,6 +1103,8 @@ static void disk_release(struct device *dev)
        might_sleep();
        WARN_ON_ONCE(disk_live(disk));
 
+       blk_mq_cancel_work_sync(disk->queue);
+
        disk_release_events(disk);
        kfree(disk->random);
        xa_destroy(&disk->part_tbl);