mdmon: use activate spare for re-add
Disks that are not in-sync or failed are not assembled into member arrays by mdadm. Teach mdmon to resolve this situation by checking for spares at start. imsm_activate_spare() is updated to prefer devices that can be re-added versus new spares. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
3393c6af8b
commit
272906ef49
11
monitor.c
11
monitor.c
|
@ -243,10 +243,15 @@ static int read_and_act(struct active_array *a)
|
||||||
* readonly ???
|
* readonly ???
|
||||||
*/
|
*/
|
||||||
get_resync_start(a);
|
get_resync_start(a);
|
||||||
// printf("Found a readonly array at %llu\n", a->resync_start);
|
if (a->resync_start == ~0ULL) {
|
||||||
if (a->resync_start == ~0ULL)
|
|
||||||
a->next_state = read_auto; /* array is clean */
|
a->next_state = read_auto; /* array is clean */
|
||||||
else {
|
/* give the metadata a chance to force active if
|
||||||
|
* we have some recovery to do. metadata sets
|
||||||
|
* resync_start to !MaxSector in this case
|
||||||
|
*/
|
||||||
|
a->container->ss->set_array_state(a, 1);
|
||||||
|
}
|
||||||
|
if (a->resync_start != ~0ULL) {
|
||||||
a->container->ss->set_array_state(a, 0);
|
a->container->ss->set_array_state(a, 0);
|
||||||
a->next_state = active;
|
a->next_state = active;
|
||||||
}
|
}
|
||||||
|
|
216
super-intel.c
216
super-intel.c
|
@ -2169,6 +2169,10 @@ static void imsm_set_array_state(struct active_array *a, int consistent)
|
||||||
failed = imsm_count_failed(super, map);
|
failed = imsm_count_failed(super, map);
|
||||||
map_state = imsm_check_degraded(super, inst, failed);
|
map_state = imsm_check_degraded(super, inst, failed);
|
||||||
|
|
||||||
|
if (consistent && !dev->vol.dirty &&
|
||||||
|
(dev->vol.migr_state || map_state != IMSM_T_STATE_NORMAL))
|
||||||
|
a->resync_start = 0ULL;
|
||||||
|
|
||||||
if (a->resync_start == ~0ULL) {
|
if (a->resync_start == ~0ULL) {
|
||||||
/* complete recovery or initial resync */
|
/* complete recovery or initial resync */
|
||||||
if (map->map_state != map_state) {
|
if (map->map_state != map_state) {
|
||||||
|
@ -2191,6 +2195,7 @@ static void imsm_set_array_state(struct active_array *a, int consistent)
|
||||||
dev->vol.migr_state = 1;
|
dev->vol.migr_state = 1;
|
||||||
dev->vol.migr_type = failed ? 1 : 0;
|
dev->vol.migr_type = failed ? 1 : 0;
|
||||||
dup_map(dev);
|
dup_map(dev);
|
||||||
|
a->check_degraded = 1;
|
||||||
super->updates_pending++;
|
super->updates_pending++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2309,6 +2314,93 @@ static void imsm_sync_metadata(struct supertype *container)
|
||||||
super->updates_pending = 0;
|
super->updates_pending = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dl *imsm_readd(struct intel_super *super, int idx, struct active_array *a)
|
||||||
|
{
|
||||||
|
struct imsm_dev *dev = get_imsm_dev(super, a->info.container_member);
|
||||||
|
struct imsm_map *map = get_imsm_map(dev, 0);
|
||||||
|
int i = get_imsm_disk_idx(map, idx);
|
||||||
|
struct dl *dl;
|
||||||
|
|
||||||
|
for (dl = super->disks; dl; dl = dl->next)
|
||||||
|
if (dl->index == i)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (__le32_to_cpu(dl->disk.status) & FAILED_DISK)
|
||||||
|
dl = NULL;
|
||||||
|
|
||||||
|
if (dl)
|
||||||
|
dprintf("%s: found %x:%x\n", __func__, dl->major, dl->minor);
|
||||||
|
|
||||||
|
return dl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dl *imsm_add_spare(struct intel_super *super, int idx, struct active_array *a)
|
||||||
|
{
|
||||||
|
struct imsm_dev *dev = get_imsm_dev(super, a->info.container_member);
|
||||||
|
struct imsm_map *map = get_imsm_map(dev, 0);
|
||||||
|
unsigned long long esize;
|
||||||
|
unsigned long long pos;
|
||||||
|
struct mdinfo *d;
|
||||||
|
struct extent *ex;
|
||||||
|
int j;
|
||||||
|
int found;
|
||||||
|
__u32 array_start;
|
||||||
|
struct dl *dl;
|
||||||
|
|
||||||
|
for (dl = super->disks; dl; dl = dl->next) {
|
||||||
|
/* If in this array, skip */
|
||||||
|
for (d = a->info.devs ; d ; d = d->next)
|
||||||
|
if (d->disk.major == dl->major &&
|
||||||
|
d->disk.minor == dl->minor) {
|
||||||
|
dprintf("%x:%x already in array\n", dl->major, dl->minor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (d)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Does this unused device have the requisite free space?
|
||||||
|
* We need a->info.component_size sectors
|
||||||
|
*/
|
||||||
|
ex = get_extents(super, dl);
|
||||||
|
if (!ex) {
|
||||||
|
dprintf("cannot get extents\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
found = 0;
|
||||||
|
j = 0;
|
||||||
|
pos = 0;
|
||||||
|
array_start = __le32_to_cpu(map->pba_of_lba0);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* check that we can start at pba_of_lba0 with
|
||||||
|
* a->info.component_size of space
|
||||||
|
*/
|
||||||
|
esize = ex[j].start - pos;
|
||||||
|
if (array_start >= pos &&
|
||||||
|
array_start + a->info.component_size < ex[j].start) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos = ex[j].start + ex[j].size;
|
||||||
|
j++;
|
||||||
|
|
||||||
|
} while (ex[j-1].size);
|
||||||
|
|
||||||
|
free(ex);
|
||||||
|
if (!found) {
|
||||||
|
dprintf("%x:%x does not have %llu at %d\n",
|
||||||
|
dl->major, dl->minor,
|
||||||
|
a->info.component_size,
|
||||||
|
__le32_to_cpu(map->pba_of_lba0));
|
||||||
|
/* No room */
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dl;
|
||||||
|
}
|
||||||
|
|
||||||
static struct mdinfo *imsm_activate_spare(struct active_array *a,
|
static struct mdinfo *imsm_activate_spare(struct active_array *a,
|
||||||
struct metadata_update **updates)
|
struct metadata_update **updates)
|
||||||
{
|
{
|
||||||
|
@ -2352,7 +2444,6 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* For each slot, if it is not working, find a spare */
|
/* For each slot, if it is not working, find a spare */
|
||||||
dl = super->disks;
|
|
||||||
for (i = 0; i < a->info.array.raid_disks; i++) {
|
for (i = 0; i < a->info.array.raid_disks; i++) {
|
||||||
for (d = a->info.devs ; d ; d = d->next)
|
for (d = a->info.devs ; d ; d = d->next)
|
||||||
if (d->disk.raid_disk == i)
|
if (d->disk.raid_disk == i)
|
||||||
|
@ -2361,96 +2452,47 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
|
||||||
if (d && (d->state_fd >= 0))
|
if (d && (d->state_fd >= 0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* OK, this device needs recovery. Find a spare */
|
/*
|
||||||
for ( ; dl ; dl = dl->next) {
|
* OK, this device needs recovery. Try to re-add the previous
|
||||||
unsigned long long esize;
|
* occupant of this slot, if this fails add a new spare
|
||||||
unsigned long long pos;
|
*/
|
||||||
struct mdinfo *d2;
|
dl = imsm_readd(super, i, a);
|
||||||
struct extent *ex;
|
if (!dl)
|
||||||
int j;
|
dl = imsm_add_spare(super, i, a);
|
||||||
int found;
|
if (!dl)
|
||||||
__u32 array_start;
|
continue;
|
||||||
|
|
||||||
|
/* found a usable disk with enough space */
|
||||||
|
di = malloc(sizeof(*di));
|
||||||
|
memset(di, 0, sizeof(*di));
|
||||||
|
|
||||||
/* If in this array, skip */
|
/* dl->index will be -1 in the case we are activating a
|
||||||
for (d2 = a->info.devs ; d2 ; d2 = d2->next)
|
* pristine spare. imsm_process_update() will create a
|
||||||
if (d2->disk.major == dl->major &&
|
* new index in this case. Once a disk is found to be
|
||||||
d2->disk.minor == dl->minor) {
|
* failed in all member arrays it is kicked from the
|
||||||
dprintf("%x:%x already in array\n", dl->major, dl->minor);
|
* metadata
|
||||||
break;
|
*/
|
||||||
}
|
di->disk.number = dl->index;
|
||||||
if (d2)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Does this unused device have the requisite free space?
|
/* (ab)use di->devs to store a pointer to the device
|
||||||
* We need a->info.component_size sectors
|
* we chose
|
||||||
*/
|
*/
|
||||||
ex = get_extents(super, dl);
|
di->devs = (struct mdinfo *) dl;
|
||||||
if (!ex) {
|
|
||||||
dprintf("cannot get extents\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
found = 0;
|
|
||||||
j = 0;
|
|
||||||
pos = 0;
|
|
||||||
array_start = __le32_to_cpu(map->pba_of_lba0);
|
|
||||||
|
|
||||||
do {
|
di->disk.raid_disk = i;
|
||||||
/* check that we can start at pba_of_lba0 with
|
di->disk.major = dl->major;
|
||||||
* a->info.component_size of space
|
di->disk.minor = dl->minor;
|
||||||
*/
|
di->disk.state = 0;
|
||||||
esize = ex[j].start - pos;
|
di->data_offset = __le32_to_cpu(map->pba_of_lba0);
|
||||||
if (array_start >= pos &&
|
di->component_size = a->info.component_size;
|
||||||
array_start + a->info.component_size < ex[j].start) {
|
di->container_member = inst;
|
||||||
found = 1;
|
di->next = rv;
|
||||||
break;
|
rv = di;
|
||||||
}
|
num_spares++;
|
||||||
pos = ex[j].start + ex[j].size;
|
dprintf("%x:%x to be %d at %llu\n", dl->major, dl->minor,
|
||||||
j++;
|
i, di->data_offset);
|
||||||
|
|
||||||
} while (ex[j-1].size);
|
|
||||||
|
|
||||||
free(ex);
|
break;
|
||||||
if (!found) {
|
|
||||||
dprintf("%x:%x does not have %llu at %d\n",
|
|
||||||
dl->major, dl->minor,
|
|
||||||
a->info.component_size,
|
|
||||||
__le32_to_cpu(map->pba_of_lba0));
|
|
||||||
/* No room */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* found a usable disk with enough space */
|
|
||||||
di = malloc(sizeof(*di));
|
|
||||||
memset(di, 0, sizeof(*di));
|
|
||||||
|
|
||||||
/* dl->index will be -1 in the case we are activating a
|
|
||||||
* pristine spare. imsm_process_update() will create a
|
|
||||||
* new index in this case. Once a disk is found to be
|
|
||||||
* failed in all member arrays it is kicked from the
|
|
||||||
* metadata
|
|
||||||
*/
|
|
||||||
di->disk.number = dl->index;
|
|
||||||
|
|
||||||
/* (ab)use di->devs to store a pointer to the device
|
|
||||||
* we chose
|
|
||||||
*/
|
|
||||||
di->devs = (struct mdinfo *) dl;
|
|
||||||
|
|
||||||
di->disk.raid_disk = i;
|
|
||||||
di->disk.major = dl->major;
|
|
||||||
di->disk.minor = dl->minor;
|
|
||||||
di->disk.state = 0;
|
|
||||||
di->data_offset = array_start;
|
|
||||||
di->component_size = a->info.component_size;
|
|
||||||
di->container_member = inst;
|
|
||||||
di->next = rv;
|
|
||||||
rv = di;
|
|
||||||
num_spares++;
|
|
||||||
dprintf("%x:%x to be %d at %llu\n", dl->major, dl->minor,
|
|
||||||
i, pos);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rv)
|
if (!rv)
|
||||||
|
|
Loading…
Reference in New Issue