summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-11-22 20:58:06 +1100
committerNeilBrown <neilb@suse.de>2010-11-22 20:58:06 +1100
commitd2db30455891a97ac0ac17bb64848de52bfb1566 (patch)
treedfb02e2a2edd5384c20f534aafc24e257e9eb458
parent625b25071bb6db4d1c019d5bab0344d82d5ae4c4 (diff)
Add action=spare-same-slot policy.
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>
-rw-r--r--Incremental.c96
-rw-r--r--mdadm.h6
-rw-r--r--policy.c2
3 files changed, 84 insertions, 20 deletions
diff --git a/Incremental.c b/Incremental.c
index 3e361d0a..62362818 100644
--- a/Incremental.c
+++ b/Incremental.c
@@ -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 43934115..6c6e352d 100644
--- 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
};
diff --git a/policy.c b/policy.c
index 28751fb9..cc126949 100644
--- 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;