Commit 73acaff5 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by openeuler-sync-bot
Browse files

md: fix error handling in md_alloc

mainline inclusion
from mainline-v6.0-rc1
commit c57094a6
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I81XCK

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c57094a6e1ed5dd2d6401f79b8e6da34dd28f959



--------------------------------

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: 5e55e2f5 ("[PATCH] md: convert compile time warnings into runtime warnings")
Fixes: 9be68dd7 ("md: add error handling support for add_disk()")
Fixes: 7ad10691 ("md: properly unwind when failing to add the kobject in md_alloc")
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarLogan Gunthorpe <logang@deltatee.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarSong Liu <song@kernel.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>

Conflict:
	drivers/md/md.c
	Commit 8b9ab626 ("block: remove blk_cleanup_disk") change
	blk_cleanup_disk() to put_disk(). Keep using blk_cleanup_disk()
	here. And add_disk_safe().

Signed-off-by: default avatarLi Nan <linan122@huawei.com>
(cherry picked from commit 6d01bb59)
parent 024dc8ec
Loading
Loading
Loading
Loading
+32 −13
Original line number Diff line number Diff line
@@ -800,6 +800,15 @@ static struct mddev *mddev_alloc(dev_t unit)
	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;

void mddev_unlock(struct mddev *mddev)
@@ -5736,8 +5745,8 @@ static int md_alloc(dev_t dev, char *name)
	mutex_lock(&disks_mutex);
	mddev = mddev_alloc(dev);
	if (IS_ERR(mddev)) {
		mutex_unlock(&disks_mutex);
		return PTR_ERR(mddev);
		error = PTR_ERR(mddev);
		goto out_unlock;
	}

	partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
@@ -5755,7 +5764,7 @@ static int md_alloc(dev_t dev, char *name)
			    strcmp(mddev2->gendisk->disk_name, name) == 0) {
				spin_unlock(&all_mddevs_lock);
				error = -EEXIST;
				goto out_unlock_disks_mutex;
				goto out_free_mddev;
			}
		spin_unlock(&all_mddevs_lock);
	}
@@ -5768,7 +5777,7 @@ static int md_alloc(dev_t dev, char *name)
	error = -ENOMEM;
	disk = blk_alloc_disk(NUMA_NO_NODE);
	if (!disk)
		goto out_unlock_disks_mutex;
		goto out_free_mddev;

	disk->major = MAJOR(mddev->unit);
	disk->first_minor = unit << shift;
@@ -5794,26 +5803,36 @@ static int md_alloc(dev_t dev, char *name)
	mddev->gendisk = disk;
	error = add_disk_safe(disk);
	if (error)
		goto out_cleanup_disk;
		goto out_put_disk;

	kobject_init(&mddev->kobj, &md_ktype);
	error = kobject_add(&mddev->kobj, &disk_to_dev(disk)->kobj, "%s", "md");
	if (error)
		goto out_del_gendisk;
	if (error) {
		/*
		 * 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);
	mddev->sysfs_state = sysfs_get_dirent_safe(mddev->kobj.sd, "array_state");
	mddev->sysfs_level = sysfs_get_dirent_safe(mddev->kobj.sd, "level");
	goto out_unlock_disks_mutex;

out_del_gendisk:
	del_gendisk(disk);
out_cleanup_disk:
	blk_cleanup_disk(disk);
out_unlock_disks_mutex:
done:
	mutex_unlock(&disks_mutex);
	mddev_put(mddev);
	return error;

out_put_disk:
	blk_cleanup_disk(disk);
out_free_mddev:
	mddev_free(mddev);
out_unlock:
	mutex_unlock(&disks_mutex);
	return error;
}

static struct kobject *md_probe(dev_t dev, int *part, void *data)