diff options
-rw-r--r-- | drivers/md/md.c | 12 | ||||
-rw-r--r-- | drivers/md/md.h | 2 | ||||
-rw-r--r-- | drivers/md/raid5-ppl.c | 4 | ||||
-rw-r--r-- | drivers/md/raid5.c | 53 |
4 files changed, 68 insertions, 3 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index a774030..af91187 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4996,14 +4996,20 @@ consistency_policy_show(struct mddev *mddev, char *page) static ssize_t consistency_policy_store(struct mddev *mddev, const char *buf, size_t len) { + int err = 0; + if (mddev->pers) { - return -EBUSY; + if (mddev->pers->change_consistency_policy) + err = mddev->pers->change_consistency_policy(mddev, buf); + else + err = -EBUSY; } else if (mddev->external && strncmp(buf, "ppl", 3) == 0) { set_bit(MD_HAS_PPL, &mddev->flags); - return len; } else { - return -EINVAL; + err = -EINVAL; } + + return err ? err : len; } static struct md_sysfs_entry md_consistency_policy = diff --git a/drivers/md/md.h b/drivers/md/md.h index a7b2f16..e094006 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -545,6 +545,8 @@ struct md_personality /* congested implements bdi.congested_fn(). * Will not be called while array is 'suspended' */ int (*congested)(struct mddev *mddev, int bits); + /* Changes the consistency policy of an active array. */ + int (*change_consistency_policy)(struct mddev *mddev, const char *buf); }; struct md_sysfs_entry { diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c index 4af420f..27bad3e 100644 --- a/drivers/md/raid5-ppl.c +++ b/drivers/md/raid5-ppl.c @@ -1187,6 +1187,10 @@ int ppl_init_log(struct r5conf *conf) */ mddev->recovery_cp = MaxSector; set_bit(MD_SB_CHANGE_CLEAN, &mddev->sb_flags); + } else if (mddev->pers && ppl_conf->mismatch_count > 0) { + /* no mismatch allowed when enabling PPL for a running array */ + ret = -EINVAL; + goto err; } conf->log_private = ppl_conf; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6760af2..88cc898 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -8334,6 +8334,58 @@ static void *raid6_takeover(struct mddev *mddev) return setup_conf(mddev); } +static void raid5_reset_stripe_cache(struct mddev *mddev) +{ + struct r5conf *conf = mddev->private; + + mutex_lock(&conf->cache_size_mutex); + while (conf->max_nr_stripes && + drop_one_stripe(conf)) + ; + while (conf->min_nr_stripes > conf->max_nr_stripes && + grow_one_stripe(conf, GFP_KERNEL)) + ; + mutex_unlock(&conf->cache_size_mutex); +} + +static int raid5_change_consistency_policy(struct mddev *mddev, const char *buf) +{ + struct r5conf *conf; + int err; + + err = mddev_lock(mddev); + if (err) + return err; + conf = mddev->private; + if (!conf) { + mddev_unlock(mddev); + return -ENODEV; + } + + if (strncmp(buf, "ppl", 3) == 0 && !raid5_has_ppl(conf)) { + mddev_suspend(mddev); + set_bit(MD_HAS_PPL, &mddev->flags); + err = log_init(conf, NULL); + if (!err) + raid5_reset_stripe_cache(mddev); + mddev_resume(mddev); + } else if (strncmp(buf, "resync", 6) == 0 && raid5_has_ppl(conf)) { + mddev_suspend(mddev); + log_exit(conf); + raid5_reset_stripe_cache(mddev); + mddev_resume(mddev); + } else { + err = -EINVAL; + } + + if (!err) + md_update_sb(mddev, 1); + + mddev_unlock(mddev); + + return err; +} + static struct md_personality raid6_personality = { .name = "raid6", @@ -8379,6 +8431,7 @@ static struct md_personality raid5_personality = .quiesce = raid5_quiesce, .takeover = raid5_takeover, .congested = raid5_congested, + .change_consistency_policy = raid5_change_consistency_policy, }; static struct md_personality raid4_personality = |