]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
imsm: prepare memory for level migration update
authorPrzemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>
Wed, 4 May 2011 15:12:14 +0000 (17:12 +0200)
committerNeilBrown <neilb@suse.de>
Mon, 9 May 2011 01:45:53 +0000 (11:45 +1000)
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>
super-intel.c

index 71687f1c0098e0f8045ac255f5c8d3fb0897a511..8ee371025d425e59d6418196c61dfbe05cdbe9ff 100644 (file)
@@ -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: {