[PATCH 0/5] Support for IMSM raid0->raid5 migration
[PATCH 0/5] Support for IMSM raid0->raid5 migration
am 28.04.2011 23:59:32 von unknown
The following series implements support for raid0->raid5 migration for IMSM
metadata. These patches also blocks opposite direction of migration.
Code mostly bases on patches sent to you by Adam Kwolek. I have incorporated
your remarks and I tested it quite extensively for comformity with IMSM
standard. I have also removed opposite direction, as it is:
* not standarized yet,
* the design is not settled with you,
* generic grow routines are not compatible with change of chunk size.
Please do not include these patches on 'master' branch, as they are supposed
to be a part of next minor mdadm version (ie. mdadm 3.2.3). I think good place
for them is 'devel-3.2'. Master should be reserved just for bug/stability fixes
for previous release.
---
Przemyslaw Czarnowski (5):
imsm: prepare update for level migrations reshape
imsm: fix: disable migration from raid5->raid0
imsm: prepare memory for level migration update
imsm: process update for raid level migrations
imsm: add new chunk size to metadata update
super-intel.c | 343 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 333 insertions(+), 10 deletions(-)
--
Best Regards,
Przemyslaw Czarnowski
--
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/5] imsm: prepare update for level migrations reshape
am 29.04.2011 00:00:05 von unknown
Introducing raid0->raid5 level migration metadata update structure
is prepared for future use.
Adding spare device is required to hold additional raid5 parity.
Mdadm just checks for spares, but it is not included in update.
If there are no spares available, abort. Otherwise we will create
degraded array what should be not allowed.
Mdmon will decide what spare device is used for parity.
Signed-off-by: Adam Kwolek
Signed-off-by: Przemyslaw Czarnowski
---
super-intel.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 107 insertions(+), 5 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 83135a6..9bf4714 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,20 @@ struct imsm_update_reshape {
enum imsm_update_type type;
int old_raid_disks;
int new_raid_disks;
+
+ int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
+};
+
+struct imsm_update_reshape_migration {
+ 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 */
};
@@ -6337,6 +6352,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);
@@ -6730,6 +6748,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;
@@ -7025,12 +7046,12 @@ static int imsm_create_metadata_update_for_reshape(
struct supertype *st,
struct geo_params *geo,
int old_raid_disks,
- struct imsm_update_reshape **updatep)
+ struct imsm_update_reshape_migration **updatep)
{
struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor;
int update_memory_size = 0;
- struct imsm_update_reshape *u = NULL;
+ struct imsm_update_reshape_migration *u = NULL;
struct mdinfo *spares = NULL;
int i;
int delta_disks = 0;
@@ -7105,6 +7126,70 @@ 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_migration **updatep)
+{
+ struct intel_super *super = st->sb;
+ int update_memory_size = 0;
+ struct imsm_update_reshape_migration *u = NULL;
+ struct imsm_dev *dev;
+ int previous_level = -1;
+
+ dprintf("imsm_create_metadata_update_for_migration(enter)"
+ " New Level = %i\n", geo->level);
+
+ /* size of all update data without anchor */
+ update_memory_size = sizeof(struct imsm_update_reshape_migration);
+
+ 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;
+
+ dev = get_imsm_dev(super, u->subdev);
+ if (dev) {
+ struct imsm_map *map;
+
+ map = get_imsm_map(dev, 0);
+ if (map)
+ previous_level = map->raid_level;
+ }
+ if ((geo->level == 5) && (previous_level == 0)) {
+ struct mdinfo *spares = NULL;
+
+ u->new_raid_disks++;
+ spares = get_spares_for_grow(st);
+ if ((spares == NULL) || (spares->array.spare_disks < 1)) {
+ free(u);
+ sysfs_free(spares);
+ update_memory_size = 0;
+ dprintf("error: cannot get spare device "
+ "for requested migration");
+ return 0;
+ }
+ sysfs_free(spares);
+ }
+ 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)
{
@@ -7341,7 +7426,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
if (imsm_reshape_is_allowed_on_container(
st, &geo, &old_raid_disks)) {
- struct imsm_update_reshape *u = NULL;
+ struct imsm_update_reshape_migration *u = NULL;
int len;
len = imsm_create_metadata_update_for_reshape(
@@ -7393,9 +7478,26 @@ 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_migration *u = NULL;
+ int len =
+ imsm_create_metadata_update_for_migration(
+ st, &geo, &u);
+ if (len < 1) {
+ dprintf("imsm: "
+ "Cannot prepare update\n");
+ break;
+ }
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/5] imsm: fix: disable migration from raid5->raid0
am 29.04.2011 00:00:38 von unknown
it is not supported yet, so start such transition is improper.
Signed-off-by: Przemyslaw Czarnowski
---
super-intel.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 9bf4714..c02c5c8 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -7247,10 +7247,6 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
check_devs = 1;
}
break;
- case 5:
- if (geo->level == 0)
- change = CH_MIGRATION;
- break;
case 10:
if (geo->level == 0) {
change = CH_TAKEOVER;
--
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/5] imsm: prepare memory for level migration update
am 29.04.2011 00:01:12 von unknown
When level is changed from raid0 to raid5 memory is required for replace device
smaller device/array object.
This memory is allocated in manager context in prepare_update()
Prepare_update() is called in manager context so memory allocation are
allowed here. This allows us to look for spare devices for meta update.
Signed-off-by: Adam Kwolek
Signed-off-by: Przemyslaw Czarnowski
---
super-intel.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 86 insertions(+), 0 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index c02c5c8..877d9e6 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -6651,6 +6651,8 @@ static void imsm_process_update(struct supertype *st,
}
}
+static struct mdinfo *get_spares_for_grow(struct supertype *st);
+
static void imsm_prepare_update(struct supertype *st,
struct metadata_update *update)
{
@@ -6749,6 +6751,90 @@ 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_migration *u = (void *)update->buf;
+ struct intel_dev *id;
+ void **space_tail = (void **)&update->space_list;
+ int size;
+ void *s;
+ int current_level = -1;
+
+ 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;
+
+ /* add spare device to update
+ */
+ for (id = super->devlist ; id; id = id->next)
+ if (id->index == (unsigned)u->subdev) {
+ struct imsm_dev *dev;
+ struct imsm_map *map;
+
+ dev = get_imsm_dev(super, u->subdev);
+ map = get_imsm_map(dev, 0);
+ current_level = map->raid_level;
+ break;
+ }
+ if ((u->new_level == 5) && (u->new_level != current_level)) {
+ struct mdinfo *spares;
+
+ 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);
+ }
+ }
+ 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 4/5] imsm: process update for raid level migrations
am 29.04.2011 00:01:45 von unknown
Received update and prepared memory is processed to update imsm metadata.
Signed-off-by: Adam Kwolek
Signed-off-by: Przemyslaw Czarnowski
---
super-intel.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 122 insertions(+), 1 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 877d9e6..d4a45d7 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -6088,6 +6088,124 @@ static int add_remove_disk_update(struct intel_super *super)
return check_degraded;
}
+
+static int apply_reshape_migration_update(struct imsm_update_reshape_migration *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->raid_level == 0)) {
+ map->num_members++;
+ /* this should not happen */
+ 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);
+ if (u->new_level > -1)
+ map->raid_level = u->new_level;
+ migr_map = get_imsm_map(new_dev, 1);
+ if ((u->new_level == 5) &&
+ (migr_map->raid_level == 0)) {
+ int ord = map->num_members - 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) ||
+ (migr_map->raid_level != 0) ||
+ (migr_map->raid_level == map->raid_level))
+ 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)
@@ -6353,6 +6471,10 @@ static void imsm_process_update(struct supertype *st,
break;
}
case update_reshape_migration: {
+ struct imsm_update_reshape_migration *u = (void *)update->buf;
+ if (apply_reshape_migration_update(
+ u, super, &update->space_list))
+ super->updates_pending++;
break;
}
case update_activate_spare: {
@@ -6381,7 +6503,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 5/5] imsm: add new chunk size to metadata update
am 29.04.2011 00:02:22 von unknown
Put information about new chunk size change in to migration metadata
update allowing simultaneous level change and re-striping.
Signed-off-by: Adam Kwolek
Signed-off-by: Przemyslaw Czarnowski
---
super-intel.c | 20 +++++++++++++++++++-
1 files changed, 19 insertions(+), 1 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index d4a45d7..e3f3f19 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -354,6 +354,7 @@ struct imsm_update_reshape_migration {
int subdev;
int new_level;
int new_layout;
+ int new_chunksize;
int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
};
@@ -6156,6 +6157,12 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration *
id->dev = new_dev;
tofree = (void **)dev;
+ /* update chunk size
+ */
+ if (u->new_chunksize > 0)
+ map->blocks_per_strip =
+ __cpu_to_le16(u->new_chunksize * 2);
+
/* add disk
*/
if ((u->new_level != 5) ||
@@ -7367,14 +7374,25 @@ static int imsm_create_metadata_update_for_migration(
u->new_layout = geo->layout;
u->new_raid_disks = u->old_raid_disks = geo->raid_disks;
u->new_disks[0] = -1;
+ u->new_chunksize = -1;
dev = get_imsm_dev(super, u->subdev);
if (dev) {
struct imsm_map *map;
map = get_imsm_map(dev, 0);
- if (map)
+ if (map) {
+ int current_chunk_size =
+ __le16_to_cpu(map->blocks_per_strip) / 2;
+
+ if (geo->chunksize != current_chunk_size) {
+ u->new_chunksize = geo->chunksize / 1024;
+ dprintf("imsm: "
+ "chunk size change from %i to %i\n",
+ current_chunk_size, u->new_chunksize);
+ }
previous_level = map->raid_level;
+ }
}
if ((geo->level == 5) && (previous_level == 0)) {
struct mdinfo *spares = NULL;
--
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 1/5] imsm: prepare update for level migrations reshape
am 02.05.2011 08:15:10 von NeilBrown
On Fri, 29 Apr 2011 00:00:05 +0200 Przemyslaw Czarnowski
wrote:
struct intel_dev *dv;
> @@ -7025,12 +7046,12 @@ static int imsm_create_metadata_update_for_reshape(
> struct supertype *st,
> struct geo_params *geo,
> int old_raid_disks,
> - struct imsm_update_reshape **updatep)
> + struct imsm_update_reshape_migration **updatep)
> {
Why are you changing the type of 'updatep' for
imsm_create_metadata_update_for_reshape?
The subsequent code allocated memory based on the 'imsm_update_reshape'
structure, but then sets 'new_disk' entries based on the new structure.
That has got to be wrong.
Please review and fix this up.
NeilBrown
--
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