md: tidy up error paths in md_alloc
As the recent bug in md_alloc showed, having a single exit path for unlocking and putting is a good idea. So restructure md_alloc to have a single mutex_unlock and mddev_put, and use gotos where necessary. Found-by: Jiri Slaby <jirislaby@gmail.com> Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
parent
1ec22eb2b4
commit
0909dc448c
|
@ -3846,11 +3846,9 @@ static int md_alloc(dev_t dev, char *name)
|
|||
flush_scheduled_work();
|
||||
|
||||
mutex_lock(&disks_mutex);
|
||||
if (mddev->gendisk) {
|
||||
mutex_unlock(&disks_mutex);
|
||||
mddev_put(mddev);
|
||||
return -EEXIST;
|
||||
}
|
||||
error = -EEXIST;
|
||||
if (mddev->gendisk)
|
||||
goto abort;
|
||||
|
||||
if (name) {
|
||||
/* Need to ensure that 'name' is not a duplicate.
|
||||
|
@ -3862,19 +3860,15 @@ static int md_alloc(dev_t dev, char *name)
|
|||
if (mddev2->gendisk &&
|
||||
strcmp(mddev2->gendisk->disk_name, name) == 0) {
|
||||
spin_unlock(&all_mddevs_lock);
|
||||
mutex_unlock(&disks_mutex);
|
||||
mddev_put(mddev);
|
||||
return -EEXIST;
|
||||
goto abort;
|
||||
}
|
||||
spin_unlock(&all_mddevs_lock);
|
||||
}
|
||||
|
||||
error = -ENOMEM;
|
||||
mddev->queue = blk_alloc_queue(GFP_KERNEL);
|
||||
if (!mddev->queue) {
|
||||
mutex_unlock(&disks_mutex);
|
||||
mddev_put(mddev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!mddev->queue)
|
||||
goto abort;
|
||||
mddev->queue->queuedata = mddev;
|
||||
|
||||
/* Can be unlocked because the queue is new: no concurrency */
|
||||
|
@ -3884,11 +3878,9 @@ static int md_alloc(dev_t dev, char *name)
|
|||
|
||||
disk = alloc_disk(1 << shift);
|
||||
if (!disk) {
|
||||
mutex_unlock(&disks_mutex);
|
||||
blk_cleanup_queue(mddev->queue);
|
||||
mddev->queue = NULL;
|
||||
mddev_put(mddev);
|
||||
return -ENOMEM;
|
||||
goto abort;
|
||||
}
|
||||
disk->major = MAJOR(mddev->unit);
|
||||
disk->first_minor = unit << shift;
|
||||
|
@ -3910,16 +3902,22 @@ static int md_alloc(dev_t dev, char *name)
|
|||
mddev->gendisk = disk;
|
||||
error = kobject_init_and_add(&mddev->kobj, &md_ktype,
|
||||
&disk_to_dev(disk)->kobj, "%s", "md");
|
||||
mutex_unlock(&disks_mutex);
|
||||
if (error)
|
||||
if (error) {
|
||||
/* This isn't possible, but as kobject_init_and_add is marked
|
||||
* __must_check, we must do something with the result
|
||||
*/
|
||||
printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
|
||||
disk->disk_name);
|
||||
else {
|
||||
error = 0;
|
||||
}
|
||||
abort:
|
||||
mutex_unlock(&disks_mutex);
|
||||
if (!error) {
|
||||
kobject_uevent(&mddev->kobj, KOBJ_ADD);
|
||||
mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
|
||||
}
|
||||
mddev_put(mddev);
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct kobject *md_probe(dev_t dev, int *part, void *data)
|
||||
|
|
Loading…
Reference in New Issue