return join_u32(map->blocks_per_member_lo, map->blocks_per_member_hi);
}
+#ifndef MDASSEMBLE
static unsigned long long num_data_stripes(struct imsm_map *map)
{
if (map == NULL)
{
split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
}
+#endif
static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n)
{
}
return rv;
}
+static unsigned long long imsm_component_size_aligment_check(int level,
+ int chunk_size,
+ unsigned long long component_size)
+{
+ unsigned int component_size_alligment;
+
+ /* check component size aligment
+ */
+ component_size_alligment = component_size % (chunk_size/512);
+
+ dprintf("imsm_component_size_aligment_check(Level: %i, "
+ "chunk_size = %i, component_size = %llu), "
+ "component_size_alligment = %u\n",
+ level, chunk_size, component_size,
+ component_size_alligment);
+
+ if (component_size_alligment && (level != 1) && (level != UnSet)) {
+ dprintf("imsm: reported component size alligned from %llu ",
+ component_size);
+ component_size -= component_size_alligment;
+ dprintf("to %llu (%i).\n",
+ component_size, component_size_alligment);
+ }
+
+ return component_size;
+}
static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
{
struct imsm_map *map_to_analyse = map;
struct dl *dl;
char *devname;
- unsigned int component_size_alligment;
int map_disks = info->array.raid_disks;
memset(info, 0, sizeof(*info));
info->data_offset = pba_of_lba0(map_to_analyse);
info->component_size = blocks_per_member(map_to_analyse);
- /* check component size aligment
- */
- component_size_alligment =
- info->component_size % (info->array.chunk_size/512);
-
- if (component_size_alligment &&
- (info->array.level != 1) && (info->array.level != UnSet)) {
- dprintf("imsm: reported component size alligned from %llu ",
- info->component_size);
- info->component_size -= component_size_alligment;
- dprintf("to %llu (%i).\n",
- info->component_size, component_size_alligment);
- }
+ info->component_size = imsm_component_size_aligment_check(
+ info->array.level,
+ info->array.chunk_size,
+ info->component_size);
memset(info->uuid, 0, sizeof(info->uuid));
info->recovery_start = MaxSector;
if (s == champion)
continue;
+ mpb->attributes |= s->anchor->attributes & MPB_ATTRIB_2TB_DISK;
+
for (i = 0; i < mpb->num_disks; i++) {
struct imsm_disk *disk;
} else {
if (s)
free(s);
- if (dfd)
+ if (dfd >= 0)
close(dfd);
}
if ((dfd >= 0) && (!keep_fd))
map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
map->failed_disk_num = ~0;
if (info->level > 0)
- map->map_state = IMSM_T_STATE_UNINITIALIZED;
+ map->map_state = (info->state ? IMSM_T_STATE_NORMAL
+ : IMSM_T_STATE_UNINITIALIZED);
else
map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED :
IMSM_T_STATE_NORMAL;
free(dv);
}
}
+ closedir(dir);
return devlist;
}
return 1;
}
-static int reserve_space(struct supertype *st, int raiddisks,
+static int imsm_get_free_size(struct supertype *st, int raiddisks,
unsigned long long size, int chunk,
unsigned long long *freesize)
{
*freesize = size;
+ dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
+
return 1;
}
+static int reserve_space(struct supertype *st, int raiddisks,
+ unsigned long long size, int chunk,
+ unsigned long long *freesize)
+{
+ struct intel_super *super = st->sb;
+ struct dl *dl;
+ int cnt;
+ int rv = 0;
+
+ rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
+ if (rv) {
+ cnt = 0;
+ for (dl = super->disks; dl; dl = dl->next)
+ if (dl->e)
+ dl->raiddisk = cnt++;
+ rv = 1;
+ }
+
+ return rv;
+}
+
static int validate_geometry_imsm(struct supertype *st, int level, int layout,
int raiddisks, int *chunk, unsigned long long size,
char *dev, unsigned long long *freesize,
struct imsm_dev *dev = get_imsm_dev(super, inst);
struct imsm_map *map = get_imsm_map(dev, MAP_0);
struct imsm_disk *disk;
+ struct mdinfo *mdi;
+ int recovery_not_finished = 0;
int failed;
__u32 ord;
__u8 map_state;
dprintf("normal: ");
if (is_rebuilding(dev)) {
dprintf("while rebuilding");
+ /* check if recovery is really finished */
+ for (mdi = a->info.devs; mdi ; mdi = mdi->next)
+ if (mdi->recovery_start != MaxSector) {
+ recovery_not_finished = 1;
+ break;
+ }
+ if (recovery_not_finished) {
+ dprintf("\nimsm: Rebuild has not finished yet, "
+ "state not changed");
+ if (a->last_checkpoint < mdi->recovery_start) {
+ a->last_checkpoint = mdi->recovery_start;
+ super->updates_pending++;
+ }
+ break;
+ }
end_migration(dev, super, map_state);
map = get_imsm_map(dev, MAP_0);
map->failed_disk_num = ~0;
static int imsm_reshape_is_allowed_on_container(struct supertype *st,
struct geo_params *geo,
- int *old_raid_disks)
+ int *old_raid_disks,
+ int direction)
{
/* currently we only support increasing the number of devices
* for a container. This increases the number of device for each
return ret_val;
}
+ if (direction == ROLLBACK_METADATA_CHANGES) {
+ dprintf("imsm: Metadata changes rollback is not supported for "
+ "container operation.\n");
+ return ret_val;
+ }
+
info = container_content_imsm(st, NULL);
for (member = info; member; member = member->next) {
int result;
* Function: imsm_analyze_change
* Description: Function analyze change for single volume
* and validate if transition is supported
-* Parameters: Geometry parameters, supertype structure
+* Parameters: Geometry parameters, supertype structure,
+* metadata change direction (apply/rollback)
* Returns: Operation type code on success, -1 if fail
****************************************************************************/
enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
- struct geo_params *geo)
+ struct geo_params *geo,
+ int direction)
{
struct mdinfo info;
int change = -1;
struct imsm_dev *dev;
struct intel_super *super;
long long current_size;
+ unsigned long long free_size;
+ long long max_size;
+ int rv;
getinfo_super_imsm_volume(st, &info, NULL);
if ((geo->level != info.array.level) &&
super = st->sb;
dev = get_imsm_dev(super, super->current_vol);
data_disks = imsm_num_data_members(dev , MAP_0);
- /* compute current size in K per disk member
+ /* compute current size per disk member
*/
- current_size = info.custom_array_size / 2 / data_disks;
+ current_size = info.custom_array_size / data_disks;
+
+ if (geo->size > 0) {
+ /* align component size
+ */
+ geo->size = imsm_component_size_aligment_check(
+ get_imsm_raid_level(dev->vol.map),
+ chunk * 1024,
+ geo->size * 2);
+ }
- if ((current_size != geo->size) && (geo->size > 0)) {
+ if ((current_size != geo->size) && (geo->size >= 0)) {
if (change != -1) {
fprintf(stderr,
Name " Error. Size change should be the only "
super->current_vol, st->devnum);
goto analyse_change_exit;
}
- geo->size *= 2;
- /* round size due to metadata compatibility
+ /* check the maximum available size
*/
- geo->size = (geo->size >> SECT_PER_MB_SHIFT)
- << SECT_PER_MB_SHIFT;
- dprintf("Prepare update for size change to %llu\n", geo->size );
- if (current_size >= geo->size) {
- fprintf(stderr,
- Name " Error. Size expanssion is supported only"
- " (current size is %llu, requested size "
- "/rounded/ is %llu).\n",
- current_size, geo->size);
- goto analyse_change_exit;
+ rv = imsm_get_free_size(st, dev->vol.map->num_members,
+ 0, chunk, &free_size);
+ if (rv == 0)
+ /* Cannot find maximum available space
+ */
+ max_size = 0;
+ else {
+ max_size = free_size + current_size;
+ /* align component size
+ */
+ max_size = imsm_component_size_aligment_check(
+ get_imsm_raid_level(dev->vol.map),
+ chunk * 1024,
+ max_size);
+ }
+ if (geo->size == 0) {
+ /* requested size change to the maximum available size
+ */
+ if (max_size == 0) {
+ fprintf(stderr, Name " Error. Cannot find "
+ "maximum available space.\n");
+ change = -1;
+ goto analyse_change_exit;
+ } else
+ geo->size = max_size;
+ }
+
+ if ((direction == ROLLBACK_METADATA_CHANGES)) {
+ /* accept size for rollback only
+ */
+ } else {
+ /* round size due to metadata compatibility
+ */
+ geo->size = (geo->size >> SECT_PER_MB_SHIFT)
+ << SECT_PER_MB_SHIFT;
+ dprintf("Prepare update for size change to %llu\n",
+ geo->size );
+ if (current_size >= geo->size) {
+ fprintf(stderr,
+ Name " Error. Size expansion is "
+ "supported only (current size is %llu, "
+ "requested size /rounded/ is %llu).\n",
+ current_size, geo->size);
+ goto analyse_change_exit;
+ }
+ if (max_size && geo->size > max_size) {
+ fprintf(stderr,
+ Name " Error. Requested size is larger "
+ "than maximum available size (maximum "
+ "available size is %llu, "
+ "requested size /rounded/ is %llu).\n",
+ max_size, geo->size);
+ goto analyse_change_exit;
+ }
}
geo->size *= data_disks;
geo->raid_disks = dev->vol.map->num_members;
}
analyse_change_exit:
-
+ if ((direction == ROLLBACK_METADATA_CHANGES) &&
+ ((change == CH_MIGRATION) || (change == CH_TAKEOVER))) {
+ dprintf("imsm: Metadata changes rollback is not supported for "
+ "migration and takeover operations.\n");
+ change = -1;
+ }
return change;
}
int old_raid_disks = 0;
if (imsm_reshape_is_allowed_on_container(
- st, &geo, &old_raid_disks)) {
+ st, &geo, &old_raid_disks, direction)) {
struct imsm_update_reshape *u = NULL;
int len;
goto exit_imsm_reshape_super;
}
super->current_vol = dev->index;
- change = imsm_analyze_change(st, &geo);
+ change = imsm_analyze_change(st, &geo, direction);
switch (change) {
case CH_TAKEOVER:
ret_val = imsm_takeover(st, &geo);
int degraded)
{
unsigned long long new_degraded;
- sysfs_get_ll(info, NULL, "degraded", &new_degraded);
- if (new_degraded != (unsigned long long)degraded) {
+ int rv;
+
+ rv = sysfs_get_ll(info, NULL, "degraded", &new_degraded);
+ if ((rv == -1) || (new_degraded != (unsigned long long)degraded)) {
/* check each device to ensure it is still working */
struct mdinfo *sd;
new_degraded = 0;