[PATCH v2 03/11] md: workaround for inconsistency of config state in takeover

From: tada keisuke
Date: Thu Apr 18 2024 - 03:00:43 EST


This patch depends on patch 01.

An inconsistency occurs between config state in takeover and percpu_ref state.
Differentiate percpu_ref state setting for takeover and other to avoid the inconsistency.
Therefore, add percpu_ref state setting to match config state in takeover.

Signed-off-by: Keisuke TADA <keisuke1.tada@xxxxxxxxxx>
Signed-off-by: Toshifumi OHTAKE <toshifumi.ootake@xxxxxxxxxx>
---
drivers/md/raid5.c | 39 +++++++++++++++++++++++++++++++--------
1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 25da83eaa2ef..b7056854375d 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -7396,7 +7396,8 @@ static unsigned long raid5_cache_count(struct shrinker *shrink,
return max_stripes - min_stripes;
}

-static struct r5conf *setup_conf(struct mddev *mddev)
+
+static struct r5conf *setup_conf(struct mddev *mddev, bool quiesce)
{
struct r5conf *conf;
int raid_disk, memory, max_disks;
@@ -7407,6 +7408,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
int group_cnt;
struct r5worker_group *new_group;
int ret = -ENOMEM;
+ unsigned int percpu_ref_init_flags;

if (mddev->new_level != 5
&& mddev->new_level != 4
@@ -7477,6 +7479,10 @@ static struct r5conf *setup_conf(struct mddev *mddev)
init_llist_head(&conf->released_stripes);
atomic_set(&conf->active_stripes, 0);
atomic_set(&conf->preread_active_stripes, 0);
+ if (quiesce)
+ percpu_ref_init_flags = PERCPU_REF_ALLOW_REINIT | PERCPU_REF_INIT_DEAD;
+ else
+ percpu_ref_init_flags = PERCPU_REF_ALLOW_REINIT;
atomic_set(&conf->active_aligned_reads, 0);
spin_lock_init(&conf->pending_bios_lock);
conf->batch_bio_dispatch = true;
@@ -7657,6 +7663,23 @@ static struct r5conf *setup_conf(struct mddev *mddev)
return ERR_PTR(ret);
}

+static struct r5conf *setup_conf_for_run(struct mddev *mddev)
+{
+ return setup_conf(mddev, false);
+}
+
+static struct r5conf *setup_conf_for_takeover(struct mddev *mddev)
+{
+ struct r5conf *conf;
+ bool quiesce = false;
+
+ if (mddev->level == 4 || mddev->level == 5 || mddev->level == 6) {
+ conf = mddev->private;
+ quiesce = false;
+ }
+ return setup_conf(mddev, quiesce);
+}
+
static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded)
{
switch (algo) {
@@ -7884,7 +7907,7 @@ static int raid5_run(struct mddev *mddev)
}

if (mddev->private == NULL)
- conf = setup_conf(mddev);
+ conf = setup_conf_for_run(mddev);
else
conf = mddev->private;

@@ -8627,7 +8650,7 @@ static void *raid45_takeover_raid0(struct mddev *mddev, int level)
/* make sure it will be not marked as dirty */
mddev->recovery_cp = MaxSector;

- return setup_conf(mddev);
+ return setup_conf_for_takeover(mddev);
}

static void *raid5_takeover_raid1(struct mddev *mddev)
@@ -8655,7 +8678,7 @@ static void *raid5_takeover_raid1(struct mddev *mddev)
mddev->new_layout = ALGORITHM_LEFT_SYMMETRIC;
mddev->new_chunk_sectors = chunksect;

- ret = setup_conf(mddev);
+ ret = setup_conf_for_takeover(mddev);
if (!IS_ERR(ret))
mddev_clear_unsupported_flags(mddev,
UNSUPPORTED_MDDEV_FLAGS);
@@ -8692,7 +8715,7 @@ static void *raid5_takeover_raid6(struct mddev *mddev)
mddev->new_layout = new_layout;
mddev->delta_disks = -1;
mddev->raid_disks -= 1;
- return setup_conf(mddev);
+ return setup_conf_for_takeover(mddev);
}

static int raid5_check_reshape(struct mddev *mddev)
@@ -8770,7 +8793,7 @@ static void *raid5_takeover(struct mddev *mddev)
if (mddev->level == 4) {
mddev->new_layout = ALGORITHM_PARITY_N;
mddev->new_level = 5;
- return setup_conf(mddev);
+ return setup_conf_for_takeover(mddev);
}
if (mddev->level == 6)
return raid5_takeover_raid6(mddev);
@@ -8790,7 +8813,7 @@ static void *raid4_takeover(struct mddev *mddev)
mddev->layout == ALGORITHM_PARITY_N) {
mddev->new_layout = 0;
mddev->new_level = 4;
- return setup_conf(mddev);
+ return setup_conf_for_takeover(mddev);
}
return ERR_PTR(-EINVAL);
}
@@ -8840,7 +8863,7 @@ static void *raid6_takeover(struct mddev *mddev)
mddev->new_layout = new_layout;
mddev->delta_disks = 1;
mddev->raid_disks += 1;
- return setup_conf(mddev);
+ return setup_conf_for_takeover(mddev);
}

static int raid5_change_consistency_policy(struct mddev *mddev, const char *buf)
--
2.34.1