diff --git a/block/genhd.c b/block/genhd.c
index 796baf761202..d71821c6ad6a 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -692,69 +692,6 @@ static void disk_scan_partitions(struct gendisk *disk)
 		blkdev_put(bdev, FMODE_READ);
 }
 
-static void register_disk(struct device *parent, struct gendisk *disk,
-			  const struct attribute_group **groups)
-{
-	struct device *ddev = disk_to_dev(disk);
-	struct disk_part_iter piter;
-	struct hd_struct *part;
-	int err;
-
-	ddev->parent = parent;
-
-	dev_set_name(ddev, "%s", disk->disk_name);
-
-	/* delay uevents, until we scanned partition table */
-	dev_set_uevent_suppress(ddev, 1);
-
-	if (groups) {
-		WARN_ON(ddev->groups);
-		ddev->groups = groups;
-	}
-	if (device_add(ddev))
-		return;
-	if (!sysfs_deprecated) {
-		err = sysfs_create_link(block_depr, &ddev->kobj,
-					kobject_name(&ddev->kobj));
-		if (err) {
-			device_del(ddev);
-			return;
-		}
-	}
-
-	/*
-	 * avoid probable deadlock caused by allocating memory with
-	 * GFP_KERNEL in runtime_resume callback of its all ancestor
-	 * devices
-	 */
-	pm_runtime_set_memalloc_noio(ddev, true);
-
-	disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
-	disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
-
-	if (disk->flags & GENHD_FL_HIDDEN)
-		return;
-
-	disk_scan_partitions(disk);
-
-	/* announce disk after possible partitions are created */
-	dev_set_uevent_suppress(ddev, 0);
-	kobject_uevent(&ddev->kobj, KOBJ_ADD);
-
-	/* announce possible partitions */
-	disk_part_iter_init(&piter, disk, 0);
-	while ((part = disk_part_iter_next(&piter)))
-		kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
-	disk_part_iter_exit(&piter);
-
-	if (disk->queue->backing_dev_info->dev) {
-		err = sysfs_create_link(&ddev->kobj,
-			  &disk->queue->backing_dev_info->dev->kobj,
-			  "bdi");
-		WARN_ON(err);
-	}
-}
-
 /**
  * __device_add_disk - add disk information to kernel list
  * @parent: parent device for the disk
@@ -764,13 +701,14 @@ static void register_disk(struct device *parent, struct gendisk *disk,
  *
  * This function registers the partitioning information in @disk
  * with the kernel.
- *
- * FIXME: error handling
  */
-static void __device_add_disk(struct device *parent, struct gendisk *disk,
-			      const struct attribute_group **groups,
-			      bool register_queue)
+static int __device_add_disk(struct device *parent, struct gendisk *disk,
+			     const struct attribute_group **groups,
+			     bool register_queue)
 {
+	struct device *ddev = disk_to_dev(disk);
+	struct disk_part_iter piter;
+	struct hd_struct *part;
 	dev_t devt;
 	int retval;
 
@@ -794,15 +732,12 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
 	disk->flags |= GENHD_FL_UP;
 
 	retval = blk_alloc_devt(&disk->part0, &devt);
-	if (retval) {
-		WARN_ON(1);
-		return;
-	}
+	if (retval)
+		return retval;
+
 	disk->major = MAJOR(devt);
 	disk->first_minor = MINOR(devt);
-
 	disk_alloc_events(disk);
-
 	if (disk->flags & GENHD_FL_HIDDEN) {
 		/*
 		 * Don't let hidden disks show up in /proc/partitions,
@@ -813,17 +748,71 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
 	} else {
 		struct backing_dev_info *bdi = disk->queue->backing_dev_info;
 		struct device *dev = disk_to_dev(disk);
-		int ret;
 
 		/* Register BDI before referencing it from bdev */
 		dev->devt = devt;
-		ret = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt));
-		WARN_ON(ret);
+		retval = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt));
+		if (retval)
+			goto out_free_devt;
 		bdi_set_owner(bdi, dev);
 		blk_register_region(disk_devt(disk), disk->minors, NULL,
 				    exact_match, exact_lock, disk);
 	}
-	register_disk(parent, disk, groups);
+
+	ddev->parent = parent;
+	dev_set_name(ddev, "%s", disk->disk_name);
+
+	/* delay uevents, until we scanned partition table */
+	dev_set_uevent_suppress(ddev, 1);
+
+	if (groups) {
+		WARN_ON(ddev->groups);
+		ddev->groups = groups;
+	}
+
+	retval = device_add(ddev);
+	if (retval)
+		goto out_unregister_bdi;
+
+	if (!sysfs_deprecated) {
+		retval = sysfs_create_link(block_depr, &ddev->kobj,
+					   kobject_name(&ddev->kobj));
+		if (retval)
+			goto out_device_del;
+	}
+
+	/*
+	 * avoid probable deadlock caused by allocating memory with
+	 * GFP_KERNEL in runtime_resume callback of its all ancestor
+	 * devices
+	 */
+	pm_runtime_set_memalloc_noio(ddev, true);
+
+	disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
+	disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
+
+	if (!(disk->flags & GENHD_FL_HIDDEN)) {
+
+		disk_scan_partitions(disk);
+
+		/* announce disk after possible partitions are created */
+		dev_set_uevent_suppress(ddev, 0);
+		kobject_uevent(&ddev->kobj, KOBJ_ADD);
+
+		/* announce possible partitions */
+		disk_part_iter_init(&piter, disk, 0);
+		while ((part = disk_part_iter_next(&piter)))
+			kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
+		disk_part_iter_exit(&piter);
+
+		if (disk->queue->backing_dev_info->dev) {
+			retval = sysfs_create_link(&ddev->kobj,
+					&disk->queue->backing_dev_info->dev->kobj, "bdi");
+			if (retval)
+				goto out_put_slave_dir;
+		}
+	}
+
 	if (register_queue)
 		blk_register_queue(disk);
 
@@ -832,16 +821,28 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
 	 * so that it sticks around as long as @disk is there.
 	 */
 	WARN_ON_ONCE(!blk_get_queue(disk->queue));
-
 	disk_add_events(disk);
 	blk_integrity_add(disk);
+	return 0;
+
+out_device_del:
+	device_del(ddev);
+out_put_slave_dir:
+	kobject_put(disk->slave_dir);
+	kobject_put(disk->part0.holder_dir);
+out_unregister_bdi:
+	if (!(disk->flags & GENHD_FL_HIDDEN))
+		bdi_unregister(disk->queue->backing_dev_info);
+out_free_devt:
+	blk_free_devt(devt);
+
+	return retval;
 }
 
-void device_add_disk(struct device *parent, struct gendisk *disk,
+int device_add_disk(struct device *parent, struct gendisk *disk,
 		     const struct attribute_group **groups)
-
 {
-	__device_add_disk(parent, disk, groups, true);
+	return __device_add_disk(parent, disk, groups, true);
 }
 EXPORT_SYMBOL(device_add_disk);
 
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index e4517d483bdc..2b648bcc3b72 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -2163,7 +2163,11 @@ static int loop_add(struct loop_device **l, int i)
 	disk->private_data	= lo;
 	disk->queue		= lo->lo_queue;
 	sprintf(disk->disk_name, "loop%d", i);
-	add_disk(disk);
+
+	/* Make this loop device reachable from pathname. */
+	err = add_disk(disk);
+	if (err)
+		goto out_free_queue;
 	*l = lo;
 	return lo->lo_number;
 
@@ -2176,6 +2180,7 @@ static int loop_add(struct loop_device **l, int i)
 out_free_dev:
 	kfree(lo);
 out:
+	*l = NULL;
 	return err;
 }
 
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 03da3f603d30..3bcce4864337 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -288,11 +288,11 @@ extern void disk_part_iter_exit(struct disk_part_iter *piter);
 extern bool disk_has_partitions(struct gendisk *disk);
 
 /* block/genhd.c */
-extern void device_add_disk(struct device *parent, struct gendisk *disk,
-			    const struct attribute_group **groups);
-static inline void add_disk(struct gendisk *disk)
+int device_add_disk(struct device *parent, struct gendisk *disk,
+		const struct attribute_group **groups);
+static inline int add_disk(struct gendisk *disk)
 {
-	device_add_disk(NULL, disk, NULL);
+	return device_add_disk(NULL, disk, NULL);
 }
 extern void device_add_disk_no_queue_reg(struct device *parent, struct gendisk *disk);
 static inline void add_disk_no_queue_reg(struct gendisk *disk)