X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=super-intel.c;h=6e4a7d90d8e9676a7ba329790768af37922d4ccd;hp=f55d707667b17baa47b31172eea02a8e8f78ffa6;hb=148acb7baaa810b68d55df4c1784d6bd0dfd1b78;hpb=db575f3b9ebfdf0d7ac8dd5f9b1d4b4d0e446e80 diff --git a/super-intel.c b/super-intel.c index f55d7076..6e4a7d90 100644 --- a/super-intel.c +++ b/super-intel.c @@ -53,6 +53,7 @@ #define MPB_SECTOR_CNT 418 #define IMSM_RESERVED_SECTORS 4096 +#define SECT_PER_MB_SHIFT 11 /* Disk configuration info. */ #define IMSM_MAX_DEVICES 255 @@ -88,7 +89,7 @@ struct imsm_map { __u8 num_members; /* number of member disks */ __u8 num_domains; /* number of parity domains */ __u8 failed_disk_num; /* valid only when state is degraded */ - __u8 reserved[1]; + __u8 ddf; __u32 filler[7]; /* expansion area */ #define IMSM_ORD_REBUILD (1 << 24) __u32 disk_ord_tbl[1]; /* disk_ord_tbl[num_members], @@ -105,6 +106,7 @@ struct imsm_vol { #define MIGR_VERIFY 2 /* analagous to echo check > sync_action */ #define MIGR_GEN_MIGR 3 #define MIGR_STATE_CHANGE 4 +#define MIGR_REPAIR 5 __u8 migr_type; /* Initializing, Rebuilding, ... */ __u8 dirty; __u8 fs_state; /* fast-sync state for CnG (0xff == disabled) */ @@ -193,6 +195,29 @@ struct bbm_log { static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" }; #endif +static __u8 migr_type(struct imsm_dev *dev) +{ + if (dev->vol.migr_type == MIGR_VERIFY && + dev->status & DEV_VERIFY_AND_FIX) + return MIGR_REPAIR; + else + return dev->vol.migr_type; +} + +static void set_migr_type(struct imsm_dev *dev, __u8 migr_type) +{ + /* for compatibility with older oroms convert MIGR_REPAIR, into + * MIGR_VERIFY w/ DEV_VERIFY_AND_FIX status + */ + if (migr_type == MIGR_REPAIR) { + dev->vol.migr_type = MIGR_VERIFY; + dev->status |= DEV_VERIFY_AND_FIX; + } else { + dev->vol.migr_type = migr_type; + dev->status &= ~DEV_VERIFY_AND_FIX; + } +} + static unsigned int sector_count(__u32 bytes) { return ((bytes + (512-1)) & (~(512-1))) / 512; @@ -222,6 +247,7 @@ struct intel_super { int creating_imsm; /* flag to indicate container creation */ int current_vol; /* index of raid device undergoing creation */ __u32 create_offset; /* common start for 'current_vol' */ + __u32 random; /* random data for seeding new family numbers */ struct intel_dev *devlist; struct dl { struct dl *next; @@ -233,6 +259,7 @@ struct intel_super { int fd; int extent_cnt; struct extent *e; /* for determining freespace @ create */ + int raiddisk; /* slot to fill in autolayout */ } *disks; struct dl *add; /* list of disks to add while mdmon active */ struct dl *missing; /* disks removed while we weren't looking */ @@ -620,10 +647,23 @@ static void print_imsm_dev(struct imsm_dev *dev, char *uuid, int disk_idx) printf(" Chunk Size : %u KiB\n", __le16_to_cpu(map->blocks_per_strip) / 2); printf(" Reserved : %d\n", __le32_to_cpu(dev->reserved_blocks)); - printf(" Migrate State : %s", dev->vol.migr_state ? "migrating" : "idle"); - if (dev->vol.migr_state) - printf(": %s", dev->vol.migr_type ? "rebuilding" : "initializing"); - printf("\n"); + printf(" Migrate State : %s", dev->vol.migr_state ? "migrating" : "idle\n"); + if (dev->vol.migr_state) { + if (migr_type(dev) == MIGR_INIT) + printf(": initializing\n"); + else if (migr_type(dev) == MIGR_REBUILD) + printf(": rebuilding\n"); + else if (migr_type(dev) == MIGR_VERIFY) + printf(": check\n"); + else if (migr_type(dev) == MIGR_GEN_MIGR) + printf(": general migration\n"); + else if (migr_type(dev) == MIGR_STATE_CHANGE) + printf(": state change\n"); + else if (migr_type(dev) == MIGR_REPAIR) + printf(": repair\n"); + else + printf(": \n", migr_type(dev)); + } printf(" Map State : %s", map_state_str[map->map_state]); if (dev->vol.migr_state) { struct imsm_map *map = get_imsm_map(dev, 1); @@ -675,10 +715,11 @@ static void examine_super_imsm(struct supertype *st, char *homehost) printf(" Magic : %s\n", str); snprintf(str, strlen(MPB_VERSION_RAID0), "%s", get_imsm_version(mpb)); printf(" Version : %s\n", get_imsm_version(mpb)); + printf(" Orig Family : %08x\n", __le32_to_cpu(mpb->orig_family_num)); printf(" Family : %08x\n", __le32_to_cpu(mpb->family_num)); printf(" Generation : %08x\n", __le32_to_cpu(mpb->generation_num)); getinfo_super_imsm(st, &info); - fname_from_uuid(st, &info, nbuf,'-'); + fname_from_uuid(st, &info, nbuf, ':'); printf(" UUID : %s\n", nbuf + 5); sum = __le32_to_cpu(mpb->check_sum); printf(" Checksum : %08x %s\n", sum, @@ -696,7 +737,8 @@ static void examine_super_imsm(struct supertype *st, char *homehost) printf(" Signature : %x\n", __le32_to_cpu(log->signature)); printf(" Entry Count : %d\n", __le32_to_cpu(log->entry_count)); printf(" Spare Blocks : %d\n", __le32_to_cpu(log->reserved_spare_block_count)); - printf(" First Spare : %llx\n", __le64_to_cpu(log->first_spare_lba)); + printf(" First Spare : %llx\n", + (unsigned long long) __le64_to_cpu(log->first_spare_lba)); } for (i = 0; i < mpb->num_raid_devs; i++) { struct mdinfo info; @@ -704,7 +746,7 @@ static void examine_super_imsm(struct supertype *st, char *homehost) super->current_vol = i; getinfo_super_imsm(st, &info); - fname_from_uuid(st, &info, nbuf, '-'); + fname_from_uuid(st, &info, nbuf, ':'); print_imsm_dev(dev, nbuf + 5, super->disks->index); } for (i = 0; i < mpb->num_disks; i++) { @@ -714,7 +756,7 @@ static void examine_super_imsm(struct supertype *st, char *homehost) } } -static void brief_examine_super_imsm(struct supertype *st) +static void brief_examine_super_imsm(struct supertype *st, int verbose) { /* We just write a generic IMSM ARRAY entry */ struct mdinfo info; @@ -723,22 +765,38 @@ static void brief_examine_super_imsm(struct supertype *st) struct intel_super *super = st->sb; int i; - if (!super->anchor->num_raid_devs) + if (!super->anchor->num_raid_devs) { + printf("ARRAY metadata=imsm\n"); return; + } getinfo_super_imsm(st, &info); - fname_from_uuid(st, &info, nbuf,'-'); - printf("ARRAY metadata=imsm auto=md UUID=%s\n", nbuf + 5); + fname_from_uuid(st, &info, nbuf, ':'); for (i = 0; i < super->anchor->num_raid_devs; i++) { struct imsm_dev *dev = get_imsm_dev(super, i); super->current_vol = i; getinfo_super_imsm(st, &info); - fname_from_uuid(st, &info, nbuf1,'-'); - printf("ARRAY /dev/md/%.16s container=%s\n" - " member=%d auto=mdp UUID=%s\n", + fname_from_uuid(st, &info, nbuf1, ':'); + printf("ARRAY /dev/md/%.16s container=%s member=%d UUID=%s\n", dev->volume, nbuf + 5, i, nbuf1 + 5); } + printf("ARRAY metadata=imsm UUID=%s\n", nbuf + 5); +} + +static void export_examine_super_imsm(struct supertype *st) +{ + struct intel_super *super = st->sb; + struct imsm_super *mpb = super->anchor; + struct mdinfo info; + char nbuf[64]; + + getinfo_super_imsm(st, &info); + fname_from_uuid(st, &info, nbuf, ':'); + printf("MD_METADATA=imsm\n"); + printf("MD_LEVEL=container\n"); + printf("MD_UUID=%s\n", nbuf+5); + printf("MD_DEVICES=%u\n", mpb->num_disks); } static void detail_super_imsm(struct supertype *st, char *homehost) @@ -747,7 +805,7 @@ static void detail_super_imsm(struct supertype *st, char *homehost) char nbuf[64]; getinfo_super_imsm(st, &info); - fname_from_uuid(st, &info, nbuf,'-'); + fname_from_uuid(st, &info, nbuf, ':'); printf("\n UUID : %s\n", nbuf + 5); } @@ -756,7 +814,7 @@ static void brief_detail_super_imsm(struct supertype *st) struct mdinfo info; char nbuf[64]; getinfo_super_imsm(st, &info); - fname_from_uuid(st, &info, nbuf,'-'); + fname_from_uuid(st, &info, nbuf, ':'); printf(" UUID=%s", nbuf + 5); } @@ -979,6 +1037,23 @@ static int detail_platform_imsm(int verbose, int enumerate_only) imsm_orom_has_raid1e(orom) ? " raid1e" : "", imsm_orom_has_raid10(orom) ? " raid10" : "", imsm_orom_has_raid5(orom) ? " raid5" : ""); + printf(" Chunk Sizes :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + imsm_orom_has_chunk(orom, 2) ? " 2k" : "", + imsm_orom_has_chunk(orom, 4) ? " 4k" : "", + imsm_orom_has_chunk(orom, 8) ? " 8k" : "", + imsm_orom_has_chunk(orom, 16) ? " 16k" : "", + imsm_orom_has_chunk(orom, 32) ? " 32k" : "", + imsm_orom_has_chunk(orom, 64) ? " 64k" : "", + imsm_orom_has_chunk(orom, 128) ? " 128k" : "", + imsm_orom_has_chunk(orom, 256) ? " 256k" : "", + imsm_orom_has_chunk(orom, 512) ? " 512k" : "", + imsm_orom_has_chunk(orom, 1024*1) ? " 1M" : "", + imsm_orom_has_chunk(orom, 1024*2) ? " 2M" : "", + imsm_orom_has_chunk(orom, 1024*4) ? " 4M" : "", + imsm_orom_has_chunk(orom, 1024*8) ? " 8M" : "", + imsm_orom_has_chunk(orom, 1024*16) ? " 16M" : "", + imsm_orom_has_chunk(orom, 1024*32) ? " 32M" : "", + imsm_orom_has_chunk(orom, 1024*64) ? " 64M" : ""); printf(" Max Disks : %d\n", orom->tds); printf(" Max Volumes : %d\n", orom->vpa); printf(" I/O Controller : %s\n", hba_path); @@ -1018,7 +1093,7 @@ static int match_home_imsm(struct supertype *st, char *homehost) /* the imsm metadata format does not specify any host * identification information. We return -1 since we can never * confirm nor deny whether a given array is "meant" for this - * host. We rely on compare_super and the 'family_num' field to + * host. We rely on compare_super and the 'family_num' fields to * exclude member disks that do not belong, and we rely on * mdadm.conf to specify the arrays that should be assembled. * Auto-assembly may still pick up "foreign" arrays. @@ -1046,7 +1121,7 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4]) */ /* imsm does not track uuid's so we synthesis one using sha1 on * - The signature (Which is constant for all imsm array, but no matter) - * - the family_num of the container + * - the orig_family_num of the container * - the index number of the volume * - the 'serial' number of the volume. * Hopefully these are all constant. @@ -1056,10 +1131,18 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4]) char buf[20]; struct sha1_ctx ctx; struct imsm_dev *dev = NULL; + __u32 family_num; + /* some mdadm versions failed to set ->orig_family_num, in which + * case fall back to ->family_num. orig_family_num will be + * fixed up with the first metadata update. + */ + family_num = super->anchor->orig_family_num; + if (family_num == 0) + family_num = super->anchor->family_num; sha1_init_ctx(&ctx); sha1_process_bytes(super->anchor->sig, MPB_SIG_LEN, &ctx); - sha1_process_bytes(&super->anchor->family_num, sizeof(__u32), &ctx); + sha1_process_bytes(&family_num, sizeof(__u32), &ctx); if (super->current_vol >= 0) dev = get_imsm_dev(super, super->current_vol); if (dev) { @@ -1119,7 +1202,11 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info) struct intel_super *super = st->sb; struct imsm_dev *dev = get_imsm_dev(super, super->current_vol); struct imsm_map *map = get_imsm_map(dev, 0); + struct dl *dl; + for (dl = super->disks; dl; dl = dl->next) + if (dl->raiddisk == info->disk.raid_disk) + break; info->container_member = super->current_vol; info->array.raid_disks = map->num_members; info->array.level = get_imsm_raid_level(map); @@ -1129,9 +1216,16 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info) info->array.utime = 0; info->array.chunk_size = __le16_to_cpu(map->blocks_per_strip) << 9; info->array.state = !dev->vol.dirty; + 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); info->disk.major = 0; info->disk.minor = 0; + if (dl) { + info->disk.major = dl->major; + info->disk.minor = dl->minor; + } info->data_offset = __le32_to_cpu(map->pba_of_lba0); info->component_size = __le32_to_cpu(map->blocks_per_member); @@ -1140,7 +1234,8 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info) if (map->map_state == IMSM_T_STATE_UNINITIALIZED || dev->vol.dirty) info->resync_start = 0; else if (dev->vol.migr_state) - info->resync_start = __le32_to_cpu(dev->vol.curr_migr_unit); + /* FIXME add curr_migr_unit to resync_start conversion */ + info->resync_start = 0; else info->resync_start = ~0ULL; @@ -1355,7 +1450,8 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) */ if (first->anchor->num_raid_devs > 0 && sec->anchor->num_raid_devs > 0) { - if (first->anchor->family_num != sec->anchor->family_num) + if (first->anchor->orig_family_num != sec->anchor->orig_family_num || + first->anchor->family_num != sec->anchor->family_num) return 3; } @@ -1395,6 +1491,7 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) imsm_copy_dev(get_imsm_dev(first, i), get_imsm_dev(sec, i)); first->anchor->num_raid_devs = sec->anchor->num_raid_devs; + first->anchor->orig_family_num = sec->anchor->orig_family_num; first->anchor->family_num = sec->anchor->family_num; } @@ -1435,7 +1532,10 @@ static int imsm_read_serial(int fd, char *devname, int rv; int rsp_len; int len; - char *c, *rsp_buf; + char *dest; + char *src; + char *rsp_buf; + int i; memset(scsi_serial, 0, sizeof(scsi_serial)); @@ -1455,7 +1555,6 @@ static int imsm_read_serial(int fd, char *devname, return rv; } - /* trim leading whitespace */ rsp_len = scsi_serial[3]; if (!rsp_len) { if (devname) @@ -1465,24 +1564,33 @@ static int imsm_read_serial(int fd, char *devname, return 2; } rsp_buf = (char *) &scsi_serial[4]; - c = rsp_buf; - while (isspace(*c)) - c++; - /* truncate len to the end of rsp_buf if necessary */ - if (c + MAX_RAID_SERIAL_LEN > rsp_buf + rsp_len) - len = rsp_len - (c - rsp_buf); - else + /* trim all whitespace and non-printable characters and convert + * ':' to ';' + */ + for (i = 0, dest = rsp_buf; i < rsp_len; i++) { + src = &rsp_buf[i]; + if (*src > 0x20) { + /* ':' is reserved for use in placeholder serial + * numbers for missing disks + */ + if (*src == ':') + *dest++ = ';'; + else + *dest++ = *src; + } + } + len = dest - rsp_buf; + dest = rsp_buf; + + /* truncate leading characters */ + if (len > MAX_RAID_SERIAL_LEN) { + dest += len - MAX_RAID_SERIAL_LEN; len = MAX_RAID_SERIAL_LEN; + } - /* initialize the buffer and copy rsp_buf characters */ memset(serial, 0, MAX_RAID_SERIAL_LEN); - memcpy(serial, c, len); - - /* trim trailing whitespace starting with the last character copied */ - c = (char *) &serial[len - 1]; - while (isspace(*c) || *c == '\0') - *c-- = '\0'; + memcpy(serial, dest, len); return 0; } @@ -1601,7 +1709,7 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd) * 1/ Idle (migr_state=0 map0state=normal||unitialized||degraded||failed) * 2/ Initialize (migr_state=1 migr_type=MIGR_INIT map0state=normal * map1state=unitialized) - * 3/ Verify (Resync) (migr_state=1 migr_type=MIGR_REBUILD map0state=normal + * 3/ Repair (Resync) (migr_state=1 migr_type=MIGR_REPAIR map0state=normal * map1state=normal) * 4/ Rebuild (migr_state=1 migr_type=MIGR_REBUILD map0state=normal * map1state=degraded) @@ -1612,7 +1720,7 @@ static void migrate(struct imsm_dev *dev, __u8 to_state, int migr_type) struct imsm_map *src = get_imsm_map(dev, 0); dev->vol.migr_state = 1; - dev->vol.migr_type = migr_type; + set_migr_type(dev, migr_type); dev->vol.curr_migr_unit = 0; dest = get_imsm_map(dev, 1); @@ -1694,7 +1802,8 @@ static int parse_raid_devices(struct intel_super *super) if (posix_memalign(&buf, 512, len) != 0) return 1; - memcpy(buf, super->buf, len); + memcpy(buf, super->buf, super->len); + memset(buf + super->len, 0, len - super->len); free(super->buf); super->buf = buf; super->len = len; @@ -1976,9 +2085,14 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, int rv; int devnum = fd2devnum(fd); int retry; + enum sysfs_read_flags flags; - /* check if this disk is a member of an active array */ - sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE); + flags = GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE; + if (mdmon_running(devnum)) + flags |= SKIP_GONE_DEVS; + + /* check if 'fd' an opened container */ + sra = sysfs_read(fd, 0, flags); if (!sra) return 1; @@ -2067,8 +2181,10 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, if (st->subarray[0]) { if (atoi(st->subarray) <= super->anchor->num_raid_devs) super->current_vol = atoi(st->subarray); - else + else { + free_imsm(super); return 1; + } } *sbp = super; @@ -2093,8 +2209,8 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) if (load_super_imsm_all(st, fd, &st->sb, devname, 1) == 0) return 0; #endif - if (st->subarray[0]) - return 1; /* FIXME */ + + free_super_imsm(st); super = alloc_super(0); if (!super) { @@ -2115,6 +2231,15 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) return rv; } + if (st->subarray[0]) { + if (atoi(st->subarray) <= super->anchor->num_raid_devs) + super->current_vol = atoi(st->subarray); + else { + free_imsm(super); + return 1; + } + } + st->sb = super; if (st->ss == NULL) { st->ss = &super_imsm; @@ -2133,13 +2258,12 @@ static __u16 info_to_blocks_per_strip(mdu_array_info_t *info) return info->chunk_size >> 9; } -static __u32 info_to_num_data_stripes(mdu_array_info_t *info) +static __u32 info_to_num_data_stripes(mdu_array_info_t *info, int num_domains) { __u32 num_stripes; num_stripes = (info->size * 2) / info_to_blocks_per_strip(info); - if (info->level == 1) - num_stripes /= 2; + num_stripes /= num_domains; return num_stripes; } @@ -2216,6 +2340,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, int i; unsigned long long array_blocks; size_t size_old, size_new; + __u32 num_data_stripes; if (super->orom && mpb->num_raid_devs >= super->orom->vpa) { fprintf(stderr, Name": This imsm-container already has the " @@ -2278,36 +2403,44 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, array_blocks = calc_array_size(info->level, info->raid_disks, info->layout, info->chunk_size, info->size*2); + /* round array size down to closest MB */ + array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT; + 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); vol = &dev->vol; vol->migr_state = 0; - vol->migr_type = MIGR_INIT; + set_migr_type(dev, MIGR_INIT); vol->dirty = 0; vol->curr_migr_unit = 0; map = get_imsm_map(dev, 0); map->pba_of_lba0 = __cpu_to_le32(super->create_offset); map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info)); map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info)); - map->num_data_stripes = __cpu_to_le32(info_to_num_data_stripes(info)); map->failed_disk_num = ~0; map->map_state = info->level ? IMSM_T_STATE_UNINITIALIZED : IMSM_T_STATE_NORMAL; + map->ddf = 1; if (info->level == 1 && info->raid_disks > 2) { fprintf(stderr, Name": imsm does not support more than 2 disks" "in a raid1 volume\n"); return 0; } + + map->raid_level = info->level; if (info->level == 10) { map->raid_level = 1; map->num_domains = info->raid_disks / 2; - } else { - map->raid_level = info->level; - map->num_domains = !!map->raid_level; - } + } else if (info->level == 1) + map->num_domains = info->raid_disks; + else + map->num_domains = 1; + + num_data_stripes = info_to_num_data_stripes(info, map->num_domains); + map->num_data_stripes = __cpu_to_le32(num_data_stripes); map->num_members = info->raid_disks; for (i = 0; i < map->num_members; i++) { @@ -2393,10 +2526,19 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, return 1; } - for (dl = super->disks; dl ; dl = dl->next) - if (dl->major == dk->major && - dl->minor == dk->minor) - break; + if (fd == -1) { + /* we're doing autolayout so grab the pre-marked (in + * validate_geometry) raid_disk + */ + for (dl = super->disks; dl; dl = dl->next) + if (dl->raiddisk == dk->raid_disk) + break; + } else { + for (dl = super->disks; dl ; dl = dl->next) + if (dl->major == dk->major && + dl->minor == dk->minor) + break; + } if (!dl) { fprintf(stderr, Name ": %s is not a member of the same container\n", devname); @@ -2419,8 +2561,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, *_dev = *dev; *_disk = dl->disk; - sum = __gen_imsm_checksum(mpb); + sum = random32(); + sum += __gen_imsm_checksum(mpb); mpb->family_num = __cpu_to_le32(sum); + mpb->orig_family_num = mpb->family_num; } return 0; @@ -2517,6 +2661,7 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose) mpb->disk[0] = d->disk; sum = __gen_imsm_checksum(mpb); mpb->family_num = __cpu_to_le32(sum); + mpb->orig_family_num = 0; sum = __gen_imsm_checksum(mpb); mpb->check_sum = __cpu_to_le32(sum); @@ -2551,6 +2696,12 @@ static int write_super_imsm(struct intel_super *super, int doclose) generation++; mpb->generation_num = __cpu_to_le32(generation); + /* fix up cases where previous mdadm releases failed to set + * orig_family_num + */ + if (mpb->orig_family_num == 0) + mpb->orig_family_num = mpb->family_num; + mpb_size += sizeof(struct imsm_disk) * mpb->num_disks; for (d = super->disks; d; d = d->next) { if (d->index == -1) @@ -2594,17 +2745,16 @@ static int write_super_imsm(struct intel_super *super, int doclose) } -static int create_array(struct supertype *st) +static int create_array(struct supertype *st, int dev_idx) { size_t len; struct imsm_update_create_array *u; struct intel_super *super = st->sb; - struct imsm_dev *dev = get_imsm_dev(super, super->current_vol); + struct imsm_dev *dev = get_imsm_dev(super, dev_idx); struct imsm_map *map = get_imsm_map(dev, 0); struct disk_info *inf; struct imsm_disk *disk; int i; - int idx; len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0) + sizeof(*inf) * map->num_members; @@ -2616,11 +2766,12 @@ static int create_array(struct supertype *st) } u->type = update_create_array; - u->dev_idx = super->current_vol; + u->dev_idx = dev_idx; imsm_copy_dev(&u->dev, dev); inf = get_disk_info(u); for (i = 0; i < map->num_members; i++) { - idx = get_imsm_disk_idx(dev, i); + int idx = get_imsm_disk_idx(dev, i); + disk = get_imsm_disk(super, idx); serialcpy(inf[i].serial, disk->serial); } @@ -2654,21 +2805,26 @@ static int _add_disk(struct supertype *st) static int write_init_super_imsm(struct supertype *st) { + struct intel_super *super = st->sb; + int current_vol = super->current_vol; + + /* we are done with current_vol reset it to point st at the container */ + super->current_vol = -1; + if (st->update_tail) { /* queue the recently created array / added disk * as a metadata update */ - struct intel_super *super = st->sb; struct dl *d; int rv; /* determine if we are creating a volume or adding a disk */ - if (super->current_vol < 0) { + if (current_vol < 0) { /* in the add disk case we are running in mdmon * context, so don't close fd's */ return _add_disk(st); } else - rv = create_array(st); + rv = create_array(st, current_vol); for (d = super->disks; d ; d = d->next) { close(d->fd); @@ -2790,7 +2946,7 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten int i, j; int start_extent; unsigned long long pos; - unsigned long long start; + unsigned long long start = 0; unsigned long long maxsize; unsigned long reserve; @@ -3047,6 +3203,78 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, return 1; } +static int reserve_space(struct supertype *st, int raiddisks, + unsigned long long size, int chunk, + unsigned long long *freesize) +{ + struct intel_super *super = st->sb; + struct imsm_super *mpb = super->anchor; + struct dl *dl; + int i; + int extent_cnt; + struct extent *e; + unsigned long long maxsize; + unsigned long long minsize; + int cnt; + int used; + + /* find the largest common start free region of the possible disks */ + used = 0; + extent_cnt = 0; + cnt = 0; + for (dl = super->disks; dl; dl = dl->next) { + dl->raiddisk = -1; + + if (dl->index >= 0) + used++; + + /* don't activate new spares if we are orom constrained + * and there is already a volume active in the container + */ + if (super->orom && dl->index < 0 && mpb->num_raid_devs) + continue; + + e = get_extents(super, dl); + if (!e) + continue; + for (i = 1; e[i-1].size; i++) + ; + dl->e = e; + dl->extent_cnt = i; + extent_cnt += i; + cnt++; + } + + maxsize = merge_extents(super, extent_cnt); + minsize = size; + if (size == 0) + minsize = chunk; + + if (cnt < raiddisks || + (super->orom && used && used != raiddisks) || + maxsize < minsize) { + fprintf(stderr, Name ": not enough devices with space to create array.\n"); + return 0; /* No enough free spaces large enough */ + } + + if (size == 0) { + size = maxsize; + if (chunk) { + size /= chunk; + size *= chunk; + } + } + + cnt = 0; + for (dl = super->disks; dl; dl = dl->next) + if (dl->e) + dl->raiddisk = cnt++; + + *freesize = size; + + return 1; +} + static int validate_geometry_imsm(struct supertype *st, int level, int layout, int raiddisks, int chunk, unsigned long long size, char *dev, unsigned long long *freesize, @@ -3068,9 +3296,15 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, if (!dev) { if (st->sb && freesize) { - /* Should do auto-layout here */ - fprintf(stderr, Name ": IMSM does not support auto-layout yet\n"); - return 0; + /* we are being asked to automatically layout a + * new volume based on the current contents of + * the container. If the the parameters can be + * satisfied reserve_space will record the disks, + * start offset, and size of the volume to be + * created. add_to_super and getinfo_super + * detect when autolayout is in progress. + */ + return reserve_space(st, raiddisks, size, chunk, freesize); } return 1; } @@ -3172,6 +3406,18 @@ static struct mdinfo *container_content_imsm(struct supertype *st) struct mdinfo *this; int slot; + /* do not publish arrays that are in the middle of an + * unsupported migration + */ + if (dev->vol.migr_state && + (migr_type(dev) == MIGR_GEN_MIGR || + migr_type(dev) == MIGR_STATE_CHANGE)) { + fprintf(stderr, Name ": cannot assemble volume '%.16s':" + " unsupported migration in progress\n", + dev->volume); + continue; + } + this = malloc(sizeof(*this)); memset(this, 0, sizeof(*this)); this->next = rest; @@ -3218,7 +3464,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st) info_d = malloc(sizeof(*info_d)); if (!info_d) { fprintf(stderr, Name ": failed to allocate disk" - " for volume %s\n", (char *) dev->volume); + " for volume %.16s\n", dev->volume); free(this); this = rest; break; @@ -3372,7 +3618,8 @@ static int is_resyncing(struct imsm_dev *dev) if (!dev->vol.migr_state) return 0; - if (dev->vol.migr_type == MIGR_INIT) + if (migr_type(dev) == MIGR_INIT || + migr_type(dev) == MIGR_REPAIR) return 1; migr_map = get_imsm_map(dev, 1); @@ -3390,7 +3637,7 @@ static int is_rebuilding(struct imsm_dev *dev) if (!dev->vol.migr_state) return 0; - if (dev->vol.migr_type != MIGR_REBUILD) + if (migr_type(dev) != MIGR_REBUILD) return 0; migr_map = get_imsm_map(dev, 1); @@ -3421,7 +3668,7 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx) disk->status |= FAILED_DISK; set_imsm_ord_tbl_ent(map, slot, idx | IMSM_ORD_REBUILD); - if (map->failed_disk_num == ~0) + if (~map->failed_disk_num == 0) map->failed_disk_num = slot; return 1; } @@ -3481,20 +3728,14 @@ static int imsm_set_array_state(struct active_array *a, int consistent) } else if (!is_resyncing(dev) && !failed) { /* mark the start of the init process if nothing is failed */ dprintf("imsm: mark resync start (%llu)\n", a->resync_start); - if (map->map_state == IMSM_T_STATE_NORMAL) - migrate(dev, IMSM_T_STATE_NORMAL, MIGR_REBUILD); - else + if (map->map_state == IMSM_T_STATE_UNINITIALIZED) migrate(dev, IMSM_T_STATE_NORMAL, MIGR_INIT); + else + migrate(dev, IMSM_T_STATE_NORMAL, MIGR_REPAIR); super->updates_pending++; } - /* check if we can update the migration checkpoint */ - if (dev->vol.migr_state && - __le32_to_cpu(dev->vol.curr_migr_unit) != a->resync_start) { - dprintf("imsm: checkpoint migration (%llu)\n", a->resync_start); - dev->vol.curr_migr_unit = __cpu_to_le32(a->resync_start); - super->updates_pending++; - } + /* FIXME check if we can update curr_migr_unit from resync_start */ /* mark dirty / clean */ if (dev->vol.dirty != !consistent) { @@ -3638,14 +3879,13 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot, int idx = get_imsm_disk_idx(dev, slot); struct imsm_super *mpb = super->anchor; struct imsm_map *map; - unsigned long long esize; unsigned long long pos; struct mdinfo *d; struct extent *ex; int i, j; int found; __u32 array_start; - __u32 blocks; + __u32 array_end; struct dl *dl; for (dl = super->disks; dl; dl = dl->next) { @@ -3697,15 +3937,14 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot, j = 0; pos = 0; array_start = __le32_to_cpu(map->pba_of_lba0); - blocks = __le32_to_cpu(map->blocks_per_member); + array_end = array_start + + __le32_to_cpu(map->blocks_per_member) - 1; do { /* check that we can start at pba_of_lba0 with * blocks_per_member of space */ - esize = ex[j].start - pos; - if (array_start >= pos && - array_start + blocks < ex[j].start) { + if (array_start >= pos && array_end < ex[j].start) { found = 1; break; } @@ -3719,9 +3958,8 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot, free(ex); if (i < mpb->num_raid_devs) { - dprintf("%x:%x does not have %u at %u\n", - dl->major, dl->minor, - blocks, array_start); + dprintf("%x:%x does not have %u to %u available\n", + dl->major, dl->minor, array_start, array_end); /* No room */ continue; } @@ -3823,6 +4061,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a, di->data_offset = __le32_to_cpu(map->pba_of_lba0); di->component_size = a->info.component_size; di->container_member = inst; + super->random = random32(); di->next = rv; rv = di; num_spares++; @@ -3989,6 +4228,15 @@ static void imsm_process_update(struct supertype *st, set_imsm_ord_tbl_ent(map, u->slot, dl->index); set_imsm_ord_tbl_ent(migr_map, u->slot, dl->index | IMSM_ORD_REBUILD); + /* update the family_num to mark a new container + * generation, being careful to record the existing + * family_num in orig_family_num to clean up after + * earlier mdadm versions that neglected to set it. + */ + if (mpb->orig_family_num == 0) + mpb->orig_family_num = mpb->family_num; + mpb->family_num += super->random; + /* count arrays using the victim in the metadata */ found = 0; for (a = st->arrays; a ; a = a->next) { @@ -4238,7 +4486,9 @@ static void imsm_prepare_update(struct supertype *st, free(super->next_buf); super->next_len = buf_len; - if (posix_memalign(&super->next_buf, 512, buf_len) != 0) + if (posix_memalign(&super->next_buf, 512, buf_len) == 0) + memset(super->next_buf, 0, buf_len); + else super->next_buf = NULL; } } @@ -4300,6 +4550,7 @@ struct superswitch super_imsm = { #ifndef MDASSEMBLE .examine_super = examine_super_imsm, .brief_examine_super = brief_examine_super_imsm, + .export_examine_super = export_examine_super_imsm, .detail_super = detail_super_imsm, .brief_detail_super = brief_detail_super_imsm, .write_init_super = write_init_super_imsm,