Commit 5815341f authored by Li Nan's avatar Li Nan Committed by Jialin Zhang
Browse files

md: fix sysfs duplicate file while adding rdev

hulk inclusion
category: bugfix
bugzilla: 188553, https://gitee.com/openeuler/kernel/issues/I6TNFX


CVE: NA

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

rdev->del_work has not been queued to md_rdev_misc_wq and flush_workqueue
will not flush it if tow threads add and remove same device. sysfs might
WARN duplicate filename as below.

    //T1	             //T2
    mdadm write super
			     add success
			     remove
			      unbind_rdev_from_array

    md_ioctl
     flush_workqueue
			      INIT_WORK
                               queue_work
     md_add_new_disk
      duplicate filename dev-xxx

Check if there is any kobj with the same name, and return busy if true.

Fixes: 5792a285 ("md: avoid a deadlock when removing a device from an md array via sysfs")
Signed-off-by: default avatarLi Nan <linan122@huawei.com>
Reviewed-by: default avatarHou Tao <houtao1@huawei.com>
parent ff461e2d
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -2402,8 +2402,9 @@ EXPORT_SYMBOL(md_integrity_add_rdev);

static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
{
	char b[BDEVNAME_SIZE];
	char b[BDEVNAME_SIZE + 4];
	struct kobject *ko;
	struct kernfs_node *sysfs_rdev;
	int err;

	/* prevent duplicates */
@@ -2454,7 +2455,8 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
			mdname(mddev), mddev->max_disks);
		return -EBUSY;
	}
	bdevname(rdev->bdev,b);
	memcpy(b, "dev-", 4);
	bdevname(rdev->bdev, b + 4);
	strreplace(b, '/', '!');

	rdev->mddev = mddev;
@@ -2463,7 +2465,15 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
	if (mddev->raid_disks)
		mddev_create_serial_pool(mddev, rdev, false);

	if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
	sysfs_rdev = sysfs_get_dirent_safe(mddev->kobj.sd, b);
	if (sysfs_rdev) {
		sysfs_put(sysfs_rdev);
		err = -EBUSY;
		goto fail;
	}

	err = kobject_add(&rdev->kobj, &mddev->kobj, b);
	if (err)
		goto fail;

	ko = &part_to_dev(rdev->bdev->bd_part)->kobj;
@@ -2484,7 +2494,7 @@ static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
	return 0;

 fail:
	pr_warn("md: failed to register dev-%s for %s\n",
	pr_warn("md: failed to register %s for %s\n",
		b, mdname(mddev));
	return err;
}