X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=super-intel.c;h=b400fded45c393ccd7093121c28bc7b1a5fbca27;hp=9074485ab06d5295ea59a33d1a2d0e91985094f5;hb=1ade5cc15a61c6fe3084c5170934e05e9a574843;hpb=81a5b4f52f0697f3c494c7ee2723e5f833b9ec51 diff --git a/super-intel.c b/super-intel.c index 9074485a..b400fded 100644 --- a/super-intel.c +++ b/super-intel.c @@ -95,15 +95,16 @@ #define IMSM_MAX_DEVICES 255 struct imsm_disk { __u8 serial[MAX_RAID_SERIAL_LEN];/* 0xD8 - 0xE7 ascii serial number */ - __u32 total_blocks; /* 0xE8 - 0xEB total blocks */ + __u32 total_blocks_lo; /* 0xE8 - 0xEB total blocks lo */ __u32 scsi_id; /* 0xEC - 0xEF scsi ID */ #define SPARE_DISK __cpu_to_le32(0x01) /* Spare */ #define CONFIGURED_DISK __cpu_to_le32(0x02) /* Member of some RaidDev */ #define FAILED_DISK __cpu_to_le32(0x04) /* Permanent failure */ __u32 status; /* 0xF0 - 0xF3 */ - __u32 owner_cfg_num; /* which config 0,1,2... owns this disk */ -#define IMSM_DISK_FILLERS 4 - __u32 filler[IMSM_DISK_FILLERS]; /* 0xF4 - 0x107 MPB_DISK_FILLERS for future expansion */ + __u32 owner_cfg_num; /* which config 0,1,2... owns this disk */ + __u32 total_blocks_hi; /* 0xF4 - 0xF5 total blocks hi */ +#define IMSM_DISK_FILLERS 3 + __u32 filler[IMSM_DISK_FILLERS]; /* 0xF5 - 0x107 MPB_DISK_FILLERS for future expansion */ }; /* map selector for map managment @@ -114,9 +115,9 @@ struct imsm_disk { /* RAID map configuration infos. */ struct imsm_map { - __u32 pba_of_lba0; /* start address of partition */ - __u32 blocks_per_member;/* blocks per member */ - __u32 num_data_stripes; /* number of data stripes */ + __u32 pba_of_lba0_lo; /* start address of partition */ + __u32 blocks_per_member_lo;/* blocks per member */ + __u32 num_data_stripes_lo; /* number of data stripes */ __u16 blocks_per_strip; __u8 map_state; /* Normal, Uninitialized, Degraded, Failed */ #define IMSM_T_STATE_NORMAL 0 @@ -131,7 +132,10 @@ struct imsm_map { __u8 num_domains; /* number of parity domains */ __u8 failed_disk_num; /* valid only when state is degraded */ __u8 ddf; - __u32 filler[7]; /* expansion area */ + __u32 pba_of_lba0_hi; + __u32 blocks_per_member_hi; + __u32 num_data_stripes_hi; + __u32 filler[4]; /* expansion area */ #define IMSM_ORD_REBUILD (1 << 24) __u32 disk_ord_tbl[1]; /* disk_ord_tbl[num_members], * top byte contains some flags @@ -231,7 +235,6 @@ struct bbm_log { struct bbm_log_entry mapped_block_entries[BBM_LOG_MAX_ENTRIES]; } __attribute__ ((__packed__)); - #ifndef MDASSEMBLE static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" }; #endif @@ -245,7 +248,6 @@ static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" * MIGR_REC_BUF_SIZE <= MIGR_REC_POSITION */ - #define UNIT_SRC_NORMAL 0 /* Source data for curr_migr_unit must * be recovered using srcMap */ #define UNIT_SRC_IN_CP_AREA 1 /* Source data for curr_migr_unit has @@ -277,6 +279,22 @@ struct migr_record { * (for recovered migrations) */ } __attribute__ ((__packed__)); +struct md_list { + /* usage marker: + * 1: load metadata + * 2: metadata does not match + * 4: already checked + */ + int used; + char *devname; + int found; + int container; + dev_t st_rdev; + struct md_list *next; +}; + +#define pr_vrb(fmt, arg...) (void) (verbose && pr_err(fmt, ##arg)) + static __u8 migr_type(struct imsm_dev *dev) { if (dev->vol.migr_type == MIGR_VERIFY && @@ -302,7 +320,7 @@ static void set_migr_type(struct imsm_dev *dev, __u8 migr_type) static unsigned int sector_count(__u32 bytes) { - return ((bytes + (512-1)) & (~(512-1))) / 512; + return ROUND_UP(bytes, 512) / 512; } static unsigned int mpb_sectors(struct imsm_super *mpb) @@ -337,12 +355,15 @@ struct intel_super { void *migr_rec_buf; /* buffer for I/O operations */ struct migr_record *migr_rec; /* migration record */ }; + int clean_migration_record_by_mdmon; /* when reshape is switched to next + array, it indicates that mdmon is allowed to clean migration + record */ size_t len; /* size of the 'buf' allocation */ void *next_buf; /* for realloc'ing buf from the manager */ size_t next_len; int updates_pending; /* count of pending updates for mdmon */ int current_vol; /* index of raid device undergoing creation */ - __u32 create_offset; /* common start for 'current_vol' */ + unsigned long long create_offset; /* common start for 'current_vol' */ __u32 random; /* random data for seeding new family numbers */ struct intel_dev *devlist; struct dl { @@ -382,6 +403,7 @@ struct extent { enum imsm_reshape_type { CH_TAKEOVER, CH_MIGRATION, + CH_ARRAY_SIZE, }; /* definition of messages passed to imsm_process_update */ @@ -395,6 +417,7 @@ enum imsm_update_type { update_reshape_migration, update_takeover, update_general_migration_checkpoint, + update_size_change, }; struct imsm_update_activate_spare { @@ -406,9 +429,9 @@ struct imsm_update_activate_spare { }; struct geo_params { - int dev_id; + char devnm[32]; char *dev_name; - long long size; + unsigned long long size; int level; int layout; int chunksize; @@ -447,6 +470,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; @@ -477,11 +506,11 @@ struct imsm_update_add_remove_disk { enum imsm_update_type type; }; - static const char *_sys_dev_type[] = { [SYS_DEV_UNKNOWN] = "Unknown", [SYS_DEV_SAS] = "SAS", - [SYS_DEV_SATA] = "SATA" + [SYS_DEV_SATA] = "SATA", + [SYS_DEV_NVME] = "NVMe" }; const char *get_sys_dev_type(enum sys_dev_type type) @@ -494,14 +523,14 @@ const char *get_sys_dev_type(enum sys_dev_type type) static struct intel_hba * alloc_intel_hba(struct sys_dev *device) { - struct intel_hba *result = malloc(sizeof(*result)); - if (result) { - result->type = device->type; - result->path = strdup(device->path); - result->next = NULL; - if (result->path && (result->pci_id = strrchr(result->path, '/')) != NULL) - result->pci_id++; - } + struct intel_hba *result = xmalloc(sizeof(*result)); + + result->type = device->type; + result->path = xstrdup(device->path); + result->next = NULL; + if (result->path && (result->pci_id = strrchr(result->path, '/')) != NULL) + result->pci_id++; + return result; } @@ -531,11 +560,17 @@ static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device hba = super->hba; /* Intel metadata allows for all disks attached to the same type HBA. - * Do not sypport odf HBA types mixing + * Do not support HBA types mixing */ if (device->type != hba->type) return 2; + /* Multiple same type HBAs can be used if they share the same OROM */ + const struct imsm_orom *device_orom = get_orom_by_device_id(device->dev_id); + + if (device_orom != super->orom) + return 2; + while (hba->next) hba = hba->next; @@ -545,7 +580,7 @@ static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device static struct sys_dev* find_disk_attached_hba(int fd, const char *devname) { - struct sys_dev *list, *elem, *prev; + struct sys_dev *list, *elem; char *disk_path; if ((list = find_intel_devices()) == NULL) @@ -556,32 +591,19 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname) else disk_path = diskfd_to_devpath(fd); - if (!disk_path) { - free_sys_dev(&list); + if (!disk_path) return 0; - } - for (prev = NULL, elem = list; elem; prev = elem, elem = elem->next) { - if (path_attached_to_hba(disk_path, elem->path)) { - if (prev == NULL) - list = list->next; - else - prev->next = elem->next; - elem->next = NULL; - if (disk_path != devname) - free(disk_path); - free_sys_dev(&list); + for (elem = list; elem; elem = elem->next) + if (path_attached_to_hba(disk_path, elem->path)) return elem; - } - } + if (disk_path != devname) free(disk_path); - free_sys_dev(&list); return NULL; } - static int find_intel_hba_capability(int fd, struct intel_super *super, char *devname); @@ -594,11 +616,7 @@ static struct supertype *match_metadata_desc_imsm(char *arg) ) return NULL; - st = malloc(sizeof(*st)); - if (!st) - return NULL; - memset(st, 0, sizeof(*st)); - st->container_dev = NoMdDev; + st = xcalloc(1, sizeof(*st)); st->ss = &super_imsm; st->max_devs = IMSM_MAX_DEVICES; st->minor_version = 0; @@ -657,12 +675,12 @@ static __u32 __gen_imsm_checksum(struct imsm_super *mpb) __u32 *p = (__u32 *) mpb; __u32 sum = 0; - while (end--) { - sum += __le32_to_cpu(*p); + while (end--) { + sum += __le32_to_cpu(*p); p++; } - return sum - __le32_to_cpu(mpb->check_sum); + return sum - __le32_to_cpu(mpb->check_sum); } static size_t sizeof_imsm_map(struct imsm_map *map) @@ -851,6 +869,71 @@ static int count_memberships(struct dl *dl, struct intel_super *super) static __u32 imsm_min_reserved_sectors(struct intel_super *super); +static int split_ull(unsigned long long n, __u32 *lo, __u32 *hi) +{ + if (lo == 0 || hi == 0) + return 1; + *lo = __le32_to_cpu((unsigned)n); + *hi = __le32_to_cpu((unsigned)(n >> 32)); + return 0; +} + +static unsigned long long join_u32(__u32 lo, __u32 hi) +{ + return (unsigned long long)__le32_to_cpu(lo) | + (((unsigned long long)__le32_to_cpu(hi)) << 32); +} + +static unsigned long long total_blocks(struct imsm_disk *disk) +{ + if (disk == NULL) + return 0; + return join_u32(disk->total_blocks_lo, disk->total_blocks_hi); +} + +static unsigned long long pba_of_lba0(struct imsm_map *map) +{ + if (map == NULL) + return 0; + return join_u32(map->pba_of_lba0_lo, map->pba_of_lba0_hi); +} + +static unsigned long long blocks_per_member(struct imsm_map *map) +{ + if (map == NULL) + return 0; + return join_u32(map->blocks_per_member_lo, map->blocks_per_member_hi); +} + +#ifndef MDASSEMBLE +static unsigned long long num_data_stripes(struct imsm_map *map) +{ + if (map == NULL) + return 0; + return join_u32(map->num_data_stripes_lo, map->num_data_stripes_hi); +} + +static void set_total_blocks(struct imsm_disk *disk, unsigned long long n) +{ + split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi); +} +#endif + +static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n) +{ + split_ull(n, &map->pba_of_lba0_lo, &map->pba_of_lba0_hi); +} + +static void set_blocks_per_member(struct imsm_map *map, unsigned long long n) +{ + split_ull(n, &map->blocks_per_member_lo, &map->blocks_per_member_hi); +} + +static void set_num_data_stripes(struct imsm_map *map, unsigned long long n) +{ + split_ull(n, &map->num_data_stripes_lo, &map->num_data_stripes_hi); +} + static struct extent *get_extents(struct intel_super *super, struct dl *dl) { /* find a list of used extents on the given physical device */ @@ -868,9 +951,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl) else reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS; - rv = malloc(sizeof(struct extent) * (memberships + 1)); - if (!rv) - return NULL; + rv = xcalloc(sizeof(struct extent), (memberships + 1)); e = rv; for (i = 0; i < super->anchor->num_raid_devs; i++) { @@ -878,24 +959,23 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl) struct imsm_map *map = get_imsm_map(dev, MAP_0); if (get_imsm_disk_slot(map, dl->index) >= 0) { - e->start = __le32_to_cpu(map->pba_of_lba0); - e->size = __le32_to_cpu(map->blocks_per_member); + e->start = pba_of_lba0(map); + e->size = blocks_per_member(map); e++; } } qsort(rv, memberships, sizeof(*rv), cmp_extent); - /* determine the start of the metadata + /* determine the start of the metadata * when no raid devices are defined use the default * ...otherwise allow the metadata to truncate the value * as is the case with older versions of imsm */ if (memberships) { struct extent *last = &rv[memberships - 1]; - __u32 remainder; + unsigned long long remainder; - remainder = __le32_to_cpu(dl->disk.total_blocks) - - (last->start + last->size); + remainder = total_blocks(&dl->disk) - (last->start + last->size); /* round down to 1k block to satisfy precision of the kernel * 'size' interface */ @@ -906,7 +986,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl) if (reservation > remainder) reservation = remainder; } - e->start = __le32_to_cpu(dl->disk.total_blocks) - reservation; + e->start = total_blocks(&dl->disk) - reservation; e->size = 0; return rv; } @@ -935,7 +1015,7 @@ static __u32 imsm_reserved_sectors(struct intel_super *super, struct dl *dl) for (i = 0; e[i].size; i++) continue; - rv = __le32_to_cpu(dl->disk.total_blocks) - e[i].start; + rv = total_blocks(&dl->disk) - e[i].start; free(e); @@ -965,7 +1045,8 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super) { struct extent *e; int i; - __u32 min_active, remainder; + unsigned long long min_active; + __u32 remainder; __u32 rv = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS; struct dl *dl, *dl_min = NULL; @@ -976,9 +1057,10 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super) for (dl = super->disks; dl; dl = dl->next) { if (dl->index < 0) continue; - if (dl->disk.total_blocks < min_active || min_active == 0) { + unsigned long long blocks = total_blocks(&dl->disk); + if (blocks < min_active || min_active == 0) { dl_min = dl; - min_active = dl->disk.total_blocks; + min_active = blocks; } } if (!dl_min) @@ -1096,13 +1178,13 @@ static void print_imsm_dev(struct intel_super *super, sz += __le32_to_cpu(dev->size_low); printf(" Array Size : %llu%s\n", (unsigned long long)sz, human_size(sz * 512)); - sz = __le32_to_cpu(map->blocks_per_member); + sz = blocks_per_member(map); printf(" Per Dev Size : %llu%s\n", (unsigned long long)sz, human_size(sz * 512)); - printf(" Sector Offset : %u\n", - __le32_to_cpu(map->pba_of_lba0)); - printf(" Num Stripes : %u\n", - __le32_to_cpu(map->num_data_stripes)); + printf(" Sector Offset : %llu\n", + pba_of_lba0(map)); + printf(" Num Stripes : %llu\n", + num_data_stripes(map)); printf(" Chunk Size : %u KiB", __le16_to_cpu(map->blocks_per_strip) / 2); if (map2) @@ -1163,7 +1245,7 @@ static void print_imsm_disk(struct imsm_disk *disk, int index, __u32 reserved) is_configured(disk) ? " active" : "", is_failed(disk) ? " failed" : ""); printf(" Id : %08x\n", __le32_to_cpu(disk->scsi_id)); - sz = __le32_to_cpu(disk->total_blocks) - reserved; + sz = total_blocks(disk) - reserved; printf(" Usable Size : %llu%s\n", (unsigned long long)sz, human_size(sz * 512)); } @@ -1228,12 +1310,12 @@ void examine_migr_rec_imsm(struct intel_super *super) /******************************************************************************* * function: imsm_check_attributes * Description: Function checks if features represented by attributes flags - * are supported by mdadm. + * are supported by mdadm. * Parameters: * attributes - Attributes read from metadata * Returns: - * 0 - passed attributes contains unsupported features flags - * 1 - all features are supported + * 0 - passed attributes contains unsupported features flags + * 1 - all features are supported ******************************************************************************/ static int imsm_check_attributes(__u32 attributes) { @@ -1244,7 +1326,7 @@ static int imsm_check_attributes(__u32 attributes) not_supported &= attributes; if (not_supported) { - fprintf(stderr, Name "(IMSM): Unsupported attributes : %x\n", + pr_err("(IMSM): Unsupported attributes : %x\n", (unsigned)__le32_to_cpu(not_supported)); if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) { dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n"); @@ -1304,7 +1386,7 @@ static int imsm_check_attributes(__u32 attributes) } if (not_supported) - dprintf(Name "(IMSM): Unknown attributes : %x\n", not_supported); + dprintf("(IMSM): Unknown attributes : %x\n", not_supported); ret_val = 0; } @@ -1440,6 +1522,59 @@ static void export_examine_super_imsm(struct supertype *st) printf("MD_DEVICES=%u\n", mpb->num_disks); } +static int copy_metadata_imsm(struct supertype *st, int from, int to) +{ + /* The second last 512byte sector of the device contains + * the "struct imsm_super" metadata. + * This contains mpb_size which is the size in bytes of the + * extended metadata. This is located immediately before + * the imsm_super. + * We want to read all that, plus the last sector which + * may contain a migration record, and write it all + * to the target. + */ + void *buf; + unsigned long long dsize, offset; + int sectors; + struct imsm_super *sb; + int written = 0; + + if (posix_memalign(&buf, 4096, 4096) != 0) + return 1; + + if (!get_dev_size(from, NULL, &dsize)) + goto err; + + if (lseek64(from, dsize-1024, 0) < 0) + goto err; + if (read(from, buf, 512) != 512) + goto err; + sb = buf; + if (strncmp((char*)sb->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0) + goto err; + + sectors = mpb_sectors(sb) + 2; + offset = dsize - sectors * 512; + if (lseek64(from, offset, 0) < 0 || + lseek64(to, offset, 0) < 0) + goto err; + while (written < sectors * 512) { + int n = sectors*512 - written; + if (n > 4096) + n = 4096; + if (read(from, buf, n) != n) + goto err; + if (write(to, buf, n) != n) + goto err; + written += n; + } + free(buf); + return 0; +err: + free(buf); + return 1; +} + static void detail_super_imsm(struct supertype *st, char *homehost) { struct mdinfo info; @@ -1475,8 +1610,8 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b unsigned long port_mask = (1 << port_count) - 1; if (port_count > (int)sizeof(port_mask) * 8) { - if (verbose) - fprintf(stderr, Name ": port_count %d out of range\n", port_count); + if (verbose > 0) + pr_err("port_count %d out of range\n", port_count); return 2; } @@ -1508,15 +1643,15 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b /* retrieve the scsi device type */ if (asprintf(&device, "/sys/dev/block/%d:%d/device/xxxxxxx", major, minor) < 0) { - if (verbose) - fprintf(stderr, Name ": failed to allocate 'device'\n"); + if (verbose > 0) + pr_err("failed to allocate 'device'\n"); err = 2; break; } sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor); if (load_sys(device, buf) != 0) { - if (verbose) - fprintf(stderr, Name ": failed to read device type for %s\n", + if (verbose > 0) + pr_err("failed to read device type for %s\n", path); err = 2; free(device); @@ -1568,18 +1703,19 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b /* chop device path to 'host%d' and calculate the port number */ c = strchr(&path[hba_len], '/'); if (!c) { - if (verbose) - fprintf(stderr, Name ": %s - invalid path name\n", path + hba_len); + if (verbose > 0) + pr_err("%s - invalid path name\n", path + hba_len); err = 2; break; } *c = '\0'; - if (sscanf(&path[hba_len], "host%d", &port) == 1) + if ((sscanf(&path[hba_len], "ata%d", &port) == 1) || + ((sscanf(&path[hba_len], "host%d", &port) == 1))) port -= host_base; else { - if (verbose) { + if (verbose > 0) { *c = '/'; /* repair the full string */ - fprintf(stderr, Name ": failed to determine port number for %s\n", + pr_err("failed to determine port number for %s\n", path); } err = 2; @@ -1628,11 +1764,13 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b static void print_found_intel_controllers(struct sys_dev *elem) { for (; elem; elem = elem->next) { - fprintf(stderr, Name ": found Intel(R) "); + pr_err("found Intel(R) "); if (elem->type == SYS_DEV_SATA) fprintf(stderr, "SATA "); else if (elem->type == SYS_DEV_SAS) fprintf(stderr, "SAS "); + else if (elem->type == SYS_DEV_NVME) + fprintf(stderr, "NVMe "); fprintf(stderr, "RAID controller"); if (elem->pci_id) fprintf(stderr, " at %s", elem->pci_id); @@ -1654,7 +1792,8 @@ static int ahci_get_port_count(const char *hba_path, int *port_count) for (ent = readdir(dir); ent; ent = readdir(dir)) { int host; - if (sscanf(ent->d_name, "host%d", &host) != 1) + if ((sscanf(ent->d_name, "ata%d", &host) != 1) && + ((sscanf(ent->d_name, "host%d", &host) != 1))) continue; if (*port_count == 0) host_base = host; @@ -1670,9 +1809,15 @@ static int ahci_get_port_count(const char *hba_path, int *port_count) static void print_imsm_capability(const struct imsm_orom *orom) { - printf(" Platform : Intel(R) Matrix Storage Manager\n"); - printf(" Version : %d.%d.%d.%d\n", orom->major_ver, orom->minor_ver, - orom->hotfix_ver, orom->build); + printf(" Platform : Intel(R) "); + if (orom->capabilities == 0 && orom->driver_features == 0) + printf("Matrix Storage Manager\n"); + else + printf("Rapid Storage Technology%s\n", + imsm_orom_is_enterprise(orom) ? " enterprise" : ""); + if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) + printf(" Version : %d.%d.%d.%d\n", orom->major_ver, + orom->minor_ver, orom->hotfix_ver, orom->build); printf(" RAID Levels :%s%s%s%s%s\n", imsm_orom_has_raid0(orom) ? " raid0" : "", imsm_orom_has_raid1(orom) ? " raid1" : "", @@ -1696,12 +1841,54 @@ static void print_imsm_capability(const struct imsm_orom *orom) 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(" 2TB volumes :%s supported\n", + (orom->attr & IMSM_OROM_ATTR_2TB)?"":" not"); + printf(" 2TB disks :%s supported\n", + (orom->attr & IMSM_OROM_ATTR_2TB_DISK)?"":" not"); printf(" Max Disks : %d\n", orom->tds); - printf(" Max Volumes : %d\n", orom->vpa); + printf(" Max Volumes : %d per array, %d per %s\n", + orom->vpa, orom->vphba, + imsm_orom_is_nvme(orom) ? "platform" : "controller"); return; } -static int detail_platform_imsm(int verbose, int enumerate_only) +static void print_imsm_capability_export(const struct imsm_orom *orom) +{ + printf("MD_FIRMWARE_TYPE=imsm\n"); + if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) + printf("IMSM_VERSION=%d.%d.%d.%d\n", orom->major_ver, orom->minor_ver, + orom->hotfix_ver, orom->build); + printf("IMSM_SUPPORTED_RAID_LEVELS=%s%s%s%s%s\n", + imsm_orom_has_raid0(orom) ? "raid0 " : "", + imsm_orom_has_raid1(orom) ? "raid1 " : "", + imsm_orom_has_raid1e(orom) ? "raid1e " : "", + imsm_orom_has_raid5(orom) ? "raid10 " : "", + imsm_orom_has_raid10(orom) ? "raid5 " : ""); + printf("IMSM_SUPPORTED_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("IMSM_2TB_VOLUMES=%s\n",(orom->attr & IMSM_OROM_ATTR_2TB) ? "yes" : "no"); + printf("IMSM_2TB_DISKS=%s\n",(orom->attr & IMSM_OROM_ATTR_2TB_DISK) ? "yes" : "no"); + printf("IMSM_MAX_DISKS=%d\n",orom->tds); + printf("IMSM_MAX_VOLUMES_PER_ARRAY=%d\n",orom->vpa); + printf("IMSM_MAX_VOLUMES_PER_CONTROLLER=%d\n",orom->vphba); +} + +static int detail_platform_imsm(int verbose, int enumerate_only, char *controller_path) { /* There are two components to imsm platform support, the ahci SATA * controller and the option-rom. To find the SATA controller we @@ -1714,11 +1901,10 @@ static int detail_platform_imsm(int verbose, int enumerate_only) * platform capabilities. If raid support is disabled in the BIOS the * option-rom capability structure will not be available. */ - const struct imsm_orom *orom; struct sys_dev *list, *hba; int host_base = 0; int port_count = 0; - int result=0; + int result=1; if (enumerate_only) { if (check_env("IMSM_NO_PLATFORM")) @@ -1727,53 +1913,111 @@ static int detail_platform_imsm(int verbose, int enumerate_only) if (!list) return 2; for (hba = list; hba; hba = hba->next) { - orom = find_imsm_capability(hba->type); - if (!orom) { - result = 2; + if (find_imsm_capability(hba)) { + result = 0; break; } + else + result = 2; } - free_sys_dev(&list); return result; } list = find_intel_devices(); if (!list) { - if (verbose) - fprintf(stderr, Name ": no active Intel(R) RAID " + if (verbose > 0) + pr_err("no active Intel(R) RAID " "controller found.\n"); - free_sys_dev(&list); return 2; - } else if (verbose) + } else if (verbose > 0) print_found_intel_controllers(list); for (hba = list; hba; hba = hba->next) { - orom = find_imsm_capability(hba->type); - if (!orom) - fprintf(stderr, Name ": imsm capabilities not found for controller: %s (type %s)\n", + if (controller_path && (compare_paths(hba->path, controller_path) != 0)) + continue; + if (!find_imsm_capability(hba)) { + pr_err("imsm capabilities not found for controller: %s (type %s)\n", hba->path, get_sys_dev_type(hba->type)); - else - print_imsm_capability(orom); + continue; + } + result = 0; } - for (hba = list; hba; hba = hba->next) { - printf(" I/O Controller : %s (%s)\n", - hba->path, get_sys_dev_type(hba->type)); - - if (hba->type == SYS_DEV_SATA) { - host_base = ahci_get_port_count(hba->path, &port_count); - if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) { - if (verbose) - fprintf(stderr, Name ": failed to enumerate " - "ports on SATA controller at %s.", hba->pci_id); - result |= 2; + if (controller_path && result == 1) { + pr_err("no active Intel(R) RAID controller found under %s\n", + controller_path); + return result; + } + + const struct orom_entry *oroms = get_oroms(); + int i; + + for (i = 0; i < SYS_DEV_MAX && oroms[i].devid_list; i++) { + print_imsm_capability(&oroms[i].orom); + + if (imsm_orom_is_nvme(&oroms[i].orom)) { + for (hba = list; hba; hba = hba->next) { + if (hba->type == SYS_DEV_NVME) + printf(" NVMe Device : %s\n", hba->path); + } + continue; + } + + struct devid_list *devid; + for (devid = oroms[i].devid_list; devid; devid = devid->next) { + hba = device_by_id(devid->devid); + if (!hba) + continue; + + printf(" I/O Controller : %s (%s)\n", + hba->path, get_sys_dev_type(hba->type)); + if (hba->type == SYS_DEV_SATA) { + host_base = ahci_get_port_count(hba->path, &port_count); + if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) { + if (verbose > 0) + pr_err("failed to enumerate " + "ports on SATA controller at %s.\n", hba->pci_id); + result |= 2; + } } } + printf("\n"); + } + + return result; +} + +static int export_detail_platform_imsm(int verbose, char *controller_path) +{ + struct sys_dev *list, *hba; + int result=1; + + list = find_intel_devices(); + if (!list) { + if (verbose > 0) + pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_INTEL_DEVICES\n"); + result = 2; + return result; + } + + for (hba = list; hba; hba = hba->next) { + if (controller_path && (compare_paths(hba->path,controller_path) != 0)) + continue; + if (!find_imsm_capability(hba) && verbose > 0) + pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n", hba->path); + else + result = 0; } - free_sys_dev(&list); + const struct orom_entry *oroms = get_oroms(); + int i; + + for (i = 0; i < SYS_DEV_MAX && oroms[i].devid_list; i++) + print_imsm_capability_export(&oroms[i].orom); + return result; } + #endif static int match_home_imsm(struct supertype *st, char *homehost) @@ -1800,7 +2044,7 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4]) * not the device-set. * uuid to recognise same set when adding a missing device back * to an array. This is a uuid for the device-set. - * + * * For each of these we can make do with a truncated * or hashed uuid rather than the original, as long as * everyone agrees. @@ -1940,13 +2184,15 @@ static __u8 imsm_num_data_members(struct imsm_dev *dev, int second_map) switch (get_imsm_raid_level(map)) { case 0: + return map->num_members; + break; case 1: case 10: - return map->num_members; + return map->num_members/2; case 5: return map->num_members - 1; default: - dprintf("%s: unsupported raid level\n", __func__); + dprintf("unsupported raid level\n"); return 0; } } @@ -2079,16 +2325,14 @@ static int read_imsm_migr_rec(int fd, struct intel_super *super) get_dev_size(fd, NULL, &dsize); if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) { - fprintf(stderr, - Name ": Cannot seek to anchor block: %s\n", - strerror(errno)); + pr_err("Cannot seek to anchor block: %s\n", + strerror(errno)); goto out; } if (read(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE) { - fprintf(stderr, - Name ": Cannot read migr record block: %s\n", - strerror(errno)); + pr_err("Cannot read migr record block: %s\n", + strerror(errno)); goto out; } ret_val = 0; @@ -2205,7 +2449,7 @@ static int imsm_create_metadata_checkpoint_update( int update_memory_size = 0; - dprintf("imsm_create_metadata_checkpoint_update(enter)\n"); + dprintf("(enter)\n"); if (u == NULL) return 0; @@ -2215,21 +2459,18 @@ static int imsm_create_metadata_checkpoint_update( update_memory_size = sizeof(struct imsm_update_general_migration_checkpoint); - *u = calloc(1, update_memory_size); + *u = xcalloc(1, update_memory_size); if (*u == NULL) { - dprintf("error: cannot get memory for " - "imsm_create_metadata_checkpoint_update update\n"); + dprintf("error: cannot get memory\n"); return 0; } (*u)->type = update_general_migration_checkpoint; (*u)->curr_migr_unit = __le32_to_cpu(super->migr_rec->curr_migr_unit); - dprintf("imsm_create_metadata_checkpoint_update: prepared for %u\n", - (*u)->curr_migr_unit); + dprintf("prepared for %u\n", (*u)->curr_migr_unit); return update_memory_size; } - static void imsm_update_metadata_locally(struct supertype *st, void *buf, int len); @@ -2285,16 +2526,14 @@ static int write_imsm_migr_rec(struct supertype *st) continue; get_dev_size(fd, NULL, &dsize); if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) { - fprintf(stderr, - Name ": Cannot seek to anchor block: %s\n", - strerror(errno)); + pr_err("Cannot seek to anchor block: %s\n", + strerror(errno)); goto out; } if (write(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE) { - fprintf(stderr, - Name ": Cannot write migr record block: %s\n", - strerror(errno)); + pr_err("Cannot write migr record block: %s\n", + strerror(errno)); goto out; } close(fd); @@ -2352,6 +2591,30 @@ int imsm_reshape_blocks_arrays_changes(struct intel_super *super) } return rv; } +static unsigned long long imsm_component_size_aligment_check(int level, + int chunk_size, + unsigned long long component_size) +{ + unsigned int component_size_alligment; + + /* check component size aligment + */ + component_size_alligment = component_size % (chunk_size/512); + + dprintf("(Level: %i, chunk_size = %i, component_size = %llu), component_size_alligment = %u\n", + level, chunk_size, component_size, + component_size_alligment); + + if (component_size_alligment && (level != 1) && (level != UnSet)) { + dprintf("imsm: reported component size alligned from %llu ", + component_size); + component_size -= component_size_alligment; + dprintf_cont("to %llu (%i).\n", + component_size, component_size_alligment); + } + + return component_size; +} static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap) { @@ -2362,8 +2625,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, struct imsm_map *prev_map = get_imsm_map(dev, MAP_1); struct imsm_map *map_to_analyse = map; struct dl *dl; - char *devname; - unsigned int component_size_alligment; int map_disks = info->array.raid_disks; memset(info, 0, sizeof(*info)); @@ -2443,23 +2704,13 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, dl->index); } - info->data_offset = __le32_to_cpu(map_to_analyse->pba_of_lba0); - info->component_size = - __le32_to_cpu(map_to_analyse->blocks_per_member); - - /* check component size aligment - */ - component_size_alligment = - info->component_size % (info->array.chunk_size/512); + info->data_offset = pba_of_lba0(map_to_analyse); + info->component_size = blocks_per_member(map_to_analyse); - if (component_size_alligment && - (info->array.level != 1) && (info->array.level != UnSet)) { - dprintf("imsm: reported component size alligned from %llu ", - info->component_size); - info->component_size -= component_size_alligment; - dprintf("to %llu (%i).\n", - info->component_size, component_size_alligment); - } + info->component_size = imsm_component_size_aligment_check( + info->array.level, + info->array.chunk_size, + info->component_size); memset(info->uuid, 0, sizeof(info->uuid)); info->recovery_start = MaxSector; @@ -2506,7 +2757,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, used_disks = imsm_num_data_members(dev, MAP_1); if (used_disks > 0) { - array_blocks = map->blocks_per_member * + array_blocks = blocks_per_member(map) * used_disks; /* round array size down to closest MB */ @@ -2535,11 +2786,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, info->array.major_version = -1; info->array.minor_version = -2; - devname = devnum2devname(st->container_dev); - *info->text_version = '\0'; - if (devname) - sprintf(info->text_version, "/%s/%d", devname, info->container_member); - free(devname); + sprintf(info->text_version, "/%s/%d", st->container_devnm, info->container_member); info->safe_mode_delay = 4000; /* 4 secs like the Matrix driver */ uuid_from_super_imsm(st, info->uuid); @@ -2564,7 +2811,6 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, static int imsm_count_failed(struct intel_super *super, struct imsm_dev *dev, int look_in_map); - #ifndef MDASSEMBLE static void manage_second_map(struct intel_super *super, struct imsm_dev *dev) { @@ -2615,7 +2861,7 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char * info->array.level = LEVEL_CONTAINER; info->array.layout = 0; info->array.md_minor = -1; - info->array.ctime = 0; /* N/A for imsm */ + info->array.ctime = 0; /* N/A for imsm */ info->array.utime = 0; info->array.chunk_size = 0; @@ -2667,20 +2913,30 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char * enough = 0; else /* we're normal, or already degraded */ enough = 1; - + if (is_gen_migration(dev) && missing) { + /* during general migration we need all disks + * that process is running on. + * No new missing disk is allowed. + */ + max_enough = -1; + enough = -1; + /* no more checks necessary + */ + break; + } /* in the missing/failed disk case check to see * if at least one array is runnable */ max_enough = max(max_enough, enough); } - dprintf("%s: enough: %d\n", __func__, max_enough); + dprintf("enough: %d\n", max_enough); info->container_enough = max_enough; if (super->disks) { __u32 reserved = imsm_reserved_sectors(super, super->disks); disk = &super->disks->disk; - info->data_offset = __le32_to_cpu(disk->total_blocks) - reserved; + info->data_offset = total_blocks(&super->disks->disk) - reserved; info->component_size = reserved; info->disk.state = is_configured(disk) ? (1 << MD_DISK_ACTIVE) : 0; /* we don't change info->disk.raid_disk here because @@ -2720,23 +2976,11 @@ struct mdinfo *getinfo_super_disks_imsm(struct supertype *st) if (!super || !super->disks) return NULL; dl = super->disks; - mddev = malloc(sizeof(*mddev)); - if (!mddev) { - fprintf(stderr, Name ": Failed to allocate memory.\n"); - return NULL; - } - memset(mddev, 0, sizeof(*mddev)); + mddev = xcalloc(1, sizeof(*mddev)); while (dl) { struct mdinfo *tmp; disk = &dl->disk; - tmp = malloc(sizeof(*tmp)); - if (!tmp) { - fprintf(stderr, Name ": Failed to allocate memory.\n"); - if (mddev) - sysfs_free(mddev); - return NULL; - } - memset(tmp, 0, sizeof(*tmp)); + tmp = xcalloc(1, sizeof(*tmp)); if (mddev->devs) tmp->next = mddev->devs; mddev->devs = tmp; @@ -2842,7 +3086,8 @@ static size_t disks_to_mpb_size(int disks) return size; } -static __u64 avail_size_imsm(struct supertype *st, __u64 devsize) +static __u64 avail_size_imsm(struct supertype *st, __u64 devsize, + unsigned long long data_offset) { if (devsize < (MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS)) return 0; @@ -2879,21 +3124,27 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) struct intel_super *first = st->sb; struct intel_super *sec = tst->sb; - if (!first) { - st->sb = tst->sb; - tst->sb = NULL; - return 0; - } + if (!first) { + st->sb = tst->sb; + tst->sb = NULL; + return 0; + } /* in platform dependent environment test if the disks * use the same Intel hba + * If not on Intel hba at all, allow anything. */ - if (!check_env("IMSM_NO_PLATFORM")) { - if (!first->hba || !sec->hba || - (first->hba->type != sec->hba->type)) { + if (!check_env("IMSM_NO_PLATFORM") && first->hba && sec->hba) { + if (first->hba->type != sec->hba->type) { fprintf(stderr, - "HBAs of devices does not match %s != %s\n", - first->hba ? get_sys_dev_type(first->hba->type) : NULL, - sec->hba ? get_sys_dev_type(sec->hba->type) : NULL); + "HBAs of devices do not match %s != %s\n", + get_sys_dev_type(first->hba->type), + get_sys_dev_type(sec->hba->type)); + return 3; + } + if (first->orom != sec->orom) { + fprintf(stderr, + "HBAs of devices do not match %s != %s\n", + first->hba->pci_id, sec->hba->pci_id); return 3; } } @@ -2924,7 +3175,6 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) } - /* if 'first' is a spare promote it to a populated mpb with sec's * family number */ @@ -2938,14 +3188,8 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) * fails here we don't associate the spare */ for (i = 0; i < sec->anchor->num_raid_devs; i++) { - dv = malloc(sizeof(*dv)); - if (!dv) - break; - dev = malloc(sizeof_imsm_dev(get_imsm_dev(sec, i), 1)); - if (!dev) { - free(dv); - break; - } + dv = xmalloc(sizeof(*dv)); + dev = xmalloc(sizeof_imsm_dev(get_imsm_dev(sec, i), 1)); dv->dev = dev; dv->index = i; dv->next = first->devlist; @@ -2954,7 +3198,7 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst) if (i < sec->anchor->num_raid_devs) { /* allocation failure */ free_devlist(first); - fprintf(stderr, "imsm: failed to associate spare\n"); + pr_err("imsm: failed to associate spare\n"); return 3; } first->anchor->num_raid_devs = sec->anchor->num_raid_devs; @@ -2985,7 +3229,7 @@ static void fd2devname(int fd, char *name) rv = readlink(path, dname, sizeof(dname)-1); if (rv <= 0) return; - + dname[rv] = '\0'; nm = strrchr(dname, '/'); if (nm) { @@ -3020,18 +3264,16 @@ static int imsm_read_serial(int fd, char *devname, if (rv != 0) { if (devname) - fprintf(stderr, - Name ": Failed to retrieve serial for %s\n", - devname); + pr_err("Failed to retrieve serial for %s\n", + devname); return rv; } rsp_len = scsi_serial[3]; if (!rsp_len) { if (devname) - fprintf(stderr, - Name ": Failed to retrieve serial for %s\n", - devname); + pr_err("Failed to retrieve serial for %s\n", + devname); return 2; } rsp_buf = (char *) &scsi_serial[4]; @@ -3120,14 +3362,7 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd) if (rv != 0) return 2; - dl = calloc(1, sizeof(*dl)); - if (!dl) { - if (devname) - fprintf(stderr, - Name ": failed to allocate disk buffer for %s\n", - devname); - return 2; - } + dl = xcalloc(1, sizeof(*dl)); fstat(fd, &stb); dl->major = major(stb.st_rdev); @@ -3141,9 +3376,9 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd) dl->e = NULL; fd2devname(fd, name); if (devname) - dl->devname = strdup(devname); + dl->devname = xstrdup(devname); else - dl->devname = strdup(name); + dl->devname = xstrdup(name); /* look up this disk's index in the current anchor */ disk = __serial_to_disk(dl->serial, super->anchor, &dl->index); @@ -3269,19 +3504,13 @@ static int parse_raid_devices(struct intel_super *super) len_migr = sizeof_imsm_dev(dev_iter, 1); if (len_migr > len) space_needed += len_migr - len; - - dv = malloc(sizeof(*dv)); - if (!dv) - return 1; + + dv = xmalloc(sizeof(*dv)); if (max_len < len_migr) max_len = len_migr; if (max_len > len_migr) space_needed += max_len - len_migr; - dev_new = malloc(max_len); - if (!dev_new) { - free(dv); - return 1; - } + dev_new = xmalloc(max_len); imsm_copy_dev(dev_new, dev_iter); dv->dev = dev_new; dv->index = i; @@ -3305,7 +3534,7 @@ static int parse_raid_devices(struct intel_super *super) super->buf = buf; super->len = len; } - + return 0; } @@ -3317,7 +3546,7 @@ struct bbm_log *__get_imsm_bbm_log(struct imsm_super *mpb) if (__le32_to_cpu(mpb->bbm_log_size)) { ptr = mpb; ptr += mpb->mpb_size - __le32_to_cpu(mpb->bbm_log_size); - } + } return ptr; } @@ -3348,7 +3577,7 @@ int check_mpb_migr_compatibility(struct intel_super *super) /* This device is migrating */ map0 = get_imsm_map(dev_iter, MAP_0); map1 = get_imsm_map(dev_iter, MAP_1); - if (map0->pba_of_lba0 != map1->pba_of_lba0) + if (pba_of_lba0(map0) != pba_of_lba0(map1)) /* migration optimization area was used */ return -1; if (migr_rec->ascending_migr == 0 @@ -3376,40 +3605,35 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname) get_dev_size(fd, NULL, &dsize); if (dsize < 1024) { if (devname) - fprintf(stderr, - Name ": %s: device to small for imsm\n", - devname); + pr_err("%s: device to small for imsm\n", + devname); return 1; } if (lseek64(fd, dsize - (512 * 2), SEEK_SET) < 0) { if (devname) - fprintf(stderr, Name - ": Cannot seek to anchor block on %s: %s\n", - devname, strerror(errno)); + pr_err("Cannot seek to anchor block on %s: %s\n", + devname, strerror(errno)); return 1; } if (posix_memalign((void**)&anchor, 512, 512) != 0) { if (devname) - fprintf(stderr, - Name ": Failed to allocate imsm anchor buffer" - " on %s\n", devname); + pr_err("Failed to allocate imsm anchor buffer" + " on %s\n", devname); return 1; } if (read(fd, anchor, 512) != 512) { if (devname) - fprintf(stderr, - Name ": Cannot read anchor block on %s: %s\n", - devname, strerror(errno)); + pr_err("Cannot read anchor block on %s: %s\n", + devname, strerror(errno)); free(anchor); return 1; } if (strncmp((char *) anchor->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0) { if (devname) - fprintf(stderr, - Name ": no IMSM anchor on %s\n", devname); + pr_err("no IMSM anchor on %s\n", devname); free(anchor); return 2; } @@ -3422,9 +3646,8 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname) super->len = ROUND_UP(anchor->mpb_size, 512); if (posix_memalign(&super->buf, 512, super->len) != 0) { if (devname) - fprintf(stderr, - Name ": unable to allocate %zu byte mpb buffer\n", - super->len); + pr_err("unable to allocate %zu byte mpb buffer\n", + super->len); free(anchor); return 2; } @@ -3434,21 +3657,20 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname) free(anchor); if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) { - fprintf(stderr, Name - ": %s could not allocate migr_rec buffer\n", __func__); + pr_err("could not allocate migr_rec buffer\n"); free(super->buf); return 2; } + super->clean_migration_record_by_mdmon = 0; if (!sectors) { check_sum = __gen_imsm_checksum(super->anchor); if (check_sum != __le32_to_cpu(super->anchor->check_sum)) { if (devname) - fprintf(stderr, - Name ": IMSM checksum %x != %x on %s\n", - check_sum, - __le32_to_cpu(super->anchor->check_sum), - devname); + pr_err("IMSM checksum %x != %x on %s\n", + check_sum, + __le32_to_cpu(super->anchor->check_sum), + devname); return 2; } @@ -3458,27 +3680,24 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname) /* read the extended mpb */ if (lseek64(fd, dsize - (512 * (2 + sectors)), SEEK_SET) < 0) { if (devname) - fprintf(stderr, - Name ": Cannot seek to extended mpb on %s: %s\n", - devname, strerror(errno)); + pr_err("Cannot seek to extended mpb on %s: %s\n", + devname, strerror(errno)); return 1; } if ((unsigned)read(fd, super->buf + 512, super->len - 512) != super->len - 512) { if (devname) - fprintf(stderr, - Name ": Cannot read extended mpb on %s: %s\n", - devname, strerror(errno)); + pr_err("Cannot read extended mpb on %s: %s\n", + devname, strerror(errno)); return 2; } check_sum = __gen_imsm_checksum(super->anchor); if (check_sum != __le32_to_cpu(super->anchor->check_sum)) { if (devname) - fprintf(stderr, - Name ": IMSM checksum %x != %x on %s\n", - check_sum, __le32_to_cpu(super->anchor->check_sum), - devname); + pr_err("IMSM checksum %x != %x on %s\n", + check_sum, __le32_to_cpu(super->anchor->check_sum), + devname); return 3; } @@ -3493,6 +3712,32 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname) static int read_imsm_migr_rec(int fd, struct intel_super *super); +/* clears hi bits in metadata if MPB_ATTRIB_2TB_DISK not set */ +static void clear_hi(struct intel_super *super) +{ + struct imsm_super *mpb = super->anchor; + int i, n; + if (mpb->attributes & MPB_ATTRIB_2TB_DISK) + return; + for (i = 0; i < mpb->num_disks; ++i) { + struct imsm_disk *disk = &mpb->disk[i]; + disk->total_blocks_hi = 0; + } + for (i = 0; i < mpb->num_raid_devs; ++i) { + struct imsm_dev *dev = get_imsm_dev(super, i); + if (!dev) + return; + for (n = 0; n < 2; ++n) { + struct imsm_map *map = get_imsm_map(dev, n); + if (!map) + continue; + map->pba_of_lba0_hi = 0; + map->blocks_per_member_hi = 0; + map->num_data_stripes_hi = 0; + } + } +} + static int load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd) { @@ -3505,7 +3750,7 @@ load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd if (err) return err; err = parse_raid_devices(super); - + clear_hi(super); return err; } @@ -3591,13 +3836,10 @@ static void free_super_imsm(struct supertype *st) static struct intel_super *alloc_super(void) { - struct intel_super *super = malloc(sizeof(*super)); + struct intel_super *super = xcalloc(1, sizeof(*super)); - if (super) { - memset(super, 0, sizeof(*super)); - super->current_vol = -1; - super->create_offset = ~((__u32 ) 0); - } + super->current_vol = -1; + super->create_offset = ~((unsigned long long) 0); return super; } @@ -3617,9 +3859,8 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de hba_name = find_disk_attached_hba(fd, NULL); if (!hba_name) { if (devname) - fprintf(stderr, - Name ": %s is not attached to Intel(R) RAID controller.\n", - devname); + pr_err("%s is not attached to Intel(R) RAID controller.\n", + devname); return 1; } rv = attach_hba_to_super(super, hba_name); @@ -3627,14 +3868,14 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de if (devname) { struct intel_hba *hba = super->hba; - fprintf(stderr, Name ": %s is attached to Intel(R) %s RAID " + pr_err("%s is attached to Intel(R) %s RAID " "controller (%s),\n" " but the container is assigned to Intel(R) " "%s RAID controller (", devname, - hba_name->path, + get_sys_dev_type(hba_name->type), hba_name->pci_id ? : "Err!", - get_sys_dev_type(hba_name->type)); + get_sys_dev_type(super->hba->type)); while (hba) { fprintf(stderr, "%s", hba->pci_id ? : "Err!"); @@ -3642,18 +3883,16 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de fprintf(stderr, ", "); hba = hba->next; } - fprintf(stderr, ").\n" " Mixing devices attached to different controllers " "is not allowed.\n"); } - free_sys_dev(&hba_name); return 2; } - super->orom = find_imsm_capability(hba_name->type); - free_sys_dev(&hba_name); + super->orom = find_imsm_capability(hba_name); if (!super->orom) return 3; + return 0; } @@ -3674,13 +3913,11 @@ static int find_missing(struct intel_super *super) if (dl) continue; - dl = malloc(sizeof(*dl)); - if (!dl) - return 1; + dl = xmalloc(sizeof(*dl)); dl->major = 0; dl->minor = 0; dl->fd = -1; - dl->devname = strdup("missing"); + dl->devname = xstrdup("missing"); dl->index = i; serialcpy(dl->serial, disk->serial); dl->disk = *disk; @@ -3720,8 +3957,8 @@ static int __prep_thunderdome(struct intel_super **table, int tbl_size, if (tbl_mpb->family_num == mpb->family_num) { if (tbl_mpb->check_sum == mpb->check_sum) { - dprintf("%s: mpb from %d:%d matches %d:%d\n", - __func__, super->disks->major, + dprintf("mpb from %d:%d matches %d:%d\n", + super->disks->major, super->disks->minor, table[i]->disks->major, table[i]->disks->minor); @@ -3738,8 +3975,8 @@ static int __prep_thunderdome(struct intel_super **table, int tbl_size, */ struct intel_disk *idisk; - dprintf("%s: mpb from %d:%d replaces %d:%d\n", - __func__, super->disks->major, + dprintf("mpb from %d:%d replaces %d:%d\n", + super->disks->major, super->disks->minor, table[i]->disks->major, table[i]->disks->minor); @@ -3767,8 +4004,8 @@ static int __prep_thunderdome(struct intel_super **table, int tbl_size, idisk->disk.status |= CONFIGURED_DISK; } - dprintf("%s: mpb from %d:%d prefer %d:%d\n", - __func__, super->disks->major, + dprintf("mpb from %d:%d prefer %d:%d\n", + super->disks->major, super->disks->minor, table[i]->disks->major, table[i]->disks->minor); @@ -3795,9 +4032,7 @@ static int __prep_thunderdome(struct intel_super **table, int tbl_size, is_failed(&idisk->disk)) idisk->disk.status &= ~(SPARE_DISK); } else { - idisk = calloc(1, sizeof(*idisk)); - if (!idisk) - return -1; + idisk = xcalloc(1, sizeof(*idisk)); idisk->owner = IMSM_UNKNOWN_OWNER; idisk->disk = *disk; idisk->next = *disk_list; @@ -3829,12 +4064,12 @@ validate_members(struct intel_super *super, struct intel_disk *disk_list, idisk->owner == IMSM_UNKNOWN_OWNER) ok_count++; else - dprintf("%s: '%.16s' owner %d != %d\n", - __func__, disk->serial, idisk->owner, + dprintf("'%.16s' owner %d != %d\n", + disk->serial, idisk->owner, owner); } else { - dprintf("%s: unknown disk %x [%d]: %.16s\n", - __func__, __le32_to_cpu(mpb->family_num), i, + dprintf("unknown disk %x [%d]: %.16s\n", + __le32_to_cpu(mpb->family_num), i, disk->serial); break; } @@ -3852,7 +4087,7 @@ static void show_conflicts(__u32 family_num, struct intel_super *super_list) for (s = super_list; s; s = s->next) { if (family_num != s->anchor->family_num) continue; - fprintf(stderr, "Conflict, offlining family %#x on '%s'\n", + pr_err("Conflict, offlining family %#x on '%s'\n", __le32_to_cpu(family_num), s->disks->devname); } } @@ -3890,8 +4125,8 @@ imsm_thunderdome(struct intel_super **super_list, int len) s = NULL; if (!s) - dprintf("%s: marking family: %#x from %d:%d offline\n", - __func__, mpb->family_num, + dprintf("marking family: %#x from %d:%d offline\n", + mpb->family_num, super_table[i]->disks->major, super_table[i]->disks->minor); super_table[i] = s; @@ -3938,7 +4173,7 @@ imsm_thunderdome(struct intel_super **super_list, int len) champion = s; if (conflict) - fprintf(stderr, "Chose family %#x on '%s', " + pr_err("Chose family %#x on '%s', " "assemble conflicts to new container with '--update=uuid'\n", __le32_to_cpu(s->anchor->family_num), s->disks->devname); @@ -3952,6 +4187,8 @@ imsm_thunderdome(struct intel_super **super_list, int len) if (s == champion) continue; + mpb->attributes |= s->anchor->attributes & MPB_ATTRIB_2TB_DISK; + for (i = 0; i < mpb->num_disks; i++) { struct imsm_disk *disk; @@ -4009,70 +4246,34 @@ imsm_thunderdome(struct intel_super **super_list, int len) return champion; } +static int +get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd); +static int get_super_block(struct intel_super **super_list, char *devnm, char *devname, + int major, int minor, int keep_fd); +static int +get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list, + int *max, int keep_fd); + static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, - char *devname) + char *devname, struct md_list *devlist, + int keep_fd) { - struct mdinfo *sra; struct intel_super *super_list = NULL; struct intel_super *super = NULL; - int devnum = fd2devnum(fd); - struct mdinfo *sd; - int retry; int err = 0; - int i; - - /* check if 'fd' an opened container */ - sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE); - if (!sra) - return 1; + int i = 0; - if (sra->array.major_version != -1 || - sra->array.minor_version != -2 || - strcmp(sra->text_version, "imsm") != 0) { - err = 1; - goto error; - } - /* load all mpbs */ - for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) { - struct intel_super *s = alloc_super(); - char nm[32]; - int dfd; - int rv; - - err = 1; - if (!s) - goto error; - s->next = super_list; - super_list = s; - - err = 2; - sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor); - dfd = dev_open(nm, O_RDWR); - if (dfd < 0) - goto error; - - rv = find_intel_hba_capability(dfd, s, devname); - /* no orom/efi or non-intel hba of the disk */ - if (rv != 0) - goto error; - - err = load_and_parse_mpb(dfd, s, NULL, 1); - - /* retry the load if we might have raced against mdmon */ - if (err == 3 && mdmon_running(devnum)) - for (retry = 0; retry < 3; retry++) { - usleep(3000); - err = load_and_parse_mpb(dfd, s, NULL, 1); - if (err != 3) - break; - } - if (err) - goto error; - } - - /* all mpbs enter, maybe one leaves */ - super = imsm_thunderdome(&super_list, i); - if (!super) { + if (fd >= 0) + /* 'fd' is an opened container */ + err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd); + else + /* get super block from devlist devices */ + err = get_devlist_super_block(devlist, &super_list, &i, keep_fd); + if (err) + goto error; + /* all mpbs enter, maybe one leaves */ + super = imsm_thunderdome(&super_list, i); + if (!super) { err = 1; goto error; } @@ -4095,7 +4296,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, /* Check migration compatibility */ if ((err == 0) && (check_mpb_migr_compatibility(super) != 0)) { - fprintf(stderr, Name ": Unsupported migration detected"); + pr_err("Unsupported migration detected"); if (devname) fprintf(stderr, " on %s\n", devname); else @@ -4114,13 +4315,15 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, super_list = super_list->next; free_imsm(s); } - sysfs_free(sra); if (err) return err; *sbp = super; - st->container_dev = devnum; + if (fd >= 0) + strcpy(st->container_devnm, fd2devnm(fd)); + else + st->container_devnm[0] = 0; if (err == 0 && st->ss == NULL) { st->ss = &super_imsm; st->minor_version = 0; @@ -4129,9 +4332,140 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp, return 0; } +static int +get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list, + int *max, int keep_fd) +{ + struct md_list *tmpdev; + int err = 0; + int i = 0; + + for (i = 0, tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) { + if (tmpdev->used != 1) + continue; + if (tmpdev->container == 1) { + int lmax = 0; + int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL); + if (fd < 0) { + pr_err("cannot open device %s: %s\n", + tmpdev->devname, strerror(errno)); + err = 8; + goto error; + } + err = get_sra_super_block(fd, super_list, + tmpdev->devname, &lmax, + keep_fd); + i += lmax; + close(fd); + if (err) { + err = 7; + goto error; + } + } else { + int major = major(tmpdev->st_rdev); + int minor = minor(tmpdev->st_rdev); + err = get_super_block(super_list, + NULL, + tmpdev->devname, + major, minor, + keep_fd); + i++; + if (err) { + err = 6; + goto error; + } + } + } + error: + *max = i; + return err; +} + +static int get_super_block(struct intel_super **super_list, char *devnm, char *devname, + int major, int minor, int keep_fd) +{ + struct intel_super*s = NULL; + char nm[32]; + int dfd = -1; + int err = 0; + int retry; + + s = alloc_super(); + if (!s) { + err = 1; + goto error; + } + + sprintf(nm, "%d:%d", major, minor); + dfd = dev_open(nm, O_RDWR); + if (dfd < 0) { + err = 2; + goto error; + } + + find_intel_hba_capability(dfd, s, devname); + err = load_and_parse_mpb(dfd, s, NULL, keep_fd); + + /* retry the load if we might have raced against mdmon */ + if (err == 3 && devnm && mdmon_running(devnm)) + for (retry = 0; retry < 3; retry++) { + usleep(3000); + err = load_and_parse_mpb(dfd, s, NULL, keep_fd); + if (err != 3) + break; + } + error: + if (!err) { + s->next = *super_list; + *super_list = s; + } else { + if (s) + free(s); + if (dfd >= 0) + close(dfd); + } + if ((dfd >= 0) && (!keep_fd)) + close(dfd); + return err; + +} + +static int +get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd) +{ + struct mdinfo *sra; + char *devnm; + struct mdinfo *sd; + int err = 0; + int i = 0; + sra = sysfs_read(fd, NULL, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE); + if (!sra) + return 1; + + if (sra->array.major_version != -1 || + sra->array.minor_version != -2 || + strcmp(sra->text_version, "imsm") != 0) { + err = 1; + goto error; + } + /* load all mpbs */ + devnm = fd2devnm(fd); + for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) { + if (get_super_block(super_list, devnm, devname, + sd->disk.major, sd->disk.minor, keep_fd) != 0) { + err = 7; + goto error; + } + } + error: + sysfs_free(sra); + *max = i; + return err; +} + static int load_container_imsm(struct supertype *st, int fd, char *devname) { - return load_super_imsm_all(st, fd, &st->sb, devname); + return load_super_imsm_all(st, fd, &st->sb, devname, NULL, 1); } #endif @@ -4139,6 +4473,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) { struct intel_super *super; int rv; + int retry; if (test_partition(fd)) /* IMSM not allowed on partitions */ @@ -4147,12 +4482,6 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) free_super_imsm(st); super = alloc_super(); - if (!super) { - fprintf(stderr, - Name ": malloc of %zu failed.\n", - sizeof(*super)); - return 1; - } /* Load hba and capabilities if they exist. * But do not preclude loading metadata in case capabilities or hba are * non-compliant and ignore_hw_compat is set. @@ -4161,18 +4490,32 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) /* no orom/efi or non-intel hba of the disk */ if ((rv != 0) && (st->ignore_hw_compat == 0)) { if (devname) - fprintf(stderr, - Name ": No OROM/EFI properties for %s\n", devname); + pr_err("No OROM/EFI properties for %s\n", devname); free_imsm(super); return 2; } rv = load_and_parse_mpb(fd, super, devname, 0); + /* retry the load if we might have raced against mdmon */ + if (rv == 3) { + struct mdstat_ent *mdstat = mdstat_by_component(fd2devnm(fd)); + + if (mdstat && mdmon_running(mdstat->devnm) && getpid() != mdmon_pid(mdstat->devnm)) { + for (retry = 0; retry < 3; retry++) { + usleep(3000); + rv = load_and_parse_mpb(fd, super, devname, 0); + if (rv != 3) + break; + } + } + + free_mdstat(mdstat); + } + if (rv) { if (devname) - fprintf(stderr, - Name ": Failed to load all information " - "sections on %s\n", devname); + pr_err("Failed to load all information " + "sections on %s\n", devname); free_imsm(super); return rv; } @@ -4188,8 +4531,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) if (load_imsm_migr_rec(super, NULL) == 0) { /* Check for unsupported migration features */ if (check_mpb_migr_compatibility(super) != 0) { - fprintf(stderr, - Name ": Unsupported migration detected"); + pr_err("Unsupported migration detected"); if (devname) fprintf(stderr, " on %s\n", devname); else @@ -4208,22 +4550,13 @@ 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, int num_domains) -{ - __u32 num_stripes; - - num_stripes = (info->size * 2) / info_to_blocks_per_strip(info); - num_stripes /= num_domains; - - return num_stripes; -} - -static __u32 info_to_blocks_per_member(mdu_array_info_t *info) +static unsigned long long info_to_blocks_per_member(mdu_array_info_t *info, + unsigned long long size) { if (info->level == 1) - return info->size * 2; + return size * 2; else - return (info->size * 2) & ~(info_to_blocks_per_strip(info) - 1); + return (size * 2) & ~(info_to_blocks_per_strip(info) - 1); } static void imsm_update_version_info(struct intel_super *super) @@ -4292,14 +4625,15 @@ static int check_name(struct intel_super *super, char *name, int quiet) } if (reason && !quiet) - fprintf(stderr, Name ": imsm volume name %s\n", reason); + pr_err("imsm volume name %s\n", reason); return !reason; } static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, unsigned long long size, char *name, - char *homehost, int *uuid) + char *homehost, int *uuid, + long long data_offset) { /* We are creating a volume inside a pre-existing container. * so st->sb is already set. @@ -4314,10 +4648,10 @@ 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; + unsigned long long num_data_stripes; if (super->orom && mpb->num_raid_devs >= super->orom->vpa) { - fprintf(stderr, Name": This imsm-container already has the " + pr_err("This imsm-container already has the " "maximum of %d volumes\n", super->orom->vpa); return 0; } @@ -4330,14 +4664,12 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, size_t size_round = ROUND_UP(size_new, 512); if (posix_memalign(&mpb_new, 512, size_round) != 0) { - fprintf(stderr, Name": could not allocate new mpb\n"); + pr_err("could not allocate new mpb\n"); return 0; } if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) { - fprintf(stderr, Name - ": %s could not allocate migr_rec buffer\n", - __func__); + pr_err("could not allocate migr_rec buffer\n"); free(super->buf); free(super); free(mpb_new); @@ -4381,32 +4713,19 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, for (d = super->missing; d; d = d->next) missing++; if (info->failed_disks > missing) { - fprintf(stderr, Name": unable to add 'missing' disk to container\n"); + pr_err("unable to add 'missing' disk to container\n"); return 0; } } if (!check_name(super, name, 0)) return 0; - dv = malloc(sizeof(*dv)); - if (!dv) { - fprintf(stderr, Name ": failed to allocate device list entry\n"); - return 0; - } - 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; - } - + dv = xmalloc(sizeof(*dv)); + dev = xcalloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1)); strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN); - if (info->level == 1) - array_blocks = info_to_blocks_per_member(info); - else - array_blocks = calc_array_size(info->level, info->raid_disks, + array_blocks = calc_array_size(info->level, info->raid_disks, info->layout, info->chunk_size, - info->size*2); + size * 2); /* round array size down to closest MB */ array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT; @@ -4419,12 +4738,13 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, vol->dirty = !info->state; vol->curr_migr_unit = 0; map = get_imsm_map(dev, MAP_0); - map->pba_of_lba0 = __cpu_to_le32(super->create_offset); - map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info)); + set_pba_of_lba0(map, super->create_offset); + set_blocks_per_member(map, info_to_blocks_per_member(info, size)); map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info)); map->failed_disk_num = ~0; if (info->level > 0) - map->map_state = IMSM_T_STATE_UNINITIALIZED; + map->map_state = (info->state ? IMSM_T_STATE_NORMAL + : IMSM_T_STATE_UNINITIALIZED); else map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED : IMSM_T_STATE_NORMAL; @@ -4433,7 +4753,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, if (info->level == 1 && info->raid_disks > 2) { free(dev); free(dv); - fprintf(stderr, Name": imsm does not support more than 2 disks" + pr_err("imsm does not support more than 2 disks" "in a raid1 volume\n"); return 0; } @@ -4447,8 +4767,10 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, 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); + /* info->size is only int so use the 'size' parameter instead */ + num_data_stripes = (size * 2) / info_to_blocks_per_strip(info); + num_data_stripes /= map->num_domains; + set_num_data_stripes(map, num_data_stripes); map->num_members = info->raid_disks; for (i = 0; i < map->num_members; i++) { @@ -4469,7 +4791,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, static int init_super_imsm(struct supertype *st, mdu_array_info_t *info, unsigned long long size, char *name, - char *homehost, int *uuid) + char *homehost, int *uuid, + unsigned long long data_offset) { /* This is primarily called by Create when creating a new array. * We will then get add_to_super called for each component, and then @@ -4484,8 +4807,14 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info, size_t mpb_size; char *version; + if (data_offset != INVALID_SECTORS) { + pr_err("data-offset not supported by imsm\n"); + return 0; + } + if (st->sb) - return init_super_imsm_volume(st, info, size, name, homehost, uuid); + return init_super_imsm_volume(st, info, size, name, homehost, uuid, + data_offset); if (info) mpb_size = disks_to_mpb_size(info->nr_disks); @@ -4498,13 +4827,11 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info, super = NULL; } if (!super) { - fprintf(stderr, Name - ": %s could not allocate superblock\n", __func__); + pr_err("could not allocate superblock\n"); return 0; } if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) { - fprintf(stderr, Name - ": %s could not allocate migr_rec buffer\n", __func__); + pr_err("could not allocate migr_rec buffer\n"); free(super->buf); free(super); return 0; @@ -4545,7 +4872,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, map = get_imsm_map(dev, MAP_0); if (! (dk->state & (1<index); if (slot >= 0 && (get_imsm_ord_tbl_ent(dev, slot, MAP_X) & IMSM_ORD_REBUILD) == 0) { - fprintf(stderr, Name ": %s has been included in this array twice\n", + pr_err("%s has been included in this array twice\n", devname); return 1; } @@ -4591,8 +4918,8 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, */ if (super->current_vol == 0) { for (df = super->missing; df; df = df->next) { - if (dl->disk.total_blocks > df->disk.total_blocks) - df->disk.total_blocks = dl->disk.total_blocks; + if (total_blocks(&dl->disk) > total_blocks(&df->disk)) + set_total_blocks(&df->disk, total_blocks(&dl->disk)); _disk = __get_imsm_disk(mpb, df->index); *_disk = df->disk; } @@ -4634,7 +4961,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, _disk = __get_imsm_disk(mpb, dl->index); if (!_dev || !_disk) { - fprintf(stderr, Name ": BUG mpb setup error\n"); + pr_err("BUG mpb setup error\n"); return 1; } *_dev = *dev; @@ -4681,7 +5008,8 @@ int mark_spare(struct dl *disk) } static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, - int fd, char *devname) + int fd, char *devname, + unsigned long long data_offset) { struct intel_super *super = st->sb; struct dl *dd; @@ -4707,31 +5035,36 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, return add_to_super_imsm_volume(st, dk, fd, devname); fstat(fd, &stb); - dd = malloc(sizeof(*dd)); - if (!dd) { - fprintf(stderr, - Name ": malloc failed %s:%d.\n", __func__, __LINE__); - return 1; - } - memset(dd, 0, sizeof(*dd)); + dd = xcalloc(sizeof(*dd), 1); dd->major = major(stb.st_rdev); dd->minor = minor(stb.st_rdev); - dd->devname = devname ? strdup(devname) : NULL; + dd->devname = devname ? xstrdup(devname) : NULL; dd->fd = fd; dd->e = NULL; dd->action = DISK_ADD; rv = imsm_read_serial(fd, devname, dd->serial); if (rv) { - fprintf(stderr, - Name ": failed to retrieve scsi serial, aborting\n"); + pr_err("failed to retrieve scsi serial, aborting\n"); free(dd); abort(); } get_dev_size(fd, NULL, &size); + /* clear migr_rec when adding disk to container */ + memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SIZE); + if (lseek64(fd, size - MIGR_REC_POSITION, SEEK_SET) >= 0) { + if (write(fd, super->migr_rec_buf, + MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE) + perror("Write migr_rec failed"); + } + size /= 512; serialcpy(dd->disk.serial, dd->serial); - dd->disk.total_blocks = __cpu_to_le32(size); + set_total_blocks(&dd->disk, size); + if (__le32_to_cpu(dd->disk.total_blocks_hi) > 0) { + struct imsm_super *mpb = super->anchor; + mpb->attributes |= MPB_ATTRIB_2TB_DISK; + } mark_spare(dd); if (sysfs_disk_to_scsi_id(fd, &id) == 0) dd->disk.scsi_id = __cpu_to_le32(id); @@ -4750,7 +5083,6 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, return 0; } - static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk) { struct intel_super *super = st->sb; @@ -4761,18 +5093,10 @@ static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk) * is prepared. */ if (!st->update_tail) { - fprintf(stderr, - Name ": %s shall be used in mdmon context only" - "(line %d).\n", __func__, __LINE__); + pr_err("shall be used in mdmon context only\n"); return 1; } - dd = malloc(sizeof(*dd)); - if (!dd) { - fprintf(stderr, - Name ": malloc failed %s:%d.\n", __func__, __LINE__); - return 1; - } - memset(dd, 0, sizeof(*dd)); + dd = xcalloc(1, sizeof(*dd)); dd->major = dk->major; dd->minor = dk->minor; dd->fd = -1; @@ -4782,7 +5106,6 @@ static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk) dd->next = super->disk_mgmt_list; super->disk_mgmt_list = dd; - return 0; } @@ -4819,6 +5142,9 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose) continue; spare->disk[0] = d->disk; + if (__le32_to_cpu(d->disk.total_blocks_hi) > 0) + spare->attributes |= MPB_ATTRIB_2TB_DISK; + sum = __gen_imsm_checksum(spare); spare->family_num = __cpu_to_le32(sum); spare->orig_family_num = 0; @@ -4826,8 +5152,8 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose) spare->check_sum = __cpu_to_le32(sum); if (store_imsm_mpb(d->fd, spare)) { - fprintf(stderr, "%s: failed for device %d:%d %s\n", - __func__, d->major, d->minor, strerror(errno)); + pr_err("failed for device %d:%d %s\n", + d->major, d->minor, strerror(errno)); return 1; } if (doclose) { @@ -4895,6 +5221,10 @@ static int write_super_imsm(struct supertype *st, int doclose) sum = __gen_imsm_checksum(mpb); mpb->check_sum = __cpu_to_le32(sum); + if (super->clean_migration_record_by_mdmon) { + clear_migration_record = 1; + super->clean_migration_record_by_mdmon = 0; + } if (clear_migration_record) memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SIZE); @@ -4902,9 +5232,7 @@ static int write_super_imsm(struct supertype *st, int doclose) for (d = super->disks; d ; d = d->next) { if (d->index < 0 || is_failed(&d->disk)) continue; - if (store_imsm_mpb(d->fd, mpb)) - fprintf(stderr, "%s: failed for device %d:%d %s\n", - __func__, d->major, d->minor, strerror(errno)); + if (clear_migration_record) { unsigned long long dsize; @@ -4915,6 +5243,13 @@ static int write_super_imsm(struct supertype *st, int doclose) perror("Write migr_rec failed"); } } + + if (store_imsm_mpb(d->fd, mpb)) + fprintf(stderr, + "failed for device %d:%d (fd: %d)%s\n", + d->major, d->minor, + d->fd, strerror(errno)); + if (doclose) { close(d->fd); d->fd = -1; @@ -4927,7 +5262,6 @@ static int write_super_imsm(struct supertype *st, int doclose) return 0; } - static int create_array(struct supertype *st, int dev_idx) { size_t len; @@ -4941,13 +5275,7 @@ static int create_array(struct supertype *st, int dev_idx) len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0) + sizeof(*inf) * map->num_members; - u = malloc(len); - if (!u) { - fprintf(stderr, "%s: failed to allocate update buffer\n", - __func__); - return 1; - } - + u = xmalloc(len); u->type = update_create_array; u->dev_idx = dev_idx; imsm_copy_dev(&u->dev, dev); @@ -4956,6 +5284,8 @@ static int create_array(struct supertype *st, int dev_idx) int idx = get_imsm_disk_idx(dev, i, MAP_X); disk = get_imsm_disk(super, idx); + if (!disk) + disk = get_imsm_missing(super, idx); serialcpy(inf[i].serial, disk->serial); } append_metadata_update(st, u, len); @@ -4973,13 +5303,7 @@ static int mgmt_disk(struct supertype *st) return 0; len = sizeof(*u); - u = malloc(len); - if (!u) { - fprintf(stderr, "%s: failed to allocate update buffer\n", - __func__); - return 1; - } - + u = xmalloc(len); u->type = update_add_remove_disk; append_metadata_update(st, u, len); @@ -5012,7 +5336,7 @@ static int write_init_super_imsm(struct supertype *st) } else { struct dl *d; for (d = super->disks; d; d = d->next) - Kill(d->devname, NULL, 0, 1, 1); + Kill(d->devname, NULL, 0, -1, 1); return write_super_imsm(st, 1); } } @@ -5041,7 +5365,9 @@ static int imsm_bbm_log_size(struct imsm_super *mpb) #ifndef MDASSEMBLE static int validate_geometry_imsm_container(struct supertype *st, int level, int layout, int raiddisks, int chunk, - unsigned long long size, char *dev, + unsigned long long size, + unsigned long long data_offset, + char *dev, unsigned long long *freesize, int verbose) { @@ -5057,8 +5383,8 @@ static int validate_geometry_imsm_container(struct supertype *st, int level, fd = open(dev, O_RDONLY|O_EXCL, 0); if (fd < 0) { - if (verbose) - fprintf(stderr, Name ": imsm: Cannot open %s: %s\n", + if (verbose > 0) + pr_err("imsm: Cannot open %s: %s\n", dev, strerror(errno)); return 0; } @@ -5071,20 +5397,12 @@ static int validate_geometry_imsm_container(struct supertype *st, int level, * note that there is no fd for the disks in array. */ super = alloc_super(); - if (!super) { - fprintf(stderr, - Name ": malloc of %zu failed.\n", - sizeof(*super)); - close(fd); - return 0; - } - - rv = find_intel_hba_capability(fd, super, verbose ? dev : NULL); + rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL); if (rv != 0) { #if DEBUG char str[256]; fd2devname(fd, str); - dprintf("validate_geometry_imsm_container: fd: %d %s orom: %p rv: %d raiddisk: %d\n", + dprintf("fd: %d %s orom: %p rv: %d raiddisk: %d\n", fd, str, super->orom, rv, raiddisks); #endif /* no orom/efi or non-intel hba of the disk */ @@ -5093,17 +5411,25 @@ static int validate_geometry_imsm_container(struct supertype *st, int level, return 0; } close(fd); - if (super->orom && raiddisks > super->orom->tds) { - if (verbose) - fprintf(stderr, Name ": %d exceeds maximum number of" - " platform supported disks: %d\n", - raiddisks, super->orom->tds); - - free_imsm(super); - return 0; + if (super->orom) { + if (raiddisks > super->orom->tds) { + if (verbose) + pr_err("%d exceeds maximum number of" + " platform supported disks: %d\n", + raiddisks, super->orom->tds); + free_imsm(super); + return 0; + } + if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 && + (ldsize >> 9) >> 32 > 0) { + if (verbose) + pr_err("%s exceeds maximum platform supported size\n", dev); + free_imsm(super); + return 0; + } } - *freesize = avail_size_imsm(st, ldsize >> 9); + *freesize = avail_size_imsm(st, ldsize >> 9, data_offset); free_imsm(super); return 1; @@ -5142,7 +5468,7 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten * 'maxsize' given the "all disks in an array must share a common start * offset" constraint */ - struct extent *e = calloc(sum_extents, sizeof(*e)); + struct extent *e = xcalloc(sum_extents, sizeof(*e)); struct dl *dl; int i, j; int start_extent; @@ -5151,9 +5477,6 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten unsigned long long maxsize; unsigned long reserve; - if (!e) - return 0; - /* coalesce and sort all extents. also, check to see if we need to * reserve space between member arrays */ @@ -5209,7 +5532,7 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten if (maxsize < reserve) return 0; - super->create_offset = ~((__u32) 0); + super->create_offset = ~((unsigned long long) 0); if (start + reserve > super->create_offset) return 0; /* start overflows create_offset */ super->create_offset = start + reserve; @@ -5239,6 +5562,346 @@ static int is_raid_level_supported(const struct imsm_orom *orom, int level, int return 0; } +static int +active_arrays_by_format(char *name, char* hba, struct md_list **devlist, + int dpa, int verbose) +{ + struct mdstat_ent *mdstat = mdstat_read(0, 0); + struct mdstat_ent *memb = NULL; + int count = 0; + int num = 0; + struct md_list *dv = NULL; + int found; + + for (memb = mdstat ; memb ; memb = memb->next) { + if (memb->metadata_version && + (strncmp(memb->metadata_version, "external:", 9) == 0) && + (strcmp(&memb->metadata_version[9], name) == 0) && + !is_subarray(memb->metadata_version+9) && + memb->members) { + struct dev_member *dev = memb->members; + int fd = -1; + while(dev && (fd < 0)) { + char *path = xmalloc(strlen(dev->name) + strlen("/dev/") + 1); + num = sprintf(path, "%s%s", "/dev/", dev->name); + if (num > 0) + fd = open(path, O_RDONLY, 0); + if ((num <= 0) || (fd < 0)) { + pr_vrb(": Cannot open %s: %s\n", + dev->name, strerror(errno)); + } + free(path); + dev = dev->next; + } + found = 0; + if ((fd >= 0) && disk_attached_to_hba(fd, hba)) { + struct mdstat_ent *vol; + for (vol = mdstat ; vol ; vol = vol->next) { + if ((vol->active > 0) && + vol->metadata_version && + is_container_member(vol, memb->dev)) { + found++; + count++; + } + } + if (*devlist && (found < dpa)) { + dv = xcalloc(1, sizeof(*dv)); + dv->devname = xmalloc(strlen(memb->dev) + strlen("/dev/") + 1); + sprintf(dv->devname, "%s%s", "/dev/", memb->dev); + dv->found = found; + dv->used = 0; + dv->next = *devlist; + *devlist = dv; + } + } + if (fd >= 0) + close(fd); + } + } + free_mdstat(mdstat); + return count; +} + +#ifdef DEBUG_LOOP +static struct md_list* +get_loop_devices(void) +{ + int i; + struct md_list *devlist = NULL; + struct md_list *dv = NULL; + + for(i = 0; i < 12; i++) { + dv = xcalloc(1, sizeof(*dv)); + dv->devname = xmalloc(40); + sprintf(dv->devname, "/dev/loop%d", i); + dv->next = devlist; + devlist = dv; + } + return devlist; +} +#endif + +static struct md_list* +get_devices(const char *hba_path) +{ + struct md_list *devlist = NULL; + struct md_list *dv = NULL; + struct dirent *ent; + DIR *dir; + int err = 0; + +#if DEBUG_LOOP + devlist = get_loop_devices(); + return devlist; +#endif + /* scroll through /sys/dev/block looking for devices attached to + * this hba + */ + dir = opendir("/sys/dev/block"); + for (ent = dir ? readdir(dir) : NULL; ent; ent = readdir(dir)) { + int fd; + char buf[1024]; + int major, minor; + char *path = NULL; + if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2) + continue; + path = devt_to_devpath(makedev(major, minor)); + if (!path) + continue; + if (!path_attached_to_hba(path, hba_path)) { + free(path); + path = NULL; + continue; + } + free(path); + path = NULL; + fd = dev_open(ent->d_name, O_RDONLY); + if (fd >= 0) { + fd2devname(fd, buf); + close(fd); + } else { + pr_err("cannot open device: %s\n", + ent->d_name); + continue; + } + + dv = xcalloc(1, sizeof(*dv)); + dv->devname = xstrdup(buf); + dv->next = devlist; + devlist = dv; + } + if (err) { + while(devlist) { + dv = devlist; + devlist = devlist->next; + free(dv->devname); + free(dv); + } + } + closedir(dir); + return devlist; +} + +static int +count_volumes_list(struct md_list *devlist, char *homehost, + int verbose, int *found) +{ + struct md_list *tmpdev; + int count = 0; + struct supertype *st = NULL; + + /* first walk the list of devices to find a consistent set + * that match the criterea, if that is possible. + * We flag the ones we like with 'used'. + */ + *found = 0; + st = match_metadata_desc_imsm("imsm"); + if (st == NULL) { + pr_vrb(": cannot allocate memory for imsm supertype\n"); + return 0; + } + + for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) { + char *devname = tmpdev->devname; + struct stat stb; + struct supertype *tst; + int dfd; + if (tmpdev->used > 1) + continue; + tst = dup_super(st); + if (tst == NULL) { + pr_vrb(": cannot allocate memory for imsm supertype\n"); + goto err_1; + } + tmpdev->container = 0; + dfd = dev_open(devname, O_RDONLY|O_EXCL); + if (dfd < 0) { + dprintf("cannot open device %s: %s\n", + devname, strerror(errno)); + tmpdev->used = 2; + } else if (fstat(dfd, &stb)< 0) { + /* Impossible! */ + dprintf("fstat failed for %s: %s\n", + devname, strerror(errno)); + tmpdev->used = 2; + } else if ((stb.st_mode & S_IFMT) != S_IFBLK) { + dprintf("%s is not a block device.\n", + devname); + tmpdev->used = 2; + } else if (must_be_container(dfd)) { + struct supertype *cst; + cst = super_by_fd(dfd, NULL); + if (cst == NULL) { + dprintf("cannot recognize container type %s\n", + devname); + tmpdev->used = 2; + } else if (tst->ss != st->ss) { + dprintf("non-imsm container - ignore it: %s\n", + devname); + tmpdev->used = 2; + } else if (!tst->ss->load_container || + tst->ss->load_container(tst, dfd, NULL)) + tmpdev->used = 2; + else { + tmpdev->container = 1; + } + if (cst) + cst->ss->free_super(cst); + } else { + tmpdev->st_rdev = stb.st_rdev; + if (tst->ss->load_super(tst,dfd, NULL)) { + dprintf("no RAID superblock on %s\n", + devname); + tmpdev->used = 2; + } else if (tst->ss->compare_super == NULL) { + dprintf("Cannot assemble %s metadata on %s\n", + tst->ss->name, devname); + tmpdev->used = 2; + } + } + if (dfd >= 0) + close(dfd); + if (tmpdev->used == 2 || tmpdev->used == 4) { + /* Ignore unrecognised devices during auto-assembly */ + goto loop; + } + else { + struct mdinfo info; + tst->ss->getinfo_super(tst, &info, NULL); + + if (st->minor_version == -1) + st->minor_version = tst->minor_version; + + if (memcmp(info.uuid, uuid_zero, + sizeof(int[4])) == 0) { + /* this is a floating spare. It cannot define + * an array unless there are no more arrays of + * this type to be found. It can be included + * in an array of this type though. + */ + tmpdev->used = 3; + goto loop; + } + + if (st->ss != tst->ss || + st->minor_version != tst->minor_version || + st->ss->compare_super(st, tst) != 0) { + /* Some mismatch. If exactly one array matches this host, + * we can resolve on that one. + * Or, if we are auto assembling, we just ignore the second + * for now. + */ + dprintf("superblock on %s doesn't match others - assembly aborted\n", + devname); + goto loop; + } + tmpdev->used = 1; + *found = 1; + dprintf("found: devname: %s\n", devname); + } + loop: + if (tst) + tst->ss->free_super(tst); + } + if (*found != 0) { + int err; + if ((err = load_super_imsm_all(st, -1, &st->sb, NULL, devlist, 0)) == 0) { + struct mdinfo *iter, *head = st->ss->container_content(st, NULL); + for (iter = head; iter; iter = iter->next) { + dprintf("content->text_version: %s vol\n", + iter->text_version); + if (iter->array.state & (1<text_version); + } else + count++; + } + sysfs_free(head); + + } else { + dprintf("No valid super block on device list: err: %d %p\n", + err, st->sb); + } + } else { + dprintf("no more devices to examine\n"); + } + + for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) { + if ((tmpdev->used == 1) && (tmpdev->found)) { + if (count) { + if (count < tmpdev->found) + count = 0; + else + count -= tmpdev->found; + } + } + if (tmpdev->used == 1) + tmpdev->used = 4; + } + err_1: + if (st) + st->ss->free_super(st); + return count; +} + +static int +count_volumes(char *hba, int dpa, int verbose) +{ + struct md_list *devlist = NULL; + int count = 0; + int found = 0;; + + devlist = get_devices(hba); + /* if no intel devices return zero volumes */ + if (devlist == NULL) + return 0; + + count = active_arrays_by_format("imsm", hba, &devlist, dpa, verbose); + dprintf("path: %s active arrays: %d\n", hba, count); + if (devlist == NULL) + return 0; + do { + found = 0; + count += count_volumes_list(devlist, + NULL, + verbose, + &found); + dprintf("found %d count: %d\n", found, count); + } while (found); + + dprintf("path: %s total number of volumes: %d\n", hba, count); + + while(devlist) { + struct md_list *dv = devlist; + devlist = devlist->next; + free(dv->devname); + free(dv); + } + return count; +} + static int imsm_default_chunk(const struct imsm_orom *orom) { /* up to 512 if the plaform supports it, otherwise the platform max. @@ -5249,10 +5912,9 @@ static int imsm_default_chunk(const struct imsm_orom *orom) return min(512, (1 << fs)); } -#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, unsigned long long size, int verbose) { /* check/set platform and metadata limits/defaults */ if (super->orom && raiddisks > super->orom->dpa) { @@ -5261,17 +5923,17 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout, return 0; } - /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */ + /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */ 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 (chunk && (*chunk == 0 || *chunk == UnSet)) + if (*chunk == 0 || *chunk == UnSet) *chunk = imsm_default_chunk(super->orom); - if (super->orom && chunk && !imsm_orom_has_chunk(super->orom, *chunk)) { + if (super->orom && !imsm_orom_has_chunk(super->orom, *chunk)) { pr_vrb(": platform does not support a chunk size of: " "%d\n", *chunk); return 0; @@ -5287,15 +5949,24 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout, layout, level); return 0; } + + if (super->orom && (super->orom->attr & IMSM_OROM_ATTR_2TB) == 0 && + (calc_array_size(level, raiddisks, layout, *chunk, size) >> 32) > 0) { + pr_vrb(": platform does not support a volume size over 2TB\n"); + return 0; + } + return 1; } -/* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd +/* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd * FIX ME add ahci details */ static int validate_geometry_imsm_volume(struct supertype *st, int level, int layout, int raiddisks, int *chunk, - unsigned long long size, char *dev, + unsigned long long size, + unsigned long long data_offset, + char *dev, unsigned long long *freesize, int verbose) { @@ -5314,14 +5985,8 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, mpb = super->anchor; - if (mpb->num_raid_devs > 0 && mpb->num_disks != raiddisks) { - fprintf(stderr, Name ": the option-rom requires all " - "member disks to be a member of all volumes.\n"); - return 0; - } - - if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose)) { - fprintf(stderr, Name ": RAID gemetry validation failed. " + if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, size, verbose)) { + pr_err("RAID gemetry validation failed. " "Cannot proceed with the action(s).\n"); return 0; } @@ -5363,7 +6028,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, } if (dcnt < raiddisks) { if (verbose) - fprintf(stderr, Name ": imsm: Not enough " + pr_err("imsm: Not enough " "devices with space for this array " "(%d < %d)\n", dcnt, raiddisks); @@ -5384,7 +6049,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, } if (!dl) { if (verbose) - fprintf(stderr, Name ": %s is not in the " + pr_err("%s is not in the " "same imsm set\n", dev); return 0; } else if (super->orom && dl->index < 0 && mpb->num_raid_devs) { @@ -5393,9 +6058,14 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, * understand this configuration (all member disks must be * members of each array in the container). */ - fprintf(stderr, Name ": %s is a spare and a volume" + pr_err("%s is a spare and a volume" " is already defined for this container\n", dev); - fprintf(stderr, Name ": The option-rom requires all member" + pr_err("The option-rom requires all member" + " disks to be a member of all volumes\n"); + return 0; + } else if (super->orom && mpb->num_raid_devs > 0 && + mpb->num_disks != raiddisks) { + pr_err("The option-rom requires all member" " disks to be a member of all volumes\n"); return 0; } @@ -5418,13 +6088,13 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, dl->extent_cnt = i; } else { if (verbose) - fprintf(stderr, Name ": unable to determine free space for: %s\n", + pr_err("unable to determine free space for: %s\n", dev); return 0; } if (maxsize < size) { if (verbose) - fprintf(stderr, Name ": %s not enough space (%llu < %llu)\n", + pr_err("%s not enough space (%llu < %llu)\n", dev, maxsize, size); return 0; } @@ -5439,25 +6109,41 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, if (!check_env("IMSM_NO_PLATFORM") && mpb->num_raid_devs > 0 && size && size != maxsize) { - fprintf(stderr, Name ": attempting to create a second " + pr_err("attempting to create a second " "volume with size less then remaining space. " "Aborting...\n"); return 0; } if (maxsize < size || maxsize == 0) { - if (verbose) - fprintf(stderr, Name ": not enough space after merge (%llu < %llu)\n", - maxsize, size); + if (verbose) { + if (maxsize == 0) + pr_err("no free space" + " left on device. Aborting...\n"); + else + pr_err("not enough space" + " to create volume of given size" + " (%llu < %llu). Aborting...\n", + maxsize, size); + } return 0; } *freesize = maxsize; + if (super->orom) { + int count = count_volumes(super->hba->path, + super->orom->dpa, verbose); + if (super->orom->vphba <= count) { + pr_vrb(": platform does not support more than %d raid volumes.\n", + super->orom->vphba); + return 0; + } + } return 1; } -static int reserve_space(struct supertype *st, int raiddisks, +static int imsm_get_free_size(struct supertype *st, int raiddisks, unsigned long long size, int chunk, unsigned long long *freesize) { @@ -5509,7 +6195,7 @@ static int reserve_space(struct supertype *st, int raiddisks, (super->orom && used && used != raiddisks) || maxsize < minsize || maxsize == 0) { - fprintf(stderr, Name ": not enough devices with space to create array.\n"); + pr_err("not enough devices with space to create array.\n"); return 0; /* No enough free spaces large enough */ } @@ -5519,8 +6205,15 @@ static int reserve_space(struct supertype *st, int raiddisks, size /= 2 * chunk; size *= 2 * chunk; } + maxsize = size; + } + if (!check_env("IMSM_NO_PLATFORM") && + mpb->num_raid_devs > 0 && size && size != maxsize) { + pr_err("attempting to create a second " + "volume with size less then remaining space. " + "Aborting...\n"); + return 0; } - cnt = 0; for (dl = super->disks; dl; dl = dl->next) if (dl->e) @@ -5528,11 +6221,35 @@ static int reserve_space(struct supertype *st, int raiddisks, *freesize = size; + dprintf("imsm: imsm_get_free_size() returns : %llu\n", size); + 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 dl *dl; + int cnt; + int rv = 0; + + rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize); + if (rv) { + cnt = 0; + for (dl = super->disks; dl; dl = dl->next) + if (dl->e) + dl->raiddisk = cnt++; + rv = 1; + } + + return rv; +} + static int validate_geometry_imsm(struct supertype *st, int level, int layout, int raiddisks, int *chunk, unsigned long long size, + unsigned long long data_offset, char *dev, unsigned long long *freesize, int verbose) { @@ -5548,15 +6265,17 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, /* Must be a fresh device to add to a container */ return validate_geometry_imsm_container(st, level, layout, raiddisks, - chunk?*chunk:0, size, + *chunk, + size, data_offset, dev, freesize, verbose); } - + if (!dev) { if (st->sb) { + struct intel_super *super = st->sb; if (!validate_geometry_imsm_orom(st->sb, level, layout, - raiddisks, chunk, + raiddisks, chunk, size, verbose)) return 0; /* we are being asked to automatically layout a @@ -5567,9 +6286,22 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, * created. add_to_super and getinfo_super * detect when autolayout is in progress. */ + /* assuming that freesize is always given when array is + created */ + if (super->orom && freesize) { + int count; + count = count_volumes(super->hba->path, + super->orom->dpa, verbose); + if (super->orom->vphba <= count) { + pr_vrb(": platform does not support more" + " than %d raid volumes.\n", + super->orom->vphba); + return 0; + } + } if (freesize) return reserve_space(st, raiddisks, size, - chunk?*chunk:0, freesize); + *chunk, freesize); } return 1; } @@ -5577,6 +6309,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, /* creating in a given container */ return validate_geometry_imsm_volume(st, level, layout, raiddisks, chunk, size, + data_offset, dev, freesize, verbose); } @@ -5584,15 +6317,14 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, fd = open(dev, O_RDONLY|O_EXCL, 0); if (fd >= 0) { if (verbose) - fprintf(stderr, - Name ": Cannot create this array on device %s\n", - dev); + pr_err("Cannot create this array on device %s\n", + dev); close(fd); return 0; } if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) { if (verbose) - fprintf(stderr, Name ": Cannot open %s: %s\n", + pr_err("Cannot open %s: %s\n", dev, strerror(errno)); return 0; } @@ -5601,11 +6333,11 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, close(fd); if (cfd < 0) { if (verbose) - fprintf(stderr, Name ": Cannot use %s: It is busy\n", + pr_err("Cannot use %s: It is busy\n", dev); return 0; } - sra = sysfs_read(cfd, 0, GET_VERSION); + sra = sysfs_read(cfd, NULL, GET_VERSION); if (sra && sra->array.major_version == -1 && strcmp(sra->text_version, "imsm") == 0) is_member = 1; @@ -5616,20 +6348,20 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, */ struct intel_super *super; - if (load_super_imsm_all(st, cfd, (void **) &super, NULL) == 0) { + if (load_super_imsm_all(st, cfd, (void **) &super, NULL, NULL, 1) == 0) { st->sb = super; - st->container_dev = fd2devnum(cfd); + strcpy(st->container_devnm, fd2devnm(cfd)); close(cfd); return validate_geometry_imsm_volume(st, level, layout, raiddisks, chunk, - size, dev, + size, data_offset, dev, freesize, 1) ? 1 : -1; } } if (verbose) - fprintf(stderr, Name ": failed container membership check\n"); + pr_err("failed container membership check\n"); close(cfd); return 0; @@ -5676,20 +6408,17 @@ static int kill_subarray_imsm(struct supertype *st) if (i < current_vol) continue; sprintf(subarray, "%u", i); - if (is_subarray_active(subarray, st->devname)) { - fprintf(stderr, - Name ": deleting subarray-%d would change the UUID of active subarray-%d, aborting\n", - current_vol, i); + if (is_subarray_active(subarray, st->devnm)) { + pr_err("deleting subarray-%d would change the UUID of active subarray-%d, aborting\n", + current_vol, i); return 2; } } if (st->update_tail) { - struct imsm_update_kill_array *u = malloc(sizeof(*u)); + struct imsm_update_kill_array *u = xmalloc(sizeof(*u)); - if (!u) - return 2; u->type = update_kill_array; u->dev_idx = current_vol; append_metadata_update(st, u, sizeof(*u)); @@ -5735,9 +6464,8 @@ static int update_subarray_imsm(struct supertype *st, char *subarray, char *ep; int vol; - if (is_subarray_active(subarray, st->devname)) { - fprintf(stderr, - Name ": Unable to update name of active subarray\n"); + if (is_subarray_active(subarray, st->devnm)) { + pr_err("Unable to update name of active subarray\n"); return 2; } @@ -5749,10 +6477,8 @@ static int update_subarray_imsm(struct supertype *st, char *subarray, return 2; if (st->update_tail) { - struct imsm_update_rename_array *u = malloc(sizeof(*u)); + struct imsm_update_rename_array *u = xmalloc(sizeof(*u)); - if (!u) - return 2; u->type = update_rename_array; u->dev_idx = vol; snprintf((char *) u->name, MAX_RAID_SERIAL_LEN, "%s", name); @@ -5852,7 +6578,7 @@ static void update_recovery_start(struct intel_super *super, * IMSM_ORD_REBUILD, so assume they are missing and the * disk_ord_tbl was not correctly updated */ - dprintf("%s: failed to locate out-of-sync disk\n", __func__); + dprintf("failed to locate out-of-sync disk\n"); return; } @@ -5886,18 +6612,17 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra /* do not assemble arrays when not all attributes are supported */ if (imsm_check_attributes(mpb->attributes) == 0) { sb_errors = 1; - fprintf(stderr, Name ": Unsupported attributes in IMSM metadata." + pr_err("Unsupported attributes in IMSM metadata." "Arrays activation is blocked.\n"); } /* check for bad blocks */ if (imsm_bbm_log_size(super->anchor)) { - fprintf(stderr, Name ": BBM log found in IMSM metadata." - "Arrays activation is blocked.\n"); + pr_err("BBM log found in IMSM metadata." + "Arrays activation is blocked.\n"); sb_errors = 1; } - /* count spare devices, not used in maps */ for (d = super->disks; d; d = d->next) @@ -5928,7 +6653,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra */ if (dev->vol.migr_state && (migr_type(dev) == MIGR_STATE_CHANGE)) { - fprintf(stderr, Name ": cannot assemble volume '%.16s':" + pr_err("cannot assemble volume '%.16s':" " unsupported migration in progress\n", dev->volume); continue; @@ -5937,12 +6662,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra * OROM/EFI */ - this = malloc(sizeof(*this)); - if (!this) { - fprintf(stderr, Name ": failed to allocate %zu bytes\n", - sizeof(*this)); - break; - } + this = xmalloc(sizeof(*this)); super->current_vol = i; getinfo_super_imsm_volume(st, this, NULL); @@ -5954,9 +6674,9 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra get_imsm_raid_level(map), /* RAID level */ imsm_level_to_layout(get_imsm_raid_level(map)), map->num_members, /* raid disks */ - &chunk, + &chunk, join_u32(dev->size_low, dev->size_high), 1 /* verbose */)) { - fprintf(stderr, Name ": IMSM RAID geometry validation" + pr_err("IMSM RAID geometry validation" " failed. Array %s activation is blocked.\n", dev->volume); this->array.state |= @@ -5994,7 +6714,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra if (ord & IMSM_ORD_REBUILD) recovery_start = 0; - /* + /* * if we skip some disks the array will be assmebled degraded; * reset resync start to avoid a dirty-degraded * situation when performing the intial sync @@ -6006,21 +6726,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra if (skip) continue; - info_d = calloc(1, sizeof(*info_d)); - if (!info_d) { - fprintf(stderr, Name ": failed to allocate disk" - " for volume %.16s\n", dev->volume); - info_d = this->devs; - while (info_d) { - struct mdinfo *d = info_d->next; - - free(info_d); - info_d = d; - } - free(this); - this = rest; - break; - } + info_d = xcalloc(1, sizeof(*info_d)); info_d->next = this->devs; this->devs = info_d; @@ -6044,8 +6750,8 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra this->array.working_disks++; info_d->events = __le32_to_cpu(mpb->generation_num); - info_d->data_offset = __le32_to_cpu(map->pba_of_lba0); - info_d->component_size = __le32_to_cpu(map->blocks_per_member); + info_d->data_offset = pba_of_lba0(map); + info_d->component_size = blocks_per_member(map); } /* now that the disk list is up-to-date fixup recovery_start */ update_recovery_start(super, dev, this); @@ -6062,7 +6768,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra return rest; } - static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, int failed, int look_in_map) { @@ -6071,7 +6776,7 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, map = get_imsm_map(dev, look_in_map); if (!failed) - return map->map_state == IMSM_T_STATE_UNINITIALIZED ? + return map->map_state == IMSM_T_STATE_UNINITIALIZED ? IMSM_T_STATE_UNINITIALIZED : IMSM_T_STATE_NORMAL; switch (get_imsm_raid_level(map)) { @@ -6101,7 +6806,7 @@ static __u8 imsm_check_degraded(struct intel_super *super, struct imsm_dev *dev, struct imsm_disk *disk; /* reset the potential in-sync count on even-numbered - * slots. num_copies is always 2 for imsm raid10 + * slots. num_copies is always 2 for imsm raid10 */ if ((i & 1) == 0) insync = 2; @@ -6192,10 +6897,9 @@ static int imsm_open_new(struct supertype *c, struct active_array *a, { struct intel_super *super = c->sb; struct imsm_super *mpb = super->anchor; - + if (atoi(inst) >= mpb->num_raid_devs) { - fprintf(stderr, "%s: subarry index %d, out of range\n", - __func__, atoi(inst)); + pr_err("subarry index %d, out of range\n", atoi(inst)); return -ENODEV; } @@ -6292,6 +6996,12 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev) if (!super->missing) return; + /* When orom adds replacement for missing disk it does + * not remove entry of missing disk, but just updates map with + * new added disk. So it is not enough just to test if there is + * any missing disk, we have to look if there are any failed disks + * in map to stop migration */ + dprintf("imsm: mark missing\n"); /* end process for initialization and rebuild only */ @@ -6302,14 +7012,16 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev) failed = imsm_count_failed(super, dev, MAP_0); map_state = imsm_check_degraded(super, dev, failed, MAP_0); - end_migration(dev, super, map_state); + if (failed) + end_migration(dev, super, map_state); } for (dl = super->missing; dl; dl = dl->next) mark_missing(dev, &dl->disk, dl->index); 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; @@ -6328,8 +7040,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 = map->blocks_per_member * 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 */ @@ -6386,7 +7107,8 @@ 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++; } } @@ -6443,7 +7165,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent) used_disks = imsm_num_data_members(dev, MAP_0); if (used_disks > 0) { array_blocks = - map->blocks_per_member * + blocks_per_member(map) * used_disks; /* round array size down to closest MB */ @@ -6549,12 +7271,14 @@ static void imsm_set_disk(struct active_array *a, int n, int state) struct imsm_dev *dev = get_imsm_dev(super, inst); struct imsm_map *map = get_imsm_map(dev, MAP_0); struct imsm_disk *disk; + struct mdinfo *mdi; + int recovery_not_finished = 0; int failed; __u32 ord; __u8 map_state; if (n > map->num_members) - fprintf(stderr, "imsm: set_disk %d out of range 0..%d\n", + pr_err("imsm: set_disk %d out of range 0..%d\n", n, map->num_members - 1); if (n < 0) @@ -6588,7 +7312,22 @@ static void imsm_set_disk(struct active_array *a, int n, int state) case IMSM_T_STATE_NORMAL: /* transition to normal state */ dprintf("normal: "); if (is_rebuilding(dev)) { - dprintf("while rebuilding"); + dprintf_cont("while rebuilding"); + /* check if recovery is really finished */ + for (mdi = a->info.devs; mdi ; mdi = mdi->next) + if (mdi->recovery_start != MaxSector) { + recovery_not_finished = 1; + break; + } + if (recovery_not_finished) { + dprintf_cont("\n"); + dprintf("Rebuild has not finished yet, state not changed"); + if (a->last_checkpoint < mdi->recovery_start) { + a->last_checkpoint = mdi->recovery_start; + super->updates_pending++; + } + break; + } end_migration(dev, super, map_state); map = get_imsm_map(dev, MAP_0); map->failed_disk_num = ~0; @@ -6597,7 +7336,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state) break; } if (is_gen_migration(dev)) { - dprintf("while general migration"); + dprintf_cont("while general migration"); if (a->last_checkpoint >= a->info.component_size) end_migration(dev, super, map_state); else @@ -6609,26 +7348,26 @@ static void imsm_set_disk(struct active_array *a, int n, int state) } break; case IMSM_T_STATE_DEGRADED: /* transition to degraded state */ - dprintf("degraded: "); + dprintf_cont("degraded: "); if ((map->map_state != map_state) && !dev->vol.migr_state) { - dprintf("mark degraded"); + dprintf_cont("mark degraded"); map->map_state = map_state; super->updates_pending++; a->last_checkpoint = 0; break; } if (is_rebuilding(dev)) { - dprintf("while rebuilding."); + dprintf_cont("while rebuilding."); if (map->map_state != map_state) { - dprintf(" Map state change"); + dprintf_cont(" Map state change"); end_migration(dev, super, map_state); super->updates_pending++; } break; } if (is_gen_migration(dev)) { - dprintf("while general migration"); + dprintf_cont("while general migration"); if (a->last_checkpoint >= a->info.component_size) end_migration(dev, super, map_state); else { @@ -6639,22 +7378,22 @@ static void imsm_set_disk(struct active_array *a, int n, int state) break; } if (is_initializing(dev)) { - dprintf("while initialization."); + dprintf_cont("while initialization."); map->map_state = map_state; super->updates_pending++; break; } break; case IMSM_T_STATE_FAILED: /* transition to failed state */ - dprintf("failed: "); + dprintf_cont("failed: "); if (is_gen_migration(dev)) { - dprintf("while general migration"); + dprintf_cont("while general migration"); map->map_state = map_state; super->updates_pending++; break; } if (map->map_state != map_state) { - dprintf("mark failed"); + dprintf_cont("mark failed"); end_migration(dev, super, map_state); super->updates_pending++; a->last_checkpoint = 0; @@ -6662,10 +7401,9 @@ static void imsm_set_disk(struct active_array *a, int n, int state) } break; default: - dprintf("state %i\n", map_state); + dprintf_cont("state %i\n", map_state); } - dprintf("\n"); - + dprintf_cont("\n"); } static int store_imsm_mpb(int fd, struct imsm_super *mpb) @@ -6727,7 +7465,7 @@ static struct dl *imsm_readd(struct intel_super *super, int idx, struct active_a dl = NULL; if (dl) - dprintf("%s: found %x:%x\n", __func__, dl->major, dl->minor); + dprintf("found %x:%x\n", dl->major, dl->minor); return dl; } @@ -6810,9 +7548,9 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot, found = 0; j = 0; pos = 0; - array_start = __le32_to_cpu(map->pba_of_lba0); + array_start = pba_of_lba0(map); array_end = array_start + - __le32_to_cpu(map->blocks_per_member) - 1; + blocks_per_member(map) - 1; do { /* check that we can start at pba_of_lba0 with @@ -6843,7 +7581,6 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot, return dl; } - static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed) { struct imsm_dev *dev2; @@ -6987,12 +7724,9 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a, dl = imsm_add_spare(super, i, a, 1, rv); if (!dl) continue; - + /* found a usable disk with enough space */ - di = malloc(sizeof(*di)); - if (!di) - continue; - memset(di, 0, sizeof(*di)); + di = xcalloc(1, sizeof(*di)); /* dl->index will be -1 in the case we are activating a * pristine spare. imsm_process_update() will create a @@ -7012,7 +7746,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a, di->disk.minor = dl->minor; di->disk.state = 0; di->recovery_start = 0; - di->data_offset = __le32_to_cpu(map->pba_of_lba0); + di->data_offset = pba_of_lba0(map); di->component_size = a->info.component_size; di->container_member = inst; super->random = random32(); @@ -7030,24 +7764,9 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a, * Create a metadata_update record to update the * disk_ord_tbl for the array */ - mu = malloc(sizeof(*mu)); - if (mu) { - mu->buf = malloc(sizeof(struct imsm_update_activate_spare) * num_spares); - if (mu->buf == NULL) { - free(mu); - mu = NULL; - } - } - if (!mu) { - while (rv) { - struct mdinfo *n = rv->next; - - free(rv); - rv = n; - } - return NULL; - } - + mu = xmalloc(sizeof(*mu)); + mu->buf = xcalloc(num_spares, + sizeof(struct imsm_update_activate_spare)); mu->space = NULL; mu->space_list = NULL; mu->len = sizeof(struct imsm_update_activate_spare) * num_spares; @@ -7089,7 +7808,6 @@ static int disks_overlap(struct intel_super *super, int idx, struct imsm_update_ return 0; } - static struct dl *get_disk_super(struct intel_super *super, int major, int minor) { struct dl *dl = NULL; @@ -7114,8 +7832,7 @@ static int remove_disk_super(struct intel_super *super, int major, int minor) super->disks = dl->next; dl->next = NULL; __free_imsm_disk(dl); - dprintf("%s: removed %x:%x\n", - __func__, major, minor); + dprintf("removed %x:%x\n", major, minor); break; } prev = dl; @@ -7141,9 +7858,8 @@ static int add_remove_disk_update(struct intel_super *super) disk_cfg->next = super->disks; super->disks = disk_cfg; check_degraded = 1; - dprintf("%s: added %x:%x\n", - __func__, disk_cfg->major, - disk_cfg->minor); + dprintf("added %x:%x\n", + disk_cfg->major, disk_cfg->minor); } else if (disk_cfg->action == DISK_REMOVE) { dprintf("Disk remove action processed: %x.%x\n", disk_cfg->major, disk_cfg->minor); @@ -7167,7 +7883,6 @@ static int add_remove_disk_update(struct intel_super *super) return check_degraded; } - static int apply_reshape_migration_update(struct imsm_update_reshape_migration *u, struct intel_super *super, void ***space_list) @@ -7176,7 +7891,7 @@ static int apply_reshape_migration_update(struct imsm_update_reshape_migration * void **tofree = NULL; int ret_val = 0; - dprintf("apply_reshape_migration_update()\n"); + dprintf("(enter)\n"); if ((u->subdev < 0) || (u->subdev > 1)) { dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev); @@ -7275,7 +7990,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; } @@ -7290,8 +8005,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("(enter)\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("(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 intel_super *super, struct active_array *active_array) { struct imsm_super *mpb = super->anchor; @@ -7319,7 +8070,7 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u, break; if (!dl) { - fprintf(stderr, "error: imsm_activate_spare passed " + pr_err("error: imsm_activate_spare passed " "an unknown disk (index: %d)\n", u->dl->index); return 0; @@ -7420,7 +8171,7 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u, int ret_val = 0; unsigned int dev_id; - dprintf("imsm: apply_reshape_container_disks_update()\n"); + dprintf("(enter)\n"); /* enable spares to use in array */ for (i = 0; i < delta_disks; i++) { @@ -7489,7 +8240,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; @@ -7625,9 +8376,9 @@ static void imsm_process_update(struct supertype *st, * the arrays for general migration and convert selected spares * into active devices. * update_activate_spare - a spare device has replaced a failed - * device in an array, update the disk_ord_tbl. If this disk is - * present in all member arrays then also clear the SPARE_DISK - * flag + * device in an array, update the disk_ord_tbl. If this disk is + * present in all member arrays then also clear the SPARE_DISK + * flag * update_create_array * update_kill_array * update_rename_array @@ -7661,8 +8412,7 @@ static void imsm_process_update(struct supertype *st, struct imsm_update_general_migration_checkpoint *u = (void *)update->buf; - dprintf("imsm: process_update() " - "for update_general_migration_checkpoint called\n"); + dprintf("called for update_general_migration_checkpoint\n"); /* find device under general migration */ for (id = super->devlist ; id; id = id->next) { @@ -7697,8 +8447,14 @@ 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; + struct imsm_update_activate_spare *u = (void *) update->buf; if (apply_update_activate_spare(u, super, st->arrays)) super->updates_pending++; break; @@ -7725,21 +8481,20 @@ static void imsm_process_update(struct supertype *st, /* handle racing creates: first come first serve */ if (u->dev_idx < mpb->num_raid_devs) { - dprintf("%s: subarray %d already defined\n", - __func__, u->dev_idx); + dprintf("subarray %d already defined\n", u->dev_idx); goto create_error; } /* check update is next in sequence */ if (u->dev_idx != mpb->num_raid_devs) { - dprintf("%s: can not create array %d expected index %d\n", - __func__, u->dev_idx, mpb->num_raid_devs); + dprintf("can not create array %d expected index %d\n", + u->dev_idx, mpb->num_raid_devs); goto create_error; } new_map = get_imsm_map(&u->dev, MAP_0); - new_start = __le32_to_cpu(new_map->pba_of_lba0); - new_end = new_start + __le32_to_cpu(new_map->blocks_per_member); + new_start = pba_of_lba0(new_map); + new_end = new_start + blocks_per_member(new_map); inf = get_disk_info(u); /* handle activate_spare versus create race: @@ -7749,8 +8504,8 @@ static void imsm_process_update(struct supertype *st, for (i = 0; i < mpb->num_raid_devs; i++) { dev = get_imsm_dev(super, i); map = get_imsm_map(dev, MAP_0); - start = __le32_to_cpu(map->pba_of_lba0); - end = start + __le32_to_cpu(map->blocks_per_member); + start = pba_of_lba0(map); + end = start + blocks_per_member(map); if ((new_start >= start && new_start <= end) || (start >= new_start && start <= new_end)) /* overlap */; @@ -7758,14 +8513,14 @@ static void imsm_process_update(struct supertype *st, continue; if (disks_overlap(super, i, u)) { - dprintf("%s: arrays overlap\n", __func__); + dprintf("arrays overlap\n"); goto create_error; } } /* check that prepare update was successful */ if (!update->space) { - dprintf("%s: prepare update failed\n", __func__); + dprintf("prepare update failed\n"); goto create_error; } @@ -7777,7 +8532,7 @@ static void imsm_process_update(struct supertype *st, for (i = 0; i < new_map->num_members; i++) { dl = serial_to_dl(inf[i].serial, super); if (!dl) { - dprintf("%s: disk disappeared\n", __func__); + dprintf("disk disappeared\n"); goto create_error; } } @@ -7883,7 +8638,7 @@ static void imsm_process_update(struct supertype *st, } case update_add_remove_disk: { /* we may be able to repair some arrays if disks are - * being added, check teh status of add_remove_disk + * being added, check the status of add_remove_disk * if discs has been added. */ if (add_remove_disk_update(super)) { @@ -7896,15 +8651,15 @@ static void imsm_process_update(struct supertype *st, break; } default: - fprintf(stderr, "error: unsuported process update type:" + pr_err("error: unsuported process update type:" "(type: %d)\n", type); } } static struct mdinfo *get_spares_for_grow(struct supertype *st); -static void imsm_prepare_update(struct supertype *st, - struct metadata_update *update) +static int imsm_prepare_update(struct supertype *st, + struct metadata_update *update) { /** * Allocate space to hold new disk entries, raid-device entries or a new @@ -7913,19 +8668,27 @@ static void imsm_prepare_update(struct supertype *st, * integrated by the monitor thread without worrying about live pointers * in the manager thread. */ - enum imsm_update_type type = *(enum imsm_update_type *) update->buf; + enum imsm_update_type type; struct intel_super *super = st->sb; struct imsm_super *mpb = super->anchor; size_t buf_len; size_t len = 0; + if (update->len < (int)sizeof(type)) + return 0; + + type = *(enum imsm_update_type *) update->buf; + switch (type) { case update_general_migration_checkpoint: - dprintf("imsm: prepare_update() " - "for update_general_migration_checkpoint called\n"); + if (update->len < (int)sizeof(struct imsm_update_general_migration_checkpoint)) + return 0; + dprintf("called for update_general_migration_checkpoint\n"); break; case update_takeover: { struct imsm_update_takeover *u = (void *)update->buf; + if (update->len < (int)sizeof(*u)) + return 0; if (u->direction == R0_TO_R10) { void **tail = (void **)&update->space_list; struct imsm_dev *dev = get_imsm_dev(super, u->subarray); @@ -7933,15 +8696,10 @@ static void imsm_prepare_update(struct supertype *st, int num_members = map->num_members; void *space; int size, i; - int err = 0; /* allocate memory for added disks */ for (i = 0; i < num_members; i++) { size = sizeof(struct dl); - space = malloc(size); - if (!space) { - err++; - break; - } + space = xmalloc(size); *tail = space; tail = space; *tail = NULL; @@ -7949,24 +8707,11 @@ static void imsm_prepare_update(struct supertype *st, /* allocate memory for new device */ size = sizeof_imsm_dev(super->devlist->dev, 0) + (num_members * sizeof(__u32)); - space = malloc(size); - if (!space) - err++; - else { - *tail = space; - tail = space; - *tail = NULL; - } - if (!err) { - len = disks_to_mpb_size(num_members * 2); - } else { - /* if allocation didn't success, free buffer */ - while (update->space_list) { - void **sp = update->space_list; - update->space_list = *sp; - free(sp); - } - } + space = xmalloc(size); + *tail = space; + tail = space; + *tail = NULL; + len = disks_to_mpb_size(num_members * 2); } break; @@ -7984,7 +8729,10 @@ static void imsm_prepare_update(struct supertype *st, struct intel_dev *dl; void **space_tail = (void**)&update->space_list; - dprintf("imsm: imsm_prepare_update() for update_reshape\n"); + if (update->len < (int)sizeof(*u)) + return 0; + + dprintf("for update_reshape\n"); for (dl = super->devlist; dl; dl = dl->next) { int size = sizeof_imsm_dev(dl->dev, 1); @@ -7992,9 +8740,7 @@ static void imsm_prepare_update(struct supertype *st, 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; + s = xmalloc(size); *space_tail = s; space_tail = s; *space_tail = NULL; @@ -8018,7 +8764,10 @@ static void imsm_prepare_update(struct supertype *st, void *s; int current_level = -1; - dprintf("imsm: imsm_prepare_update() for update_reshape\n"); + if (update->len < (int)sizeof(*u)) + return 0; + + dprintf("for update_reshape\n"); /* add space for bigger array in update */ @@ -8028,9 +8777,7 @@ static void imsm_prepare_update(struct supertype *st, 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; + s = xmalloc(size); *space_tail = s; space_tail = s; *space_tail = NULL; @@ -8043,12 +8790,7 @@ static void imsm_prepare_update(struct supertype *st, /* add space for disk in update */ size = sizeof(struct dl); - s = malloc(size); - if (!s) { - free(update->space_list); - update->space_list = NULL; - break; - } + s = xmalloc(size); *space_tail = s; space_tail = s; *space_tail = NULL; @@ -8091,6 +8833,16 @@ static void imsm_prepare_update(struct supertype *st, dprintf("New anchor length is %llu\n", (unsigned long long)len); break; } + case update_size_change: { + if (update->len < (int)sizeof(struct imsm_update_size_change)) + return 0; + break; + } + case update_activate_spare: { + if (update->len < (int)sizeof(struct imsm_update_activate_spare)) + return 0; + break; + } case update_create_array: { struct imsm_update_create_array *u = (void *) update->buf; struct intel_dev *dv; @@ -8101,19 +8853,15 @@ static void imsm_prepare_update(struct supertype *st, int i; int activate = 0; + if (update->len < (int)sizeof(*u)) + return 0; + inf = get_disk_info(u); len = sizeof_imsm_dev(dev, 1); /* allocate a new super->devlist entry */ - dv = malloc(sizeof(*dv)); - if (dv) { - dv->dev = malloc(len); - if (dv->dev) - update->space = dv; - else { - free(dv); - update->space = NULL; - } - } + dv = xmalloc(sizeof(*dv)); + dv->dev = xmalloc(len); + update->space = dv; /* count how many spares will be converted to members */ for (i = 0; i < map->num_members; i++) { @@ -8129,9 +8877,22 @@ static void imsm_prepare_update(struct supertype *st, } len += activate * sizeof(struct imsm_disk); break; - default: + } + case update_kill_array: { + if (update->len < (int)sizeof(struct imsm_update_kill_array)) + return 0; + break; + } + case update_rename_array: { + if (update->len < (int)sizeof(struct imsm_update_rename_array)) + return 0; break; } + case update_add_remove_disk: + /* no update->len needed */ + break; + default: + return 0; } /* check if we need a larger metadata buffer */ @@ -8155,6 +8916,7 @@ static void imsm_prepare_update(struct supertype *st, else super->next_buf = NULL; } + return 1; } /* must be called while manager is quiesced */ @@ -8167,8 +8929,7 @@ static void imsm_delete(struct intel_super *super, struct dl **dlp, unsigned ind int i, j, num_members; __u32 ord; - dprintf("%s: deleting device[%d] from imsm_super\n", - __func__, index); + dprintf("deleting device[%d] from imsm_super\n", index); /* shift all indexes down one */ for (iter = super->disks; iter; iter = iter->next) @@ -8230,6 +8991,7 @@ static int imsm_get_allowed_degradation(int level, int raid_disks, struct imsm_dev *dev) { switch (level) { + case 1: case 10:{ int ret_val = 0; struct imsm_map *map; @@ -8277,7 +9039,6 @@ static int imsm_get_allowed_degradation(int level, int raid_disks, } } - /******************************************************************************* * Function: open_backup_targets * Description: Function opens file descriptors for all devices given in @@ -8318,7 +9079,7 @@ int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds, sd->disk.minor, 1); raid_fds[sd->disk.raid_disk] = dev_open(dn, O_RDWR); if (raid_fds[sd->disk.raid_disk] < 0) { - fprintf(stderr, "cannot open component\n"); + pr_err("cannot open component\n"); continue; } opened++; @@ -8329,13 +9090,90 @@ int open_backup_targets(struct mdinfo *info, int raid_disks, int *raid_fds, imsm_get_allowed_degradation(info->new_level, raid_disks, super, dev)) { - fprintf(stderr, "Not enough disks can be opened.\n"); + pr_err("Not enough disks can be opened.\n"); close_targets(raid_fds, raid_disks); return -2; } return 0; } +/******************************************************************************* + * Function: validate_container_imsm + * Description: This routine validates container after assemble, + * eg. if devices in container are under the same controller. + * + * Parameters: + * info : linked list with info about devices used in array + * Returns: + * 1 : HBA mismatch + * 0 : Success + ******************************************************************************/ +int validate_container_imsm(struct mdinfo *info) +{ + if (check_env("IMSM_NO_PLATFORM")) + return 0; + + struct sys_dev *idev; + struct sys_dev *hba = NULL; + struct sys_dev *intel_devices = find_intel_devices(); + char *dev_path = devt_to_devpath(makedev(info->disk.major, + info->disk.minor)); + + for (idev = intel_devices; idev; idev = idev->next) { + if (dev_path && strstr(dev_path, idev->path)) { + hba = idev; + break; + } + } + if (dev_path) + free(dev_path); + + if (!hba) { + pr_err("WARNING - Cannot detect HBA for device %s!\n", + devid2kname(makedev(info->disk.major, info->disk.minor))); + return 1; + } + + const struct imsm_orom *orom = get_orom_by_device_id(hba->dev_id); + struct mdinfo *dev; + + for (dev = info->next; dev; dev = dev->next) { + dev_path = devt_to_devpath(makedev(dev->disk.major, dev->disk.minor)); + + struct sys_dev *hba2 = NULL; + for (idev = intel_devices; idev; idev = idev->next) { + if (dev_path && strstr(dev_path, idev->path)) { + hba2 = idev; + break; + } + } + if (dev_path) + free(dev_path); + + const struct imsm_orom *orom2 = hba2 == NULL ? NULL : + get_orom_by_device_id(hba2->dev_id); + + if (hba2 && hba->type != hba2->type) { + pr_err("WARNING - HBAs of devices do not match %s != %s\n", + get_sys_dev_type(hba->type), get_sys_dev_type(hba2->type)); + return 1; + } + + if (orom != orom2) { + pr_err("WARNING - IMSM container assembled with disks under different HBAs!\n" + " This operation is not supported and can lead to data loss.\n"); + return 1; + } + + if (!orom) { + pr_err("WARNING - IMSM container assembled with disks under HBAs without IMSM platform support!\n" + " This operation is not supported and can lead to data loss.\n"); + return 1; + } + } + + return 0; +} #ifndef MDASSEMBLE /******************************************************************************* * Function: init_migr_record_imsm @@ -8371,7 +9209,8 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev, migr_rec->dest_depth_per_unit = GEN_MIGR_AREA_SIZE / max(map_dest->blocks_per_strip, map_src->blocks_per_strip); - migr_rec->dest_depth_per_unit *= map_dest->blocks_per_strip; + migr_rec->dest_depth_per_unit *= + max(map_dest->blocks_per_strip, map_src->blocks_per_strip); new_data_disks = imsm_num_data_members(dev, MAP_0); migr_rec->blocks_per_unit = __cpu_to_le32(migr_rec->dest_depth_per_unit * new_data_disks); @@ -8388,7 +9227,6 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev, migr_rec->post_migr_vol_cap = dev->size_low; migr_rec->post_migr_vol_cap_hi = dev->size_high; - /* Find the smallest dev */ for (sd = info->devs ; sd ; sd = sd->next) { sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor); @@ -8443,16 +9281,12 @@ int save_backup_imsm(struct supertype *st, unsigned long long start; int data_disks = imsm_num_data_members(dev, MAP_0); - targets = malloc(new_disks * sizeof(int)); - if (!targets) - goto abort; + targets = xmalloc(new_disks * sizeof(int)); for (i = 0; i < new_disks; i++) targets[i] = -1; - target_offsets = malloc(new_disks * sizeof(unsigned long long)); - if (!target_offsets) - goto abort; + target_offsets = xcalloc(new_disks, sizeof(unsigned long long)); start = info->reshape_progress * 512; for (i = 0; i < new_disks; i++) { @@ -8483,7 +9317,7 @@ int save_backup_imsm(struct supertype *st, start, length, buf) != 0) { - fprintf(stderr, Name ": Error restoring stripes\n"); + pr_err("Error restoring stripes\n"); goto abort; } @@ -8609,18 +9443,15 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info) write_offset = ((unsigned long long) __le32_to_cpu(migr_rec->dest_1st_member_lba) + - __le32_to_cpu(map_dest->pba_of_lba0)) * 512; + pba_of_lba0(map_dest)) * 512; unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512; if (posix_memalign((void **)&buf, 512, unit_len) != 0) goto abort; - targets = malloc(new_disks * sizeof(int)); - if (!targets) - goto abort; + targets = xcalloc(new_disks, sizeof(int)); if (open_backup_targets(info, new_disks, targets, super, id->dev)) { - fprintf(stderr, - Name ": Cannot open some devices belonging to array.\n"); + pr_err("Cannot open some devices belonging to array.\n"); goto abort; } @@ -8630,30 +9461,26 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info) continue; } if (lseek64(targets[i], read_offset, SEEK_SET) < 0) { - fprintf(stderr, - Name ": Cannot seek to block: %s\n", - strerror(errno)); + pr_err("Cannot seek to block: %s\n", + strerror(errno)); skipped_disks++; continue; } if ((unsigned)read(targets[i], buf, unit_len) != unit_len) { - fprintf(stderr, - Name ": Cannot read copy area block: %s\n", - strerror(errno)); + pr_err("Cannot read copy area block: %s\n", + strerror(errno)); skipped_disks++; continue; } if (lseek64(targets[i], write_offset, SEEK_SET) < 0) { - fprintf(stderr, - Name ": Cannot seek to block: %s\n", - strerror(errno)); + pr_err("Cannot seek to block: %s\n", + strerror(errno)); skipped_disks++; continue; } if ((unsigned)write(targets[i], buf, unit_len) != unit_len) { - fprintf(stderr, - Name ": Cannot restore block: %s\n", - strerror(errno)); + pr_err("Cannot restore block: %s\n", + strerror(errno)); skipped_disks++; continue; } @@ -8663,9 +9490,8 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info) new_disks, super, id->dev)) { - fprintf(stderr, - Name ": Cannot restore data from backup." - " Too many failed disks\n"); + pr_err("Cannot restore data from backup." + " Too many failed disks\n"); goto abort; } @@ -8696,7 +9522,7 @@ static const char *imsm_get_disk_controller_domain(const char *path) char *drv=NULL; struct stat st; - strncpy(disk_path, disk_by_path, PATH_MAX - 1); + strcpy(disk_path, disk_by_path); strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1); if (stat(disk_path, &st) == 0) { struct sys_dev* hba; @@ -8710,35 +9536,35 @@ static const char *imsm_get_disk_controller_domain(const char *path) drv = "isci"; else if (hba && hba->type == SYS_DEV_SATA) drv = "ahci"; - else + else drv = "unknown"; dprintf("path: %s hba: %s attached: %s\n", path, (hba) ? hba->path : "NULL", drv); free(path); - if (hba) - free_sys_dev(&hba); } return drv; } -static int imsm_find_array_minor_by_subdev(int subdev, int container, int *minor) +static char *imsm_find_array_devnm_by_subdev(int subdev, char *container) { + static char devnm[32]; char subdev_name[20]; struct mdstat_ent *mdstat; sprintf(subdev_name, "%d", subdev); mdstat = mdstat_by_subdev(subdev_name, container); if (!mdstat) - return -1; + return NULL; - *minor = mdstat->devnum; + strcpy(devnm, mdstat->devnm); free_mdstat(mdstat); - return 0; + return devnm; } static int imsm_reshape_is_allowed_on_container(struct supertype *st, struct geo_params *geo, - int *old_raid_disks) + int *old_raid_disks, + int direction) { /* currently we only support increasing the number of devices * for a container. This increases the number of device for each @@ -8749,10 +9575,9 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st, int devices_that_can_grow = 0; dprintf("imsm: imsm_reshape_is_allowed_on_container(ENTER): " - "st->devnum = (%i)\n", - st->devnum); + "st->devnm = (%s)\n", st->devnm); - if (geo->size != -1 || + if (geo->size > 0 || geo->level != UnSet || geo->layout != UnSet || geo->chunksize != 0 || @@ -8762,10 +9587,15 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st, return ret_val; } + if (direction == ROLLBACK_METADATA_CHANGES) { + dprintf("imsm: Metadata changes rollback is not supported for " + "container operation.\n"); + return ret_val; + } + info = container_content_imsm(st, NULL); for (member = info; member; member = member->next) { - int result; - int minor; + char *result; dprintf("imsm: checking device_num: %i\n", member->container_member); @@ -8822,10 +9652,9 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st, * so they need to be assembled. We have already * checked that no recovery etc is happening. */ - result = imsm_find_array_minor_by_subdev(member->container_member, - st->container_dev, - &minor); - if (result < 0) { + result = imsm_find_array_devnm_by_subdev(member->container_member, + st->container_devnm); + if (result == NULL) { dprintf("imsm: cannot find array\n"); break; } @@ -8836,19 +9665,19 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st, ret_val = 1; if (ret_val) - dprintf("\tContainer operation allowed\n"); + dprintf("Container operation allowed\n"); else - dprintf("\tError: %i\n", ret_val); + dprintf("Error: %i\n", ret_val); return ret_val; } /* Function: get_spares_for_grow * Description: Allocates memory and creates list of spare devices - * avaliable in container. Checks if spare drive size is acceptable. + * avaliable in container. Checks if spare drive size is acceptable. * Parameters: Pointer to the supertype structure * Returns: Pointer to the list of spare devices (mdinfo structure) on success, - * NULL if fail + * NULL if fail */ static struct mdinfo *get_spares_for_grow(struct supertype *st) { @@ -8876,8 +9705,7 @@ static int imsm_create_metadata_update_for_reshape( int delta_disks = 0; struct mdinfo *dev; - dprintf("imsm_update_metadata_for_reshape(enter) raid_disks = %i\n", - geo->raid_disks); + dprintf("(enter) raid_disks = %i\n", geo->raid_disks); delta_disks = geo->raid_disks - old_raid_disks; @@ -8887,12 +9715,7 @@ static int imsm_create_metadata_update_for_reshape( /* now add space for spare disks that we need to add. */ update_memory_size += sizeof(u->new_disks[0]) * (delta_disks - 1); - u = calloc(1, update_memory_size); - if (u == NULL) { - dprintf("error: " - "cannot get memory for imsm_update_reshape update\n"); - return 0; - } + u = xcalloc(1, update_memory_size); u->type = update_reshape_container_disks; u->old_raid_disks = old_raid_disks; u->new_raid_disks = geo->raid_disks; @@ -8903,7 +9726,7 @@ static int imsm_create_metadata_update_for_reshape( if (spares == NULL || delta_disks > spares->array.spare_disks) { - fprintf(stderr, Name ": imsm: ERROR: Cannot get spare devices " + pr_err("imsm: ERROR: Cannot get spare devices " "for %s.\n", geo->dev_name); i = -1; goto abort; @@ -8936,16 +9759,46 @@ abort: dprintf("imsm: reshape update preparation :"); if (i == delta_disks) { - dprintf(" OK\n"); + dprintf_cont(" OK\n"); *updatep = u; return update_memory_size; } free(u); - dprintf(" Error\n"); + dprintf_cont(" Error\n"); 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("(enter) New size = %llu\n", geo->size); + + /* size of all update data without anchor */ + update_memory_size = sizeof(struct imsm_update_size_change); + + u = xcalloc(1, update_memory_size); + 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. @@ -8962,18 +9815,12 @@ static int imsm_create_metadata_update_for_migration( struct imsm_dev *dev; int previous_level = -1; - dprintf("imsm_create_metadata_update_for_migration(enter)" - " New Level = %i\n", geo->level); + dprintf("(enter) New Level = %i\n", geo->level); /* size of all update data without anchor */ update_memory_size = sizeof(struct imsm_update_reshape_migration); - u = calloc(1, update_memory_size); - if (u == NULL) { - dprintf("error: cannot get memory for " - "imsm_create_metadata_update_for_migration\n"); - return 0; - } + u = xcalloc(1, update_memory_size); u->type = update_reshape_migration; u->subdev = super->current_vol; u->new_level = geo->level; @@ -9031,8 +9878,8 @@ static void imsm_update_metadata_locally(struct supertype *st, mu.space = NULL; mu.space_list = NULL; mu.next = NULL; - imsm_prepare_update(st, &mu); - imsm_process_update(st, &mu); + if (imsm_prepare_update(st, &mu)) + imsm_process_update(st, &mu); while (mu.space_list) { void **space = mu.space_list; @@ -9044,12 +9891,14 @@ static void imsm_update_metadata_locally(struct supertype *st, /*************************************************************************** * Function: imsm_analyze_change * Description: Function analyze change for single volume -* and validate if transition is supported -* Parameters: Geometry parameters, supertype structure +* and validate if transition is supported +* Parameters: Geometry parameters, supertype structure, +* metadata change direction (apply/rollback) * Returns: Operation type code on success, -1 if fail ****************************************************************************/ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, - struct geo_params *geo) + struct geo_params *geo, + int direction) { struct mdinfo info; int change = -1; @@ -9059,6 +9908,13 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, int devNumChange = 0; /* imsm compatible layout value for array geometry verification */ int imsm_layout = -1; + int data_disks; + struct imsm_dev *dev; + struct intel_super *super; + unsigned long long current_size; + unsigned long long free_size; + unsigned long long max_size; + int rv; getinfo_super_imsm_volume(st, &info, NULL); if ((geo->level != info.array.level) && @@ -9069,10 +9925,9 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, if (geo->level == 5) { change = CH_MIGRATION; if (geo->layout != ALGORITHM_LEFT_ASYMMETRIC) { - fprintf(stderr, - Name " Error. Requested Layout " - "not supported (left-asymmetric layout " - "is supported only)!\n"); + pr_err("Error. Requested Layout " + "not supported (left-asymmetric layout " + "is supported only)!\n"); change = -1; goto analyse_change_exit; } @@ -9097,10 +9952,9 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, break; } if (change == -1) { - fprintf(stderr, - Name " Error. Level Migration from %d to %d " - "not supported!\n", - info.array.level, geo->level); + pr_err("Error. Level Migration from %d to %d " + "not supported!\n", + info.array.level, geo->level); goto analyse_change_exit; } } else @@ -9120,10 +9974,9 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, geo->layout = 0; geo->level = 5; } else { - fprintf(stderr, - Name " Error. Layout Migration from %d to %d " - "not supported!\n", - info.array.layout, geo->layout); + pr_err("Error. Layout Migration from %d to %d " + "not supported!\n", + info.array.layout, geo->layout); change = -1; goto analyse_change_exit; } @@ -9140,12 +9993,108 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, geo->chunksize = info.array.chunk_size; chunk = geo->chunksize / 1024; + + super = st->sb; + dev = get_imsm_dev(super, super->current_vol); + data_disks = imsm_num_data_members(dev , MAP_0); + /* compute current size per disk member + */ + current_size = info.custom_array_size / data_disks; + + if ((geo->size > 0) && (geo->size != MAX_SIZE)) { + /* align component size + */ + geo->size = imsm_component_size_aligment_check( + get_imsm_raid_level(dev->vol.map), + chunk * 1024, + geo->size * 2); + if (geo->size == 0) { + pr_err("Error. Size expansion is " \ + "supported only (current size is %llu, " \ + "requested size /rounded/ is 0).\n", + current_size); + goto analyse_change_exit; + } + } + + if ((current_size != geo->size) && (geo->size > 0)) { + if (change != -1) { + pr_err("Error. Size change should be the only " + "one at a time.\n"); + change = -1; + goto analyse_change_exit; + } + if ((super->current_vol + 1) != super->anchor->num_raid_devs) { + pr_err("Error. The last volume in container " + "can be expanded only (%i/%s).\n", + super->current_vol, st->devnm); + goto analyse_change_exit; + } + /* check the maximum available size + */ + rv = imsm_get_free_size(st, dev->vol.map->num_members, + 0, chunk, &free_size); + if (rv == 0) + /* Cannot find maximum available space + */ + max_size = 0; + else { + max_size = free_size + current_size; + /* align component size + */ + max_size = imsm_component_size_aligment_check( + get_imsm_raid_level(dev->vol.map), + chunk * 1024, + max_size); + } + if (geo->size == MAX_SIZE) { + /* requested size change to the maximum available size + */ + if (max_size == 0) { + pr_err("Error. Cannot find " + "maximum available space.\n"); + change = -1; + goto analyse_change_exit; + } else + geo->size = max_size; + } + + if ((direction == ROLLBACK_METADATA_CHANGES)) { + /* accept size for rollback only + */ + } else { + /* round size due to metadata compatibility + */ + geo->size = (geo->size >> SECT_PER_MB_SHIFT) + << SECT_PER_MB_SHIFT; + dprintf("Prepare update for size change to %llu\n", + geo->size ); + if (current_size >= geo->size) { + pr_err("Error. Size expansion is " + "supported only (current size is %llu, " + "requested size /rounded/ is %llu).\n", + current_size, geo->size); + goto analyse_change_exit; + } + if (max_size && geo->size > max_size) { + pr_err("Error. Requested size is larger " + "than maximum available size (maximum " + "available size is %llu, " + "requested size /rounded/ is %llu).\n", + max_size, geo->size); + goto analyse_change_exit; + } + } + geo->size *= data_disks; + geo->raid_disks = dev->vol.map->num_members; + change = CH_ARRAY_SIZE; + } if (!validate_geometry_imsm(st, geo->level, imsm_layout, geo->raid_disks + devNumChange, &chunk, - geo->size, + geo->size, INVALID_SECTORS, 0, 0, 1)) change = -1; @@ -9154,17 +10103,21 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, struct imsm_super *mpb = super->anchor; if (mpb->num_raid_devs > 1) { - fprintf(stderr, - Name " Error. Cannot perform operation on %s" - "- for this operation it MUST be single " - "array in container\n", - geo->dev_name); + pr_err("Error. Cannot perform operation on %s" + "- for this operation it MUST be single " + "array in container\n", + geo->dev_name); change = -1; } } analyse_change_exit: - + if ((direction == ROLLBACK_METADATA_CHANGES) && + ((change == CH_MIGRATION) || (change == CH_TAKEOVER))) { + dprintf("imsm: Metadata changes rollback is not supported for " + "migration and takeover operations.\n"); + change = -1; + } return change; } @@ -9173,9 +10126,7 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo) struct intel_super *super = st->sb; struct imsm_update_takeover *u; - u = malloc(sizeof(struct imsm_update_takeover)); - if (u == NULL) - return 1; + u = xmalloc(sizeof(struct imsm_update_takeover)); u->type = update_takeover; u->subarray = super->current_vol; @@ -9201,20 +10152,21 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo) return 0; } -static int imsm_reshape_super(struct supertype *st, long long size, int level, +static int imsm_reshape_super(struct supertype *st, unsigned long long size, + int level, int layout, int chunksize, int raid_disks, int delta_disks, char *backup, char *dev, - int verbose) + int direction, int verbose) { int ret_val = 1; struct geo_params geo; - dprintf("imsm: reshape_super called.\n"); + dprintf("(enter)\n"); memset(&geo, 0, sizeof(struct geo_params)); geo.dev_name = dev; - geo.dev_id = st->devnum; + strcpy(geo.devnm, st->devnm); geo.size = size; geo.level = level; geo.layout = layout; @@ -9223,19 +10175,19 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level, 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); + dprintf("for level : %i\n", geo.level); + dprintf("for raid_disks : %i\n", geo.raid_disks); if (experimental() == 0) return ret_val; - if (st->container_dev == st->devnum) { + if (strcmp(st->container_devnm, st->devnm) == 0) { /* On container level we can only increase number of devices. */ dprintf("imsm: info: Container operation\n"); int old_raid_disks = 0; if (imsm_reshape_is_allowed_on_container( - st, &geo, &old_raid_disks)) { + st, &geo, &old_raid_disks, direction)) { struct imsm_update_reshape *u = NULL; int len; @@ -9257,7 +10209,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level, free(u); } else { - fprintf(stderr, Name ": (imsm) Operation " + pr_err("(imsm) Operation " "is not allowed on this container\n"); } } else { @@ -9268,23 +10220,24 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level, */ struct intel_super *super = st->sb; struct intel_dev *dev = super->devlist; - int change, devnum; + int change; dprintf("imsm: info: Volume operation\n"); /* find requested device */ while (dev) { - if (imsm_find_array_minor_by_subdev( - dev->index, st->container_dev, &devnum) == 0 - && devnum == geo.dev_id) + char *devnm = + imsm_find_array_devnm_by_subdev( + dev->index, st->container_devnm); + if (devnm && strcmp(devnm, geo.devnm) == 0) break; dev = dev->next; } if (dev == NULL) { - fprintf(stderr, Name " Cannot find %s (%i) subarray\n", - geo.dev_name, geo.dev_id); + pr_err("Cannot find %s (%s) subarray\n", + geo.dev_name, geo.devnm); goto exit_imsm_reshape_super; } super->current_vol = dev->index; - change = imsm_analyze_change(st, &geo); + change = imsm_analyze_change(st, &geo, direction); switch (change) { case CH_TAKEOVER: ret_val = imsm_takeover(st, &geo); @@ -9309,6 +10262,26 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level, free(u); } break; + case CH_ARRAY_SIZE: { + 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: ret_val = 1; } @@ -9333,37 +10306,33 @@ exit_imsm_reshape_super: ******************************************************************************/ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata) { - int fd = sysfs_get_fd(sra, NULL, "reshape_position"); + int fd = sysfs_get_fd(sra, NULL, "sync_completed"); unsigned long long completed; /* to_complete : new sync_max position */ unsigned long long to_complete = sra->reshape_progress; unsigned long long position_to_set = to_complete / ndata; if (fd < 0) { - dprintf("imsm: wait_for_reshape_imsm() " - "cannot open reshape_position\n"); + dprintf("cannot open reshape_position\n"); return 1; } if (sysfs_fd_get_ll(fd, &completed) < 0) { - dprintf("imsm: wait_for_reshape_imsm() " - "cannot read reshape_position (no reshape in progres)\n"); + dprintf("cannot read reshape_position (no reshape in progres)\n"); close(fd); return 0; } - if (completed > to_complete) { - dprintf("imsm: wait_for_reshape_imsm() " - "wrong next position to set %llu (%llu)\n", - to_complete, completed); + if (completed > position_to_set) { + dprintf("wrong next position to set %llu (%llu)\n", + to_complete, position_to_set); close(fd); return -1; } dprintf("Position set: %llu\n", position_to_set); if (sysfs_set_num(sra, NULL, "sync_max", position_to_set) != 0) { - dprintf("imsm: wait_for_reshape_imsm() " - "cannot set reshape position to %llu\n", + dprintf("cannot set reshape position to %llu\n", position_to_set); close(fd); return -1; @@ -9371,21 +10340,17 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata) do { char action[20]; - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - select(fd+1, &rfds, NULL, NULL, NULL); + sysfs_wait(fd, NULL); if (sysfs_get_str(sra, NULL, "sync_action", action, 20) > 0 && strncmp(action, "reshape", 7) != 0) break; if (sysfs_fd_get_ll(fd, &completed) < 0) { - dprintf("imsm: wait_for_reshape_imsm() " - "cannot read reshape_position (in loop)\n"); + dprintf("cannot read reshape_position (in loop)\n"); close(fd); return 1; } - } while (completed < to_complete); + } while (completed < position_to_set); close(fd); return 0; @@ -9406,8 +10371,10 @@ int check_degradation_change(struct mdinfo *info, int degraded) { unsigned long long new_degraded; - sysfs_get_ll(info, NULL, "degraded", &new_degraded); - if (new_degraded != (unsigned long long)degraded) { + int rv; + + rv = sysfs_get_ll(info, NULL, "degraded", &new_degraded); + if ((rv == -1) || (new_degraded != (unsigned long long)degraded)) { /* check each device to ensure it is still working */ struct mdinfo *sd; new_degraded = 0; @@ -9497,7 +10464,7 @@ static int imsm_manage_reshape( } /* Only one volume can migrate at the same time */ if (migr_vol_qan != 1) { - fprintf(stderr, Name " : %s", migr_vol_qan ? + pr_err(": %s", migr_vol_qan ? "Number of migrating volumes greater than 1\n" : "There is no volume during migrationg\n"); goto abort; @@ -9524,6 +10491,18 @@ static int imsm_manage_reshape( "are present in copy area.\n"); goto abort; } + /* Save checkpoint to update migration record for current + * reshape position (in md). It can be farther than current + * reshape position in metadata. + */ + if (save_checkpoint_imsm(st, sra, UNIT_SRC_NORMAL) == 1) { + /* ignore error == 2, this can mean end of reshape here + */ + dprintf("imsm: Cannot write checkpoint to " + "migration record (UNIT_SRC_NORMAL, " + "initial save)\n"); + goto abort; + } } /* size for data */ @@ -9641,6 +10620,8 @@ static int imsm_manage_reshape( dprintf("wait_for_reshape_imsm returned error!\n"); goto abort; } + if (sigterm) + goto abort; if (save_checkpoint_imsm(st, sra, UNIT_SRC_NORMAL) == 1) { /* ignore error == 2, this can mean end of reshape here @@ -9652,6 +10633,24 @@ static int imsm_manage_reshape( } + /* clear migr_rec on disks after successful migration */ + struct dl *d; + + memset(super->migr_rec_buf, 0, MIGR_REC_BUF_SIZE); + for (d = super->disks; d; d = d->next) { + if (d->index < 0 || is_failed(&d->disk)) + continue; + unsigned long long dsize; + + get_dev_size(d->fd, NULL, &dsize); + if (lseek64(d->fd, dsize - MIGR_REC_POSITION, + SEEK_SET) >= 0) { + if (write(d->fd, super->migr_rec_buf, + MIGR_REC_BUF_SIZE) != MIGR_REC_BUF_SIZE) + perror("Write migr_rec failed"); + } + } + /* return '1' if done */ ret_val = 1; abort: @@ -9660,6 +10659,7 @@ abort: return ret_val; } + #endif /* MDASSEMBLE */ struct superswitch super_imsm = { @@ -9675,6 +10675,7 @@ struct superswitch super_imsm = { .add_to_super = add_to_super_imsm, .remove_from_super = remove_from_super_imsm, .detail_platform = detail_platform_imsm, + .export_detail_platform = export_detail_platform_imsm, .kill_subarray = kill_subarray_imsm, .update_subarray = update_subarray_imsm, .load_container = load_container_imsm, @@ -9683,6 +10684,7 @@ struct superswitch super_imsm = { .reshape_super = imsm_reshape_super, .manage_reshape = imsm_manage_reshape, .recover_backup = recover_backup_imsm, + .copy_metadata = copy_metadata_imsm, #endif .match_home = match_home_imsm, .uuid_from_super= uuid_from_super_imsm, @@ -9701,7 +10703,7 @@ struct superswitch super_imsm = { .free_super = free_super_imsm, .match_metadata_desc = match_metadata_desc_imsm, .container_content = container_content_imsm, - + .validate_container = validate_container_imsm, .external = 1, .name = "imsm",