From 272906ef4906002a4238e0388fa2e7e8387995ad Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 12 Aug 2008 02:25:46 -0700 Subject: [PATCH] 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 --- monitor.c | 11 ++- super-intel.c | 216 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 137 insertions(+), 90 deletions(-) diff --git a/monitor.c b/monitor.c index 7cce5a8..382cad4 100644 --- a/monitor.c +++ b/monitor.c @@ -243,10 +243,15 @@ static int read_and_act(struct active_array *a) * readonly ??? */ 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 */ - 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->next_state = active; } diff --git a/super-intel.c b/super-intel.c index 62bd32d..28b26d9 100644 --- a/super-intel.c +++ b/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); 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) { /* complete recovery or initial resync */ 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_type = failed ? 1 : 0; dup_map(dev); + a->check_degraded = 1; super->updates_pending++; } @@ -2309,6 +2314,93 @@ static void imsm_sync_metadata(struct supertype *container) 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, struct metadata_update **updates) { @@ -2352,7 +2444,6 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a, return NULL; /* 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 (d = a->info.devs ; d ; d = d->next) 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)) continue; - /* OK, this device needs recovery. Find a spare */ - for ( ; dl ; dl = dl->next) { - unsigned long long esize; - unsigned long long pos; - struct mdinfo *d2; - struct extent *ex; - int j; - int found; - __u32 array_start; + /* + * OK, this device needs recovery. Try to re-add the previous + * occupant of this slot, if this fails add a new spare + */ + dl = imsm_readd(super, i, a); + if (!dl) + dl = imsm_add_spare(super, i, a); + if (!dl) + continue; + + /* found a usable disk with enough space */ + di = malloc(sizeof(*di)); + memset(di, 0, sizeof(*di)); - /* If in this array, skip */ - for (d2 = a->info.devs ; d2 ; d2 = d2->next) - if (d2->disk.major == dl->major && - d2->disk.minor == dl->minor) { - dprintf("%x:%x already in array\n", dl->major, dl->minor); - break; - } - if (d2) - continue; + /* 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; - /* 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); + /* (ab)use di->devs to store a pointer to the device + * we chose + */ + di->devs = (struct mdinfo *) dl; - 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); + di->disk.raid_disk = i; + di->disk.major = dl->major; + di->disk.minor = dl->minor; + di->disk.state = 0; + di->data_offset = __le32_to_cpu(map->pba_of_lba0); + 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, di->data_offset); - 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; - } - - /* 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; - } + break; } if (!rv)