imsm: fix reshape for >2TB drives
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 <pawel.baldysiak@intel.com> Signed-off-by: Jes Sorensen <jsorensen@fb.com>
This commit is contained in:
parent
a4e96fd8f3
commit
9f4218274c
149
super-intel.c
149
super-intel.c
|
@ -296,7 +296,7 @@ struct migr_record {
|
||||||
__u32 rec_status; /* Status used to determine how to restart
|
__u32 rec_status; /* Status used to determine how to restart
|
||||||
* migration in case it aborts
|
* migration in case it aborts
|
||||||
* in some fashion */
|
* 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
|
__u32 family_num; /* Family number of MPB
|
||||||
* containing the RaidDev
|
* containing the RaidDev
|
||||||
* that is migrating */
|
* that is migrating */
|
||||||
|
@ -306,16 +306,23 @@ struct migr_record {
|
||||||
__u32 dest_depth_per_unit; /* Num member blocks each destMap
|
__u32 dest_depth_per_unit; /* Num member blocks each destMap
|
||||||
* member disk
|
* member disk
|
||||||
* advances per unit-of-operation */
|
* advances per unit-of-operation */
|
||||||
__u32 ckpt_area_pba; /* Pba of first block of ckpt copy area */
|
__u32 ckpt_area_pba_lo; /* Pba of first block of ckpt copy area */
|
||||||
__u32 dest_1st_member_lba; /* First member lba on first
|
__u32 dest_1st_member_lba_lo; /* First member lba on first
|
||||||
* stripe of destination */
|
* stripe of destination */
|
||||||
__u32 num_migr_units; /* Total num migration units-of-op */
|
__u32 num_migr_units_lo; /* Total num migration units-of-op */
|
||||||
__u32 post_migr_vol_cap; /* Size of volume after
|
__u32 post_migr_vol_cap; /* Size of volume after
|
||||||
* migration completes */
|
* migration completes */
|
||||||
__u32 post_migr_vol_cap_hi; /* Expansion space for LBA64 */
|
__u32 post_migr_vol_cap_hi; /* Expansion space for LBA64 */
|
||||||
__u32 ckpt_read_disk_num; /* Which member disk in destSubMap[0] the
|
__u32 ckpt_read_disk_num; /* Which member disk in destSubMap[0] the
|
||||||
* migration ckpt record was read from
|
* migration ckpt record was read from
|
||||||
* (for recovered migrations) */
|
* (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__));
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
struct md_list {
|
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);
|
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)
|
static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
|
||||||
{
|
{
|
||||||
split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
|
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);
|
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)
|
static unsigned long long per_dev_array_size(struct imsm_map *map)
|
||||||
{
|
{
|
||||||
unsigned long long array_size = 0;
|
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;
|
struct migr_record *migr_rec = super->migr_rec;
|
||||||
|
|
||||||
migr_rec->blocks_per_unit /= IMSM_4K_DIV;
|
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;
|
migr_rec->dest_depth_per_unit /= IMSM_4K_DIV;
|
||||||
split_ull((join_u32(migr_rec->post_migr_vol_cap,
|
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_hi) / IMSM_4K_DIV),
|
||||||
&migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap_hi);
|
&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)
|
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");
|
printf("Normal\n");
|
||||||
else
|
else
|
||||||
printf("Contains Data\n");
|
printf("Contains Data\n");
|
||||||
printf(" Current Unit : %u\n",
|
printf(" Current Unit : %llu\n",
|
||||||
__le32_to_cpu(migr_rec->curr_migr_unit));
|
current_migr_unit(migr_rec));
|
||||||
printf(" Family : %u\n",
|
printf(" Family : %u\n",
|
||||||
__le32_to_cpu(migr_rec->family_num));
|
__le32_to_cpu(migr_rec->family_num));
|
||||||
printf(" Ascending : %u\n",
|
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));
|
__le32_to_cpu(migr_rec->blocks_per_unit));
|
||||||
printf(" Dest. Depth Per Unit : %u\n",
|
printf(" Dest. Depth Per Unit : %u\n",
|
||||||
__le32_to_cpu(migr_rec->dest_depth_per_unit));
|
__le32_to_cpu(migr_rec->dest_depth_per_unit));
|
||||||
printf(" Checkpoint Area pba : %u\n",
|
printf(" Checkpoint Area pba : %llu\n",
|
||||||
__le32_to_cpu(migr_rec->ckpt_area_pba));
|
migr_chkp_area_pba(migr_rec));
|
||||||
printf(" First member lba : %u\n",
|
printf(" First member lba : %llu\n",
|
||||||
__le32_to_cpu(migr_rec->dest_1st_member_lba));
|
migr_dest_1st_member_lba(migr_rec));
|
||||||
printf(" Total Number of Units : %u\n",
|
printf(" Total Number of Units : %llu\n",
|
||||||
__le32_to_cpu(migr_rec->num_migr_units));
|
get_num_migr_units(migr_rec));
|
||||||
printf(" Size of volume : %u\n",
|
printf(" Size of volume : %llu\n",
|
||||||
__le32_to_cpu(migr_rec->post_migr_vol_cap));
|
join_u32(migr_rec->post_migr_vol_cap,
|
||||||
printf(" Expansion space for LBA64 : %u\n",
|
migr_rec->post_migr_vol_cap_hi));
|
||||||
__le32_to_cpu(migr_rec->post_migr_vol_cap_hi));
|
|
||||||
printf(" Record was read from : %u\n",
|
printf(" Record was read from : %u\n",
|
||||||
__le32_to_cpu(migr_rec->ckpt_read_disk_num));
|
__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;
|
struct migr_record *migr_rec = super->migr_rec;
|
||||||
|
|
||||||
migr_rec->blocks_per_unit *= IMSM_4K_DIV;
|
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;
|
migr_rec->dest_depth_per_unit *= IMSM_4K_DIV;
|
||||||
split_ull((join_u32(migr_rec->post_migr_vol_cap,
|
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_hi) * IMSM_4K_DIV),
|
||||||
&migr_rec->post_migr_vol_cap,
|
&migr_rec->post_migr_vol_cap,
|
||||||
&migr_rec->post_migr_vol_cap_hi);
|
&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)
|
void convert_from_4k(struct intel_super *super)
|
||||||
|
@ -3096,7 +3165,7 @@ static int imsm_create_metadata_checkpoint_update(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
(*u)->type = update_general_migration_checkpoint;
|
(*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);
|
dprintf("prepared for %u\n", (*u)->curr_migr_unit);
|
||||||
|
|
||||||
return update_memory_size;
|
return update_memory_size;
|
||||||
|
@ -3397,13 +3466,13 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
|
||||||
case MIGR_GEN_MIGR: {
|
case MIGR_GEN_MIGR: {
|
||||||
__u64 blocks_per_unit = blocks_per_migr_unit(super,
|
__u64 blocks_per_unit = blocks_per_migr_unit(super,
|
||||||
dev);
|
dev);
|
||||||
__u64 units = __le32_to_cpu(migr_rec->curr_migr_unit);
|
__u64 units = current_migr_unit(migr_rec);
|
||||||
unsigned long long array_blocks;
|
unsigned long long array_blocks;
|
||||||
int used_disks;
|
int used_disks;
|
||||||
|
|
||||||
if (__le32_to_cpu(migr_rec->ascending_migr) &&
|
if (__le32_to_cpu(migr_rec->ascending_migr) &&
|
||||||
(units <
|
(units <
|
||||||
(__le32_to_cpu(migr_rec->num_migr_units)-1)) &&
|
(get_num_migr_units(migr_rec)-1)) &&
|
||||||
(super->migr_rec->rec_status ==
|
(super->migr_rec->rec_status ==
|
||||||
__cpu_to_le32(UNIT_SRC_IN_CP_AREA)))
|
__cpu_to_le32(UNIT_SRC_IN_CP_AREA)))
|
||||||
units++;
|
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))
|
if (array_blocks % __le32_to_cpu(migr_rec->blocks_per_unit))
|
||||||
num_migr_units++;
|
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 = dev->size_low;
|
||||||
migr_rec->post_migr_vol_cap_hi = dev->size_high;
|
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;
|
min_dev_sectors = dev_sectors;
|
||||||
close(fd);
|
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);
|
RAID_DISK_RESERVED_BLOCKS_IMSM_HI);
|
||||||
|
|
||||||
write_imsm_migr_rec(st);
|
write_imsm_migr_rec(st);
|
||||||
|
@ -10765,8 +10834,7 @@ int save_backup_imsm(struct supertype *st,
|
||||||
|
|
||||||
start = info->reshape_progress * 512;
|
start = info->reshape_progress * 512;
|
||||||
for (i = 0; i < new_disks; i++) {
|
for (i = 0; i < new_disks; i++) {
|
||||||
target_offsets[i] = (unsigned long long)
|
target_offsets[i] = migr_chkp_area_pba(super->migr_rec) * 512;
|
||||||
__le32_to_cpu(super->migr_rec->ckpt_area_pba) * 512;
|
|
||||||
/* move back copy area adderss, it will be moved forward
|
/* move back copy area adderss, it will be moved forward
|
||||||
* in restore_stripes() using start input variable
|
* 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)
|
if (info->reshape_progress % blocks_per_unit)
|
||||||
curr_migr_unit++;
|
curr_migr_unit++;
|
||||||
|
|
||||||
super->migr_rec->curr_migr_unit =
|
set_current_migr_unit(super->migr_rec, curr_migr_unit);
|
||||||
__cpu_to_le32(curr_migr_unit);
|
|
||||||
super->migr_rec->rec_status = __cpu_to_le32(state);
|
super->migr_rec->rec_status = __cpu_to_le32(state);
|
||||||
super->migr_rec->dest_1st_member_lba =
|
set_migr_dest_1st_member_lba(super->migr_rec,
|
||||||
__cpu_to_le32(curr_migr_unit *
|
super->migr_rec->dest_depth_per_unit * curr_migr_unit);
|
||||||
__le32_to_cpu(super->migr_rec->dest_depth_per_unit));
|
|
||||||
if (write_imsm_migr_rec(st) < 0) {
|
if (write_imsm_migr_rec(st) < 0) {
|
||||||
dprintf("imsm: Cannot write migration record outside backup area\n");
|
dprintf("imsm: Cannot write migration record outside backup area\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -10884,8 +10951,8 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
unsigned int sector_size = super->sector_size;
|
unsigned int sector_size = super->sector_size;
|
||||||
unsigned long curr_migr_unit = __le32_to_cpu(migr_rec->curr_migr_unit);
|
unsigned long curr_migr_unit = current_migr_unit(migr_rec);
|
||||||
unsigned long num_migr_units = __le32_to_cpu(migr_rec->num_migr_units);
|
unsigned long num_migr_units = get_num_migr_units(migr_rec);
|
||||||
char buffer[20];
|
char buffer[20];
|
||||||
int skipped_disks = 0;
|
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);
|
map_dest = get_imsm_map(id->dev, MAP_0);
|
||||||
new_disks = map_dest->num_members;
|
new_disks = map_dest->num_members;
|
||||||
|
|
||||||
read_offset = (unsigned long long)
|
read_offset = migr_chkp_area_pba(migr_rec) * 512;
|
||||||
__le32_to_cpu(migr_rec->ckpt_area_pba) * 512;
|
|
||||||
|
|
||||||
write_offset = ((unsigned long long)
|
write_offset = (migr_dest_1st_member_lba(migr_rec) +
|
||||||
__le32_to_cpu(migr_rec->dest_1st_member_lba) +
|
|
||||||
pba_of_lba0(map_dest)) * 512;
|
pba_of_lba0(map_dest)) * 512;
|
||||||
|
|
||||||
unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 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;
|
max_position = sra->component_size * ndata;
|
||||||
source_layout = imsm_level_to_layout(map_src->raid_level);
|
source_layout = imsm_level_to_layout(map_src->raid_level);
|
||||||
|
|
||||||
while (__le32_to_cpu(migr_rec->curr_migr_unit) <
|
while (current_migr_unit(migr_rec) <
|
||||||
__le32_to_cpu(migr_rec->num_migr_units)) {
|
get_num_migr_units(migr_rec)) {
|
||||||
/* current reshape position [blocks] */
|
/* current reshape position [blocks] */
|
||||||
unsigned long long current_position =
|
unsigned long long current_position =
|
||||||
__le32_to_cpu(migr_rec->blocks_per_unit)
|
__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;
|
unsigned long long border;
|
||||||
|
|
||||||
/* Check that array hasn't become failed.
|
/* Check that array hasn't become failed.
|
||||||
|
|
Loading…
Reference in New Issue