raid5-ppl: runtime PPL enabling or disabling
authorArtur Paszkiewicz <artur.paszkiewicz@intel.com>
Thu, 9 Mar 2017 09:00:03 +0000 (10:00 +0100)
committerShaohua Li <shli@fb.com>
Thu, 16 Mar 2017 23:55:56 +0000 (16:55 -0700)
Allow writing to 'consistency_policy' attribute when the array is
active. Add a new function 'change_consistency_policy' to the
md_personality operations structure to handle the change in the
personality code. Values "ppl" and "resync" are accepted and
turn PPL on and off respectively.

When enabling PPL its location and size should first be set using
'ppl_sector' and 'ppl_size' attributes and a valid PPL header should be
written at this location on each member device.

Enabling or disabling PPL is performed under a suspended array.  The
raid5_reset_stripe_cache function frees the stripe cache and allocates
it again in order to allocate or free the ppl_pages for the stripes in
the stripe cache.

Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Signed-off-by: Shaohua Li <shli@fb.com>
drivers/md/md.c
drivers/md/md.h
drivers/md/raid5-ppl.c
drivers/md/raid5.c

index a7740306cbbd2a3dbcd0d5e79bcce3b20880a850..af911871122853f7c10804b764a0e8d5978991ab 100644 (file)
@@ -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 =
index a7b2f16452c44f137d614bb4e407344ac94cb00e..e0940064c3ec1c4778db2f726e80f7a4975088e6 100644 (file)
@@ -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 {
index 4af420f4d8c09381c1f8342d00c828007d6b17ed..27bad3e2d7ce5a804934e655674e9cb032fd2265 100644 (file)
@@ -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;
index 6760af2518642129111085bcf286a1237fd6f2b1..88cc8981bd4991ea4d65e4219e1a2c55ce8b5c9f 100644 (file)
@@ -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 =