From 9f4218274cd4a1e1f356a1617f9a1d09960cf255 Mon Sep 17 00:00:00 2001 From: Pawel Baldysiak Date: Mon, 28 Jan 2019 17:10:41 +0100 Subject: [PATCH] imsm: fix reshape for >2TB drives Git-commit: 9f4218274cd4a1e1f356a1617f9a1d09960cf255 Patch-mainline: mdadm-4.1+ References: jsc#SLE-10078, jsc#SLE-9348 If reshape is performed on drives larger then 2 TB, migration checkpoint area that is calculated exeeds 32-bit value. This checkpoint area is a reserved space threated as backup during reshape - at the end of the drive, right before metadata. As a result - wrong space is used and the data that may exists there is overwritten. Adding additional field to migration record to track high order 32-bits of pba of this area. Three other fields that may exceed 32-bit value for large drives are added as well. Signed-off-by: Pawel Baldysiak Signed-off-by: Jes Sorensen Signed-off-by: Coly Li --- super-intel.c | 149 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 107 insertions(+), 42 deletions(-) diff --git a/super-intel.c b/super-intel.c index 38a1b6c..1cc7d5f 100644 --- a/super-intel.c +++ b/super-intel.c @@ -296,7 +296,7 @@ struct migr_record { __u32 rec_status; /* Status used to determine how to restart * migration in case it aborts * in some fashion */ - __u32 curr_migr_unit; /* 0..numMigrUnits-1 */ + __u32 curr_migr_unit_lo; /* 0..numMigrUnits-1 */ __u32 family_num; /* Family number of MPB * containing the RaidDev * that is migrating */ @@ -306,16 +306,23 @@ struct migr_record { __u32 dest_depth_per_unit; /* Num member blocks each destMap * member disk * advances per unit-of-operation */ - __u32 ckpt_area_pba; /* Pba of first block of ckpt copy area */ - __u32 dest_1st_member_lba; /* First member lba on first - * stripe of destination */ - __u32 num_migr_units; /* Total num migration units-of-op */ + __u32 ckpt_area_pba_lo; /* Pba of first block of ckpt copy area */ + __u32 dest_1st_member_lba_lo; /* First member lba on first + * stripe of destination */ + __u32 num_migr_units_lo; /* Total num migration units-of-op */ __u32 post_migr_vol_cap; /* Size of volume after * migration completes */ __u32 post_migr_vol_cap_hi; /* Expansion space for LBA64 */ __u32 ckpt_read_disk_num; /* Which member disk in destSubMap[0] the * migration ckpt record was read from * (for recovered migrations) */ + __u32 curr_migr_unit_hi; /* 0..numMigrUnits-1 high order 32 bits */ + __u32 ckpt_area_pba_hi; /* Pba of first block of ckpt copy area + * high order 32 bits */ + __u32 dest_1st_member_lba_hi; /* First member lba on first stripe of + * destination - high order 32 bits */ + __u32 num_migr_units_hi; /* Total num migration units-of-op + * high order 32 bits */ } __attribute__ ((__packed__)); struct md_list { @@ -1208,6 +1215,38 @@ static unsigned long long imsm_dev_size(struct imsm_dev *dev) return join_u32(dev->size_low, dev->size_high); } +static unsigned long long migr_chkp_area_pba(struct migr_record *migr_rec) +{ + if (migr_rec == NULL) + return 0; + return join_u32(migr_rec->ckpt_area_pba_lo, + migr_rec->ckpt_area_pba_hi); +} + +static unsigned long long current_migr_unit(struct migr_record *migr_rec) +{ + if (migr_rec == NULL) + return 0; + return join_u32(migr_rec->curr_migr_unit_lo, + migr_rec->curr_migr_unit_hi); +} + +static unsigned long long migr_dest_1st_member_lba(struct migr_record *migr_rec) +{ + if (migr_rec == NULL) + return 0; + return join_u32(migr_rec->dest_1st_member_lba_lo, + migr_rec->dest_1st_member_lba_hi); +} + +static unsigned long long get_num_migr_units(struct migr_record *migr_rec) +{ + if (migr_rec == NULL) + return 0; + return join_u32(migr_rec->num_migr_units_lo, + migr_rec->num_migr_units_hi); +} + static void set_total_blocks(struct imsm_disk *disk, unsigned long long n) { split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi); @@ -1233,6 +1272,33 @@ static void set_imsm_dev_size(struct imsm_dev *dev, unsigned long long n) split_ull(n, &dev->size_low, &dev->size_high); } +static void set_migr_chkp_area_pba(struct migr_record *migr_rec, + unsigned long long n) +{ + split_ull(n, &migr_rec->ckpt_area_pba_lo, &migr_rec->ckpt_area_pba_hi); +} + +static void set_current_migr_unit(struct migr_record *migr_rec, + unsigned long long n) +{ + split_ull(n, &migr_rec->curr_migr_unit_lo, + &migr_rec->curr_migr_unit_hi); +} + +static void set_migr_dest_1st_member_lba(struct migr_record *migr_rec, + unsigned long long n) +{ + split_ull(n, &migr_rec->dest_1st_member_lba_lo, + &migr_rec->dest_1st_member_lba_hi); +} + +static void set_num_migr_units(struct migr_record *migr_rec, + unsigned long long n) +{ + split_ull(n, &migr_rec->num_migr_units_lo, + &migr_rec->num_migr_units_hi); +} + static unsigned long long per_dev_array_size(struct imsm_map *map) { unsigned long long array_size = 0; @@ -1629,12 +1695,14 @@ void convert_to_4k_imsm_migr_rec(struct intel_super *super) struct migr_record *migr_rec = super->migr_rec; migr_rec->blocks_per_unit /= IMSM_4K_DIV; - migr_rec->ckpt_area_pba /= IMSM_4K_DIV; - migr_rec->dest_1st_member_lba /= IMSM_4K_DIV; migr_rec->dest_depth_per_unit /= IMSM_4K_DIV; split_ull((join_u32(migr_rec->post_migr_vol_cap, migr_rec->post_migr_vol_cap_hi) / IMSM_4K_DIV), &migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap_hi); + set_migr_chkp_area_pba(migr_rec, + migr_chkp_area_pba(migr_rec) / IMSM_4K_DIV); + set_migr_dest_1st_member_lba(migr_rec, + migr_dest_1st_member_lba(migr_rec) / IMSM_4K_DIV); } void convert_to_4k_imsm_disk(struct imsm_disk *disk) @@ -1727,8 +1795,8 @@ void examine_migr_rec_imsm(struct intel_super *super) printf("Normal\n"); else printf("Contains Data\n"); - printf(" Current Unit : %u\n", - __le32_to_cpu(migr_rec->curr_migr_unit)); + printf(" Current Unit : %llu\n", + current_migr_unit(migr_rec)); printf(" Family : %u\n", __le32_to_cpu(migr_rec->family_num)); printf(" Ascending : %u\n", @@ -1737,16 +1805,15 @@ void examine_migr_rec_imsm(struct intel_super *super) __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(" Checkpoint Area pba : %llu\n", + migr_chkp_area_pba(migr_rec)); + printf(" First member lba : %llu\n", + migr_dest_1st_member_lba(migr_rec)); + printf(" Total Number of Units : %llu\n", + get_num_migr_units(migr_rec)); + printf(" Size of volume : %llu\n", + join_u32(migr_rec->post_migr_vol_cap, + migr_rec->post_migr_vol_cap_hi)); printf(" Record was read from : %u\n", __le32_to_cpu(migr_rec->ckpt_read_disk_num)); @@ -1759,13 +1826,15 @@ void convert_from_4k_imsm_migr_rec(struct intel_super *super) struct migr_record *migr_rec = super->migr_rec; migr_rec->blocks_per_unit *= IMSM_4K_DIV; - migr_rec->ckpt_area_pba *= IMSM_4K_DIV; - migr_rec->dest_1st_member_lba *= IMSM_4K_DIV; migr_rec->dest_depth_per_unit *= IMSM_4K_DIV; split_ull((join_u32(migr_rec->post_migr_vol_cap, migr_rec->post_migr_vol_cap_hi) * IMSM_4K_DIV), &migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap_hi); + set_migr_chkp_area_pba(migr_rec, + migr_chkp_area_pba(migr_rec) * IMSM_4K_DIV); + set_migr_dest_1st_member_lba(migr_rec, + migr_dest_1st_member_lba(migr_rec) * IMSM_4K_DIV); } void convert_from_4k(struct intel_super *super) @@ -3096,7 +3165,7 @@ static int imsm_create_metadata_checkpoint_update( return 0; } (*u)->type = update_general_migration_checkpoint; - (*u)->curr_migr_unit = __le32_to_cpu(super->migr_rec->curr_migr_unit); + (*u)->curr_migr_unit = current_migr_unit(super->migr_rec); dprintf("prepared for %u\n", (*u)->curr_migr_unit); return update_memory_size; @@ -3397,13 +3466,13 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, case MIGR_GEN_MIGR: { __u64 blocks_per_unit = blocks_per_migr_unit(super, dev); - __u64 units = __le32_to_cpu(migr_rec->curr_migr_unit); + __u64 units = current_migr_unit(migr_rec); unsigned long long array_blocks; int used_disks; if (__le32_to_cpu(migr_rec->ascending_migr) && (units < - (__le32_to_cpu(migr_rec->num_migr_units)-1)) && + (get_num_migr_units(migr_rec)-1)) && (super->migr_rec->rec_status == __cpu_to_le32(UNIT_SRC_IN_CP_AREA))) units++; @@ -10697,7 +10766,7 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev, if (array_blocks % __le32_to_cpu(migr_rec->blocks_per_unit)) num_migr_units++; - migr_rec->num_migr_units = __cpu_to_le32(num_migr_units); + set_num_migr_units(migr_rec, num_migr_units); migr_rec->post_migr_vol_cap = dev->size_low; migr_rec->post_migr_vol_cap_hi = dev->size_high; @@ -10714,7 +10783,7 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev, min_dev_sectors = dev_sectors; close(fd); } - migr_rec->ckpt_area_pba = __cpu_to_le32(min_dev_sectors - + set_migr_chkp_area_pba(migr_rec, min_dev_sectors - RAID_DISK_RESERVED_BLOCKS_IMSM_HI); write_imsm_migr_rec(st); @@ -10765,8 +10834,7 @@ int save_backup_imsm(struct supertype *st, start = info->reshape_progress * 512; for (i = 0; i < new_disks; i++) { - target_offsets[i] = (unsigned long long) - __le32_to_cpu(super->migr_rec->ckpt_area_pba) * 512; + target_offsets[i] = migr_chkp_area_pba(super->migr_rec) * 512; /* move back copy area adderss, it will be moved forward * in restore_stripes() using start input variable */ @@ -10845,12 +10913,11 @@ int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state) if (info->reshape_progress % blocks_per_unit) curr_migr_unit++; - super->migr_rec->curr_migr_unit = - __cpu_to_le32(curr_migr_unit); + set_current_migr_unit(super->migr_rec, curr_migr_unit); super->migr_rec->rec_status = __cpu_to_le32(state); - super->migr_rec->dest_1st_member_lba = - __cpu_to_le32(curr_migr_unit * - __le32_to_cpu(super->migr_rec->dest_depth_per_unit)); + set_migr_dest_1st_member_lba(super->migr_rec, + super->migr_rec->dest_depth_per_unit * curr_migr_unit); + if (write_imsm_migr_rec(st) < 0) { dprintf("imsm: Cannot write migration record outside backup area\n"); return 1; @@ -10884,8 +10951,8 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info) char *buf = NULL; int retval = 1; unsigned int sector_size = super->sector_size; - 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); + unsigned long curr_migr_unit = current_migr_unit(migr_rec); + unsigned long num_migr_units = get_num_migr_units(migr_rec); char buffer[20]; int skipped_disks = 0; @@ -10912,11 +10979,9 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info) map_dest = get_imsm_map(id->dev, MAP_0); new_disks = map_dest->num_members; - read_offset = (unsigned long long) - __le32_to_cpu(migr_rec->ckpt_area_pba) * 512; + read_offset = migr_chkp_area_pba(migr_rec) * 512; - write_offset = ((unsigned long long) - __le32_to_cpu(migr_rec->dest_1st_member_lba) + + write_offset = (migr_dest_1st_member_lba(migr_rec) + pba_of_lba0(map_dest)) * 512; unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512; @@ -12019,12 +12084,12 @@ static int imsm_manage_reshape( max_position = sra->component_size * ndata; source_layout = imsm_level_to_layout(map_src->raid_level); - while (__le32_to_cpu(migr_rec->curr_migr_unit) < - __le32_to_cpu(migr_rec->num_migr_units)) { + while (current_migr_unit(migr_rec) < + get_num_migr_units(migr_rec)) { /* current reshape position [blocks] */ unsigned long long current_position = __le32_to_cpu(migr_rec->blocks_per_unit) - * __le32_to_cpu(migr_rec->curr_migr_unit); + * current_migr_unit(migr_rec); unsigned long long border; /* Check that array hasn't become failed. -- 2.25.0