]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Add action=spare-same-slot policy.
authorNeilBrown <neilb@suse.de>
Mon, 22 Nov 2010 09:58:06 +0000 (20:58 +1100)
committerNeilBrown <neilb@suse.de>
Mon, 22 Nov 2010 09:58:06 +0000 (20:58 +1100)
When "mdadm -I" is given a device with no metadata, mdadm tries to add
it as a 'spare' somewhere based on policy.

This patch changes the behaviour in two ways:

1/ If the device is at a 'path' where a previous device was removed
  from an array or container, then we preferentially add the spare to
  that array or container.

2/ Previously only 'bare' devices were considered for adding as
  spares.  Now if action=spare-same-slot is active, we will add
  non-bare devices, but *only* if the path was previously in use
  for some array, and the device will only be added to that array.

Based on code
  From: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>

Signed-off-by: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Incremental.c
mdadm.h
policy.c

index 3e361d0ab60b02566c069b3a9de4a10c0da1df40..6236281850d0fd04ac10f02eb7dabff94e2360b1 100644 (file)
@@ -38,6 +38,7 @@ static void find_reject(int mdfd, struct supertype *st, struct mdinfo *sra,
                        int number, __u64 events, int verbose,
                        char *array_name);
 static int try_spare(char *devname, int *dfdp, struct dev_policy *pol,
+                    struct map_ent *target,
                     struct supertype *st, int verbose);
 
 static int Incremental_container(struct supertype *st, char *devname,
@@ -103,6 +104,8 @@ int Incremental(char *devname, int verbose, int runstop,
        char *name_to_use;
        mdu_array_info_t ainf;
        struct dev_policy *policy = NULL;
+       struct map_ent target_array;
+       int have_target;
 
        struct createinfo *ci = conf_get_create_info();
 
@@ -172,13 +175,16 @@ int Incremental(char *devname, int verbose, int runstop,
        dinfo.disk.minor = minor(stb.st_rdev);
 
        policy = disk_policy(&dinfo);
+       have_target = policy_check_path(&dinfo, &target_array);
 
        if (st == NULL && (st = guess_super(dfd)) == NULL) {
                if (verbose >= 0)
                        fprintf(stderr, Name
                                ": no recognisable superblock on %s.\n",
                                devname);
-               rv = try_spare(devname, &dfd, policy, st, verbose);
+               rv = try_spare(devname, &dfd, policy,
+                              have_target ? &target_array : NULL,
+                              st, verbose);
                goto out;
        }
        if (st->ss->compare_super == NULL ||
@@ -186,7 +192,9 @@ int Incremental(char *devname, int verbose, int runstop,
                if (verbose >= 0)
                        fprintf(stderr, Name ": no RAID superblock on %s.\n",
                                devname);
-               rv = try_spare(devname, &dfd, policy, st, verbose);
+               rv = try_spare(devname, &dfd, policy,
+                              have_target ? &target_array : NULL,
+                              st, verbose);
                free(st);
                goto out;
        }
@@ -749,11 +757,16 @@ static int count_active(struct supertype *st, int mdfd, char **availp,
 }
 
 static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
+                          struct map_ent *target, int bare,
                           struct supertype *st, int verbose)
 {
        /* This device doesn't have any md metadata
-        * If it is 'bare' and theh device policy allows 'spare' look for
-        * an array or container to attach it to.
+        * The device policy allows 'spare' and if !bare, it allows spare-same-slot.
+        * If 'st' is not set, then we only know that some metadata allows this,
+        * others possibly don't.
+        * So look for a container or array to attach the device to.
+        * Prefer 'target' if that is set and the array is found.
+        *
         * If st is set, then only arrays of that type are considered
         * Return 0 on success, or some exit code on failure, probably 1.
         */
@@ -832,6 +845,9 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
                         */
                        if (!policy_action_allows(pol, st2->ss->name, act_spare))
                                goto next;
+                       if (!bare && !policy_action_allows(pol, st2->ss->name,
+                                                          act_spare_same_slot))
+                               goto next;
                } else
                        st2 = st;
                get_dev_size(dfd, NULL, &devsize);
@@ -850,6 +866,31 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
 
                        goto next;
                }
+               /* test against target.
+                * If 'target' is set and 'bare' is false, we only accept
+                * arrays/containers that match 'target'.
+                * If 'target' is set and 'bare' is true, we prefer the
+                * array which matches 'target'.
+                */
+               if (target) {
+                       if (strcmp(target->metadata, mp->metadata) == 0 &&
+                           memcmp(target->uuid, mp->uuid,
+                                  sizeof(target->uuid)) == 0) {
+                               /* This is our target!! */
+                               if (chosen)
+                                       sysfs_free(chosen);
+                               chosen = sra;
+                               sra = NULL;
+                               /* skip to end so we don't check any more */
+                               while (mp->next)
+                                       mp = mp->next;
+                               goto next;
+                       }
+                       /* not our target */
+                       if (!bare)
+                               goto next;
+               }
+
                /* all tests passed, OK to add to this array */
                if (!chosen) {
                        chosen = sra;
@@ -1082,6 +1123,7 @@ static int is_bare(int dfd)
  * Arrays are given priority over partitions.
  */
 static int try_spare(char *devname, int *dfdp, struct dev_policy *pol,
+                    struct map_ent *target,
                     struct supertype *st, int verbose)
 {
        int i;
@@ -1089,38 +1131,55 @@ static int try_spare(char *devname, int *dfdp, struct dev_policy *pol,
        int arrays_ok = 0;
        int partitions_ok = 0;
        int dfd = *dfdp;
+       int bare;
 
-       /* Can only add a spare if device has at least one domains */
+       /* Can only add a spare if device has at least one domain */
        if (pol_find(pol, pol_domain) == NULL)
                return 1;
        /* And only if some action allows spares */
        if (!policy_action_allows(pol, st?st->ss->name:NULL, act_spare))
                return 1;
 
-       /* Now check if the device is bare - we don't add non-bare devices
-        * yet even if action=-spare
+       /* Now check if the device is bare.
+        * bare devices can always be added as a spare
+        * non-bare devices can only be added if spare-same-slot is permitted,
+        * and this device is replacing a previous device - in which case 'target'
+        * will be set.
         */
-
        if (!is_bare(dfd)) {
-               if (verbose > 1)
-                       fprintf(stderr, Name ": %s is not bare, so not considering as a spare\n",
-                               devname);
-               return 1;
-       }
+               /* Must have a target and allow same_slot */
+               /* Later - may allow force_spare without target */
+               if (!target ||
+                   !policy_action_allows(pol, st?st->ss->name:NULL,
+                                         act_spare_same_slot)) {
+                       if (verbose > 1)
+                               fprintf(stderr, Name ": %s is not bare, so not "
+                                       "considering as a spare\n",
+                                       devname);
+                       return 1;
+               }
+               bare = 0;
+       } else
+               bare = 1;
 
-       /* This device passes our test for 'is bare'.
-        * Let's see what policy allows for such things.
+       /* It might be OK to add this device to an array - need to see
+        * what arrays might be candidates.
         */
        if (st) {
                /* just try try 'array' or 'partition' based on this metadata */
                if (st->ss->add_to_super)
-                       return array_try_spare(devname, dfdp, pol,
+                       return array_try_spare(devname, dfdp, pol, target, bare,
                                               st, verbose);
                else
                        return partition_try_spare(devname, dfdp, pol,
                                                   st, verbose);
        }
-       /* Now see which metadata type support spare */
+       /* No metadata was specified or found so options are open.
+        * Check for whether any array metadata, or any partition metadata
+        * might allow adding the spare.  This check is just help to avoid
+        * a more costly scan of all arrays when we can be sure that will
+        * fail.
+        */
        for (i = 0; (!arrays_ok || !partitions_ok) && superlist[i] ; i++) {
                if (superlist[i]->add_to_super && !arrays_ok &&
                    policy_action_allows(pol, superlist[i]->name, act_spare))
@@ -1131,7 +1190,8 @@ static int try_spare(char *devname, int *dfdp, struct dev_policy *pol,
        }
        rv = 1;
        if (arrays_ok)
-               rv = array_try_spare(devname, dfdp, pol, st, verbose);
+               rv = array_try_spare(devname, dfdp, pol, target, bare,
+                                    st, verbose);
        if (rv != 0 && partitions_ok)
                rv = partition_try_spare(devname, dfdp, pol, st, verbose);
        return rv;
diff --git a/mdadm.h b/mdadm.h
index 43934115df40d8bba47e36cf94c63a04b7b37ae7..6c6e352d58d27c7c74cfc1f79e42522a89275afe 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -816,8 +816,10 @@ enum policy_action {
        act_default,
        act_include,
        act_re_add,
-       act_spare,
-       act_force_spare,
+       act_spare,      /* This only applies to bare devices */
+       act_spare_same_slot, /* this allows non-bare devices,
+                             * but only if recent removal */
+       act_force_spare, /* this allow non-bare devices in any case */
        act_err
 };
 
index 28751fb98993c8e96f6994bbad34ed01e1447258..cc126949a7f98ae8c675b773028c222c9c3fd5d1 100644 (file)
--- a/policy.c
+++ b/policy.c
@@ -519,6 +519,8 @@ static enum policy_action map_act(char *act)
                return act_re_add;
        if (strcmp(act, "spare") == 0)
                return act_spare;
+       if (strcmp(act, "spare-same-slot") == 0)
+               return act_spare_same_slot;
        if (strcmp(act, "force-spare") == 0)
                return act_force_spare;
        return act_err;