summaryrefslogtreecommitdiffstats
path: root/super-intel.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2008-09-15 20:58:41 -0700
committerDan Williams <dan.j.williams@intel.com>2008-09-15 20:58:41 -0700
commit0c046afd066972c8dd741cb7a78073327209ab7b (patch)
treea07549324ece902cc34a53dfd9fcd6edc37c6375 /super-intel.c
parent24565c9a99e291edb773e1d2dc9478949792ca39 (diff)
downloadmdadm-0c046afd066972c8dd741cb7a78073327209ab7b.tar.gz
mdadm-0c046afd066972c8dd741cb7a78073327209ab7b.tar.xz
mdadm-0c046afd066972c8dd741cb7a78073327209ab7b.zip
imsm: rectify map handling
The secondary map is used to reflect the migration state of the array i.e. from dev->vol.map[1] to dev->vol.map[0]. Ensure a rebuilding / initializing array is marked in the second map, while normal status is reflected in the first map. Also mark rebuilding drives with IMSM_ORD_REBUILD. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'super-intel.c')
-rw-r--r--super-intel.c194
1 files changed, 132 insertions, 62 deletions
diff --git a/super-intel.c b/super-intel.c
index 0ebf87f..c6b7be4 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -967,12 +967,31 @@ static void imsm_copy_dev(struct imsm_dev *dest, struct imsm_dev *src)
memcpy(dest, src, sizeof_imsm_dev(src, 0));
}
-static void dup_map(struct imsm_dev *dev)
+/* When migrating map0 contains the 'destination' state while map1
+ * contains the current state. When not migrating map0 contains the
+ * current state. This routine assumes that map[0].map_state is set to
+ * the current array state before being called.
+ *
+ * Migration is indicated by one of the following states
+ * 1/ Idle (migr_state=0 map0state=normal||unitialized||degraded||failed)
+ * 2/ Initialize (migr_state=1 migr_type=0 map0state=normal
+ * map1state=unitialized)
+ * 3/ Verify (Resync) (migr_state=1 migr_type=1 map0state=normal
+ * map1state=normal)
+ * 4/ Rebuild (migr_state=1 migr_type=1 map0state=normal
+ * map1state=degraded)
+ */
+static void migrate(struct imsm_dev *dev, __u8 to_state, int rebuild_resync)
{
- struct imsm_map *dest = get_imsm_map(dev, 1);
+ struct imsm_map *dest;
struct imsm_map *src = get_imsm_map(dev, 0);
+ dev->vol.migr_state = 1;
+ dev->vol.migr_type = rebuild_resync;
+ dest = get_imsm_map(dev, 1);
+
memcpy(dest, src, sizeof_imsm_map(src));
+ src->map_state = to_state;
}
static int parse_raid_devices(struct intel_super *super)
@@ -2276,56 +2295,89 @@ static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev)
return failed;
}
+static int is_resyncing(struct imsm_dev *dev)
+{
+ struct imsm_map *migr_map;
+
+ if (!dev->vol.migr_state)
+ return 0;
+
+ if (dev->vol.migr_type == 0)
+ return 1;
+
+ migr_map = get_imsm_map(dev, 1);
+
+ if (migr_map->map_state == IMSM_T_STATE_NORMAL)
+ return 1;
+ else
+ return 0;
+}
+
+static int is_rebuilding(struct imsm_dev *dev)
+{
+ struct imsm_map *migr_map;
+
+ if (!dev->vol.migr_state)
+ return 0;
+
+ if (dev->vol.migr_type == 0)
+ return 0;
+
+ migr_map = get_imsm_map(dev, 1);
+
+ if (migr_map->map_state == IMSM_T_STATE_DEGRADED)
+ return 1;
+ else
+ return 0;
+}
+
+/* Handle dirty -> clean transititions and resync. Degraded and rebuild
+ * states are handled in imsm_set_disk() with one exception, when a
+ * resync is stopped due to a new failure this routine will set the
+ * 'degraded' state for the array.
+ */
static int imsm_set_array_state(struct active_array *a, int consistent)
{
int inst = a->info.container_member;
struct intel_super *super = a->container->sb;
struct imsm_dev *dev = get_imsm_dev(super, inst);
struct imsm_map *map = get_imsm_map(dev, 0);
- int dirty = !consistent;
- int failed;
- __u8 map_state;
-
- failed = imsm_count_failed(super, dev);
- map_state = imsm_check_degraded(super, dev, failed);
+ int failed = imsm_count_failed(super, dev);
+ __u8 map_state = imsm_check_degraded(super, dev, failed);
- if (consistent && !dev->vol.dirty &&
- (dev->vol.migr_state || map_state != IMSM_T_STATE_NORMAL))
- a->resync_start = 0ULL;
- if (consistent == 2 && a->resync_start != ~0ULL)
+ if (consistent == 2 &&
+ (a->resync_start != ~0ULL ||
+ map_state != IMSM_T_STATE_NORMAL ||
+ dev->vol.migr_state))
consistent = 0;
if (a->resync_start == ~0ULL) {
- /* complete recovery or initial resync */
- if (map->map_state != map_state) {
- dprintf("imsm: map_state %d: %d\n",
- inst, map_state);
- map->map_state = map_state;
- super->updates_pending++;
- }
- if (dev->vol.migr_state) {
- dprintf("imsm: mark resync complete\n");
+ /* complete intialization / resync,
+ * recovery is completed in ->set_disk
+ */
+ if (is_resyncing(dev)) {
+ dprintf("imsm: mark resync done\n");
dev->vol.migr_state = 0;
- dev->vol.migr_type = 0;
+ map->map_state = map_state;
super->updates_pending++;
}
- } else if (!dev->vol.migr_state) {
- dprintf("imsm: mark '%s' (%llu)\n",
- failed ? "rebuild" : "initializing", a->resync_start);
- /* mark that we are rebuilding */
- map->map_state = failed ? map_state : IMSM_T_STATE_NORMAL;
- dev->vol.migr_state = 1;
- dev->vol.migr_type = failed ? 1 : 0;
- dup_map(dev);
- a->check_degraded = 1;
+ } else if (!is_resyncing(dev) && !failed) {
+ /* mark the start of the init process if nothing is failed */
+ dprintf("imsm: mark resync start (%llu)\n", a->resync_start);
+ map->map_state = map_state;
+ migrate(dev, IMSM_T_STATE_NORMAL,
+ map->map_state == IMSM_T_STATE_NORMAL);
super->updates_pending++;
}
/* mark dirty / clean */
- if (dirty != dev->vol.dirty) {
+ if (dev->vol.dirty != !consistent) {
dprintf("imsm: mark '%s' (%llu)\n",
- dirty ? "dirty" : "clean", a->resync_start);
- dev->vol.dirty = dirty;
+ consistent ? "clean" : "dirty", a->resync_start);
+ if (consistent)
+ dev->vol.dirty = 0;
+ else
+ dev->vol.dirty = 1;
super->updates_pending++;
}
return consistent;
@@ -2338,10 +2390,10 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
struct imsm_dev *dev = get_imsm_dev(super, inst);
struct imsm_map *map = get_imsm_map(dev, 0);
struct imsm_disk *disk;
+ int failed;
__u32 status;
- int failed = 0;
- int new_failure = 0;
__u32 ord;
+ __u8 map_state;
if (n > map->num_members)
fprintf(stderr, "imsm: set_disk %d out of range 0..%d\n",
@@ -2362,7 +2414,6 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
disk->status = __cpu_to_le32(status);
disk->scsi_id = __cpu_to_le32(~0UL);
memmove(&disk->serial[0], &disk->serial[1], MAX_RAID_SERIAL_LEN - 1);
- new_failure = 1;
super->updates_pending++;
}
/* check if in_sync */
@@ -2373,29 +2424,26 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
super->updates_pending++;
}
- /* the number of failures have changed, count up 'failed' to determine
- * degraded / failed status
- */
- if (new_failure && map->map_state != IMSM_T_STATE_FAILED)
- failed = imsm_count_failed(super, dev);
-
- /* determine map_state based on failed or in_sync count */
- if (failed)
- map->map_state = imsm_check_degraded(super, dev, failed);
- else if (map->map_state == IMSM_T_STATE_DEGRADED) {
- struct mdinfo *d;
- int working = 0;
-
- for (d = a->info.devs ; d ; d = d->next)
- if (d->curr_state & DS_INSYNC)
- working++;
+ failed = imsm_count_failed(super, dev);
+ map_state = imsm_check_degraded(super, dev, failed);
- if (working == a->info.array.raid_disks) {
- map->map_state = IMSM_T_STATE_NORMAL;
- dev->vol.migr_state = 0;
- dev->vol.migr_type = 0;
- super->updates_pending++;
- }
+ /* check if recovery complete, newly degraded, or failed */
+ if (map_state == IMSM_T_STATE_NORMAL && is_rebuilding(dev)) {
+ map->map_state = map_state;
+ dev->vol.migr_state = 0;
+ super->updates_pending++;
+ } else if (map_state == IMSM_T_STATE_DEGRADED &&
+ map->map_state != map_state &&
+ !dev->vol.migr_state) {
+ dprintf("imsm: mark degraded\n");
+ map->map_state = map_state;
+ super->updates_pending++;
+ } else if (map_state == IMSM_T_STATE_FAILED &&
+ map->map_state != map_state) {
+ dprintf("imsm: mark failed\n");
+ dev->vol.migr_state = 0;
+ map->map_state = map_state;
+ super->updates_pending++;
}
}
@@ -2720,12 +2768,15 @@ static void imsm_process_update(struct supertype *st,
struct imsm_update_activate_spare *u = (void *) update->buf;
struct imsm_dev *dev = get_imsm_dev(super, u->array);
struct imsm_map *map = get_imsm_map(dev, 0);
+ struct imsm_map *migr_map;
struct active_array *a;
struct imsm_disk *disk;
__u32 status;
+ __u8 to_state;
struct dl *dl;
unsigned int found;
- int victim;
+ int failed;
+ int victim = get_imsm_disk_idx(dev, u->slot);
int i;
for (dl = super->disks; dl; dl = dl->next)
@@ -2741,19 +2792,38 @@ static void imsm_process_update(struct supertype *st,
super->updates_pending++;
+ /* count failures (excluding rebuilds and the victim)
+ * to determine map[0] state
+ */
+ failed = 0;
+ for (i = 0; i < map->num_members; i++) {
+ if (i == u->slot)
+ continue;
+ disk = get_imsm_disk(super, get_imsm_disk_idx(dev, i));
+ if (!disk ||
+ __le32_to_cpu(disk->status) & FAILED_DISK)
+ failed++;
+ }
+
/* adding a pristine spare, assign a new index */
if (dl->index < 0) {
dl->index = super->anchor->num_disks;
super->anchor->num_disks++;
}
- victim = get_imsm_disk_idx(dev, u->slot);
- set_imsm_ord_tbl_ent(map, u->slot, dl->index);
disk = &dl->disk;
status = __le32_to_cpu(disk->status);
status |= CONFIGURED_DISK;
status &= ~SPARE_DISK;
disk->status = __cpu_to_le32(status);
+ /* mark rebuild */
+ to_state = imsm_check_degraded(super, dev, failed);
+ map->map_state = IMSM_T_STATE_DEGRADED;
+ migrate(dev, to_state, 1);
+ migr_map = get_imsm_map(dev, 1);
+ set_imsm_ord_tbl_ent(map, u->slot, dl->index);
+ set_imsm_ord_tbl_ent(migr_map, u->slot, dl->index | IMSM_ORD_REBUILD);
+
/* count arrays using the victim in the metadata */
found = 0;
for (a = st->arrays; a ; a = a->next) {