]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Typo in dprintf
[thirdparty/mdadm.git] / super-intel.c
index 295aa1d04a2b747c64a52c24f88662fe99aaf8cb..cd409e92cadbc19e936ae05c4128f6ff29913d8b 100644 (file)
@@ -1690,6 +1690,8 @@ static __u64 blocks_per_migr_unit(struct imsm_dev *dev)
                migr_chunk = migr_strip_blocks_resync(dev);
                disks = imsm_num_data_members(dev, 0);
                blocks_per_unit = stripes_per_unit * migr_chunk * disks;
+               if (migr_type(dev) == MIGR_GEN_MIGR)
+                       return blocks_per_unit;
                stripe = __le32_to_cpu(map->blocks_per_strip) * disks;
                segment = blocks_per_unit / stripe;
                block_rel = blocks_per_unit - segment * stripe;
@@ -1756,14 +1758,53 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        info->custom_array_size   = __le32_to_cpu(dev->size_high);
        info->custom_array_size   <<= 32;
        info->custom_array_size   |= __le32_to_cpu(dev->size_low);
-       if (prev_map) {
+       if (prev_map && map->map_state == prev_map->map_state) {
+               info->reshape_active = 1;
                info->new_level = get_imsm_raid_level(map);
                info->new_layout = imsm_level_to_layout(info->new_level);
                info->new_chunk = __le16_to_cpu(map->blocks_per_strip) << 9;
+               info->delta_disks = map->num_members - prev_map->num_members;
+               if (info->delta_disks) {
+                       /* this needs to be applied to every array
+                        * in the container.
+                        */
+                       info->reshape_active = 2;
+               }
+               /* We shape information that we give to md might have to be
+                * modify to cope with md's requirement for reshaping arrays.
+                * For example, when reshaping a RAID0, md requires it to be
+                * presented as a degraded RAID4.
+                * Also if a RAID0 is migrating to a RAID5 we need to specify
+                * the array as already being RAID5, but the 'before' layout
+                * is a RAID4-like layout.
+                */
+               switch (info->array.level) {
+               case 0:
+                       switch(info->new_level) {
+                       case 0:
+                               /* conversion is happening as RAID4 */
+                               info->array.level = 4;
+                               info->array.raid_disks += 1;
+                               break;
+                       case 5:
+                               /* conversion is happening as RAID5 */
+                               info->array.level = 5;
+                               info->array.layout = ALGORITHM_PARITY_N;
+                               info->array.raid_disks += 1;
+                               info->delta_disks -= 1;
+                               break;
+                       default:
+                               /* FIXME error message */
+                               info->array.level = UnSet;
+                               break;
+                       }
+                       break;
+               }
        } else {
                info->new_level = UnSet;
                info->new_layout = UnSet;
                info->new_chunk = info->array.chunk_size;
+               info->delta_disks = 0;
        }
        info->disk.major = 0;
        info->disk.minor = 0;
@@ -1777,13 +1818,8 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                __le32_to_cpu(map_to_analyse->blocks_per_member);
        memset(info->uuid, 0, sizeof(info->uuid));
        info->recovery_start = MaxSector;
-       info->reshape_active = (prev_map != NULL) &&
-                              (map->map_state == prev_map->map_state);
-       if (info->reshape_active)
-               info->delta_disks = map->num_members - prev_map->num_members;
-       else
-               info->delta_disks = 0;
 
+       info->reshape_progress = 0;
        if (map_to_analyse->map_state == IMSM_T_STATE_UNINITIALIZED ||
            dev->vol.dirty) {
                info->resync_start = 0;
@@ -1797,6 +1833,28 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                        info->resync_start = blocks_per_unit * units;
                        break;
                }
+               case MIGR_GEN_MIGR: {
+                       __u64 blocks_per_unit = blocks_per_migr_unit(dev);
+                       __u64 units = __le32_to_cpu(dev->vol.curr_migr_unit);
+                       unsigned long long array_blocks;
+                       int used_disks;
+
+                       info->reshape_progress = blocks_per_unit * units;
+                       dprintf("IMSM: General Migration checkpoint : %llu "
+                              "(%llu) -> read reshape progress : %llu\n",
+                               units, blocks_per_unit, info->reshape_progress);
+
+                       used_disks = imsm_num_data_members(dev, 1);
+                       if (used_disks > 0) {
+                               array_blocks = map->blocks_per_member *
+                                       used_disks;
+                               /* round array size down to closest MB
+                                */
+                               info->custom_array_size = (array_blocks
+                                               >> SECT_PER_MB_SHIFT)
+                                               << SECT_PER_MB_SHIFT;
+                       }
+               }
                case MIGR_VERIFY:
                        /* we could emulate the checkpointing of
                         * 'sync_action=check' migrations, but for now
@@ -1804,7 +1862,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                         */
                case MIGR_REBUILD:
                        /* this is handled by container_content_imsm() */
-               case MIGR_GEN_MIGR:
                case MIGR_STATE_CHANGE:
                        /* FIXME handle other migrations */
                default:
@@ -3409,12 +3466,13 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                fprintf(stderr, Name ": failed to allocate device list entry\n");
                return 0;
        }
-       dev = malloc(sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
+       dev = calloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
        if (!dev) {
                free(dv);
                fprintf(stderr, Name": could not allocate raid device\n");
                return 0;
        }
+
        strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN);
        if (info->level == 1)
                array_blocks = info_to_blocks_per_member(info);
@@ -3427,8 +3485,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
 
        dev->size_low = __cpu_to_le32((__u32) array_blocks);
        dev->size_high = __cpu_to_le32((__u32) (array_blocks >> 32));
-       dev->status = __cpu_to_le32(0);
-       dev->reserved_blocks = __cpu_to_le32(0);
+       dev->status = (DEV_READ_COALESCING | DEV_WRITE_COALESCING);
        vol = &dev->vol;
        vol->migr_state = 0;
        set_migr_type(dev, MIGR_INIT);
@@ -4165,17 +4222,21 @@ static int is_raid_level_supported(const struct imsm_orom *orom, int level, int
 #define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
 static int
 validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
-                           int raiddisks, int chunk, int verbose)
+                           int raiddisks, int *chunk, int verbose)
 {
        if (!is_raid_level_supported(super->orom, level, raiddisks)) {
                pr_vrb(": platform does not support raid%d with %d disk%s\n",
                        level, raiddisks, raiddisks > 1 ? "s" : "");
                return 0;
        }
-       if (super->orom && level != 1 &&
-           !imsm_orom_has_chunk(super->orom, chunk)) {
-               pr_vrb(": platform does not support a chunk size of: %d\n", chunk);
-               return 0;
+       if (super->orom && level != 1) {
+               if (chunk && (*chunk == 0 || *chunk == UnSet))
+                       *chunk = imsm_orom_default_chunk(super->orom);
+               else if (chunk && !imsm_orom_has_chunk(super->orom, *chunk)) {
+                       pr_vrb(": platform does not support a chunk size of: "
+                              "%d\n", *chunk);
+                       return 0;
+               }
        }
        if (layout != imsm_level_to_layout(level)) {
                if (level == 5)
@@ -4195,7 +4256,7 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
  * FIX ME add ahci details
  */
 static int validate_geometry_imsm_volume(struct supertype *st, int level,
-                                        int layout, int raiddisks, int chunk,
+                                        int layout, int raiddisks, int *chunk,
                                         unsigned long long size, char *dev,
                                         unsigned long long *freesize,
                                         int verbose)
@@ -4414,7 +4475,7 @@ static int reserve_space(struct supertype *st, int raiddisks,
 }
 
 static int validate_geometry_imsm(struct supertype *st, int level, int layout,
-                                 int raiddisks, int chunk, unsigned long long size,
+                                 int raiddisks, int *chunk, unsigned long long size,
                                  char *dev, unsigned long long *freesize,
                                  int verbose)
 {
@@ -4428,7 +4489,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        if (level == LEVEL_CONTAINER) {
                /* Must be a fresh device to add to a container */
                return validate_geometry_imsm_container(st, level, layout,
-                                                       raiddisks, chunk, size,
+                                                       raiddisks,
+                                                       chunk?*chunk:0, size,
                                                        dev, freesize,
                                                        verbose);
        }
@@ -4447,7 +4509,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                                         raiddisks, chunk,
                                                         verbose))
                                return 0;
-                       return reserve_space(st, raiddisks, size, chunk, freesize);
+                       return reserve_space(st, raiddisks, size,
+                                            chunk?*chunk:0, freesize);
                }
                return 1;
        }
@@ -4732,11 +4795,19 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
        struct mdinfo *rest = NULL;
        unsigned int i;
        int bbm_errors = 0;
+       struct dl *d;
+       int spare_disks = 0;
 
        /* check for bad blocks */
        if (imsm_bbm_log_size(super->anchor))
                bbm_errors = 1;
 
+       /* count spare devices, not used in maps
+        */
+       for (d = super->disks; d; d = d->next)
+               if (d->index == -1)
+                       spare_disks++;
+
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct imsm_dev *dev;
                struct imsm_map *map;
@@ -4785,7 +4856,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
 
                        skip = 0;
                        idx = get_imsm_disk_idx(dev, slot, 0);
-                       ord = get_imsm_ord_tbl_ent(dev, slot, 0);
+                       ord = get_imsm_ord_tbl_ent(dev, slot, -1);
                        for (d = super->disks; d ; d = d->next)
                                if (d->index == idx)
                                        break;
@@ -4853,6 +4924,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                }
                /* now that the disk list is up-to-date fixup recovery_start */
                update_recovery_start(dev, this);
+               this->array.spare_disks += spare_disks;
                rest = this;
        }
 
@@ -5009,6 +5081,8 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
        __u32 ord;
        int slot;
        struct imsm_map *map;
+       char buf[MAX_RAID_SERIAL_LEN+3];
+       unsigned int len, shift = 0;
 
        /* new failures are always set in map[0] */
        map = get_imsm_map(dev, 0);
@@ -5021,8 +5095,12 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
        if (is_failed(disk) && (ord & IMSM_ORD_REBUILD))
                return 0;
 
+       sprintf(buf, "%s:0", disk->serial);
+       if ((len = strlen(buf)) >= MAX_RAID_SERIAL_LEN)
+               shift = len - MAX_RAID_SERIAL_LEN + 1;
+       strncpy((char *)disk->serial, &buf[shift], MAX_RAID_SERIAL_LEN);
+
        disk->status |= FAILED_DISK;
-       disk->status &= ~CONFIGURED_DISK;
        set_imsm_ord_tbl_ent(map, slot, idx | IMSM_ORD_REBUILD);
        if (map->failed_disk_num == 0xff)
                map->failed_disk_num = slot;
@@ -5165,18 +5243,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                 */
                if (a->curr_action == reshape) {
                        /* still reshaping, maybe update curr_migr_unit */
-                       long long blocks_per_unit = blocks_per_migr_unit(dev);
-                       long long unit = a->last_checkpoint;
-                       if (blocks_per_unit) {
-                               unit /= blocks_per_unit;
-                               if (unit >
-                                   __le32_to_cpu(dev->vol.curr_migr_unit)) {
-                                       dev->vol.curr_migr_unit =
-                                               __cpu_to_le32(unit);
-                                       super->updates_pending++;
-                               }
-                       }
-                       return 0;
+                       goto mark_checkpoint;
                } else {
                        if (a->last_checkpoint == 0 && a->prev_action == reshape) {
                                /* for some reason we aborted the reshape.
@@ -5210,7 +5277,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                                         */
 
                                        a->check_reshape = 1;
-}
+                               }
                                /* finalize online capacity expansion/reshape */
                                for (mdi = a->info.devs; mdi; mdi = mdi->next)
                                        imsm_set_disk(a,
@@ -5253,6 +5320,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                super->updates_pending++;
        }
 
+mark_checkpoint:
        /* check if we can update curr_migr_unit from resync_start, recovery_start */
        blocks_per_unit = blocks_per_migr_unit(dev);
        if (blocks_per_unit) {
@@ -6026,8 +6094,6 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
                        *space_list = *space;
                        du = (void *)space;
                        memcpy(du, super->disks, sizeof(*du));
-                       du->disk.status = FAILED_DISK;
-                       du->disk.scsi_id = 0;
                        du->fd = -1;
                        du->minor = 0;
                        du->major = 0;
@@ -6048,9 +6114,8 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
                memcpy(dev_new, dev, sizeof(*dev));
                /* update new map */
                map = get_imsm_map(dev_new, 0);
-               map->failed_disk_num = map->num_members;
                map->num_members = map->num_members * 2;
-               map->map_state = IMSM_T_STATE_NORMAL;
+               map->map_state = IMSM_T_STATE_DEGRADED;
                map->num_domains = 2;
                map->raid_level = 1;
                /* replace dev<->dev_new */
@@ -6061,9 +6126,10 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
                if (du->index >= 0)
                        set_imsm_ord_tbl_ent(map, du->index, du->index);
        for (du = super->missing; du; du = du->next)
-               if (du->index >= 0)
-                       set_imsm_ord_tbl_ent(map, du->index,
-                                               du->index | IMSM_ORD_REBUILD);
+               if (du->index >= 0) {
+                       set_imsm_ord_tbl_ent(map, du->index, du->index);
+                       mark_missing(dev_new, &du->disk, du->index);
+               }
 
        return 1;
 }
@@ -6112,8 +6178,10 @@ static void imsm_process_update(struct supertype *st,
        switch (type) {
        case update_takeover: {
                struct imsm_update_takeover *u = (void *)update->buf;
-               if (apply_takeover_update(u, super, &update->space_list))
+               if (apply_takeover_update(u, super, &update->space_list)) {
+                       imsm_update_version_info(super);
                        super->updates_pending++;
+               }
                break;
        }
 
@@ -6842,7 +6910,8 @@ static int imsm_create_metadata_update_for_reshape(
 
        if (spares == NULL
            || delta_disks > spares->array.spare_disks) {
-               dprintf("imsm: ERROR: Cannot get spare devices.\n");
+               fprintf(stderr, Name ": imsm: ERROR: Cannot get spare devices "
+                       "for %s.\n", geo->dev_name);
                goto abort;
        }
 
@@ -6916,6 +6985,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        struct mdinfo info;
        int change = -1;
        int check_devs = 0;
+       int chunk;
 
        getinfo_super_imsm_volume(st, &info, NULL);
 
@@ -6990,11 +7060,12 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        else
                geo->chunksize = info.array.chunk_size;
 
+       chunk = geo->chunksize / 1024;
        if (!validate_geometry_imsm(st,
                                    geo->level,
                                    geo->layout,
                                    geo->raid_disks,
-                                   (geo->chunksize / 1024),
+                                   &chunk,
                                    geo->size,
                                    0, 0, 1))
                change = -1;
@@ -7053,7 +7124,8 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo)
 
 static int imsm_reshape_super(struct supertype *st, long long size, int level,
                              int layout, int chunksize, int raid_disks,
-                             char *backup, char *dev, int verbose)
+                             int delta_disks, char *backup, char *dev,
+                             int verbose)
 {
        int ret_val = 1;
        struct geo_params geo;
@@ -7069,6 +7141,8 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
        geo.layout = layout;
        geo.chunksize = chunksize;
        geo.raid_disks = raid_disks;
+       if (delta_disks != UnSet)
+               geo.raid_disks += delta_disks;
 
        dprintf("\tfor level      : %i\n", geo.level);
        dprintf("\tfor raid_disks : %i\n", geo.raid_disks);