md: initialize 'active_io' while allocating mddev
authorYu Kuai <yukuai3@huawei.com>
Fri, 25 Aug 2023 03:09:50 +0000 (11:09 +0800)
committerSong Liu <song@kernel.org>
Fri, 22 Sep 2023 17:28:26 +0000 (10:28 -0700)
'active_io' is used for mddev_suspend() and it's initialized in
md_run(), this restrict that 'reconfig_mutex' must be held and
"mddev->pers" must be set before calling mddev_suspend().

Initialize 'active_io' early so that mddev_suspend() is safe to call
once mddev is allocated, this will be helpful to refactor
mddev_suspend() in following patches.

Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230825030956.1527023-2-yukuai1@huaweicloud.com
drivers/md/dm-raid.c
drivers/md/md.c
drivers/md/md.h

index 5f9991765f270a15da5983555251926aa45fab5c..69805d37e1136da7581f741e73336368b1ef3fcf 100644 (file)
@@ -749,7 +749,11 @@ static struct raid_set *raid_set_alloc(struct dm_target *ti, struct raid_type *r
                return ERR_PTR(-ENOMEM);
        }
 
-       mddev_init(&rs->md);
+       if (mddev_init(&rs->md)) {
+               kfree(rs);
+               ti->error = "Cannot initialize raid context";
+               return ERR_PTR(-ENOMEM);
+       }
 
        rs->raid_disks = raid_devs;
        rs->delta_disks = 0;
@@ -798,6 +802,7 @@ static void raid_set_free(struct raid_set *rs)
                        dm_put_device(rs->ti, rs->dev[i].data_dev);
        }
 
+       mddev_destroy(&rs->md);
        kfree(rs);
 }
 
index 94abc6b7edbd3938bc6c52458520053d2352ba00..0f642785073f62ebc0d8dc96f8de45e0efeabaca 100644 (file)
@@ -639,8 +639,20 @@ void mddev_put(struct mddev *mddev)
 static void md_safemode_timeout(struct timer_list *t);
 static void md_start_sync(struct work_struct *ws);
 
-void mddev_init(struct mddev *mddev)
+static void active_io_release(struct percpu_ref *ref)
 {
+       struct mddev *mddev = container_of(ref, struct mddev, active_io);
+
+       wake_up(&mddev->sb_wait);
+}
+
+int mddev_init(struct mddev *mddev)
+{
+
+       if (percpu_ref_init(&mddev->active_io, active_io_release,
+                           PERCPU_REF_ALLOW_REINIT, GFP_KERNEL))
+               return -ENOMEM;
+
        mutex_init(&mddev->open_mutex);
        mutex_init(&mddev->reconfig_mutex);
        mutex_init(&mddev->sync_mutex);
@@ -665,9 +677,17 @@ void mddev_init(struct mddev *mddev)
 
        INIT_WORK(&mddev->sync_work, md_start_sync);
        INIT_WORK(&mddev->del_work, mddev_delayed_delete);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(mddev_init);
 
+void mddev_destroy(struct mddev *mddev)
+{
+       percpu_ref_exit(&mddev->active_io);
+}
+EXPORT_SYMBOL_GPL(mddev_destroy);
+
 static struct mddev *mddev_find_locked(dev_t unit)
 {
        struct mddev *mddev;
@@ -711,13 +731,16 @@ static struct mddev *mddev_alloc(dev_t unit)
        new = kzalloc(sizeof(*new), GFP_KERNEL);
        if (!new)
                return ERR_PTR(-ENOMEM);
-       mddev_init(new);
+
+       error = mddev_init(new);
+       if (error)
+               goto out_free_new;
 
        spin_lock(&all_mddevs_lock);
        if (unit) {
                error = -EEXIST;
                if (mddev_find_locked(unit))
-                       goto out_free_new;
+                       goto out_destroy_new;
                new->unit = unit;
                if (MAJOR(unit) == MD_MAJOR)
                        new->md_minor = MINOR(unit);
@@ -728,7 +751,7 @@ static struct mddev *mddev_alloc(dev_t unit)
                error = -ENODEV;
                new->unit = mddev_alloc_unit();
                if (!new->unit)
-                       goto out_free_new;
+                       goto out_destroy_new;
                new->md_minor = MINOR(new->unit);
                new->hold_active = UNTIL_STOP;
        }
@@ -736,8 +759,11 @@ static struct mddev *mddev_alloc(dev_t unit)
        list_add(&new->all_mddevs, &all_mddevs);
        spin_unlock(&all_mddevs_lock);
        return new;
-out_free_new:
+
+out_destroy_new:
        spin_unlock(&all_mddevs_lock);
+       mddev_destroy(new);
+out_free_new:
        kfree(new);
        return ERR_PTR(error);
 }
@@ -748,6 +774,7 @@ static void mddev_free(struct mddev *mddev)
        list_del(&mddev->all_mddevs);
        spin_unlock(&all_mddevs_lock);
 
+       mddev_destroy(mddev);
        kfree(mddev);
 }
 
@@ -5787,12 +5814,6 @@ static void md_safemode_timeout(struct timer_list *t)
 }
 
 static int start_dirty_degraded;
-static void active_io_release(struct percpu_ref *ref)
-{
-       struct mddev *mddev = container_of(ref, struct mddev, active_io);
-
-       wake_up(&mddev->sb_wait);
-}
 
 int md_run(struct mddev *mddev)
 {
@@ -5873,15 +5894,10 @@ int md_run(struct mddev *mddev)
                nowait = nowait && bdev_nowait(rdev->bdev);
        }
 
-       err = percpu_ref_init(&mddev->active_io, active_io_release,
-                               PERCPU_REF_ALLOW_REINIT, GFP_KERNEL);
-       if (err)
-               return err;
-
        if (!bioset_initialized(&mddev->bio_set)) {
                err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
                if (err)
-                       goto exit_active_io;
+                       return err;
        }
        if (!bioset_initialized(&mddev->sync_set)) {
                err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
@@ -6078,8 +6094,6 @@ exit_sync_set:
        bioset_exit(&mddev->sync_set);
 exit_bio_set:
        bioset_exit(&mddev->bio_set);
-exit_active_io:
-       percpu_ref_exit(&mddev->active_io);
        return err;
 }
 EXPORT_SYMBOL_GPL(md_run);
@@ -6295,7 +6309,6 @@ static void __md_stop(struct mddev *mddev)
        module_put(pers->owner);
        clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
 
-       percpu_ref_exit(&mddev->active_io);
        bioset_exit(&mddev->bio_set);
        bioset_exit(&mddev->sync_set);
        bioset_exit(&mddev->io_clone_set);
index d8c8b8c532bb43b4761aaa4c530dbc3f1ad1c5ad..3344c47f85446720553ddf06cc1afa8e340457db 100644 (file)
@@ -798,7 +798,8 @@ extern int md_integrity_register(struct mddev *mddev);
 extern int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev);
 extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
 
-extern void mddev_init(struct mddev *mddev);
+extern int mddev_init(struct mddev *mddev);
+extern void mddev_destroy(struct mddev *mddev);
 struct mddev *md_alloc(dev_t dev, char *name);
 void mddev_put(struct mddev *mddev);
 extern int md_run(struct mddev *mddev);