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>
This commit is contained in:
NeilBrown 2010-11-22 20:58:06 +11:00
parent 625b25071b
commit d2db304558
3 changed files with 84 additions and 20 deletions

View 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;

View File

@ -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
};

View File

@ -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;