[PATCH 0/4] Raid0 <-> Raid5 migrations (imsm)
[PATCH 0/4] Raid0 <-> Raid5 migrations (imsm)
am 11.02.2011 14:43:50 von adam.kwolek
The following series implements Raid5 <-> Raid0 migrations
for imsm metadata.
Patches should be applied on top of patches previously sent by me.
BR
Adam
---
Adam Kwolek (4):
FIX: Target disk number depends on source raid level
imsm: process update for raid level migrations
imsm: prepare memory for level migration update
imsm: prepare update for level migrations reshape
Grow.c | 2
super-intel.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 270 insertions(+), 4 deletions(-)
--
Signature
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/4] imsm: prepare update for level migrations reshape
am 11.02.2011 14:43:59 von adam.kwolek
For level migrations:
1. raid0->raid5
2. raid5->raid0
metadata update is prepared
If migration raid0->raid5 can get spare device it is included in to update also.
Signed-off-by: Adam Kwolek
---
super-intel.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index e06a6f4..fbc71ab 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -305,6 +305,7 @@ enum imsm_update_type {
update_rename_array,
update_add_remove_disk,
update_reshape_container_disks,
+ update_reshape_migration,
update_takeover
};
@@ -340,6 +341,12 @@ struct imsm_update_reshape {
enum imsm_update_type type;
int old_raid_disks;
int new_raid_disks;
+ /* fields for array migration changes
+ */
+ int subdev;
+ int new_level;
+ int new_layout;
+
int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
};
@@ -6132,6 +6139,9 @@ static void imsm_process_update(struct supertype *st,
super->updates_pending++;
break;
}
+ case update_reshape_migration: {
+ break;
+ }
case update_activate_spare: {
struct imsm_update_activate_spare *u = (void *) update->buf;
struct imsm_dev *dev = get_imsm_dev(super, u->array);
@@ -6525,6 +6535,9 @@ static void imsm_prepare_update(struct supertype *st,
dprintf("New anchor length is %llu\n", (unsigned long long)len);
break;
}
+ case update_reshape_migration: {
+ break;
+ }
case update_create_array: {
struct imsm_update_create_array *u = (void *) update->buf;
struct intel_dev *dv;
@@ -6891,6 +6904,78 @@ abort:
return 0;
}
+/********************************************************** ********************
+ * function: imsm_create_metadata_update_for_migration()
+ * Creates update for IMSM array.
+ *
+ ************************************************************ ******************/
+static int imsm_create_metadata_update_for_migration(
+ struct supertype *st,
+ struct geo_params *geo,
+ struct imsm_update_reshape **updatep)
+{
+ struct intel_super *super = st->sb;
+ int update_memory_size = 0;
+ struct imsm_update_reshape *u = NULL;
+ int delta_disks = 0;
+
+ dprintf("imsm_create_metadata_update_for_migration(enter)"
+ " New Level = %i\n", geo->level);
+ delta_disks = 0;
+
+ /* size of all update data without anchor */
+ update_memory_size = sizeof(struct imsm_update_reshape);
+
+ /* now add space for spare disks that we need to add. */
+ if (delta_disks > 0)
+ update_memory_size += sizeof(u->new_disks[0])
+ * (delta_disks - 1);
+
+ u = calloc(1, update_memory_size);
+ if (u == NULL) {
+ dprintf("error: cannot get memory for "
+ "imsm_create_metadata_update_for_migration\n");
+ return 0;
+ }
+ u->type = update_reshape_migration;
+ u->subdev = super->current_vol;
+ u->new_level = geo->level;
+ u->new_layout = geo->layout;
+ u->new_raid_disks = u->old_raid_disks = geo->raid_disks;
+ u->new_disks[0] = -1;
+ if (geo->level == 5) {
+ struct mdinfo *spares = NULL;
+
+ u->new_raid_disks++;
+ spares = get_spares_for_grow(st);
+ if (spares) {
+ struct dl *dl;
+ struct mdinfo *dev;
+
+ dev = spares->devs;
+ if (dev) {
+ u->new_disks[0] = makedev(dev->disk.major,
+ dev->disk.minor);
+ dl = get_disk_super(super,
+ dev->disk.major,
+ dev->disk.minor);
+ dl->index = u->old_raid_disks;
+ dev = dev->next;
+ }
+ sysfs_free(spares);
+ } else {
+ free(u);
+ dprintf("error: cannot get spare device "
+ "for requested migration");
+ return 0;
+ }
+ }
+ dprintf("imsm: reshape update preparation : OK\n");
+ *updatep = u;
+
+ return update_memory_size;
+}
+
static void imsm_update_metadata_locally(struct supertype *st,
void *buf, int len)
{
@@ -7145,9 +7230,25 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
case CH_TAKEOVER:
ret_val = imsm_takeover(st, &geo);
break;
- case CH_MIGRATION:
+ case CH_MIGRATION: {
+ struct imsm_update_reshape *u = NULL;
+ int len =
+ imsm_create_metadata_update_for_migration(
+ st, &geo, &u);
+ if (len < 1) {
+ dprintf("imsm: "
+ "Cannot prepare update\n");
+ }
ret_val = 0;
- break;
+ /* update metadata locally */
+ imsm_update_metadata_locally(st, u, len);
+ /* and possibly remotely */
+ if (st->update_tail)
+ append_metadata_update(st, u, len);
+ else
+ free(u);
+ }
+ break;
default:
ret_val = 1;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/4] imsm: prepare memory for level migration update
am 11.02.2011 14:44:07 von adam.kwolek
When level is changed from raid0 to raid5 memory is required for replace device
smaller device/array object. When update points to no spare device
(u->new_disks[0] == -1) memory for new missed disk will be required also.
This memory is allocated in manager context in prepare_update()
Signed-off-by: Adam Kwolek
---
super-intel.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 49 insertions(+), 0 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index fbc71ab..223019a 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -6536,6 +6536,55 @@ static void imsm_prepare_update(struct supertype *st,
break;
}
case update_reshape_migration: {
+ /* for migration level 0->5 we need to add disks
+ * so the same as for container operation we will copy
+ * device to the bigger location.
+ * in memory prepared device and new disk area are prepared
+ * for usage in process update
+ */
+ struct imsm_update_reshape *u = (void *)update->buf;
+ struct intel_dev *id;
+ void **space_tail = (void **)&update->space_list;
+ int size;
+ void *s;
+
+ dprintf("imsm: imsm_prepare_update() for update_reshape\n");
+
+ /* add space for bigger array in update
+ */
+ for (id = super->devlist; id; id = id->next) {
+ if (id->index == (unsigned)u->subdev) {
+ size = sizeof_imsm_dev(id->dev, 1);
+ if (u->new_raid_disks > u->old_raid_disks)
+ size += sizeof(__u32)*2*
+ (u->new_raid_disks - u->old_raid_disks);
+ s = malloc(size);
+ if (!s)
+ break;
+ *space_tail = s;
+ space_tail = s;
+ *space_tail = NULL;
+ break;
+ }
+ }
+ if (update->space_list == NULL)
+ break;
+
+ /* add space for disk in update
+ */
+ size = sizeof(struct dl);
+ s = malloc(size);
+ if (!s) {
+ free(update->space_list);
+ update->space_list = NULL;
+ break;
+ }
+ *space_tail = s;
+ space_tail = s;
+ *space_tail = NULL;
+
+ len = disks_to_mpb_size(u->new_raid_disks);
+ dprintf("New anchor length is %llu\n", (unsigned long long)len);
break;
}
case update_create_array: {
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/4] imsm: process update for raid level migrations
am 11.02.2011 14:44:15 von adam.kwolek
Received update and prepared memory is processed to update imsm metadata.
There is available cases:
1. Raid0->raid5(n+1 disk array) migration:
a) no spares: degraded raid5 array is created
b) spare disk is available: raid5 is created using spare device
2. Raid5(n disk array)->raid0(n disk array): array size is increased
Signed-off-by: Adam Kwolek
---
super-intel.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 117 insertions(+), 1 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 223019a..1e3d1b9 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -5875,6 +5875,119 @@ static int add_remove_disk_update(struct intel_super *super)
return check_degraded;
}
+
+static int apply_reshape_migration_update(struct imsm_update_reshape *u,
+ struct intel_super *super,
+ void ***space_list)
+{
+ struct intel_dev *id;
+ void **tofree = NULL;
+ int ret_val = 0;
+
+ dprintf("apply_reshape_migration_update()\n");
+ if ((u->subdev < 0) ||
+ (u->subdev > 1)) {
+ dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
+ return ret_val;
+ }
+ if ((space_list == NULL) || (*space_list == NULL)) {
+ dprintf("imsm: Error: Memory is not allocated\n");
+ return ret_val;
+ }
+
+ for (id = super->devlist ; id; id = id->next) {
+ if (id->index == (unsigned)u->subdev) {
+ struct imsm_dev *dev = get_imsm_dev(super, u->subdev);
+ struct imsm_map *map;
+ struct imsm_dev *new_dev =
+ (struct imsm_dev *)*space_list;
+ struct imsm_map *migr_map = get_imsm_map(dev, 1);
+ int to_state;
+ struct dl *new_disk;
+
+ if (new_dev == NULL)
+ return ret_val;
+ *space_list = **space_list;
+ memcpy(new_dev, dev, sizeof_imsm_dev(dev, 0));
+ map = get_imsm_map(new_dev, 0);
+ if (migr_map) {
+ dprintf("imsm: Error: migration in progress");
+ return ret_val;
+ }
+
+ to_state = map->map_state;
+ if (u->new_level == 5) {
+ map->num_members++;
+ if (u->new_disks[0] < 0) {
+ map->failed_disk_num =
+ map->num_members - 1;
+ to_state = IMSM_T_STATE_DEGRADED;
+ } else
+ to_state = IMSM_T_STATE_NORMAL;
+ }
+ migrate(new_dev, to_state, MIGR_GEN_MIGR);
+ map->raid_level = u->new_level;
+ if (u->new_level == 5) {
+ int ord = map->num_members - 1;
+ migr_map = get_imsm_map(new_dev, 1);
+ migr_map->num_members--;
+ if (u->new_disks[0] < 0)
+ ord |= IMSM_ORD_REBUILD;
+ set_imsm_ord_tbl_ent(map,
+ map->num_members - 1,
+ ord);
+ }
+ id->dev = new_dev;
+ tofree = (void **)dev;
+
+ /* add disk
+ */
+ if (u->new_level != 5)
+ goto skip_disk_add;
+
+ if (u->new_disks[0] >= 0) {
+ /* use passes spare
+ */
+ new_disk = get_disk_super(super,
+ major(u->new_disks[0]),
+ minor(u->new_disks[0]));
+ dprintf("imsm: new disk for reshape is: %i:%i "
+ "(%p, index = %i)\n",
+ major(u->new_disks[0]),
+ minor(u->new_disks[0]),
+ new_disk, new_disk->index);
+ if (new_disk == NULL)
+ goto error_disk_add;
+
+ new_disk->index = map->num_members - 1;
+ /* slot to fill in autolayout
+ */
+ new_disk->raiddisk = new_disk->index;
+ new_disk->disk.status |= CONFIGURED_DISK;
+ new_disk->disk.status &= ~SPARE_DISK;
+ } else
+ goto error_disk_add;
+
+skip_disk_add:
+ *tofree = *space_list;
+ /* calculate new size
+ */
+ imsm_set_array_size(new_dev);
+
+ ret_val = 1;
+ }
+ }
+
+ if (tofree)
+ *space_list = tofree;
+ return ret_val;
+
+error_disk_add:
+ dprintf("Error: imsm: Cannot find disk.\n");
+ return ret_val;
+}
+
+
static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
struct intel_super *super,
void ***space_list)
@@ -6140,6 +6253,10 @@ static void imsm_process_update(struct supertype *st,
break;
}
case update_reshape_migration: {
+ struct imsm_update_reshape *u = (void *)update->buf;
+ if (apply_reshape_migration_update(
+ u, super, &update->space_list))
+ super->updates_pending++;
break;
}
case update_activate_spare: {
@@ -6168,7 +6285,6 @@ static void imsm_process_update(struct supertype *st,
}
super->updates_pending++;
-
/* count failures (excluding rebuilds and the victim)
* to determine map[0] state
*/
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/4] FIX: Target disk number depends on source raid level
am 11.02.2011 14:44:22 von adam.kwolek
Target number of data disk depends on source raid level not on working raid level.
if transition is from raid0 to raid5 with working level== 5, this means that we add one disk (delta_disks == 1)
but data disks number doesn't change.
Signed-off-by: Adam Kwolek
---
Grow.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/Grow.c b/Grow.c
index b04faf1..baa493a 100644
--- a/Grow.c
+++ b/Grow.c
@@ -1174,7 +1174,7 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
return "Cannot convert to RAID5 from this level";
if (info->delta_disks == UnSet)
re->after.data_disks = re->before.data_disks;
- else if (re->level == 5)
+ else if (info->array.level == 5)
re->after.data_disks =
re->before.data_disks + info->delta_disks;
else
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/4] Raid0 <-> Raid5 migrations (imsm)
am 14.02.2011 02:21:29 von NeilBrown
On Fri, 11 Feb 2011 14:43:50 +0100 Adam Kwolek wrote:
> The following series implements Raid5 <-> Raid0 migrations
> for imsm metadata.
>
> Patches should be applied on top of patches previously sent by me.
>
> BR
> Adam
>
>
> ---
>
> Adam Kwolek (4):
> FIX: Target disk number depends on source raid level
I don't like this fix - it just addresses the obvious symptom rather
than the underlying problem. See below for that patch I have added
which should fix it and also make the code a lot cleaner.
> imsm: process update for raid level migrations
> imsm: prepare memory for level migration update
> imsm: prepare update for level migrations reshape
I don't like having mdadm choose the spares to add. That should
always be the role of mdmon.
So mdadm should at most tell mdmon that a reshape is happening
and mdmon should determine that new spares are needed.
Possibly mdadm wouldn't need to tell mdmon anything. Having
determined that the reshape is allowed, mdadm can set up the
parameters for the reshape directly in the kernel.
mdmon could notice and make the required changes to the metadata
with at most a 'ping_monitor'.
Maybe there will be some information that has to be sent to mdmon
over the socket, but it should be absolutely minimal.
Thanks,
NeilBrown
commit b545e14a2142b946446cf80127c7c8801dab55c8
Author: NeilBrown
Date: Mon Feb 14 12:17:08 2011 +1100
analyse_change: fix calculation of after.data_disks and ->delta_disks.
When changing level when a new number of raid disks was explicitly
specified, we much make sure that the change implied by the
change in level is properly incorporated into the final result.
So explicitly track the change in number of parity disks
(delta_parity) and use it together with delta_disks to determine
final data_disks.
Also set info->delta_disks so other code doesn't need to mirror
this analysis.
And add some errors in cases where a new number of disks was
requested but is not currently supported
Reported-by: Adam Kwolek
Signed-off-by: NeilBrown
diff --git a/Grow.c b/Grow.c
index 49831ad..424d489 100644
--- a/Grow.c
+++ b/Grow.c
@@ -893,6 +893,10 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
* when assembling an array that is undergoing reshape.
*/
int new_disks;
+ /* delta_parity records change in number of devices
+ * caused by level change
+ */
+ int delta_parity = 0;
/* If a new level not explicitly given, we assume no-change */
if (info->new_level == UnSet)
@@ -925,6 +929,10 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
* raid0 with 1 disk
*/
if (info->new_level == 0) {
+ if (info->delta_disks != UnSet &&
+ info->delta_disks != 0)
+ return "Cannot change number of disks "
+ "with RAID1->RAID0 conversion";
re->level = 0;
re->before.data_disks = 1;
re->after.data_disks = 1;
@@ -944,6 +952,10 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
}
if (info->array.raid_disks == 2 &&
info->new_level == 5) {
+ if (info->delta_disks != UnSet &&
+ info->delta_disks != 0)
+ return "Cannot change number of disks "
+ "with RAID1->RAID5 conversion";
re->level = 5;
re->before.data_disks = 1;
re->after.data_disks = 1;
@@ -970,10 +982,10 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
return "RAID10 can only be changed to RAID0";
new_disks = (info->array.raid_disks
/ (info->array.layout & 0xff));
- if (info->delta_disks == UnSet) {
+ if (info->delta_disks == UnSet)
info->delta_disks = (new_disks
- info->array.raid_disks);
- }
+
if (info->delta_disks != new_disks - info->array.raid_disks)
return "New number of raid-devices impossible for RAID10";
if (info->new_chunk &&
@@ -1032,16 +1044,19 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
* a raid4 style layout of the final level.
*/
switch (info->new_level) {
- case 0:
case 4:
+ delta_parity = 1;
+ case 0:
re->level = 4;
re->before.layout = 0;
break;
case 5:
+ delta_parity = 1;
re->level = 5;
re->before.layout = ALGORITHM_PARITY_N;
break;
case 6:
+ delta_parity = 2;
re->level = 6;
re->before.layout = ALGORITHM_PARITY_N;
break;
@@ -1057,6 +1072,7 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
case 5:
switch (info->new_level) {
case 0:
+ delta_parity = -1;
case 4:
re->level = info->array.level;
re->before.data_disks = info->array.raid_disks - 1;
@@ -1068,6 +1084,7 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
re->before.layout = info->array.layout;
break;
case 6:
+ delta_parity = 1;
re->level = 6;
re->before.data_disks = info->array.raid_disks - 1;
switch (info->array.layout) {
@@ -1096,6 +1113,10 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
case 1:
if (info->array.raid_disks != 2)
return "Can only convert a 2-device array to RAID1";
+ if (info->delta_disks != UnSet &&
+ info->delta_disks != 0)
+ return "Cannot set raid_disk when "
+ "converting RAID5->RAID1";
re->level = 1;
break;
default:
@@ -1106,6 +1127,7 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
switch (info->new_level) {
case 4:
case 5:
+ delta_parity = -1;
case 6:
re->level = 6;
re->before.data_disks = info->array.raid_disks - 2;
@@ -1131,11 +1153,7 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
*/
if (re->level != 4 && re->level != 5)
return "Cannot covert to RAID0 from this level";
- if (info->delta_disks == UnSet)
- re->after.data_disks = re->before.data_disks;
- else
- re->after.data_disks =
- info->array.raid_disks + info->delta_disks;
+
switch (re->level) {
case 4:
re->after.layout = 0 ; break;
@@ -1148,11 +1166,7 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
/* We can only get to RAID4 from RAID5 */
if (re->level != 4 && re->level != 5)
return "Cannot convert to RAID4 from this level";
- if (info->delta_disks == UnSet)
- re->after.data_disks = re->before.data_disks;
- else
- re->after.data_disks =
- re->before.data_disks + info->delta_disks;
+
switch (re->level) {
case 4:
re->after.layout = 0 ; break;
@@ -1165,14 +1179,7 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
/* We get to RAID5 for RAID5 or RAID6 */
if (re->level != 5 && re->level != 6)
return "Cannot convert to RAID5 from this level";
- if (info->delta_disks == UnSet)
- re->after.data_disks = re->before.data_disks;
- else if (re->level == 5)
- re->after.data_disks =
- re->before.data_disks + info->delta_disks;
- else
- re->after.data_disks =
- info->array.raid_disks + info->delta_disks - 1;
+
switch (re->level) {
case 5:
if (info->new_layout == UnSet)
@@ -1205,11 +1212,6 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
/* We must already be at level 6 */
if (re->level != 6)
return "Impossible level change";
- if (info->delta_disks == UnSet)
- re->after.data_disks = re->before.data_disks;
- else
- re->after.data_disks = (info->array.raid_disks +
- info->delta_disks) - 2;
if (info->new_layout == UnSet)
re->after.layout = info->array.layout;
else
@@ -1218,6 +1220,12 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
default:
return "Impossible level change requested";
}
+ if (info->delta_disks == UnSet)
+ info->delta_disks = delta_parity;
+
+ re->after.data_disks = (re->before.data_disks
+ + info->delta_disks
+ - delta_parity);
switch (re->level) {
case 6: re->parity = 2; break;
case 4:
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html