diff options
author | NeilBrown <neilb@suse.de> | 2010-12-16 15:48:05 +1100 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2010-12-16 15:48:05 +1100 |
commit | aad6f216a1c667ddfbb9a4a4c379ff32f69f962f (patch) | |
tree | 62c078397ae841a5f71df8a585151ba22853af4f | |
parent | 1af97990a6c8930c97f7943f0dac4b775c688274 (diff) |
Handle checkpointing during reshape
We need to allow metadata to handle progress of reshape,
completion, and abort-before-start.
Include all those in ->set_array_state()
Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r-- | managemon.c | 6 | ||||
-rw-r--r-- | monitor.c | 16 | ||||
-rw-r--r-- | super-intel.c | 56 |
3 files changed, 69 insertions, 9 deletions
diff --git a/managemon.c b/managemon.c index 860e5785..9cb80499 100644 --- a/managemon.c +++ b/managemon.c @@ -503,6 +503,7 @@ static void manage_member(struct mdstat_ent *mdstat, * and look for new stuff. */ struct mdinfo *info, *d, *d2, *newd; + unsigned long long array_size; struct active_array *newa = NULL; a->check_reshape = 0; info = sysfs_read(-1, mdstat->devnum, @@ -529,6 +530,11 @@ static void manage_member(struct mdstat_ent *mdstat, continue; disk_init_and_add(newd, d, newa); } + if (sysfs_get_ll(info, NULL, "array_size", &array_size) == 0 + && a->info.custom_array_size > array_size) { + sysfs_set_num(info, NULL, "array_size", + a->info.custom_array_size); + } out2: sysfs_free(info); if (newa) @@ -339,8 +339,8 @@ static int read_and_act(struct active_array *a) /* Check for recovery checkpoint notifications. We need to be a * minimum distance away from the last checkpoint to prevent - * over checkpointing. Note reshape checkpointing is not - * handled here. + * over checkpointing. Note reshape checkpointing is handled + * in the second branch. */ if (sync_completed > a->last_checkpoint && sync_completed - a->last_checkpoint > a->info.component_size >> 4 && @@ -350,7 +350,17 @@ static int read_and_act(struct active_array *a) */ a->last_checkpoint = sync_completed; a->container->ss->set_array_state(a, a->curr_state <= clean); - } else if (sync_completed > a->last_checkpoint) + } else if ((a->curr_action == idle && a->prev_action == reshape) || + (a->curr_action == reshape + && sync_completed > a->last_checkpoint) ) { + /* Reshape has progressed or completed so we need to + * update the array state - and possibly the array size + */ + a->last_checkpoint = sync_completed; + a->container->ss->set_array_state(a, a->curr_state <= clean); + } + + if (sync_completed > a->last_checkpoint) a->last_checkpoint = sync_completed; a->container->ss->sync_metadata(a->container); diff --git a/super-intel.c b/super-intel.c index 8fd49344..3182d474 100644 --- a/super-intel.c +++ b/super-intel.c @@ -1503,6 +1503,7 @@ static __u64 blocks_per_migr_unit(struct imsm_dev *dev) return migr_chunk * stripes_per_unit; } case MIGR_GEN_MIGR: + /* FIXME I need a number here */ case MIGR_STATE_CHANGE: default: return 0; @@ -4825,7 +4826,7 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev) static void imsm_set_disk(struct active_array *a, int n, int state); -/* Handle dirty -> clean transititions and resync. Degraded and rebuild +/* Handle dirty -> clean transititions, resync and reshape. 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. @@ -4843,12 +4844,55 @@ static int imsm_set_array_state(struct active_array *a, int consistent) if (dev->vol.migr_state && dev->vol.migr_type == MIGR_GEN_MIGR) { /* array state change is blocked due to reshape action - * - * '1' is returned to indicate that array is clean + * We might need to + * - abort the reshape (if last_checkpoint is 0 and action!= reshape) + * - finish the reshape (if last_checkpoint is big and action != reshape) + * - update curr_migr_unit */ - dprintf("imsm: imsm_set_array_state() called "\ - "during reshape.\n"); - return 1; + if (a->curr_action == reshape) { + /* still reshaping, maybe update curr_migr_unit */ + long long blocks_per_unit = blocks_per_migr_unit(dev); + long long unit = a->last_checkpoint; + unit /= blocks_per_unit; + if (unit > __le32_to_cpu(dev->vol.curr_migr_unit)) { + dev->vol.curr_migr_unit = __cpu_to_le32(unit); + super->updates_pending++; + } + } else { + if (a->last_checkpoint == 0 && a->prev_action == reshape) { + /* for some reason we aborted the reshape. + * Better clean up + */ + struct imsm_map *map2 = get_imsm_map(dev, 1); + dev->vol.migr_state = 0; + dev->vol.migr_type = 0; + dev->vol.curr_migr_unit = 0; + memcpy(map, map2, sizeof_imsm_map(map2)); + super->updates_pending++; + } + if (a->last_checkpoint >= a->info.component_size) { + unsigned long long array_blocks; + int used_disks; + /* it seems the reshape is all done */ + dev->vol.migr_state = 0; + dev->vol.migr_type = 0; + dev->vol.curr_migr_unit = 0; + + used_disks = imsm_num_data_members(dev); + array_blocks = map->blocks_per_member * used_disks; + /* round array size down to closest MB */ + array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) + << SECT_PER_MB_SHIFT; + dev->size_low = __cpu_to_le32((__u32) array_blocks); + dev->size_high = __cpu_to_le32((__u32) (array_blocks >> 32)); + a->info.custom_array_size = array_blocks; + a->check_reshape = 1; /* encourage manager to update + * array size + */ + super->updates_pending++; + } + } + return 0; } /* before we activate this array handle any missing disks */ |