diff --git a/super-intel.c b/super-intel.c index d5bab17..2d79fd8 100644 --- a/super-intel.c +++ b/super-intel.c @@ -5293,6 +5293,7 @@ static void update_recovery_start(struct intel_super *super, rebuild->recovery_start = units * blocks_per_migr_unit(super, dev); } +static int recover_backup_imsm(struct supertype *st, struct mdinfo *info); static struct mdinfo *container_content_imsm(struct supertype *st, char *subarray) { @@ -5456,6 +5457,11 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra /* now that the disk list is up-to-date fixup recovery_start */ update_recovery_start(super, dev, this); this->array.spare_disks += spare_disks; + + /* check for reshape */ + if (this->reshape_active == 1) + recover_backup_imsm(st, this); + rest = this; } @@ -7678,6 +7684,126 @@ int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state) return 0; } +static __u64 blocks_per_migr_unit(struct intel_super *super, + struct imsm_dev *dev); + +/******************************************************************************* + * Function: recover_backup_imsm + * Description: Function recovers critical data from the Migration Copy Area + * while assembling an array. + * Parameters: + * super : imsm internal array info + * info : general array info + * Returns: + * 0 : success (or there is no data to recover) + * 1 : fail + ******************************************************************************/ +int recover_backup_imsm(struct supertype *st, struct mdinfo *info) +{ + struct intel_super *super = st->sb; + struct migr_record *migr_rec = super->migr_rec; + struct imsm_map *map_dest = NULL; + struct intel_dev *id = NULL; + unsigned long long read_offset; + unsigned long long write_offset; + unsigned unit_len; + int *targets = NULL; + int new_disks, i, err; + char *buf = NULL; + int retval = 1; + unsigned long curr_migr_unit = __le32_to_cpu(migr_rec->curr_migr_unit); + unsigned long num_migr_units = __le32_to_cpu(migr_rec->num_migr_units); + int ascending = __le32_to_cpu(migr_rec->ascending_migr); + char buffer[20]; + + err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, 20); + if (err < 1) + return 1; + + /* recover data only during assemblation */ + if (strncmp(buffer, "inactive", 8) != 0) + return 0; + /* no data to recover */ + if (__le32_to_cpu(migr_rec->rec_status) == UNIT_SRC_NORMAL) + return 0; + if (curr_migr_unit >= num_migr_units) + return 1; + + /* find device during reshape */ + for (id = super->devlist; id; id = id->next) + if (is_gen_migration(id->dev)) + break; + if (id == NULL) + return 1; + + map_dest = get_imsm_map(id->dev, 0); + new_disks = map_dest->num_members; + + read_offset = (unsigned long long) + __le32_to_cpu(migr_rec->ckpt_area_pba) * 512; + + write_offset = ((unsigned long long) + __le32_to_cpu(migr_rec->dest_1st_member_lba) + + info->data_offset) * 512; + + unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512; + if (posix_memalign((void **)&buf, 512, unit_len) != 0) + goto abort; + targets = malloc(new_disks * sizeof(int)); + if (!targets) + goto abort; + + open_backup_targets(info, new_disks, targets); + + for (i = 0; i < new_disks; i++) { + if (lseek64(targets[i], read_offset, SEEK_SET) < 0) { + fprintf(stderr, + Name ": Cannot seek to block: %s\n", + strerror(errno)); + goto abort; + } + if (read(targets[i], buf, unit_len) != unit_len) { + fprintf(stderr, + Name ": Cannot read copy area block: %s\n", + strerror(errno)); + goto abort; + } + if (lseek64(targets[i], write_offset, SEEK_SET) < 0) { + fprintf(stderr, + Name ": Cannot seek to block: %s\n", + strerror(errno)); + goto abort; + } + if (write(targets[i], buf, unit_len) != unit_len) { + fprintf(stderr, + Name ": Cannot restore block: %s\n", + strerror(errno)); + goto abort; + } + } + + if (ascending && curr_migr_unit < (num_migr_units-1)) + curr_migr_unit++; + + migr_rec->curr_migr_unit = __le32_to_cpu(curr_migr_unit); + super->migr_rec->rec_status = __cpu_to_le32(UNIT_SRC_NORMAL); + if (write_imsm_migr_rec(st) == 0) { + __u64 blocks_per_unit = blocks_per_migr_unit(super, id->dev); + info->reshape_progress = curr_migr_unit * blocks_per_unit; + retval = 0; + } + +abort: + if (targets) { + for (i = 0; i < new_disks; i++) + if (targets[i]) + close(targets[i]); + free(targets); + } + free(buf); + return retval; +} + static char disk_by_path[] = "/dev/disk/by-path/"; static const char *imsm_get_disk_controller_domain(const char *path) @@ -8695,6 +8821,8 @@ struct superswitch super_imsm = { .match_metadata_desc = match_metadata_desc_imsm, .container_content = container_content_imsm, + .recover_backup = recover_backup_imsm, + .external = 1, .name = "imsm",