]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
imsm: Add new metadata update for volume size expansion
authorAdam Kwolek <adam.kwolek@intel.com>
Fri, 13 Apr 2012 14:51:57 +0000 (16:51 +0200)
committerNeilBrown <neilb@suse.de>
Tue, 17 Apr 2012 02:33:37 +0000 (12:33 +1000)
Add new meatdata update type imsm_update_size_change, and update metadata
for volume size expansion operation.

Signed-off-by: Adam Kwolek <adam.kwolek@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
super-intel.c

index 2e6a899199876d23eb4013f783fc8ed03013dd93..ac8922f2000c7b7fa49a4fc4987aaadfd40f4edb 100644 (file)
@@ -419,6 +419,7 @@ enum imsm_update_type {
        update_reshape_migration,
        update_takeover,
        update_general_migration_checkpoint,
+       update_size_change,
 };
 
 struct imsm_update_activate_spare {
@@ -471,6 +472,12 @@ struct imsm_update_reshape_migration {
        int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
 };
 
+struct imsm_update_size_change {
+       enum imsm_update_type type;
+       int subdev;
+       long long new_size;
+};
+
 struct imsm_update_general_migration_checkpoint {
        enum imsm_update_type type;
        __u32 curr_migr_unit;
@@ -6974,7 +6981,8 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
        super->updates_pending++;
 }
 
-static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
+static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
+                                             long long new_size)
 {
        int used_disks = imsm_num_data_members(dev, MAP_0);
        unsigned long long array_blocks;
@@ -6993,8 +7001,17 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
 
        /* set array size in metadata
         */
-       map = get_imsm_map(dev, MAP_0);
-       array_blocks = blocks_per_member(map) * used_disks;
+       if (new_size <= 0) {
+               /* OLCE size change is caused by added disks
+                */
+               map = get_imsm_map(dev, MAP_0);
+               array_blocks = blocks_per_member(map) * used_disks;
+       } else {
+               /* Online Volume Size Change
+                * Using  available free space
+                */
+               array_blocks = new_size;
+       }
 
        /* round array size down to closest MB
         */
@@ -7051,7 +7068,7 @@ static void imsm_progress_container_reshape(struct intel_super *super)
                memcpy(map2, map, copy_map_size);
                map2->num_members = prev_num_members;
 
-               imsm_set_array_size(dev);
+               imsm_set_array_size(dev, -1);
                super->clean_migration_record_by_mdmon = 1;
                super->updates_pending++;
        }
@@ -7941,7 +7958,7 @@ skip_disk_add:
                        *tofree = *space_list;
                        /* calculate new size
                         */
-                       imsm_set_array_size(new_dev);
+                       imsm_set_array_size(new_dev, -1);
 
                        ret_val = 1;
                }
@@ -7956,6 +7973,44 @@ error_disk_add:
        return ret_val;
 }
 
+static int apply_size_change_update(struct imsm_update_size_change *u,
+               struct intel_super *super)
+{
+       struct intel_dev *id;
+       int ret_val = 0;
+
+       dprintf("apply_size_change_update()\n");
+       if ((u->subdev < 0) ||
+           (u->subdev > 1)) {
+               dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
+               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 = get_imsm_map(dev, MAP_0);
+                       int used_disks = imsm_num_data_members(dev, MAP_0);
+                       unsigned long long blocks_per_member;
+
+                       /* calculate new size
+                        */
+                       blocks_per_member = u->new_size / used_disks;
+                       dprintf("imsm: apply_size_change_update(size: %llu, "
+                               "blocks per member: %llu)\n",
+                               u->new_size, blocks_per_member);
+                       set_blocks_per_member(map, blocks_per_member);
+                       imsm_set_array_size(dev, u->new_size);
+
+                       ret_val = 1;
+                       break;
+               }
+       }
+
+       return ret_val;
+}
+
+
 static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                                       struct intel_super *super,
                                       struct active_array *active_array)
@@ -8155,7 +8210,7 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
                        newmap = get_imsm_map(newdev, MAP_1);
                        memcpy(newmap, oldmap, sizeof_imsm_map(oldmap));
 
-                       imsm_set_array_size(newdev);
+                       imsm_set_array_size(newdev, -1);
                }
 
                sp = (void **)id->dev;
@@ -8363,6 +8418,12 @@ static void imsm_process_update(struct supertype *st,
                        super->updates_pending++;
                break;
        }
+       case update_size_change: {
+               struct imsm_update_size_change *u = (void *)update->buf;
+               if (apply_size_change_update(u, super))
+                       super->updates_pending++;
+               break;
+       }
        case update_activate_spare: {
                struct imsm_update_activate_spare *u = (void *) update->buf; 
                if (apply_update_activate_spare(u, super, st->arrays))
@@ -8757,6 +8818,9 @@ static void imsm_prepare_update(struct supertype *st,
                dprintf("New anchor length is %llu\n", (unsigned long long)len);
                break;
        }
+       case update_size_change: {
+               break;
+       }
        case update_create_array: {
                struct imsm_update_create_array *u = (void *) update->buf;
                struct intel_dev *dv;
@@ -9614,6 +9678,43 @@ abort:
        return 0;
 }
 
+
+/******************************************************************************
+ * function: imsm_create_metadata_update_for_size_change()
+ *           Creates update for IMSM array for array size change.
+ *
+ ******************************************************************************/
+static int imsm_create_metadata_update_for_size_change(
+                               struct supertype *st,
+                               struct geo_params *geo,
+                               struct imsm_update_size_change **updatep)
+{
+       struct intel_super *super = st->sb;
+       int update_memory_size = 0;
+       struct imsm_update_size_change *u = NULL;
+
+       dprintf("imsm_create_metadata_update_for_size_change(enter)"
+               " New size = %llu\n", geo->size);
+
+       /* size of all update data without anchor */
+       update_memory_size = sizeof(struct imsm_update_size_change);
+
+       u = calloc(1, update_memory_size);
+       if (u == NULL) {
+               dprintf("error: cannot get memory for "
+                       "imsm_create_metadata_update_for_size_change\n");
+               return 0;
+       }
+       u->type = update_size_change;
+       u->subdev = super->current_vol;
+       u->new_size = geo->size;
+
+       dprintf("imsm: reshape update preparation : OK\n");
+       *updatep = u;
+
+       return update_memory_size;
+}
+
 /******************************************************************************
  * function: imsm_create_metadata_update_for_migration()
  *           Creates update for IMSM array.
@@ -10023,8 +10124,23 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                }
                break;
                case CH_ARRAY_SIZE: {
-                       /* ToDo: Prepare metadata update here
-                        */
+                       struct imsm_update_size_change *u = NULL;
+                       int len =
+                               imsm_create_metadata_update_for_size_change(
+                                       st, &geo, &u);
+                       if (len < 1) {
+                               dprintf("imsm: "
+                                       "Cannot prepare update\n");
+                               break;
+                       }
+                       ret_val = 0;
+                       /* 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: