diff options
| author | Jens Axboe <axboe@kernel.dk> | 2021-04-15 12:15:48 -0600 |
|---|---|---|
| committer | Jens Axboe <axboe@kernel.dk> | 2021-04-15 12:15:48 -0600 |
| commit | 455abda6c972eddf3457ec098a64cce39b1c2652 (patch) | |
| tree | b62c1f4f4224822c4b58188359903a9b08977dad | |
| parent | e63c8eb132d5b41cb62eaa1176f13a8b1cb43a9e (diff) | |
| parent | 404a8ef512587b2460107d3272c17a89aef75edf (diff) | |
Merge branch 'md-next' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md into for-5.13/drivers
Pull MD updates from Song:
"1. mddev_find_or_alloc() clean up, from Christoph.
2. Fix NULL pointer deref with external bitmap, from Sudhakar."
* 'md-next' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md:
md/bitmap: wait for external bitmap writes to complete during tear down
md: do not return existing mddevs from mddev_find_or_alloc
md: refactor mddev_find_or_alloc
md: factor out a mddev_alloc_unit helper from mddev_find
| -rw-r--r-- | drivers/md/md-bitmap.c | 2 | ||||
| -rw-r--r-- | drivers/md/md.c | 139 |
2 files changed, 69 insertions, 72 deletions
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 200c5d0f08bf..ea3130e11680 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -1722,6 +1722,8 @@ void md_bitmap_flush(struct mddev *mddev) md_bitmap_daemon_work(mddev); bitmap->daemon_lastrun -= sleep; md_bitmap_daemon_work(mddev); + if (mddev->bitmap_info.external) + md_super_wait(mddev); md_bitmap_update_sb(bitmap); } diff --git a/drivers/md/md.c b/drivers/md/md.c index 3ce5f4e0f431..af9bdb907b2b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -745,6 +745,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; @@ -761,73 +782,46 @@ 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, *new = NULL; + struct mddev *new; + int error; if (unit && MAJOR(unit) != MD_MAJOR) - unit &= ~((1<<MdpMinorShift)-1); + unit &= ~((1 << MdpMinorShift) - 1); - retry: - spin_lock(&all_mddevs_lock); + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return ERR_PTR(-ENOMEM); + mddev_init(new); + spin_lock(&all_mddevs_lock); if (unit) { - mddev = mddev_find_locked(unit); - if (mddev) { - mddev_get(mddev); - spin_unlock(&all_mddevs_lock); - kfree(new); - return mddev; - } - - if (new) { - list_add(&new->all_mddevs, &all_mddevs); - spin_unlock(&all_mddevs_lock); - new->hold_active = UNTIL_IOCTL; - 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 = dev; - new->md_minor = MINOR(dev); + error = -EEXIST; + if (mddev_find_locked(unit)) + goto out_free_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 { + error = -ENODEV; + new->unit = mddev_alloc_unit(); + 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 ERR_PTR(error); } static struct attribute_group md_redundancy_group; @@ -5666,29 +5660,29 @@ 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; + int error ; - if (!mddev) - return -ENODEV; - - 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); 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. @@ -5700,6 +5694,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); |
