}
#ifndef MDASSEMBLE
-static __u64 blocks_per_migr_unit(struct imsm_dev *dev);
+static __u64 blocks_per_migr_unit(struct intel_super *super,
+ struct imsm_dev *dev);
-static void print_imsm_dev(struct imsm_dev *dev, char *uuid, int disk_idx)
+static void print_imsm_dev(struct intel_super *super,
+ struct imsm_dev *dev,
+ char *uuid,
+ int disk_idx)
{
__u64 sz;
int slot, i;
printf(" <-- %s", map_state_str[map->map_state]);
printf("\n Checkpoint : %u (%llu)",
__le32_to_cpu(dev->vol.curr_migr_unit),
- (unsigned long long)blocks_per_migr_unit(dev));
+ (unsigned long long)blocks_per_migr_unit(super, dev));
}
printf("\n");
printf(" Dirty State : %s\n", dev->vol.dirty ? "dirty" : "clean");
human_size(sz * 512));
}
+static int is_gen_migration(struct imsm_dev *dev);
+
+void examine_migr_rec_imsm(struct intel_super *super)
+{
+ struct migr_record *migr_rec = super->migr_rec;
+ struct imsm_super *mpb = super->anchor;
+ int i;
+
+ for (i = 0; i < mpb->num_raid_devs; i++) {
+ struct imsm_dev *dev = __get_imsm_dev(mpb, i);
+ if (is_gen_migration(dev) == 0)
+ continue;
+
+ printf("\nMigration Record Information:");
+ if (super->disks->index > 1) {
+ printf(" Empty\n ");
+ printf("Examine one of first two disks in array\n");
+ break;
+ }
+ printf("\n Status : ");
+ if (__le32_to_cpu(migr_rec->rec_status) == UNIT_SRC_NORMAL)
+ printf("Normal\n");
+ else
+ printf("Contains Data\n");
+ printf(" Current Unit : %u\n",
+ __le32_to_cpu(migr_rec->curr_migr_unit));
+ printf(" Family : %u\n",
+ __le32_to_cpu(migr_rec->family_num));
+ printf(" Ascending : %u\n",
+ __le32_to_cpu(migr_rec->ascending_migr));
+ printf(" Blocks Per Unit : %u\n",
+ __le32_to_cpu(migr_rec->blocks_per_unit));
+ printf(" Dest. Depth Per Unit : %u\n",
+ __le32_to_cpu(migr_rec->dest_depth_per_unit));
+ printf(" Checkpoint Area pba : %u\n",
+ __le32_to_cpu(migr_rec->ckpt_area_pba));
+ printf(" First member lba : %u\n",
+ __le32_to_cpu(migr_rec->dest_1st_member_lba));
+ printf(" Total Number of Units : %u\n",
+ __le32_to_cpu(migr_rec->num_migr_units));
+ printf(" Size of volume : %u\n",
+ __le32_to_cpu(migr_rec->post_migr_vol_cap));
+ printf(" Expansion space for LBA64 : %u\n",
+ __le32_to_cpu(migr_rec->post_migr_vol_cap_hi));
+ printf(" Record was read from : %u\n",
+ __le32_to_cpu(migr_rec->ckpt_read_disk_num));
+
+ break;
+ }
+}
+
static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *map);
static void examine_super_imsm(struct supertype *st, char *homehost)
super->current_vol = i;
getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(st, &info, nbuf, ':');
- print_imsm_dev(dev, nbuf + 5, super->disks->index);
+ print_imsm_dev(super, dev, nbuf + 5, super->disks->index);
}
for (i = 0; i < mpb->num_disks; i++) {
if (i == super->disks->index)
printf(" Usable Size : %llu%s\n", (unsigned long long)sz,
human_size(sz * 512));
}
+
+ examine_migr_rec_imsm(super);
}
static void brief_examine_super_imsm(struct supertype *st, int verbose)
}
}
-static __u64 blocks_per_migr_unit(struct imsm_dev *dev)
+static __u64 blocks_per_migr_unit(struct intel_super *super,
+ struct imsm_dev *dev)
{
/* calculate the conversion factor between per member 'blocks'
* (md/{resync,rebuild}_start) and imsm migration units, return
return 0;
switch (migr_type(dev)) {
- case MIGR_GEN_MIGR:
+ case MIGR_GEN_MIGR: {
+ struct migr_record *migr_rec = super->migr_rec;
+ return __le32_to_cpu(migr_rec->blocks_per_unit);
+ }
case MIGR_VERIFY:
case MIGR_REPAIR:
case MIGR_INIT: {
static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
{
struct intel_super *super = st->sb;
+ struct migr_record *migr_rec = super->migr_rec;
struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
struct imsm_map *map = get_imsm_map(dev, 0);
struct imsm_map *prev_map = get_imsm_map(dev, 1);
switch (migr_type(dev)) {
case MIGR_REPAIR:
case MIGR_INIT: {
- __u64 blocks_per_unit = blocks_per_migr_unit(dev);
+ __u64 blocks_per_unit = blocks_per_migr_unit(super,
+ dev);
__u64 units = __le32_to_cpu(dev->vol.curr_migr_unit);
info->resync_start = blocks_per_unit * units;
break;
}
case MIGR_GEN_MIGR: {
- __u64 blocks_per_unit = blocks_per_migr_unit(dev);
- __u64 units = __le32_to_cpu(dev->vol.curr_migr_unit);
+ __u64 blocks_per_unit = blocks_per_migr_unit(super,
+ dev);
+ __u64 units = __le32_to_cpu(migr_rec->curr_migr_unit);
unsigned long long array_blocks;
int used_disks;
return 0;
}
+static int is_gen_migration(struct imsm_dev *dev);
+
static int write_super_imsm(struct supertype *st, int doclose)
{
struct intel_super *super = st->sb;
int i;
__u32 mpb_size = sizeof(struct imsm_super) - sizeof(struct imsm_disk);
int num_disks = 0;
+ int clear_migration_record = 1;
/* 'generation' is incremented everytime the metadata is written */
generation = __le32_to_cpu(mpb->generation_num);
imsm_copy_dev(dev, dev2);
mpb_size += sizeof_imsm_dev(dev, 0);
}
+ if (is_gen_migration(dev2))
+ clear_migration_record = 0;
}
mpb_size += __le32_to_cpu(mpb->bbm_log_size);
mpb->mpb_size = __cpu_to_le32(mpb_size);
sum = __gen_imsm_checksum(mpb);
mpb->check_sum = __cpu_to_le32(sum);
+ if (clear_migration_record)
+ memset(super->migr_rec_buf, 0, 512);
+
/* write the mpb for disks that compose raid devices */
for (d = super->disks; d ; d = d->next) {
if (d->index < 0)
if (store_imsm_mpb(d->fd, mpb))
fprintf(stderr, "%s: failed for device %d:%d %s\n",
__func__, d->major, d->minor, strerror(errno));
+ if (clear_migration_record) {
+ unsigned long long dsize;
+
+ get_dev_size(d->fd, NULL, &dsize);
+ if (lseek64(d->fd, dsize - 512, SEEK_SET) >= 0) {
+ write(d->fd, super->migr_rec_buf, 512);
+ }
+ }
if (doclose) {
close(d->fd);
d->fd = -1;
return 0;
}
-static void update_recovery_start(struct imsm_dev *dev, struct mdinfo *array)
+static void update_recovery_start(struct intel_super *super,
+ struct imsm_dev *dev,
+ struct mdinfo *array)
{
struct mdinfo *rebuild = NULL;
struct mdinfo *d;
}
units = __le32_to_cpu(dev->vol.curr_migr_unit);
- rebuild->recovery_start = units * blocks_per_migr_unit(dev);
+ 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)
{
info_d->component_size = __le32_to_cpu(map->blocks_per_member);
}
/* now that the disk list is up-to-date fixup recovery_start */
- update_recovery_start(dev, this);
+ 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;
}
}
mark_checkpoint:
+ /* skip checkpointing for general migration,
+ * it is controlled in mdadm
+ */
+ if (is_gen_migration(dev))
+ goto skip_mark_checkpoint;
+
/* check if we can update curr_migr_unit from resync_start, recovery_start */
- blocks_per_unit = blocks_per_migr_unit(dev);
+ blocks_per_unit = blocks_per_migr_unit(super, dev);
if (blocks_per_unit) {
__u32 units32;
__u64 units;
}
}
+skip_mark_checkpoint:
/* mark dirty / clean */
if (dev->vol.dirty != !consistent) {
dprintf("imsm: mark '%s'\n", consistent ? "clean" : "dirty");
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)
sysfs_set_num(sra, NULL, "suspend_hi", next_step);
/* wait until reshape finish */
- if (wait_for_reshape_imsm(sra, next_step, ndata) < 0)
- dprintf("wait_for_reshape_imsm returned error,"
- " but we ignore it!\n");
+ if (wait_for_reshape_imsm(sra, next_step, ndata) < 0) {
+ dprintf("wait_for_reshape_imsm returned error!\n");
+ goto abort;
+ }
sra->reshape_progress = next_step;
.match_metadata_desc = match_metadata_desc_imsm,
.container_content = container_content_imsm,
+ .recover_backup = recover_backup_imsm,
+
.external = 1,
.name = "imsm",