summaryrefslogtreecommitdiff
path: root/super-intel.c
diff options
context:
space:
mode:
authorPrzemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>2011-05-04 17:12:14 +0200
committerNeilBrown <neilb@suse.de>2011-05-09 11:45:53 +1000
commitbc0b9d34968b5f681ab91ddbc27dbe5995aaa695 (patch)
tree2de7abdd6dc50c99b31058aff4193264c12fc449 /super-intel.c
parentc7958710e7ddd33914614cb73f52fd3e166e2877 (diff)
imsm: prepare memory for level migration update
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 <adam.kwolek@intel.com> Signed-off-by: Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'super-intel.c')
-rw-r--r--super-intel.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/super-intel.c b/super-intel.c
index 71687f1c..8ee37102 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -6652,6 +6652,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)
{
@@ -6750,6 +6752,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: {