__u32 filler[IMSM_DISK_FILLERS]; /* 0xF4 - 0x107 MPB_DISK_FILLERS for future expansion */
};
+/* map selector for map managment
+ */
+#define MAP_0 2
+#define MAP_1 4
+
/* RAID map configuration infos. */
struct imsm_map {
__u32 pba_of_lba0; /* start address of partition */
{
/* A device can have 2 maps if it is in the middle of a migration.
* If second_map is:
- * 0 - we return the first map
- * 1 - we return the second map if it exists, else NULL
+ * MAP_0 or 0 - we return the first map
+ * MAP_1 or 1 - we return the second map if it exists, else NULL
* -1 - we return the second map if it exists, else the first
*/
struct imsm_map *map = &dev->vol.map[0];
+ struct imsm_map *map2 = NULL;
- if (second_map == 1 && !dev->vol.migr_state)
- return NULL;
- else if (second_map == 1 ||
- (second_map < 0 && dev->vol.migr_state)) {
- void *ptr = map;
+ if (dev->vol.migr_state)
+ map2 = (void *)map + sizeof_imsm_map(map);
- return ptr + sizeof_imsm_map(map);
- } else
- return map;
+ switch (second_map) {
+ case MAP_0:
+ case 0:
+ break;
+ case MAP_1:
+ case 1:
+ map = map2;
+ break;
+ case -1:
+ if (map2)
+ map = map2;
+ break;
+ default:
+ map = NULL;
+ }
+ return map;
}
struct extent *e;
int i;
unsigned long long rv = 0;
- __u32 reservation;
if (!super)
return rv;
continue;
if (i > 0)
rv = e[i-1].start + e[i-1].size;
- reservation = __le32_to_cpu(dl->disk.total_blocks) - e[i].start;
free(e);
/* add the amount of space needed for metadata */
return rv * 512;
}
+static int is_gen_migration(struct imsm_dev *dev);
+
#ifndef MDASSEMBLE
static __u64 blocks_per_migr_unit(struct intel_super *super,
struct imsm_dev *dev);
struct imsm_map *map = get_imsm_map(dev, 1);
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(super, dev));
+ printf("\n Checkpoint : %u ",
+ __le32_to_cpu(dev->vol.curr_migr_unit));
+ if ((is_gen_migration(dev)) && (super->disks->index > 1))
+ printf("(N/A)");
+ else
+ printf("(%llu)", (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;
printf(" (%.*s)\n", MAX_RAID_SERIAL_LEN, buf);
else
printf(" ()\n");
+ close(fd);
}
- close(fd);
free(path);
path = NULL;
}
*/
for (i_dev = super->devlist; i_dev; i_dev = i_dev->next) {
dev = i_dev->dev;
- if (dev->vol.migr_state &&
- dev->vol.migr_type == MIGR_GEN_MIGR) {
+ if (is_gen_migration(dev)) {
/* No repair during any migration in container
*/
rv = 1;
info->custom_array_size = __le32_to_cpu(dev->size_high);
info->custom_array_size <<= 32;
info->custom_array_size |= __le32_to_cpu(dev->size_low);
- if (prev_map && map->map_state == prev_map->map_state) {
+ info->recovery_blocked = imsm_reshape_blocks_arrays_changes(st->sb);
+
+ if (is_gen_migration(dev)) {
info->reshape_active = 1;
info->new_level = get_imsm_raid_level(map);
info->new_layout = imsm_level_to_layout(info->new_level);
/* this needs to be applied to every array
* in the container.
*/
- info->reshape_active = 2;
+ info->reshape_active = CONTAINER_RESHAPE;
}
/* We shape information that we give to md might have to be
* modify to cope with md's requirement for reshaping arrays.
info->reshape_progress = 0;
info->resync_start = MaxSector;
- if (map_to_analyse->map_state == IMSM_T_STATE_UNINITIALIZED ||
- dev->vol.dirty) {
+ if ((map_to_analyse->map_state == IMSM_T_STATE_UNINITIALIZED ||
+ dev->vol.dirty) &&
+ imsm_reshape_blocks_arrays_changes(super) == 0) {
info->resync_start = 0;
}
if (dev->vol.migr_state) {
}
}
-static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, int failed);
-static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev);
+static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
+ int failed, int look_in_map);
+
+static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
+ int look_in_map);
+
+static void manage_second_map(struct intel_super *super, struct imsm_dev *dev)
+{
+ if (is_gen_migration(dev)) {
+ int failed;
+ __u8 map_state;
+ struct imsm_map *map2 = get_imsm_map(dev, MAP_1);
+
+ failed = imsm_count_failed(super, dev, MAP_1);
+ map_state = imsm_check_degraded(super, dev, failed,
+ MAP_1);
+ if (map2->map_state != map_state) {
+ map2->map_state = map_state;
+ super->updates_pending++;
+ }
+ }
+}
static struct imsm_disk *get_imsm_missing(struct intel_super *super, __u8 index)
{
info->disk.state = 0;
info->name[0] = 0;
info->recovery_start = MaxSector;
+ info->recovery_blocked = imsm_reshape_blocks_arrays_changes(st->sb);
/* do we have the all the insync disks that we expect? */
mpb = super->anchor;
struct imsm_map *map;
__u8 state;
- failed = imsm_count_failed(super, dev);
- state = imsm_check_degraded(super, dev, failed);
- map = get_imsm_map(dev, dev->vol.migr_state);
+ failed = imsm_count_failed(super, dev, MAP_0);
+ state = imsm_check_degraded(super, dev, failed, MAP_0);
+ map = get_imsm_map(dev, 0);
/* any newly missing disks?
* (catches single-degraded vs double-degraded)
*/
for (j = 0; j < map->num_members; j++) {
- __u32 ord = get_imsm_ord_tbl_ent(dev, i, -1);
+ __u32 ord = get_imsm_ord_tbl_ent(dev, j, 0);
__u32 idx = ord_to_idx(ord);
if (!(ord & IMSM_ORD_REBUILD) &&
sprintf(path, "/sys/dev/block/%d:%d",
major(st.st_rdev), minor(st.st_rdev));
- rv = readlink(path, dname, sizeof(dname));
+ rv = readlink(path, dname, sizeof(dname)-1);
if (rv <= 0)
return;
dname[rv] = '\0';
nm = strrchr(dname, '/');
- nm++;
- snprintf(name, MAX_RAID_SERIAL_LEN, "/dev/%s", nm);
+ if (nm) {
+ nm++;
+ snprintf(name, MAX_RAID_SERIAL_LEN, "/dev/%s", nm);
+ }
}
extern int scsi_get_serial(int fd, void *buf, size_t buf_len);
src->map_state = to_state;
}
-static void end_migration(struct imsm_dev *dev, __u8 map_state)
+static void end_migration(struct imsm_dev *dev, struct intel_super *super,
+ __u8 map_state)
{
struct imsm_map *map = get_imsm_map(dev, 0);
struct imsm_map *prev = get_imsm_map(dev, dev->vol.migr_state);
*
* FIXME add support for raid-level-migration
*/
- for (i = 0; i < prev->num_members; i++)
- for (j = 0; j < map->num_members; j++)
- /* during online capacity expansion
- * disks position can be changed if takeover is used
- */
- if (ord_to_idx(map->disk_ord_tbl[j]) ==
- ord_to_idx(prev->disk_ord_tbl[i])) {
- map->disk_ord_tbl[j] |= prev->disk_ord_tbl[i];
- break;
- }
+ if ((map_state != map->map_state) && (is_gen_migration(dev) == 0) &&
+ (prev->map_state != IMSM_T_STATE_UNINITIALIZED)) {
+ /* when final map state is other than expected
+ * merge maps (not for migration)
+ */
+ int failed;
+
+ for (i = 0; i < prev->num_members; i++)
+ for (j = 0; j < map->num_members; j++)
+ /* during online capacity expansion
+ * disks position can be changed
+ * if takeover is used
+ */
+ if (ord_to_idx(map->disk_ord_tbl[j]) ==
+ ord_to_idx(prev->disk_ord_tbl[i])) {
+ map->disk_ord_tbl[j] |=
+ prev->disk_ord_tbl[i];
+ break;
+ }
+ failed = imsm_count_failed(super, dev, MAP_0);
+ map_state = imsm_check_degraded(super, dev, failed, MAP_0);
+ }
dev->vol.migr_state = 0;
- dev->vol.migr_type = 0;
+ set_migr_type(dev, 0);
dev->vol.curr_migr_unit = 0;
map->map_state = map_state;
}
__func__);
free(super->buf);
free(super);
+ free(mpb_new);
return 0;
}
memcpy(mpb_new, mpb, size_old);
map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info));
map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
map->failed_disk_num = ~0;
- map->map_state = info->failed_disks ? IMSM_T_STATE_DEGRADED : IMSM_T_STATE_NORMAL;
+ if (info->level > 0)
+ map->map_state = IMSM_T_STATE_UNINITIALIZED;
+ else
+ map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED :
+ IMSM_T_STATE_NORMAL;
map->ddf = 1;
if (info->level == 1 && info->raid_disks > 2) {
if ((ord & IMSM_ORD_REBUILD) == 0)
continue;
set_imsm_ord_tbl_ent(map, slot, df->index | IMSM_ORD_REBUILD);
+ if (is_gen_migration(dev)) {
+ struct imsm_map *map2 = get_imsm_map(dev, 1);
+ int slot2 = get_imsm_disk_slot(map2, df->index);
+ if ((slot2 < map2->num_members) &&
+ (slot2 >= 0)) {
+ __u32 ord2 = get_imsm_ord_tbl_ent(dev,
+ slot2,
+ 1);
+ if ((unsigned)df->index ==
+ ord_to_idx(ord2))
+ set_imsm_ord_tbl_ent(map2,
+ slot2,
+ df->index |
+ IMSM_ORD_REBUILD);
+ }
+ }
dprintf("set slot:%d to missing disk:%d\n", slot, df->index);
break;
}
{
struct stat stb;
struct intel_super *super = st->sb;
- struct imsm_super *mpb = super->anchor;
+ struct imsm_super *mpb;
struct dl *dl;
unsigned long long pos = 0;
unsigned long long maxsize;
if (!super)
return 0;
+ mpb = super->anchor;
+
if (mpb->num_raid_devs > 0 && mpb->num_disks != raiddisks) {
fprintf(stderr, Name ": the option-rom requires all "
"member disks to be a member of all volumes.\n");
i += dl->extent_cnt;
maxsize = merge_extents(super, i);
+
+ if (!check_env("IMSM_NO_PLATFORM") &&
+ mpb->num_raid_devs > 0 && size && size != maxsize) {
+ fprintf(stderr, Name ": attempting to create a second "
+ "volume with size less then remaining space. "
+ "Aborting...\n");
+ return 0;
+ }
+
if (maxsize < size || maxsize == 0) {
if (verbose)
fprintf(stderr, Name ": not enough space after merge (%llu < %llu)\n",
}
if (!dev) {
- if (st->sb && freesize) {
+ if (st->sb) {
+ if (!validate_geometry_imsm_orom(st->sb, level, layout,
+ raiddisks, chunk,
+ verbose))
+ return 0;
/* we are being asked to automatically layout a
* new volume based on the current contents of
* the container. If the the parameters can be
* created. add_to_super and getinfo_super
* detect when autolayout is in progress.
*/
- if (!validate_geometry_imsm_orom(st->sb, level, layout,
- raiddisks, chunk,
- verbose))
- return 0;
- return reserve_space(st, raiddisks, size,
- chunk?*chunk:0, freesize);
+ if (freesize)
+ return reserve_space(st, raiddisks, size,
+ chunk?*chunk:0, freesize);
}
return 1;
}
return 0;
}
+#endif /* MDASSEMBLE */
static int is_gen_migration(struct imsm_dev *dev)
{
return 0;
}
-#endif /* MDASSEMBLE */
static int is_rebuilding(struct imsm_dev *dev)
{
return 0;
}
+static int is_initializing(struct imsm_dev *dev)
+{
+ struct imsm_map *migr_map;
+
+ if (!dev->vol.migr_state)
+ return 0;
+
+ if (migr_type(dev) != MIGR_INIT)
+ return 0;
+
+ migr_map = get_imsm_map(dev, 1);
+
+ if (migr_map->map_state == IMSM_T_STATE_UNINITIALIZED)
+ return 1;
+
+ return 0;
+
+}
+
static void update_recovery_start(struct intel_super *super,
struct imsm_dev *dev,
struct mdinfo *array)
struct imsm_super *mpb = super->anchor;
struct mdinfo *rest = NULL;
unsigned int i;
- int bbm_errors = 0;
+ int sb_errors = 0;
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;
+ sb_errors = 1;
+ fprintf(stderr, Name ": Unsupported attributes in IMSM metadata."
+ "Arrays activation is blocked.\n");
}
/* check for bad blocks */
- if (imsm_bbm_log_size(super->anchor))
- bbm_errors = 1;
+ if (imsm_bbm_log_size(super->anchor)) {
+ fprintf(stderr, Name ": BBM log found in IMSM metadata."
+ "Arrays activation is blocked.\n");
+ sb_errors = 1;
+ }
+
/* count spare devices, not used in maps
*/
*/
chunk = __le16_to_cpu(map->blocks_per_strip) >> 1;
-#ifndef MDASSEMBLE
- if (!validate_geometry_imsm_orom(super,
- get_imsm_raid_level(map), /* RAID level */
- imsm_level_to_layout(get_imsm_raid_level(map)),
- map->num_members, /* raid disks */
- &chunk,
- 1 /* verbose */)) {
- fprintf(stderr, Name ": RAID gemetry validation failed. "
- "Cannot proceed with the action(s).\n");
- continue;
- }
-#endif /* MDASSEMBLE */
this = malloc(sizeof(*this));
if (!this) {
fprintf(stderr, Name ": failed to allocate %zu bytes\n",
super->current_vol = i;
getinfo_super_imsm_volume(st, this, NULL);
this->next = rest;
+#ifndef MDASSEMBLE
+ /* mdadm does not support all metadata features- set the bit in all arrays state */
+ if (!validate_geometry_imsm_orom(super,
+ get_imsm_raid_level(map), /* RAID level */
+ imsm_level_to_layout(get_imsm_raid_level(map)),
+ map->num_members, /* raid disks */
+ &chunk,
+ 1 /* verbose */)) {
+ fprintf(stderr, Name ": IMSM RAID geometry validation"
+ " failed. Array %s activation is blocked.\n",
+ dev->volume);
+ this->array.state |=
+ (1<<MD_SB_BLOCK_CONTAINER_RESHAPE) |
+ (1<<MD_SB_BLOCK_VOLUME);
+ }
+#endif
+
+ /* if array has bad blocks, set suitable bit in all arrays state */
+ if (sb_errors)
+ this->array.state |=
+ (1<<MD_SB_BLOCK_CONTAINER_RESHAPE) |
+ (1<<MD_SB_BLOCK_VOLUME);
+
for (slot = 0 ; slot < map->num_members; slot++) {
unsigned long long recovery_start;
struct mdinfo *info_d;
rest = this;
}
- /* if array has bad blocks, set suitable bit in array status */
- if (bbm_errors)
- rest->array.state |= (1<<MD_SB_BBM_ERRORS);
-
return rest;
}
-static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, int failed)
+static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev,
+ int failed, int look_in_map)
{
- struct imsm_map *map = get_imsm_map(dev, 0);
+ struct imsm_map *map;
+
+ map = get_imsm_map(dev, look_in_map);
if (!failed)
return map->map_state == IMSM_T_STATE_UNINITIALIZED ?
return map->map_state;
}
-static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev)
+static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev,
+ int look_in_map)
{
int i;
int failed = 0;
struct imsm_disk *disk;
- struct imsm_map *map = get_imsm_map(dev, 0);
- struct imsm_map *prev = get_imsm_map(dev, dev->vol.migr_state);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ struct imsm_map *prev = get_imsm_map(dev, MAP_1);
+ struct imsm_map *map_for_loop;
__u32 ord;
int idx;
+ int idx_1;
/* at the beginning of migration we set IMSM_ORD_REBUILD on
* disks that are being rebuilt. New failures are recorded to
* map[0]. So we look through all the disks we started with and
* see if any failures are still present, or if any new ones
* have arrived
- *
- * FIXME add support for online capacity expansion and
- * raid-level-migration
*/
- for (i = 0; i < prev->num_members; i++) {
- ord = __le32_to_cpu(prev->disk_ord_tbl[i]);
- ord |= __le32_to_cpu(map->disk_ord_tbl[i]);
- idx = ord_to_idx(ord);
+ map_for_loop = map;
+ if (prev && (map->num_members < prev->num_members))
+ map_for_loop = prev;
+
+ for (i = 0; i < map_for_loop->num_members; i++) {
+ idx_1 = -255;
+ if (prev &&
+ (look_in_map & MAP_1) && (i < prev->num_members)) {
+ ord = __le32_to_cpu(prev->disk_ord_tbl[i]);
+ idx_1 = ord_to_idx(ord);
+
+ disk = get_imsm_disk(super, idx_1);
+ if (!disk || is_failed(disk) || ord & IMSM_ORD_REBUILD)
+ failed++;
+ }
+ if ((look_in_map & MAP_0) && (i < map->num_members)) {
+ ord = __le32_to_cpu(map->disk_ord_tbl[i]);
+ idx = ord_to_idx(ord);
- disk = get_imsm_disk(super, idx);
- if (!disk || is_failed(disk) || ord & IMSM_ORD_REBUILD)
- failed++;
+ if (idx != idx_1) {
+ disk = get_imsm_disk(super, idx);
+ if (!disk || is_failed(disk) ||
+ ord & IMSM_ORD_REBUILD)
+ failed++;
+ }
+ }
}
return failed;
if (is_failed(disk) && (ord & IMSM_ORD_REBUILD))
return 0;
- sprintf(buf, "%s:0", disk->serial);
+ memcpy(buf, disk->serial, MAX_RAID_SERIAL_LEN);
+ buf[MAX_RAID_SERIAL_LEN] = '\000';
+ strcat(buf, ":0");
if ((len = strlen(buf)) >= MAX_RAID_SERIAL_LEN)
shift = len - MAX_RAID_SERIAL_LEN + 1;
strncpy((char *)disk->serial, &buf[shift], MAX_RAID_SERIAL_LEN);
disk->status |= FAILED_DISK;
set_imsm_ord_tbl_ent(map, slot, idx | IMSM_ORD_REBUILD);
+ /* mark failures in second map if second map exists and this disk
+ * in this slot.
+ * This is valid for migration, initialization and rebuild
+ */
+ if (dev->vol.migr_state) {
+ struct imsm_map *map2 = get_imsm_map(dev, 1);
+ int slot2 = get_imsm_disk_slot(map2, idx);
+
+ if ((slot2 < map2->num_members) &&
+ (slot2 >= 0))
+ set_imsm_ord_tbl_ent(map2, slot2,
+ idx | IMSM_ORD_REBUILD);
+ }
if (map->failed_disk_num == 0xff)
map->failed_disk_num = slot;
return 1;
static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
{
- __u8 map_state;
struct dl *dl;
- int failed;
if (!super->missing)
return;
- failed = imsm_count_failed(super, dev);
- map_state = imsm_check_degraded(super, dev, failed);
dprintf("imsm: mark missing\n");
- end_migration(dev, map_state);
+ /* end process for initialization and rebuild only
+ */
+ if (is_gen_migration(dev) == 0) {
+ __u8 map_state;
+ int failed;
+
+ failed = imsm_count_failed(super, dev, MAP_0);
+ map_state = imsm_check_degraded(super, dev, failed, MAP_0);
+
+ end_migration(dev, super, map_state);
+ }
for (dl = super->missing; dl; dl = dl->next)
mark_missing(dev, &dl->disk, dl->index);
super->updates_pending++;
map->num_members = prev_disks;
dev->vol.migr_state = 1;
dev->vol.curr_migr_unit = 0;
- dev->vol.migr_type = MIGR_GEN_MIGR;
+ set_migr_type(dev, MIGR_GEN_MIGR);
for (i = prev_num_members;
i < map->num_members; i++)
set_imsm_ord_tbl_ent(map, i, i);
struct intel_super *super = a->container->sb;
struct imsm_dev *dev = get_imsm_dev(super, inst);
struct imsm_map *map = get_imsm_map(dev, 0);
- int failed = imsm_count_failed(super, dev);
- __u8 map_state = imsm_check_degraded(super, dev, failed);
+ int failed = imsm_count_failed(super, dev, MAP_0);
+ __u8 map_state = imsm_check_degraded(super, dev, failed, MAP_0);
__u32 blocks_per_unit;
if (dev->vol.migr_state &&
if (0) {
struct imsm_map *map2 = get_imsm_map(dev, 1);
dev->vol.migr_state = 0;
- dev->vol.migr_type = 0;
+ set_migr_type(dev, 0);
dev->vol.curr_migr_unit = 0;
memcpy(map, map2, sizeof_imsm_map(map2));
super->updates_pending++;
*/
if (is_resyncing(dev)) {
dprintf("imsm: mark resync done\n");
- end_migration(dev, map_state);
+ end_migration(dev, super, map_state);
super->updates_pending++;
a->last_checkpoint = 0;
}
- } else if (!is_resyncing(dev) && !failed) {
+ } else if ((!is_resyncing(dev) && !failed) &&
+ (imsm_reshape_blocks_arrays_changes(super) == 0)) {
/* mark the start of the init process if nothing is failed */
dprintf("imsm: mark resync start\n");
if (map->map_state == IMSM_T_STATE_UNINITIALIZED)
dprintf("imsm: set_disk %d:%x\n", n, state);
- ord = get_imsm_ord_tbl_ent(dev, n, -1);
+ ord = get_imsm_ord_tbl_ent(dev, n, 0);
disk = get_imsm_disk(super, ord_to_idx(ord));
/* check for new failures */
super->updates_pending++;
}
- failed = imsm_count_failed(super, dev);
- map_state = imsm_check_degraded(super, dev, failed);
+ failed = imsm_count_failed(super, dev, MAP_0);
+ map_state = imsm_check_degraded(super, dev, failed, MAP_0);
/* check if recovery complete, newly degraded, or failed */
- if (map_state == IMSM_T_STATE_NORMAL && is_rebuilding(dev)) {
- end_migration(dev, map_state);
- map = get_imsm_map(dev, 0);
- map->failed_disk_num = ~0;
- super->updates_pending++;
- a->last_checkpoint = 0;
- } else if (map_state == IMSM_T_STATE_DEGRADED &&
- map->map_state != map_state &&
- !dev->vol.migr_state) {
- dprintf("imsm: mark degraded\n");
- map->map_state = map_state;
- super->updates_pending++;
- a->last_checkpoint = 0;
- } else if (map_state == IMSM_T_STATE_FAILED &&
- map->map_state != map_state) {
- dprintf("imsm: mark failed\n");
- end_migration(dev, map_state);
- super->updates_pending++;
- a->last_checkpoint = 0;
- } else if (is_gen_migration(dev)) {
- dprintf("imsm: Detected General Migration in state: ");
- if (map_state == IMSM_T_STATE_NORMAL) {
- end_migration(dev, map_state);
+ dprintf("imsm: Detected transition to state ");
+ switch (map_state) {
+ case IMSM_T_STATE_NORMAL: /* transition to normal state */
+ dprintf("normal: ");
+ if (is_rebuilding(dev)) {
+ dprintf("while rebuilding");
+ end_migration(dev, super, map_state);
map = get_imsm_map(dev, 0);
map->failed_disk_num = ~0;
- dprintf("normal\n");
- } else {
- if (map_state == IMSM_T_STATE_DEGRADED) {
- printf("degraded\n");
- end_migration(dev, map_state);
- } else {
- dprintf("failed\n");
+ super->updates_pending++;
+ a->last_checkpoint = 0;
+ break;
+ }
+ if (is_gen_migration(dev)) {
+ dprintf("while general migration");
+ if (a->last_checkpoint >= a->info.component_size)
+ end_migration(dev, super, map_state);
+ else
+ map->map_state = map_state;
+ map = get_imsm_map(dev, 0);
+ map->failed_disk_num = ~0;
+ super->updates_pending++;
+ break;
+ }
+ break;
+ case IMSM_T_STATE_DEGRADED: /* transition to degraded state */
+ dprintf("degraded: ");
+ if ((map->map_state != map_state) &&
+ !dev->vol.migr_state) {
+ dprintf("mark degraded");
+ map->map_state = map_state;
+ super->updates_pending++;
+ a->last_checkpoint = 0;
+ break;
+ }
+ if (is_rebuilding(dev)) {
+ dprintf("while rebuilding.");
+ if (map->map_state != map_state) {
+ dprintf(" Map state change");
+ end_migration(dev, super, map_state);
+ super->updates_pending++;
+ }
+ break;
+ }
+ if (is_gen_migration(dev)) {
+ dprintf("while general migration");
+ if (a->last_checkpoint >= a->info.component_size)
+ end_migration(dev, super, map_state);
+ else {
+ map->map_state = map_state;
+ manage_second_map(super, dev);
}
+ super->updates_pending++;
+ break;
+ }
+ if (is_initializing(dev)) {
+ dprintf("while initialization.");
map->map_state = map_state;
+ super->updates_pending++;
+ break;
}
- super->updates_pending++;
+ break;
+ case IMSM_T_STATE_FAILED: /* transition to failed state */
+ dprintf("failed: ");
+ if (is_gen_migration(dev)) {
+ dprintf("while general migration");
+ map->map_state = map_state;
+ super->updates_pending++;
+ break;
+ }
+ if (map->map_state != map_state) {
+ dprintf("mark failed");
+ end_migration(dev, super, map_state);
+ super->updates_pending++;
+ a->last_checkpoint = 0;
+ break;
+ }
+ break;
+ default:
+ dprintf("state %i\n", map_state);
}
+ dprintf("\n");
+
}
static int store_imsm_mpb(int fd, struct imsm_super *mpb)
dev2 = get_imsm_dev(cont->sb, dev_idx);
if (dev2) {
- state = imsm_check_degraded(cont->sb, dev2, failed);
+ state = imsm_check_degraded(cont->sb, dev2, failed,
+ MAP_0);
if (state == IMSM_T_STATE_FAILED) {
map = get_imsm_map(dev2, 0);
if (!map)
if (imsm_reshape_blocks_arrays_changes(super))
return NULL;
+ /* Cannot activate another spare if rebuild is in progress already
+ */
+ if (is_rebuilding(dev)) {
+ dprintf("imsm: No spare activation allowed. "
+ "Rebuild in progress already.\n");
+ return NULL;
+ }
+
if (a->info.array.level == 4)
/* No repair for takeovered array
* imsm doesn't support raid4
*/
return NULL;
- if (imsm_check_degraded(super, dev, failed) != IMSM_T_STATE_DEGRADED)
+ if (imsm_check_degraded(super, dev, failed, MAP_0) !=
+ IMSM_T_STATE_DEGRADED)
return NULL;
/*
* are removed from container.
*/
if (failed) {
- dprintf("found failed disks in %s, check if there another"
+ dprintf("found failed disks in %.*s, check if there another"
"failed sub-array.\n",
- dev->volume);
+ MAX_RAID_SERIAL_LEN, dev->volume);
/* check if states of the other volumes allow for rebuild */
for (i = 0; i < super->anchor->num_raid_devs; i++) {
if (i != inst) {
*/
dl = imsm_readd(super, i, a);
if (!dl)
- dl = imsm_add_spare(super, i, a, 0, NULL);
+ dl = imsm_add_spare(super, i, a, 0, rv);
if (!dl)
- dl = imsm_add_spare(super, i, a, 1, NULL);
+ dl = imsm_add_spare(super, i, a, 1, rv);
if (!dl)
continue;
num_spares++;
dprintf("%x:%x to be %d at %llu\n", dl->major, dl->minor,
i, di->data_offset);
-
- break;
}
if (!rv)
return ret_val;
}
+static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
+ struct intel_super *super,
+ struct active_array *active_array)
+{
+ struct imsm_super *mpb = super->anchor;
+ struct imsm_dev *dev = get_imsm_dev(super, u->array);
+ struct imsm_map *map = get_imsm_map(dev, 0);
+ struct imsm_map *migr_map;
+ struct active_array *a;
+ struct imsm_disk *disk;
+ __u8 to_state;
+ struct dl *dl;
+ unsigned int found;
+ int failed;
+ int victim;
+ int i;
+ int second_map_created = 0;
+
+ for (; u; u = u->next) {
+ victim = get_imsm_disk_idx(dev, u->slot, -1);
+
+ if (victim < 0)
+ return 0;
+
+ for (dl = super->disks; dl; dl = dl->next)
+ if (dl == u->dl)
+ break;
+
+ if (!dl) {
+ fprintf(stderr, "error: imsm_activate_spare passed "
+ "an unknown disk (index: %d)\n",
+ u->dl->index);
+ return 0;
+ }
+
+ /* count failures (excluding rebuilds and the victim)
+ * to determine map[0] state
+ */
+ failed = 0;
+ for (i = 0; i < map->num_members; i++) {
+ if (i == u->slot)
+ continue;
+ disk = get_imsm_disk(super,
+ get_imsm_disk_idx(dev, i, -1));
+ if (!disk || is_failed(disk))
+ failed++;
+ }
+
+ /* adding a pristine spare, assign a new index */
+ if (dl->index < 0) {
+ dl->index = super->anchor->num_disks;
+ super->anchor->num_disks++;
+ }
+ disk = &dl->disk;
+ disk->status |= CONFIGURED_DISK;
+ disk->status &= ~SPARE_DISK;
+
+ /* mark rebuild */
+ to_state = imsm_check_degraded(super, dev, failed,
+ MAP_0);
+ if (!second_map_created) {
+ second_map_created = 1;
+ map->map_state = IMSM_T_STATE_DEGRADED;
+ migrate(dev, super, to_state, MIGR_REBUILD);
+ } else
+ map->map_state = to_state;
+ migr_map = get_imsm_map(dev, 1);
+ set_imsm_ord_tbl_ent(map, u->slot, dl->index);
+ set_imsm_ord_tbl_ent(migr_map, u->slot,
+ dl->index | IMSM_ORD_REBUILD);
+
+ /* update the family_num to mark a new container
+ * generation, being careful to record the existing
+ * family_num in orig_family_num to clean up after
+ * earlier mdadm versions that neglected to set it.
+ */
+ if (mpb->orig_family_num == 0)
+ mpb->orig_family_num = mpb->family_num;
+ mpb->family_num += super->random;
+
+ /* count arrays using the victim in the metadata */
+ found = 0;
+ for (a = active_array; a ; a = a->next) {
+ dev = get_imsm_dev(super, a->info.container_member);
+ map = get_imsm_map(dev, 0);
+
+ if (get_imsm_disk_slot(map, victim) >= 0)
+ found++;
+ }
+
+ /* delete the victim if it is no longer being
+ * utilized anywhere
+ */
+ if (!found) {
+ struct dl **dlp;
+
+ /* We know that 'manager' isn't touching anything,
+ * so it is safe to delete
+ */
+ for (dlp = &super->disks; *dlp; dlp = &(*dlp)->next)
+ if ((*dlp)->index == victim)
+ break;
+
+ /* victim may be on the missing list */
+ if (!*dlp)
+ for (dlp = &super->missing; *dlp;
+ dlp = &(*dlp)->next)
+ if ((*dlp)->index == victim)
+ break;
+ imsm_delete(super, dlp, victim);
+ }
+ }
+
+ return 1;
+}
static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
struct intel_super *super,
devices_to_reshape--;
newdev->vol.migr_state = 1;
newdev->vol.curr_migr_unit = 0;
- newdev->vol.migr_type = MIGR_GEN_MIGR;
+ set_migr_type(newdev, MIGR_GEN_MIGR);
newmap->num_members = u->new_raid_disks;
for (i = 0; i < delta_disks; i++) {
set_imsm_ord_tbl_ent(newmap,
if (u->direction == R10_TO_R0) {
/* Number of failed disks must be half of initial disk number */
- if (imsm_count_failed(super, dev) != (map->num_members / 2))
+ if (imsm_count_failed(super, dev, MAP_0) !=
+ (map->num_members / 2))
return 0;
/* iterate through devices to mark removed disks as spare */
}
case update_activate_spare: {
struct imsm_update_activate_spare *u = (void *) update->buf;
- struct imsm_dev *dev = get_imsm_dev(super, u->array);
- struct imsm_map *map = get_imsm_map(dev, 0);
- struct imsm_map *migr_map;
- struct active_array *a;
- struct imsm_disk *disk;
- __u8 to_state;
- struct dl *dl;
- unsigned int found;
- int failed;
- int victim = get_imsm_disk_idx(dev, u->slot, -1);
- int i;
-
- for (dl = super->disks; dl; dl = dl->next)
- if (dl == u->dl)
- break;
-
- if (!dl) {
- fprintf(stderr, "error: imsm_activate_spare passed "
- "an unknown disk (index: %d)\n",
- u->dl->index);
- return;
- }
-
- super->updates_pending++;
- /* count failures (excluding rebuilds and the victim)
- * to determine map[0] state
- */
- failed = 0;
- for (i = 0; i < map->num_members; i++) {
- if (i == u->slot)
- continue;
- disk = get_imsm_disk(super,
- get_imsm_disk_idx(dev, i, -1));
- if (!disk || is_failed(disk))
- failed++;
- }
-
- /* adding a pristine spare, assign a new index */
- if (dl->index < 0) {
- dl->index = super->anchor->num_disks;
- super->anchor->num_disks++;
- }
- disk = &dl->disk;
- disk->status |= CONFIGURED_DISK;
- disk->status &= ~SPARE_DISK;
-
- /* mark rebuild */
- to_state = imsm_check_degraded(super, dev, failed);
- map->map_state = IMSM_T_STATE_DEGRADED;
- migrate(dev, super, to_state, MIGR_REBUILD);
- migr_map = get_imsm_map(dev, 1);
- set_imsm_ord_tbl_ent(map, u->slot, dl->index);
- set_imsm_ord_tbl_ent(migr_map, u->slot, dl->index | IMSM_ORD_REBUILD);
-
- /* update the family_num to mark a new container
- * generation, being careful to record the existing
- * family_num in orig_family_num to clean up after
- * earlier mdadm versions that neglected to set it.
- */
- if (mpb->orig_family_num == 0)
- mpb->orig_family_num = mpb->family_num;
- mpb->family_num += super->random;
-
- /* count arrays using the victim in the metadata */
- found = 0;
- for (a = st->arrays; a ; a = a->next) {
- dev = get_imsm_dev(super, a->info.container_member);
- map = get_imsm_map(dev, 0);
-
- if (get_imsm_disk_slot(map, victim) >= 0)
- found++;
- }
-
- /* delete the victim if it is no longer being
- * utilized anywhere
- */
- if (!found) {
- struct dl **dlp;
-
- /* We know that 'manager' isn't touching anything,
- * so it is safe to delete
- */
- for (dlp = &super->disks; *dlp; dlp = &(*dlp)->next)
- if ((*dlp)->index == victim)
- break;
-
- /* victim may be on the missing list */
- if (!*dlp)
- for (dlp = &super->missing; *dlp; dlp = &(*dlp)->next)
- if ((*dlp)->index == victim)
- break;
- imsm_delete(super, dlp, victim);
- }
+ if (apply_update_activate_spare(u, super, st->arrays))
+ super->updates_pending++;
break;
}
case update_create_array: {
}
}
#endif /* MDASSEMBLE */
+
+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)
+{
+ switch (level) {
+ case 10:{
+ int ret_val = 0;
+ struct imsm_map *map;
+ int i;
+
+ ret_val = raid_disks/2;
+ /* check map if all disks pairs not failed
+ * in both maps
+ */
+ map = get_imsm_map(dev, 0);
+ for (i = 0; i < ret_val; i++) {
+ int degradation = 0;
+ if (get_imsm_disk(super, i) == NULL)
+ degradation++;
+ if (get_imsm_disk(super, i + 1) == NULL)
+ degradation++;
+ if (degradation == 2)
+ return 0;
+ }
+ map = get_imsm_map(dev, 1);
+ /* if there is no second map
+ * result can be returned
+ */
+ if (map == NULL)
+ return ret_val;
+ /* check degradation in second map
+ */
+ for (i = 0; i < ret_val; i++) {
+ int degradation = 0;
+ if (get_imsm_disk(super, i) == NULL)
+ degradation++;
+ if (get_imsm_disk(super, i + 1) == NULL)
+ degradation++;
+ if (degradation == 2)
+ return 0;
+ }
+ return ret_val;
+ }
+ case 5:
+ return 1;
+ case 6:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+
/*******************************************************************************
* Function: open_backup_targets
* Description: Function opens file descriptors for all devices given in
* 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)
+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;
raid_fds[sd->disk.raid_disk] = dev_open(dn, O_RDWR);
if (raid_fds[sd->disk.raid_disk] < 0) {
fprintf(stderr, "cannot open component\n");
- return -1;
+ 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)) {
+ fprintf(stderr, "Not enough disks can be opened.\n");
+ close_targets(raid_fds, raid_disks);
+ return -2;
}
return 0;
}
target_offsets[i] -= start/data_disks;
}
- if (open_backup_targets(info, new_disks, targets))
+ if (open_backup_targets(info, new_disks, targets,
+ super, dev))
goto abort;
dest_layout = imsm_level_to_layout(map_dest->raid_level);
abort:
if (targets) {
- for (i = 0; i < new_disks; i++)
- if (targets[i] >= 0)
- close(targets[i]);
+ close_targets(targets, new_disks);
free(targets);
}
free(target_offsets);
unsigned long num_migr_units = __le32_to_cpu(migr_rec->num_migr_units);
char buffer[20];
int skipped_disks = 0;
- int max_degradation;
err = sysfs_get_str(info, NULL, "array_state", (char *)buffer, 20);
if (err < 1)
map_dest = get_imsm_map(id->dev, 0);
new_disks = map_dest->num_members;
- max_degradation = new_disks - imsm_num_data_members(id->dev, 0);
read_offset = (unsigned long long)
__le32_to_cpu(migr_rec->ckpt_area_pba) * 512;
if (!targets)
goto abort;
- open_backup_targets(info, new_disks, targets);
+ if (open_backup_targets(info, new_disks, targets, super, id->dev)) {
+ fprintf(stderr,
+ Name ": Cannot open some devices belonging to array.\n");
+ goto abort;
+ }
for (i = 0; i < new_disks; i++) {
if (targets[i] < 0) {
fprintf(stderr,
Name ": Cannot seek to block: %s\n",
strerror(errno));
- goto abort;
+ skipped_disks++;
+ continue;
}
if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
fprintf(stderr,
Name ": Cannot read copy area block: %s\n",
strerror(errno));
- goto abort;
+ skipped_disks++;
+ continue;
}
if (lseek64(targets[i], write_offset, SEEK_SET) < 0) {
fprintf(stderr,
Name ": Cannot seek to block: %s\n",
strerror(errno));
- goto abort;
+ skipped_disks++;
+ continue;
}
if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
fprintf(stderr,
Name ": Cannot restore block: %s\n",
strerror(errno));
- goto abort;
+ skipped_disks++;
+ continue;
}
}
- if (skipped_disks > max_degradation) {
+ if (skipped_disks > imsm_get_allowed_degradation(info->new_level,
+ new_disks,
+ super,
+ id->dev)) {
fprintf(stderr,
Name ": Cannot restore data from backup."
" Too many failed disks\n");
int change = -1;
int check_devs = 0;
int chunk;
+ int devNumChange=0;
+ int layout = -1;
getinfo_super_imsm_volume(st, &info, NULL);
if ((geo->level != info.array.level) &&
change = -1;
goto analyse_change_exit;
}
+ layout = geo->layout;
check_devs = 1;
- }
- if (geo->level == 10) {
+ devNumChange = 1; /* parity disk added */
+ } else if (geo->level == 10) {
change = CH_TAKEOVER;
check_devs = 1;
+ devNumChange = 2; /* two mirrors added */
+ layout = 0x102; /* imsm supported layout */
}
break;
case 1:
- if (geo->level == 0) {
- change = CH_TAKEOVER;
- check_devs = 1;
- }
- break;
case 10:
if (geo->level == 0) {
change = CH_TAKEOVER;
check_devs = 1;
+ devNumChange = -(geo->raid_disks/2);
+ layout = 0; /* imsm raid0 layout */
}
break;
}
chunk = geo->chunksize / 1024;
if (!validate_geometry_imsm(st,
geo->level,
- geo->layout,
- geo->raid_disks,
+ layout,
+ geo->raid_disks + devNumChange,
&chunk,
geo->size,
0, 0, 1))