(Online Capacity Expansion for IMSM) When mdadm post update uptate_grow_array mdmon has to perform 3 operations: 1. In prepare_update() calculate new anchor size in the way that greater disks number will fit allocated area. This is done by setting new value of len variable. 2. In process_update() device configuration prepared by mdadm is copied in to mdmon, and metadata update is triggered. 3. In process_update() general migration is started. Signed-off-by: Adam Kwolek <adam.kwolek@xxxxxxxxx> --- super-intel.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 123 insertions(+), 1 deletions(-) diff --git a/super-intel.c b/super-intel.c index b4a1f14..2f3c02d 100644 --- a/super-intel.c +++ b/super-intel.c @@ -5167,7 +5167,6 @@ int imsm_grow_array(struct active_array *a, int new_raid_disks) * metadata */ di->disk.number = dl->index; - dl->disk.status |= CONFIGURED_DISK; dl->disk.status &= ~SPARE_DISK; @@ -5341,6 +5340,108 @@ static void imsm_process_update(struct supertype *st, break; } case update_grow_array: { + /* every update is valid for adding single disk only + * if you want to add mmore disks, post update list + */ + struct imsm_update_grow_array *u = (void *)update->buf; + struct imsm_dev *dev = NULL; + struct imsm_dev *dev_new = NULL; + struct imsm_map *map = NULL; + struct imsm_map *migr_map = NULL; + struct imsm_map *migr_map_src = NULL; + struct dl *dl = NULL; + __u8 to_state; + int hdd_count = 0; + struct active_array *a = NULL; + int slot; + int update_grow_array_status = -1; + + slot = u->slot; + if (u->reshape_delta_disks <= 0) { + fprintf(stderr, "error:(imsm) "\ + "Wrong update is passed\n"); + goto update_grow_array_exit; + } + + /* get active array that update applies to + */ + for (a = st->arrays; a; a = a->next) { + if (a->devnum == u->devnum) + break; + } + + if (a == NULL) { + fprintf(stderr, "error:(imsm) "\ + "Cannot find requested array\n"); + goto update_grow_array_exit; + } + + dev = get_imsm_dev(super, a->info.container_member); + if (dev == NULL) { + fprintf(stderr, "error:(imsm) "\ + "Cannot find requested device\n"); + goto update_grow_array_exit; + } + + /* get map + */ + map = get_imsm_map(&u->dev, 0); + if (map == NULL) { + fprintf(stderr, + "error:(imsm) "\ + "Invalid map for requested device.\n"); + goto update_grow_array_exit; + } + + /* count HDDs + */ + for (dl = super->disks; dl; dl = dl->next) { + if (dl->index >= 0) + hdd_count++; + } + if (hdd_count > map->num_members) { + fprintf(stderr, "error:(imsm) "\ + "Received update doesn't match raid configuration\n"); + goto update_grow_array_exit; + } + + dev_new = &u->dev; + /* verify new device + */ + migr_map = get_imsm_map(dev_new, 1); + if (migr_map == NULL) { + fprintf(stderr, "error:(imsm) "\ + "Received update has corrupted device\n"); + goto update_grow_array_exit; + } + + /* it seams that everything is ok, copy device + * new size has to be reserved in managemon during + * grow detection + */ + memcpy(dev, dev_new, sizeof_imsm_dev(dev_new, 1)); + /* get migration map and backup it + */ + map = get_imsm_map(dev, 0); + + /* set migration/ no migration in progress */ + to_state = imsm_check_degraded(super, dev, 0); + migrate(dev, to_state, MIGR_GEN_MIGR); + migr_map = get_imsm_map(dev, 1); + /* get source map + */ + migr_map_src = get_imsm_map(dev_new, 1); + memcpy(migr_map, migr_map_src, sizeof_imsm_map(migr_map_src)); + + super->updates_pending++; + + /* operatio succed - no exit with error + */ + update_grow_array_status = 1; + +update_grow_array_exit: + if (update_grow_array_status < 0) + return; break; } case update_activate_spare: { @@ -5619,6 +5720,27 @@ static void imsm_prepare_update(struct supertype *st, break; } case update_grow_array: { + struct imsm_update_grow_array *u = (void *) update->buf; + struct imsm_dev *dev = &u->dev; + struct imsm_map *map = get_imsm_map(dev, 1); + + dprintf("prepare_update(): update_grow_array\n"); + + if (u->reshape_delta_disks <= 0) + break; + + /* add place for device in device list + */ + len += u->reshape_delta_disks * sizeof(struct imsm_disk); + + /* add place in first map + */ + len += u->reshape_delta_disks * sizeof(__u32); + + /* add second map + */ + len += sizeof(struct imsm_map) + (map->num_members - 1) * +sizeof(__u32); + break; } case update_create_array: { ��.n��������+%������w��{.n�����{����w��ܨ}���Ơz�j:+v�����w����ޙ��&�)ߡ�a����z�ޗ���ݢj��w�f