#define MAX_SIGNATURE_LENGTH 32
#define MAX_RAID_SERIAL_LEN 16
-#define MPB_ATTRIB_CHECKSUM_VERIFY __cpu_to_le32(0x80000000)
-#define MPB_ATTRIB_PM __cpu_to_le32(0x40000000)
-#define MPB_ATTRIB_2TB __cpu_to_le32(0x20000000)
-#define MPB_ATTRIB_RAID0 __cpu_to_le32(0x00000001)
-#define MPB_ATTRIB_RAID1 __cpu_to_le32(0x00000002)
-#define MPB_ATTRIB_RAID10 __cpu_to_le32(0x00000004)
-#define MPB_ATTRIB_RAID1E __cpu_to_le32(0x00000008)
-#define MPB_ATTRIB_RAID5 __cpu_to_le32(0x00000010)
-#define MPB_ATTRIB_RAIDCNG __cpu_to_le32(0x00000020)
+/* supports RAID0 */
+#define MPB_ATTRIB_RAID0 __cpu_to_le32(0x00000001)
+/* supports RAID1 */
+#define MPB_ATTRIB_RAID1 __cpu_to_le32(0x00000002)
+/* supports RAID10 */
+#define MPB_ATTRIB_RAID10 __cpu_to_le32(0x00000004)
+/* supports RAID1E */
+#define MPB_ATTRIB_RAID1E __cpu_to_le32(0x00000008)
+/* supports RAID5 */
+#define MPB_ATTRIB_RAID5 __cpu_to_le32(0x00000010)
+/* supports RAID CNG */
+#define MPB_ATTRIB_RAIDCNG __cpu_to_le32(0x00000020)
+/* supports expanded stripe sizes of 256K, 512K and 1MB */
+#define MPB_ATTRIB_EXP_STRIPE_SIZE __cpu_to_le32(0x00000040)
+
+/* The OROM Support RST Caching of Volumes */
+#define MPB_ATTRIB_NVM __cpu_to_le32(0x02000000)
+/* The OROM supports creating disks greater than 2TB */
+#define MPB_ATTRIB_2TB_DISK __cpu_to_le32(0x04000000)
+/* The OROM supports Bad Block Management */
+#define MPB_ATTRIB_BBM __cpu_to_le32(0x08000000)
+
+/* THe OROM Supports NVM Caching of Volumes */
+#define MPB_ATTRIB_NEVER_USE2 __cpu_to_le32(0x10000000)
+/* The OROM supports creating volumes greater than 2TB */
+#define MPB_ATTRIB_2TB __cpu_to_le32(0x20000000)
+/* originally for PMP, now it's wasted b/c. Never use this bit! */
+#define MPB_ATTRIB_NEVER_USE __cpu_to_le32(0x40000000)
+/* Verify MPB contents against checksum after reading MPB */
+#define MPB_ATTRIB_CHECKSUM_VERIFY __cpu_to_le32(0x80000000)
+
+/* Define all supported attributes that have to be accepted by mdadm
+ */
+#define MPB_ATTRIB_SUPPORTED (MPB_ATTRIB_CHECKSUM_VERIFY | \
+ MPB_ATTRIB_2TB | \
+ MPB_ATTRIB_2TB_DISK | \
+ MPB_ATTRIB_RAID0 | \
+ MPB_ATTRIB_RAID1 | \
+ MPB_ATTRIB_RAID10 | \
+ MPB_ATTRIB_RAID5 | \
+ MPB_ATTRIB_EXP_STRIPE_SIZE)
+
+/* Define attributes that are unused but not harmful */
+#define MPB_ATTRIB_IGNORED (MPB_ATTRIB_NEVER_USE)
#define MPB_SECTOR_CNT 2210
#define IMSM_RESERVED_SECTORS 4096
struct extent *e; /* for determining freespace @ create */
int raiddisk; /* slot to fill in autolayout */
enum action action;
- } *disks;
+ } *disks, *current_disk;
struct dl *disk_mgmt_list; /* list of disks to add/remove while mdmon
active */
struct dl *missing; /* disks removed while we weren't looking */
{
return &mpb->sig[MPB_SIG_LEN];
}
-#endif
+#endif
/* retrieve a disk directly from the anchor when the anchor is known to be
* up-to-date, currently only at load time
break;
}
}
+#endif /* MDASSEMBLE */
+/*******************************************************************************
+ * function: imsm_check_attributes
+ * Description: Function checks if features represented by attributes flags
+ * are supported by mdadm.
+ * Parameters:
+ * attributes - Attributes read from metadata
+ * Returns:
+ * 0 - passed attributes contains unsupported features flags
+ * 1 - all features are supported
+ ******************************************************************************/
+static int imsm_check_attributes(__u32 attributes)
+{
+ int ret_val = 1;
+ __u32 not_supported = MPB_ATTRIB_SUPPORTED^0xffffffff;
+ not_supported &= ~MPB_ATTRIB_IGNORED;
+
+ not_supported &= attributes;
+ if (not_supported) {
+ fprintf(stderr, Name "(IMSM): Unsupported attributes : %x\n",
+ (unsigned)__le32_to_cpu(not_supported));
+ if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
+ dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n");
+ not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY;
+ }
+ if (not_supported & MPB_ATTRIB_2TB) {
+ dprintf("\t\tMPB_ATTRIB_2TB\n");
+ not_supported ^= MPB_ATTRIB_2TB;
+ }
+ if (not_supported & MPB_ATTRIB_RAID0) {
+ dprintf("\t\tMPB_ATTRIB_RAID0\n");
+ not_supported ^= MPB_ATTRIB_RAID0;
+ }
+ if (not_supported & MPB_ATTRIB_RAID1) {
+ dprintf("\t\tMPB_ATTRIB_RAID1\n");
+ not_supported ^= MPB_ATTRIB_RAID1;
+ }
+ if (not_supported & MPB_ATTRIB_RAID10) {
+ dprintf("\t\tMPB_ATTRIB_RAID10\n");
+ not_supported ^= MPB_ATTRIB_RAID10;
+ }
+ if (not_supported & MPB_ATTRIB_RAID1E) {
+ dprintf("\t\tMPB_ATTRIB_RAID1E\n");
+ not_supported ^= MPB_ATTRIB_RAID1E;
+ }
+ if (not_supported & MPB_ATTRIB_RAID5) {
+ dprintf("\t\tMPB_ATTRIB_RAID5\n");
+ not_supported ^= MPB_ATTRIB_RAID5;
+ }
+ if (not_supported & MPB_ATTRIB_RAIDCNG) {
+ dprintf("\t\tMPB_ATTRIB_RAIDCNG\n");
+ not_supported ^= MPB_ATTRIB_RAIDCNG;
+ }
+ if (not_supported & MPB_ATTRIB_BBM) {
+ dprintf("\t\tMPB_ATTRIB_BBM\n");
+ not_supported ^= MPB_ATTRIB_BBM;
+ }
+ if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
+ dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY (== MPB_ATTRIB_LEGACY)\n");
+ not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY;
+ }
+ if (not_supported & MPB_ATTRIB_EXP_STRIPE_SIZE) {
+ dprintf("\t\tMPB_ATTRIB_EXP_STRIP_SIZE\n");
+ not_supported ^= MPB_ATTRIB_EXP_STRIPE_SIZE;
+ }
+ if (not_supported & MPB_ATTRIB_2TB_DISK) {
+ dprintf("\t\tMPB_ATTRIB_2TB_DISK\n");
+ not_supported ^= MPB_ATTRIB_2TB_DISK;
+ }
+ if (not_supported & MPB_ATTRIB_NEVER_USE2) {
+ dprintf("\t\tMPB_ATTRIB_NEVER_USE2\n");
+ not_supported ^= MPB_ATTRIB_NEVER_USE2;
+ }
+ if (not_supported & MPB_ATTRIB_NEVER_USE) {
+ dprintf("\t\tMPB_ATTRIB_NEVER_USE\n");
+ not_supported ^= MPB_ATTRIB_NEVER_USE;
+ }
+
+ if (not_supported)
+ dprintf(Name "(IMSM): Unknown attributes : %x\n", not_supported);
+
+ ret_val = 0;
+ }
+
+ return ret_val;
+}
+
+#ifndef MDASSEMBLE
static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *map);
static void examine_super_imsm(struct supertype *st, char *homehost)
printf(" Orig Family : %08x\n", __le32_to_cpu(mpb->orig_family_num));
printf(" Family : %08x\n", __le32_to_cpu(mpb->family_num));
printf(" Generation : %08x\n", __le32_to_cpu(mpb->generation_num));
+ printf(" Attributes : ");
+ if (imsm_check_attributes(mpb->attributes))
+ printf("All supported\n");
+ else
+ printf("not supported\n");
getinfo_super_imsm(st, &info, NULL);
fname_from_uuid(st, &info, nbuf, ':');
printf(" UUID : %s\n", nbuf + 5);
fd2devname(fd, buf);
printf(" Port%d : %s", port, buf);
if (imsm_read_serial(fd, NULL, (__u8 *) buf) == 0)
- printf(" (%s)\n", buf);
+ printf(" (%.*s)\n", MAX_RAID_SERIAL_LEN, buf);
else
- printf("()\n");
+ printf(" ()\n");
}
close(fd);
free(path);
return err;
}
-
-
static void print_found_intel_controllers(struct sys_dev *elem)
{
for (; elem; elem = elem->next) {
return retval;
}
+#ifndef MDASSEMBLE
/*******************************************************************************
* function: imsm_create_metadata_checkpoint_update
* Description: It creates update for checkpoint change.
close(fd);
return retval;
}
+#endif /* MDASSEMBLE */
static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
{
if (prev_map)
map_to_analyse = prev_map;
- dl = super->disks;
+ dl = super->current_disk;
info->container_member = super->current_vol;
info->array.raid_disks = map->num_members;
/* conversion is happening as RAID5 */
info->array.level = 5;
info->array.layout = ALGORITHM_PARITY_N;
- info->array.raid_disks += 1;
info->delta_disks -= 1;
break;
default:
info->new_chunk = info->array.chunk_size;
info->delta_disks = 0;
}
- info->disk.major = 0;
- info->disk.minor = 0;
+
if (dl) {
info->disk.major = dl->major;
info->disk.minor = dl->minor;
+ info->disk.number = dl->index;
+ info->disk.raid_disk = get_imsm_disk_slot(map_to_analyse,
+ dl->index);
}
info->data_offset = __le32_to_cpu(map_to_analyse->pba_of_lba0);
dprintf("IMSM: General Migration checkpoint : %llu "
"(%llu) -> read reshape progress : %llu\n",
- units, blocks_per_unit, info->reshape_progress);
+ (unsigned long long)units,
+ (unsigned long long)blocks_per_unit,
+ info->reshape_progress);
used_disks = imsm_num_data_members(dev, 1);
if (used_disks > 0) {
devname);
return 1;
}
- set_imsm_ord_tbl_ent(map, dk->number, dl->index);
+ set_imsm_ord_tbl_ent(map, dk->raid_disk, dl->index);
dl->disk.status = CONFIGURED_DISK;
/* if we are creating the first raid device update the family number */
mpb->family_num = __cpu_to_le32(sum);
mpb->orig_family_num = mpb->family_num;
}
-
+ super->current_disk = dl;
return 0;
}
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;
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 (write(d->fd, super->migr_rec_buf, 512) != 512)
+ perror("Write migr_rec failed");
}
}
if (doclose) {
return 0;
}
+static int imsm_default_chunk(const struct imsm_orom *orom)
+{
+ /* up to 512 if the plaform supports it, otherwise the platform max.
+ * 128 if no platform detected
+ */
+ int fs = max(7, orom ? fls(orom->sss) : 0);
+
+ return min(512, (1 << fs));
+}
#define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
/*
level, raiddisks, raiddisks > 1 ? "s" : "");
return 0;
}
- if (super->orom && level != 1) {
- if (chunk && (*chunk == 0 || *chunk == UnSet))
- *chunk = imsm_orom_default_chunk(super->orom);
- else if (chunk && !imsm_orom_has_chunk(super->orom, *chunk)) {
- pr_vrb(": platform does not support a chunk size of: "
- "%d\n", *chunk);
- return 0;
- }
+
+ if (chunk && (*chunk == 0 || *chunk == UnSet))
+ *chunk = imsm_default_chunk(super->orom);
+
+ if (super->orom && chunk && !imsm_orom_has_chunk(super->orom, *chunk)) {
+ pr_vrb(": platform does not support a chunk size of: "
+ "%d\n", *chunk);
+ return 0;
}
+
if (layout != imsm_level_to_layout(level)) {
if (level == 5)
pr_vrb(": imsm raid 5 only supports the left-asymmetric layout\n");
if (level && layout && *layout == UnSet)
*layout = imsm_level_to_layout(*level);
- if (chunk && (*chunk == UnSet || *chunk == 0) &&
- super && super->orom)
- *chunk = imsm_orom_default_chunk(super->orom);
+ if (chunk && (*chunk == UnSet || *chunk == 0))
+ *chunk = imsm_default_chunk(super->orom);
}
static void handle_missing(struct intel_super *super, struct imsm_dev *dev);
static int is_gen_migration(struct imsm_dev *dev)
{
+ if (dev == NULL)
+ return 0;
+
if (!dev->vol.migr_state)
return 0;
rebuild->recovery_start = units * blocks_per_migr_unit(super, dev);
}
+#ifndef MDASSEMBLE
static int recover_backup_imsm(struct supertype *st, struct mdinfo *info);
+#endif
static struct mdinfo *container_content_imsm(struct supertype *st, char *subarray)
{
struct dl *d;
int spare_disks = 0;
+ /* do not assemble arrays when not all attributes are supported */
+ if (imsm_check_attributes(mpb->attributes) == 0) {
+ fprintf(stderr, Name ": IMSM metadata loading not allowed "
+ "due to attributes incompatibility.\n");
+ return NULL;
+ }
+
/* check for bad blocks */
if (imsm_bbm_log_size(super->anchor))
bbm_errors = 1;
update_recovery_start(super, dev, this);
this->array.spare_disks += spare_disks;
+#ifndef MDASSEMBLE
/* check for reshape */
if (this->reshape_active == 1)
recover_backup_imsm(st, this);
-
+#endif
rest = this;
}
} else {
if (a->last_checkpoint == 0 && a->prev_action == reshape) {
/* for some reason we aborted the reshape.
- * Better clean up
+ *
+ * disable automatic metadata rollback
+ * user action is required to recover process
*/
+ if (0) {
struct imsm_map *map2 = get_imsm_map(dev, 1);
dev->vol.migr_state = 0;
dev->vol.migr_type = 0;
dev->vol.curr_migr_unit = 0;
memcpy(map, map2, sizeof_imsm_map(map2));
super->updates_pending++;
+ }
}
if (a->last_checkpoint >= a->info.component_size) {
unsigned long long array_blocks;
for (du = super->missing; du; du = du->next)
if (du->index >= 0) {
set_imsm_ord_tbl_ent(map, du->index, du->index);
- mark_missing(dev_new, &du->disk, du->index);
+ mark_missing(dv->dev, &du->disk, du->index);
}
return 1;
__free_imsm_disk(dl);
}
}
-
+#endif /* MDASSEMBLE */
/*******************************************************************************
* Function: open_backup_targets
* Description: Function opens file descriptors for all devices given in
return 0;
}
+#ifndef MDASSEMBLE
/*******************************************************************************
* Function: init_migr_record_imsm
* Description: Function inits imsm migration record
int new_disks = map_dest->num_members;
int dest_layout = 0;
int dest_chunk;
+ unsigned long long start;
+ int data_disks = imsm_num_data_members(dev, 0);
targets = malloc(new_disks * sizeof(int));
if (!targets)
goto abort;
+ for (i = 0; i < new_disks; i++)
+ targets[i] = -1;
+
target_offsets = malloc(new_disks * sizeof(unsigned long long));
if (!target_offsets)
goto abort;
+ start = info->reshape_progress * 512;
for (i = 0; i < new_disks; i++) {
- targets[i] = -1;
target_offsets[i] = (unsigned long long)
__le32_to_cpu(super->migr_rec->ckpt_area_pba) * 512;
+ /* move back copy area adderss, it will be moved forward
+ * in restore_stripes() using start input variable
+ */
+ target_offsets[i] -= start/data_disks;
}
if (open_backup_targets(info, new_disks, targets))
goto abort;
- if (map_dest->raid_level != 0)
- dest_layout = ALGORITHM_LEFT_ASYMMETRIC;
+ dest_layout = imsm_level_to_layout(map_dest->raid_level);
dest_chunk = __le16_to_cpu(map_dest->blocks_per_strip) * 512;
if (restore_stripes(targets, /* list of dest devices */
-1, /* source backup file descriptor */
0, /* input buf offset
* always 0 buf is already offseted */
- 0,
+ start,
length,
buf) != 0) {
fprintf(stderr, Name ": Error restoring stripes\n");
int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state)
{
struct intel_super *super = st->sb;
+ unsigned long long blocks_per_unit;
+ unsigned long long curr_migr_unit;
+
if (load_imsm_migr_rec(super, info) != 0) {
dprintf("imsm: ERROR: Cannot read migration record "
"for checkpoint save.\n");
return 1;
}
- if (__le32_to_cpu(super->migr_rec->blocks_per_unit) == 0) {
+ blocks_per_unit = __le32_to_cpu(super->migr_rec->blocks_per_unit);
+ if (blocks_per_unit == 0) {
dprintf("imsm: no migration in progress.\n");
return 2;
}
+ curr_migr_unit = info->reshape_progress / blocks_per_unit;
+ /* check if array is alligned to copy area
+ * if it is not alligned, add one to current migration unit value
+ * this can happend on array reshape finish only
+ */
+ if (info->reshape_progress % blocks_per_unit)
+ curr_migr_unit++;
super->migr_rec->curr_migr_unit =
- __cpu_to_le32(info->reshape_progress /
- __le32_to_cpu(super->migr_rec->blocks_per_unit));
+ __cpu_to_le32(curr_migr_unit);
super->migr_rec->rec_status = __cpu_to_le32(state);
super->migr_rec->dest_1st_member_lba =
- __cpu_to_le32((__le32_to_cpu(super->migr_rec->curr_migr_unit))
- * __le32_to_cpu(super->migr_rec->dest_depth_per_unit));
+ __cpu_to_le32(curr_migr_unit *
+ __le32_to_cpu(super->migr_rec->dest_depth_per_unit));
if (write_imsm_migr_rec(st) < 0) {
dprintf("imsm: Cannot write migration record "
"outside backup area\n");
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
strerror(errno));
goto abort;
}
- if (read(targets[i], buf, unit_len) != unit_len) {
+ if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
fprintf(stderr,
Name ": Cannot read copy area block: %s\n",
strerror(errno));
strerror(errno));
goto abort;
}
- if (write(targets[i], buf, unit_len) != unit_len) {
+ if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
fprintf(stderr,
Name ": Cannot restore block: %s\n",
strerror(errno));
|| delta_disks > spares->array.spare_disks) {
fprintf(stderr, Name ": imsm: ERROR: Cannot get spare devices "
"for %s.\n", geo->dev_name);
+ i = -1;
goto abort;
}
dprintf("imsm: info: Volume operation\n");
/* find requested device */
while (dev) {
- imsm_find_array_minor_by_subdev(dev->index, st->container_dev, &devnum);
- if (devnum == geo.dev_id)
+ if (imsm_find_array_minor_by_subdev(
+ dev->index, st->container_dev, &devnum) == 0
+ && devnum == geo.dev_id)
break;
dev = dev->next;
}
}
max_position = sra->component_size * ndata;
- if (map_src->raid_level != 0)
- source_layout = ALGORITHM_LEFT_ASYMMETRIC;
+ 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)) {
"migration record (UNIT_SRC_IN_CP_AREA)\n");
goto abort;
}
+ } else {
+ /* set next step to use whole border area */
+ border /= next_step;
+ if (border > 1)
+ next_step *= border;
}
/* When data backed up, checkpoint stored,
* kick the kernel to reshape unit of data
*/
next_step = next_step + sra->reshape_progress;
+ /* limit next step to array max position */
+ if (next_step > max_position)
+ next_step = max_position;
sysfs_set_num(sra, NULL, "suspend_lo", sra->reshape_progress);
sysfs_set_num(sra, NULL, "suspend_hi", next_step);
sra->reshape_progress = next_step;
.get_disk_controller_domain = imsm_get_disk_controller_domain,
.reshape_super = imsm_reshape_super,
.manage_reshape = imsm_manage_reshape,
+ .recover_backup = recover_backup_imsm,
#endif
.match_home = match_home_imsm,
.uuid_from_super= uuid_from_super_imsm,
.match_metadata_desc = match_metadata_desc_imsm,
.container_content = container_content_imsm,
- .recover_backup = recover_backup_imsm,
.external = 1,
.name = "imsm",