md: fix error handling in md_alloc
Error handling in md_alloc is a mess. Untangle it to just free the mddev directly before add_disk is called and thus the gendisk is globally visible. After that clear the hold flag and let the mddev_put take care of cleaning up the mddev through the usual mechanisms. Fixes: 5e55e2f5fc95 ("[PATCH] md: convert compile time warnings into runtime warnings") Fixes: 9be68dd7ac0e ("md: add error handling support for add_disk()") Fixes: 7ad1069166c0 ("md: properly unwind when failing to add the kobject in md_alloc") Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Logan Gunthorpe <logang@deltatee.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Song Liu <song@kernel.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
ca39f75024
commit
c57094a6e1
@ -790,6 +790,15 @@ out_free_new:
|
|||||||
return ERR_PTR(error);
|
return ERR_PTR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mddev_free(struct mddev *mddev)
|
||||||
|
{
|
||||||
|
spin_lock(&all_mddevs_lock);
|
||||||
|
list_del(&mddev->all_mddevs);
|
||||||
|
spin_unlock(&all_mddevs_lock);
|
||||||
|
|
||||||
|
kfree(mddev);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct attribute_group md_redundancy_group;
|
static const struct attribute_group md_redundancy_group;
|
||||||
|
|
||||||
void mddev_unlock(struct mddev *mddev)
|
void mddev_unlock(struct mddev *mddev)
|
||||||
@ -5661,8 +5670,8 @@ int md_alloc(dev_t dev, char *name)
|
|||||||
mutex_lock(&disks_mutex);
|
mutex_lock(&disks_mutex);
|
||||||
mddev = mddev_alloc(dev);
|
mddev = mddev_alloc(dev);
|
||||||
if (IS_ERR(mddev)) {
|
if (IS_ERR(mddev)) {
|
||||||
mutex_unlock(&disks_mutex);
|
error = PTR_ERR(mddev);
|
||||||
return PTR_ERR(mddev);
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
|
partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
|
||||||
@ -5680,7 +5689,7 @@ int md_alloc(dev_t dev, char *name)
|
|||||||
strcmp(mddev2->gendisk->disk_name, name) == 0) {
|
strcmp(mddev2->gendisk->disk_name, name) == 0) {
|
||||||
spin_unlock(&all_mddevs_lock);
|
spin_unlock(&all_mddevs_lock);
|
||||||
error = -EEXIST;
|
error = -EEXIST;
|
||||||
goto out_unlock_disks_mutex;
|
goto out_free_mddev;
|
||||||
}
|
}
|
||||||
spin_unlock(&all_mddevs_lock);
|
spin_unlock(&all_mddevs_lock);
|
||||||
}
|
}
|
||||||
@ -5693,7 +5702,7 @@ int md_alloc(dev_t dev, char *name)
|
|||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
disk = blk_alloc_disk(NUMA_NO_NODE);
|
disk = blk_alloc_disk(NUMA_NO_NODE);
|
||||||
if (!disk)
|
if (!disk)
|
||||||
goto out_unlock_disks_mutex;
|
goto out_free_mddev;
|
||||||
|
|
||||||
disk->major = MAJOR(mddev->unit);
|
disk->major = MAJOR(mddev->unit);
|
||||||
disk->first_minor = unit << shift;
|
disk->first_minor = unit << shift;
|
||||||
@ -5714,26 +5723,36 @@ int md_alloc(dev_t dev, char *name)
|
|||||||
mddev->gendisk = disk;
|
mddev->gendisk = disk;
|
||||||
error = add_disk(disk);
|
error = add_disk(disk);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_cleanup_disk;
|
goto out_put_disk;
|
||||||
|
|
||||||
kobject_init(&mddev->kobj, &md_ktype);
|
kobject_init(&mddev->kobj, &md_ktype);
|
||||||
error = kobject_add(&mddev->kobj, &disk_to_dev(disk)->kobj, "%s", "md");
|
error = kobject_add(&mddev->kobj, &disk_to_dev(disk)->kobj, "%s", "md");
|
||||||
if (error)
|
if (error) {
|
||||||
goto out_del_gendisk;
|
/*
|
||||||
|
* The disk is already live at this point. Clear the hold flag
|
||||||
|
* and let mddev_put take care of the deletion, as it isn't any
|
||||||
|
* different from a normal close on last release now.
|
||||||
|
*/
|
||||||
|
mddev->hold_active = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
kobject_uevent(&mddev->kobj, KOBJ_ADD);
|
kobject_uevent(&mddev->kobj, KOBJ_ADD);
|
||||||
mddev->sysfs_state = sysfs_get_dirent_safe(mddev->kobj.sd, "array_state");
|
mddev->sysfs_state = sysfs_get_dirent_safe(mddev->kobj.sd, "array_state");
|
||||||
mddev->sysfs_level = sysfs_get_dirent_safe(mddev->kobj.sd, "level");
|
mddev->sysfs_level = sysfs_get_dirent_safe(mddev->kobj.sd, "level");
|
||||||
goto out_unlock_disks_mutex;
|
|
||||||
|
|
||||||
out_del_gendisk:
|
done:
|
||||||
del_gendisk(disk);
|
|
||||||
out_cleanup_disk:
|
|
||||||
put_disk(disk);
|
|
||||||
out_unlock_disks_mutex:
|
|
||||||
mutex_unlock(&disks_mutex);
|
mutex_unlock(&disks_mutex);
|
||||||
mddev_put(mddev);
|
mddev_put(mddev);
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
out_put_disk:
|
||||||
|
put_disk(disk);
|
||||||
|
out_free_mddev:
|
||||||
|
mddev_free(mddev);
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&disks_mutex);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void md_probe(dev_t dev)
|
static void md_probe(dev_t dev)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user