imsm: use saved fds during migration

IMSM super keeps open descriptors in super->disks structure, they are
reliable and should be chosen if possible. The repeatedly called open
and close during reshape generates redundant udev change events on
each member drive.

Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
This commit is contained in:
Mariusz Tkaczyk 2021-01-13 09:58:45 +01:00 committed by Jes Sorensen
parent f7a6246bab
commit 2f86fda346
1 changed files with 55 additions and 155 deletions

View File

@ -3055,15 +3055,13 @@ static struct imsm_dev *imsm_get_device_during_migration(
* sector of disk)
* Parameters:
* super : imsm internal array info
* info : general array info
* Returns:
* 0 : success
* -1 : fail
* -2 : no migration in progress
******************************************************************************/
static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
static int load_imsm_migr_rec(struct intel_super *super)
{
struct mdinfo *sd;
struct dl *dl;
char nm[30];
int retval = -1;
@ -3071,6 +3069,7 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
struct imsm_dev *dev;
struct imsm_map *map;
int slot = -1;
int keep_fd = 1;
/* find map under migration */
dev = imsm_get_device_during_migration(super);
@ -3079,44 +3078,40 @@ static int load_imsm_migr_rec(struct intel_super *super, struct mdinfo *info)
if (dev == NULL)
return -2;
if (info) {
for (sd = info->devs ; sd ; sd = sd->next) {
/* read only from one of the first two slots */
if ((sd->disk.raid_disk < 0) ||
(sd->disk.raid_disk > 1))
continue;
map = get_imsm_map(dev, MAP_0);
if (!map)
return -1;
sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
fd = dev_open(nm, O_RDONLY);
if (fd >= 0)
break;
}
}
if (fd < 0) {
map = get_imsm_map(dev, MAP_0);
for (dl = super->disks; dl; dl = dl->next) {
/* skip spare and failed disks
*/
if (dl->index < 0)
continue;
/* read only from one of the first two slots */
if (map)
slot = get_imsm_disk_slot(map, dl->index);
if (map == NULL || slot > 1 || slot < 0)
continue;
for (dl = super->disks; dl; dl = dl->next) {
/* skip spare and failed disks
*/
if (dl->index < 0)
continue;
/* read only from one of the first two slots
*/
slot = get_imsm_disk_slot(map, dl->index);
if (slot > 1 || slot < 0)
continue;
if (dl->fd < 0) {
sprintf(nm, "%d:%d", dl->major, dl->minor);
fd = dev_open(nm, O_RDONLY);
if (fd >= 0)
if (fd >= 0) {
keep_fd = 0;
break;
}
} else {
fd = dl->fd;
break;
}
}
if (fd < 0)
goto out;
retval = read_imsm_migr_rec(fd, super);
out:
if (fd >= 0)
if (fd < 0)
return retval;
retval = read_imsm_migr_rec(fd, super);
if (!keep_fd)
close(fd);
return retval;
}
@ -3177,8 +3172,6 @@ static int write_imsm_migr_rec(struct supertype *st)
struct intel_super *super = st->sb;
unsigned int sector_size = super->sector_size;
unsigned long long dsize;
char nm[30];
int fd = -1;
int retval = -1;
struct dl *sd;
int len;
@ -3211,26 +3204,21 @@ static int write_imsm_migr_rec(struct supertype *st)
if (map == NULL || slot > 1 || slot < 0)
continue;
sprintf(nm, "%d:%d", sd->major, sd->minor);
fd = dev_open(nm, O_RDWR);
if (fd < 0)
continue;
get_dev_size(fd, NULL, &dsize);
if (lseek64(fd, dsize - (MIGR_REC_SECTOR_POSITION*sector_size),
get_dev_size(sd->fd, NULL, &dsize);
if (lseek64(sd->fd, dsize - (MIGR_REC_SECTOR_POSITION *
sector_size),
SEEK_SET) < 0) {
pr_err("Cannot seek to anchor block: %s\n",
strerror(errno));
goto out;
}
if ((unsigned int)write(fd, super->migr_rec_buf,
if ((unsigned int)write(sd->fd, super->migr_rec_buf,
MIGR_REC_BUF_SECTORS*sector_size) !=
MIGR_REC_BUF_SECTORS*sector_size) {
pr_err("Cannot write migr record block: %s\n",
strerror(errno));
goto out;
}
close(fd);
fd = -1;
}
if (sector_size == 4096)
convert_from_4k_imsm_migr_rec(super);
@ -3256,8 +3244,6 @@ static int write_imsm_migr_rec(struct supertype *st)
retval = 0;
out:
if (fd >= 0)
close(fd);
return retval;
}
@ -5011,7 +4997,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
}
/* load migration record */
err = load_imsm_migr_rec(super, NULL);
err = load_imsm_migr_rec(super);
if (err == -1) {
/* migration is in progress,
* but migr_rec cannot be loaded,
@ -5260,7 +5246,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
}
/* load migration record */
if (load_imsm_migr_rec(super, NULL) == 0) {
if (load_imsm_migr_rec(super) == 0) {
/* Check for unsupported migration features */
if (check_mpb_migr_compatibility(super) != 0) {
pr_err("Unsupported migration detected");
@ -10381,21 +10367,6 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind
}
}
static void close_targets(int *targets, int new_disks)
{
int i;
if (!targets)
return;
for (i = 0; i < new_disks; i++) {
if (targets[i] >= 0) {
close(targets[i]);
targets[i] = -1;
}
}
}
static int imsm_get_allowed_degradation(int level, int raid_disks,
struct intel_super *super,
struct imsm_dev *dev)
@ -10449,62 +10420,6 @@ static int imsm_get_allowed_degradation(int level, int raid_disks,
}
}
/*******************************************************************************
* Function: open_backup_targets
* Description: Function opens file descriptors for all devices given in
* info->devs
* Parameters:
* info : general array info
* raid_disks : number of disks
* raid_fds : table of device's file descriptors
* super : intel super for raid10 degradation check
* dev : intel device for raid10 degradation check
* Returns:
* 0 : success
* -1 : fail
******************************************************************************/
int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds,
struct intel_super *super, struct imsm_dev *dev)
{
struct mdinfo *sd;
int i;
int opened = 0;
for (i = 0; i < raid_disks; i++)
raid_fds[i] = -1;
for (sd = info->devs ; sd ; sd = sd->next) {
char *dn;
if (sd->disk.state & (1<<MD_DISK_FAULTY)) {
dprintf("disk is faulty!!\n");
continue;
}
if (sd->disk.raid_disk >= raid_disks || sd->disk.raid_disk < 0)
continue;
dn = map_dev(sd->disk.major,
sd->disk.minor, 1);
raid_fds[sd->disk.raid_disk] = dev_open(dn, O_RDWR);
if (raid_fds[sd->disk.raid_disk] < 0) {
pr_err("cannot open component\n");
continue;
}
opened++;
}
/* check if maximum array degradation level is not exceeded
*/
if ((raid_disks - opened) >
imsm_get_allowed_degradation(info->new_level, raid_disks,
super, dev)) {
pr_err("Not enough disks can be opened.\n");
close_targets(raid_fds, raid_disks);
return -2;
}
return 0;
}
/*******************************************************************************
* Function: validate_container_imsm
* Description: This routine validates container after assemble,
@ -10745,13 +10660,11 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
int new_data_disks;
unsigned long long dsize, dev_sectors;
long long unsigned min_dev_sectors = -1LLU;
struct mdinfo *sd;
char nm[30];
int fd;
struct imsm_map *map_dest = get_imsm_map(dev, MAP_0);
struct imsm_map *map_src = get_imsm_map(dev, MAP_1);
unsigned long long num_migr_units;
unsigned long long array_blocks;
struct dl *dl_disk = NULL;
memset(migr_rec, 0, sizeof(struct migr_record));
migr_rec->family_num = __cpu_to_le32(super->anchor->family_num);
@ -10780,16 +10693,14 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
migr_rec->post_migr_vol_cap_hi = dev->size_high;
/* Find the smallest dev */
for (sd = info->devs ; sd ; sd = sd->next) {
sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
fd = dev_open(nm, O_RDONLY);
if (fd < 0)
for (dl_disk = super->disks; dl_disk ; dl_disk = dl_disk->next) {
/* ignore spares in container */
if (dl_disk->index < 0)
continue;
get_dev_size(fd, NULL, &dsize);
get_dev_size(dl_disk->fd, NULL, &dsize);
dev_sectors = dsize / 512;
if (dev_sectors < min_dev_sectors)
min_dev_sectors = dev_sectors;
close(fd);
}
set_migr_chkp_area_pba(migr_rec, min_dev_sectors -
RAID_DISK_RESERVED_BLOCKS_IMSM_HI);
@ -10835,8 +10746,11 @@ int save_backup_imsm(struct supertype *st,
targets = xmalloc(new_disks * sizeof(int));
for (i = 0; i < new_disks; i++)
targets[i] = -1;
for (i = 0; i < new_disks; i++) {
struct dl *dl_disk = get_imsm_dl_disk(super, i);
targets[i] = dl_disk->fd;
}
target_offsets = xcalloc(new_disks, sizeof(unsigned long long));
@ -10849,10 +10763,6 @@ int save_backup_imsm(struct supertype *st,
target_offsets[i] -= start/data_disks;
}
if (open_backup_targets(info, new_disks, targets,
super, dev))
goto abort;
dest_layout = imsm_level_to_layout(map_dest->raid_level);
dest_chunk = __le16_to_cpu(map_dest->blocks_per_strip) * 512;
@ -10876,7 +10786,6 @@ int save_backup_imsm(struct supertype *st,
abort:
if (targets) {
close_targets(targets, new_disks);
free(targets);
}
free(target_offsets);
@ -10903,7 +10812,7 @@ int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state)
unsigned long long blocks_per_unit;
unsigned long long curr_migr_unit;
if (load_imsm_migr_rec(super, info) != 0) {
if (load_imsm_migr_rec(super) != 0) {
dprintf("imsm: ERROR: Cannot read migration record for checkpoint save.\n");
return 1;
}
@ -10954,8 +10863,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
unsigned long long read_offset;
unsigned long long write_offset;
unsigned unit_len;
int *targets = NULL;
int new_disks, i, err;
int new_disks, err;
char *buf = NULL;
int retval = 1;
unsigned int sector_size = super->sector_size;
@ -10963,6 +10871,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
unsigned long num_migr_units = get_num_migr_units(migr_rec);
char buffer[20];
int skipped_disks = 0;
struct dl *dl_disk;
err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, 20);
if (err < 1)
@ -10995,37 +10904,34 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
if (posix_memalign((void **)&buf, sector_size, unit_len) != 0)
goto abort;
targets = xcalloc(new_disks, sizeof(int));
if (open_backup_targets(info, new_disks, targets, super, id->dev)) {
pr_err("Cannot open some devices belonging to array.\n");
goto abort;
}
for (dl_disk = super->disks; dl_disk; dl_disk = dl_disk->next) {
if (dl_disk->index < 0)
continue;
for (i = 0; i < new_disks; i++) {
if (targets[i] < 0) {
if (dl_disk->fd < 0) {
skipped_disks++;
continue;
}
if (lseek64(targets[i], read_offset, SEEK_SET) < 0) {
if (lseek64(dl_disk->fd, read_offset, SEEK_SET) < 0) {
pr_err("Cannot seek to block: %s\n",
strerror(errno));
skipped_disks++;
continue;
}
if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
if (read(dl_disk->fd, buf, unit_len) != unit_len) {
pr_err("Cannot read copy area block: %s\n",
strerror(errno));
skipped_disks++;
continue;
}
if (lseek64(targets[i], write_offset, SEEK_SET) < 0) {
if (lseek64(dl_disk->fd, write_offset, SEEK_SET) < 0) {
pr_err("Cannot seek to block: %s\n",
strerror(errno));
skipped_disks++;
continue;
}
if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
if (write(dl_disk->fd, buf, unit_len) != unit_len) {
pr_err("Cannot restore block: %s\n",
strerror(errno));
skipped_disks++;
@ -11049,12 +10955,6 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
retval = 0;
abort:
if (targets) {
for (i = 0; i < new_disks; i++)
if (targets[i])
close(targets[i]);
free(targets);
}
free(buf);
return retval;
}