From 830cf3f774c5cb70f9c4fd735f5cbe272014269c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Dec 2023 20:21:11 +0800 Subject: [PATCH 1/3] md: factor out a mddev_alloc_unit helper from mddev_find mainline inclusion from mainline-v5.13-rc1 commit 85c8c3c1f8d9e31f626c93435dd91c2f85603e07 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8O6NL CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=85c8c3c1f8d9e31f626c93435dd91c2f85603e07 ------------------------------------------------- Split out a self contained helper to find a free minor for the md "unit" number. Signed-off-by: Christoph Hellwig Signed-off-by: Song Liu Signed-off-by: Li Lingfeng (cherry picked from commit 38f910c8446514d95387961777417b54ad3a57e2) --- drivers/md/md.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 3b6fe3c9ad11..95fd3af34031 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -723,6 +723,27 @@ static struct mddev *mddev_find_locked(dev_t unit) return NULL; } +/* find an unused unit number */ +static dev_t mddev_alloc_unit(void) +{ + static int next_minor = 512; + int start = next_minor; + bool is_free = 0; + dev_t dev = 0; + + while (!is_free) { + dev = MKDEV(MD_MAJOR, next_minor); + next_minor++; + if (next_minor > MINORMASK) + next_minor = 0; + if (next_minor == start) + return 0; /* Oh dear, all in use. */ + is_free = !mddev_find_locked(dev); + } + + return dev; +} + static struct mddev *mddev_find(dev_t unit) { struct mddev *mddev; @@ -765,27 +786,13 @@ static struct mddev *mddev_find_or_alloc(dev_t unit) return new; } } else if (new) { - /* find an unused unit number */ - static int next_minor = 512; - int start = next_minor; - int is_free = 0; - int dev = 0; - while (!is_free) { - dev = MKDEV(MD_MAJOR, next_minor); - next_minor++; - if (next_minor > MINORMASK) - next_minor = 0; - if (next_minor == start) { - /* Oh dear, all in use. */ - spin_unlock(&all_mddevs_lock); - kfree(new); - return NULL; - } - - is_free = !mddev_find_locked(dev); + new->unit = mddev_alloc_unit(); + if (!new->unit) { + spin_unlock(&all_mddevs_lock); + kfree(new); + return NULL; } - new->unit = dev; - new->md_minor = MINOR(dev); + new->md_minor = MINOR(new->unit); new->hold_active = UNTIL_STOP; list_add(&new->all_mddevs, &all_mddevs); spin_unlock(&all_mddevs_lock); -- Gitee From 64b2cb66cde43fb0ef9d91ffd2daf5290598e267 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Dec 2023 20:21:12 +0800 Subject: [PATCH 2/3] md: refactor mddev_find_or_alloc mainline inclusion from mainline-v5.13-rc1 commit d144fe6ff176d79efd411e520103a99e11874c36 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8O6NL CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d144fe6ff176d79efd411e520103a99e11874c36 ------------------------------------------------- Allocate the new mddev first speculatively, which greatly simplifies the code flow. Signed-off-by: Christoph Hellwig Signed-off-by: Song Liu Signed-off-by: Li Lingfeng (cherry picked from commit 6c6292c22ff845ebcbf8b81647a55fff4ff4052d) --- drivers/md/md.c | 60 ++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 95fd3af34031..7e399a5d06b5 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -762,57 +762,45 @@ static struct mddev *mddev_find(dev_t unit) static struct mddev *mddev_find_or_alloc(dev_t unit) { - struct mddev *mddev, *new = NULL; + struct mddev *mddev = NULL, *new; if (unit && MAJOR(unit) != MD_MAJOR) - unit &= ~((1<all_mddevs, &all_mddevs); - spin_unlock(&all_mddevs_lock); - new->hold_active = UNTIL_IOCTL; - return new; - } - } else if (new) { + new->unit = unit; + if (MAJOR(unit) == MD_MAJOR) + new->md_minor = MINOR(unit); + else + new->md_minor = MINOR(unit) >> MdpMinorShift; + new->hold_active = UNTIL_IOCTL; + } else { new->unit = mddev_alloc_unit(); - if (!new->unit) { - spin_unlock(&all_mddevs_lock); - kfree(new); - return NULL; - } + if (!new->unit) + goto out_free_new; new->md_minor = MINOR(new->unit); new->hold_active = UNTIL_STOP; - list_add(&new->all_mddevs, &all_mddevs); - spin_unlock(&all_mddevs_lock); - return new; } - spin_unlock(&all_mddevs_lock); - - new = kzalloc(sizeof(*new), GFP_KERNEL); - if (!new) - return NULL; - new->unit = unit; - if (MAJOR(unit) == MD_MAJOR) - new->md_minor = MINOR(unit); - else - new->md_minor = MINOR(unit) >> MdpMinorShift; - - mddev_init(new); - - goto retry; + list_add(&new->all_mddevs, &all_mddevs); + spin_unlock(&all_mddevs_lock); + return new; +out_free_new: + spin_unlock(&all_mddevs_lock); + kfree(new); + return mddev; } static struct attribute_group md_redundancy_group; -- Gitee From d1c09ab0353ec11145fe5ac5a134ab0012e80662 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 13 Dec 2023 20:21:13 +0800 Subject: [PATCH 3/3] md: do not return existing mddevs from mddev_find_or_alloc mainline inclusion from mainline-v5.13-rc1 commit 0d809b3837a0bede8f58a67e303e339585777bf4 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8O6NL CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0d809b3837a0bede8f58a67e303e339585777bf4 ------------------------------------------------- Instead of returning an existing mddev, just for it to be discarded later directly return -EEXIST. Rename the function to mddev_alloc now that it doesn't find an existing mddev. Signed-off-by: Christoph Hellwig Signed-off-by: Song Liu Conflicts: Commit 4ad5f208c38f ("md: Flush workqueue md_rdev_misc_wq in md_alloc()") add flushing md_rdev_misc_wq in md_alloc(). Signed-off-by: Li Lingfeng (cherry picked from commit 10b2c6ae5fad3f7c2c2de4e59dfc56944cdde0a8) --- drivers/md/md.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 7e399a5d06b5..763e554f44c8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -760,26 +760,24 @@ static struct mddev *mddev_find(dev_t unit) return mddev; } -static struct mddev *mddev_find_or_alloc(dev_t unit) +static struct mddev *mddev_alloc(dev_t unit) { - struct mddev *mddev = NULL, *new; + struct mddev *new; + int error; if (unit && MAJOR(unit) != MD_MAJOR) unit &= ~((1 << MdpMinorShift) - 1); new = kzalloc(sizeof(*new), GFP_KERNEL); if (!new) - return NULL; + return ERR_PTR(-ENOMEM); mddev_init(new); spin_lock(&all_mddevs_lock); if (unit) { - mddev = mddev_find_locked(unit); - if (mddev) { - mddev_get(mddev); + error = -EEXIST; + if (mddev_find_locked(unit)) goto out_free_new; - } - new->unit = unit; if (MAJOR(unit) == MD_MAJOR) new->md_minor = MINOR(unit); @@ -787,6 +785,7 @@ static struct mddev *mddev_find_or_alloc(dev_t unit) new->md_minor = MINOR(unit) >> MdpMinorShift; new->hold_active = UNTIL_IOCTL; } else { + error = -ENODEV; new->unit = mddev_alloc_unit(); if (!new->unit) goto out_free_new; @@ -800,7 +799,7 @@ static struct mddev *mddev_find_or_alloc(dev_t unit) out_free_new: spin_unlock(&all_mddevs_lock); kfree(new); - return mddev; + return ERR_PTR(error); } static struct attribute_group md_redundancy_group; @@ -5722,30 +5721,30 @@ static int md_alloc(dev_t dev, char *name) * writing to /sys/module/md_mod/parameters/new_array. */ static DEFINE_MUTEX(disks_mutex); - struct mddev *mddev = mddev_find_or_alloc(dev); + struct mddev *mddev; struct gendisk *disk; int partitioned; int shift; int unit; - int error; - - if (!mddev) - return -ENODEV; + int error ; - partitioned = (MAJOR(mddev->unit) != MD_MAJOR); - shift = partitioned ? MdpMinorShift : 0; - unit = MINOR(mddev->unit) >> shift; - - /* wait for any previous instance of this device to be - * completely removed (mddev_delayed_delete). + /* + * Wait for any previous instance of this device to be completely + * removed (mddev_delayed_delete). */ flush_workqueue(md_misc_wq); flush_workqueue(md_rdev_misc_wq); mutex_lock(&disks_mutex); - error = -EEXIST; - if (mddev->gendisk) - goto abort; + mddev = mddev_alloc(dev); + if (IS_ERR(mddev)) { + mutex_unlock(&disks_mutex); + return PTR_ERR(mddev); + } + + partitioned = (MAJOR(mddev->unit) != MD_MAJOR); + shift = partitioned ? MdpMinorShift : 0; + unit = MINOR(mddev->unit) >> shift; if (name && !dev) { /* Need to ensure that 'name' is not a duplicate. @@ -5757,6 +5756,7 @@ static int md_alloc(dev_t dev, char *name) if (mddev2->gendisk && strcmp(mddev2->gendisk->disk_name, name) == 0) { spin_unlock(&all_mddevs_lock); + error = -EEXIST; goto abort; } spin_unlock(&all_mddevs_lock); -- Gitee