From: Li Nan linan122@huawei.com
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: 5792a2856a63 ("md: avoid a deadlock when removing a device from an md array via sysfs") Signed-off-by: Li Nan linan122@huawei.com Reviewed-by: Hou Tao houtao1@huawei.com --- drivers/md/md.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c index 8fec8e845424..735fbfaa293d 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2400,8 +2400,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 */ @@ -2452,7 +2453,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; @@ -2461,7 +2463,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; @@ -2482,7 +2492,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; }