From 3164d06bd61ef34ed04cfe9829d905c1705f7f03 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Tue, 10 Oct 2023 10:48:33 +0200 Subject: Adding upstream version 4.2+20230901. Signed-off-by: Daniel Baumann --- Assemble.c | 14 +- Kill.c | 9 +- Manage.c | 13 +- Monitor.c | 3 +- lib.c | 19 +++ mapfile.c | 3 +- mdadm.c | 7 +- mdadm.h | 1 + mdmon.c | 6 +- mdopen.c | 4 +- misc/mdcheck | 8 +- platform-intel.c | 119 ++++++++++++++++- platform-intel.h | 16 ++- super-ddf.c | 3 +- super-intel.c | 385 +++++++++++++++++++++++++++++++------------------------ 15 files changed, 416 insertions(+), 194 deletions(-) diff --git a/Assemble.c b/Assemble.c index 4980494..61e8cd1 100644 --- a/Assemble.c +++ b/Assemble.c @@ -341,8 +341,10 @@ static int select_devices(struct mddev_dev *devlist, st->ss->free_super(st); dev_policy_free(pol); domain_free(domains); - if (tst) + if (tst) { tst->ss->free_super(tst); + free(tst); + } return -1; } @@ -417,6 +419,7 @@ static int select_devices(struct mddev_dev *devlist, st->ss->free_super(st); dev_policy_free(pol); domain_free(domains); + free(st); return -1; } if (c->verbose > 0) @@ -425,6 +428,8 @@ static int select_devices(struct mddev_dev *devlist, /* make sure we finished the loop */ tmpdev = NULL; + free(st); + st = NULL; goto loop; } else { content = *contentp; @@ -533,6 +538,7 @@ static int select_devices(struct mddev_dev *devlist, st->ss->free_super(st); dev_policy_free(pol); domain_free(domains); + free(tst); return -1; } tmpdev->used = 1; @@ -546,8 +552,10 @@ static int select_devices(struct mddev_dev *devlist, } dev_policy_free(pol); pol = NULL; - if (tst) + if (tst) { tst->ss->free_super(tst); + free(tst); + } } /* Check if we found some imsm spares but no members */ @@ -839,6 +847,7 @@ static int load_devices(struct devs *devices, char *devmap, close(mdfd); free(devices); free(devmap); + free(best); *stp = st; return -1; } @@ -1950,6 +1959,7 @@ out: } else if (mdfd >= 0) close(mdfd); + free(best); /* '2' means 'OK, but not started yet' */ if (rv == -1) { free(devices); diff --git a/Kill.c b/Kill.c index bfd0efd..43c9abe 100644 --- a/Kill.c +++ b/Kill.c @@ -41,6 +41,7 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl) * 4 - failed to find a superblock. */ + bool free_super = false; int fd, rv = 0; if (force) @@ -52,8 +53,10 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl) dev); return 2; } - if (st == NULL) + if (st == NULL) { st = guess_super(fd); + free_super = true; + } if (st == NULL || st->ss->init_super == NULL) { if (verbose >= 0) pr_err("Unrecognised md component device - %s\n", dev); @@ -77,6 +80,10 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl) rv = 0; } } + if (free_super && st) { + st->ss->free_super(st); + free(st); + } close(fd); return rv; } diff --git a/Manage.c b/Manage.c index f54de7c..f997b16 100644 --- a/Manage.c +++ b/Manage.c @@ -222,6 +222,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) if (verbose >= 0) pr_err("Cannot get exclusive access to %s:Perhaps a running process, mounted filesystem or active volume group?\n", devname); + sysfs_free(mdi); return 1; } /* If this is an mdmon managed array, just write 'inactive' @@ -801,8 +802,14 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, rdev, update, devname, verbose, array); dev_st->ss->free_super(dev_st); - if (rv) + if (rv) { + free(dev_st); return rv; + } + } + if (dev_st) { + dev_st->ss->free_super(dev_st); + free(dev_st); } } if (dv->disposition == 'M') { @@ -1362,7 +1369,7 @@ int Manage_subdevs(char *devname, int fd, unsigned long long array_size; struct mddev_dev *dv; int tfd = -1; - struct supertype *tst; + struct supertype *tst = NULL; char *subarray = NULL; int sysfd = -1; int count = 0; /* number of actions taken */ @@ -1699,6 +1706,7 @@ int Manage_subdevs(char *devname, int fd, break; } } + free(tst); if (frozen > 0) sysfs_set_str(&info, NULL, "sync_action","idle"); if (test && count == 0) @@ -1706,6 +1714,7 @@ int Manage_subdevs(char *devname, int fd, return 0; abort: + free(tst); if (frozen > 0) sysfs_set_str(&info, NULL, "sync_action","idle"); return !test && busy ? 2 : 1; diff --git a/Monitor.c b/Monitor.c index 6617596..e74a055 100644 --- a/Monitor.c +++ b/Monitor.c @@ -222,11 +222,10 @@ int Monitor(struct mddev_dev *devlist, info.dosyslog = dosyslog; info.test = c->test; - if (gethostname(info.hostname, sizeof(info.hostname)) != 0) { + if (s_gethostname(info.hostname, sizeof(info.hostname)) != 0) { pr_err("Cannot get hostname.\n"); return 1; } - info.hostname[sizeof(info.hostname) - 1] = '\0'; if (share){ if (check_one_sharer(c->scan) == 2) diff --git a/lib.c b/lib.c index fe5c8d2..8a4b48e 100644 --- a/lib.c +++ b/lib.c @@ -585,3 +585,22 @@ int parse_num(int *dest, const char *num) *dest = temp; return 0; } + +/** + * s_gethostname() - secure get hostname. Assure null-terminated string. + * + * @buf: buffer for hostname. + * @buf_len: buffer length. + * + * Return: gethostname() result. + */ +int s_gethostname(char *buf, int buf_len) +{ + assert(buf); + + int ret = gethostname(buf, buf_len); + + buf[buf_len - 1] = 0; + + return ret; +} diff --git a/mapfile.c b/mapfile.c index 34fea17..f1f3ee2 100644 --- a/mapfile.c +++ b/mapfile.c @@ -363,8 +363,7 @@ void RebuildMap(void) char *homehost = conf_get_homehost(&require_homehost); if (homehost == NULL || strcmp(homehost, "")==0) { - if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { - sys_hostname[sizeof(sys_hostname)-1] = 0; + if (s_gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { homehost = sys_hostname; } } diff --git a/mdadm.c b/mdadm.c index 076b45e..22d1c53 100644 --- a/mdadm.c +++ b/mdadm.c @@ -1340,8 +1340,7 @@ int main(int argc, char *argv[]) if (c.homehost == NULL && c.require_homehost) c.homehost = conf_get_homehost(&c.require_homehost); if (c.homehost == NULL || strcasecmp(c.homehost, "") == 0) { - if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { - sys_hostname[sizeof(sys_hostname)-1] = 0; + if (s_gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { c.homehost = sys_hostname; } } @@ -1709,6 +1708,10 @@ int main(int argc, char *argv[]) autodetect(); break; } + if (ss) { + ss->ss->free_super(ss); + free(ss); + } if (locked) cluster_release_dlmlock(); close_fd(&mdfd); diff --git a/mdadm.h b/mdadm.h index 83f2cf7..f0ceeb7 100644 --- a/mdadm.h +++ b/mdadm.h @@ -1805,6 +1805,7 @@ extern void set_dlm_hooks(void); extern void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt); extern bool is_directory(const char *path); extern bool is_file(const char *path); +extern int s_gethostname(char *buf, int buf_len); #define _ROUND_UP(val, base) (((val) + (base) - 1) & ~(base - 1)) #define ROUND_UP(val, base) _ROUND_UP(val, (typeof(val))(base)) diff --git a/mdmon.c b/mdmon.c index cef5bbc..a2038fe 100644 --- a/mdmon.c +++ b/mdmon.c @@ -240,7 +240,7 @@ static int make_control_sock(char *devname) return -1; addr.sun_family = PF_LOCAL; - strcpy(addr.sun_path, path); + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path); umask(077); /* ensure no world write access */ if (bind(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { close(sfd); @@ -389,7 +389,7 @@ int main(int argc, char *argv[]) if (all) { struct mdstat_ent *mdstat, *e; - int container_len = strlen(container_name); + int container_len = strnlen(container_name, MD_NAME_MAX); /* launch an mdmon instance for each container found */ mdstat = mdstat_read(0, 0); @@ -472,7 +472,7 @@ static int mdmon(char *devnm, int must_fork, int takeover) pfd[0] = pfd[1] = -1; container = xcalloc(1, sizeof(*container)); - strcpy(container->devnm, devnm); + snprintf(container->devnm, MD_NAME_MAX, "%s", devnm); container->arrays = NULL; container->sock = -1; diff --git a/mdopen.c b/mdopen.c index d3022a5..3daa71f 100644 --- a/mdopen.c +++ b/mdopen.c @@ -193,14 +193,14 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, if (dev) { if (strncmp(dev, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) { - strcpy(cname, dev + DEV_MD_DIR_LEN); + snprintf(cname, MD_NAME_MAX, "%s", dev + DEV_MD_DIR_LEN); } else if (strncmp(dev, "/dev/", 5) == 0) { char *e = dev + strlen(dev); while (e > dev && isdigit(e[-1])) e--; if (e[0]) num = strtoul(e, NULL, 10); - strcpy(cname, dev+5); + snprintf(cname, MD_NAME_MAX, "%s", dev + 5); cname[e-(dev+5)] = 0; /* name *must* be mdXX or md_dXX in this context */ if (num < 0 || diff --git a/misc/mdcheck b/misc/mdcheck index 700c3e2..f87999d 100644 --- a/misc/mdcheck +++ b/misc/mdcheck @@ -140,7 +140,13 @@ do echo $a > $fl any=yes done - if [ -z "$any" ]; then exit 0; fi + # mdcheck_continue.timer is started by mdcheck_start.timer. + # When the check action can be finished in mdcheck_start.service, + # it doesn't need mdcheck_continue anymore. + if [ -z "$any" ]; then + systemctl stop mdcheck_continue.timer + exit 0; + fi sleep 120 done diff --git a/platform-intel.c b/platform-intel.c index 914164c..ac282bc 100644 --- a/platform-intel.c +++ b/platform-intel.c @@ -214,7 +214,7 @@ struct sys_dev *device_by_id_and_path(__u16 device_id, const char *path) static int devpath_to_ll(const char *dev_path, const char *entry, unsigned long long *val) { - char path[strlen(dev_path) + strlen(entry) + 2]; + char path[strnlen(dev_path, PATH_MAX) + strnlen(entry, PATH_MAX) + 2]; int fd; int n; @@ -510,9 +510,6 @@ static const struct imsm_orom *find_imsm_hba_orom(struct sys_dev *hba) return get_orom_by_device_id(hba->dev_id); } -#define GUID_STR_MAX 37 /* according to GUID format: - * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */ - #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ ((struct efi_guid) \ {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ @@ -703,6 +700,106 @@ const struct imsm_orom *find_imsm_nvme(struct sys_dev *hba) return &nvme_orom->orom; } +#define VMD_REGISTER_OFFSET 0x3FC +#define VMD_REGISTER_SKU_SHIFT 1 +#define VMD_REGISTER_SKU_MASK (0x00000007) +#define VMD_REGISTER_SKU_PREMIUM 2 +#define MD_REGISTER_VER_MAJOR_SHIFT 4 +#define MD_REGISTER_VER_MAJOR_MASK (0x0000000F) +#define MD_REGISTER_VER_MINOR_SHIFT 8 +#define MD_REGISTER_VER_MINOR_MASK (0x0000000F) + +/* + * read_vmd_register() - Reads VMD register and writes contents to buff ptr + * @buff: buffer for vmd register data, should be the size of uint32_t + * + * Return: 0 on success, 1 on error + */ +int read_vmd_register(uint32_t *buff, struct sys_dev *hba) +{ + int fd; + char vmd_pci_config_path[PATH_MAX]; + + if (!vmd_domain_to_controller(hba, vmd_pci_config_path)) + return 1; + + strncat(vmd_pci_config_path, "/config", PATH_MAX - strnlen(vmd_pci_config_path, PATH_MAX)); + + fd = open(vmd_pci_config_path, O_RDONLY); + if (fd < 0) + return 1; + + if (pread(fd, buff, sizeof(uint32_t), VMD_REGISTER_OFFSET) != sizeof(uint32_t)) { + close(fd); + return 1; + } + close(fd); + return 0; +} + +/* + * add_vmd_orom() - Adds VMD orom cap to orom list, writes orom_entry ptr into vmd_orom + * @vmd_orom: pointer to orom entry pointer + * + * Return: 0 on success, 1 on error + */ +int add_vmd_orom(struct orom_entry **vmd_orom, struct sys_dev *hba) +{ + uint8_t sku; + uint32_t vmd_register_data; + struct imsm_orom vmd_orom_cap = { + .signature = IMSM_VMD_OROM_COMPAT_SIGNATURE, + .sss = IMSM_OROM_SSS_4kB | IMSM_OROM_SSS_8kB | + IMSM_OROM_SSS_16kB | IMSM_OROM_SSS_32kB | + IMSM_OROM_SSS_64kB | IMSM_OROM_SSS_128kB, + .dpa = IMSM_OROM_DISKS_PER_ARRAY_NVME, + .tds = IMSM_OROM_TOTAL_DISKS_VMD, + .vpa = IMSM_OROM_VOLUMES_PER_ARRAY, + .vphba = IMSM_OROM_VOLUMES_PER_HBA_VMD, + .attr = IMSM_OROM_ATTR_2TB | IMSM_OROM_ATTR_2TB_DISK, + .driver_features = IMSM_OROM_CAPABILITIES_EnterpriseSystem | + IMSM_OROM_CAPABILITIES_TPV + }; + + if (read_vmd_register(&vmd_register_data, hba) != 0) + return 1; + + sku = (uint8_t)((vmd_register_data >> VMD_REGISTER_SKU_SHIFT) & + VMD_REGISTER_SKU_MASK); + + if (sku == VMD_REGISTER_SKU_PREMIUM) + vmd_orom_cap.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 | + IMSM_OROM_RLC_RAID10 | IMSM_OROM_RLC_RAID5; + else + vmd_orom_cap.rlc = IMSM_OROM_RLC_RAID_CNG; + + vmd_orom_cap.major_ver = (uint8_t) + ((vmd_register_data >> MD_REGISTER_VER_MAJOR_SHIFT) & + MD_REGISTER_VER_MAJOR_MASK); + vmd_orom_cap.minor_ver = (uint8_t) + ((vmd_register_data >> MD_REGISTER_VER_MINOR_SHIFT) & + MD_REGISTER_VER_MINOR_MASK); + + *vmd_orom = add_orom(&vmd_orom_cap); + + return 0; +} + +const struct imsm_orom *find_imsm_vmd(struct sys_dev *hba) +{ + static struct orom_entry *vmd_orom; + + if (hba->type != SYS_DEV_VMD) + return NULL; + + if (!vmd_orom && add_vmd_orom(&vmd_orom, hba) != 0) + return NULL; + + add_orom_device_id(vmd_orom, hba->dev_id); + vmd_orom->type = SYS_DEV_VMD; + return &vmd_orom->orom; +} + const struct imsm_orom *find_imsm_capability(struct sys_dev *hba) { const struct imsm_orom *cap = get_orom_by_device_id(hba->dev_id); @@ -712,9 +809,19 @@ const struct imsm_orom *find_imsm_capability(struct sys_dev *hba) if (hba->type == SYS_DEV_NVME) return find_imsm_nvme(hba); - if ((cap = find_imsm_efi(hba)) != NULL) + + cap = find_imsm_efi(hba); + if (cap) return cap; - if ((cap = find_imsm_hba_orom(hba)) != NULL) + + if (hba->type == SYS_DEV_VMD) { + cap = find_imsm_vmd(hba); + if (cap) + return cap; + } + + cap = find_imsm_hba_orom(hba); + if (cap) return cap; return NULL; diff --git a/platform-intel.h b/platform-intel.h index 2c0f4e3..ce29d3d 100644 --- a/platform-intel.h +++ b/platform-intel.h @@ -19,11 +19,15 @@ #include #include +/* according to GUID format: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */ +#define GUID_STR_MAX 37 + /* The IMSM Capability (IMSM AHCI and ISCU OROM/EFI variable) Version Table definition */ struct imsm_orom { __u8 signature[4]; #define IMSM_OROM_SIGNATURE "$VER" #define IMSM_NVME_OROM_COMPAT_SIGNATURE "$NVM" + #define IMSM_VMD_OROM_COMPAT_SIGNATURE "$VMD" __u8 table_ver_major; /* Currently 2 (can change with future revs) */ __u8 table_ver_minor; /* Currently 2 (can change with future revs) */ __u16 major_ver; /* Example: 8 as in 8.6.0.1020 */ @@ -65,11 +69,13 @@ struct imsm_orom { __u16 tds; /* Total Disks Supported */ #define IMSM_OROM_TOTAL_DISKS 6 #define IMSM_OROM_TOTAL_DISKS_NVME 12 + #define IMSM_OROM_TOTAL_DISKS_VMD 48 __u8 vpa; /* # Volumes Per Array supported */ #define IMSM_OROM_VOLUMES_PER_ARRAY 2 __u8 vphba; /* # Volumes Per Host Bus Adapter supported */ #define IMSM_OROM_VOLUMES_PER_HBA 4 #define IMSM_OROM_VOLUMES_PER_HBA_NVME 4 + #define IMSM_OROM_VOLUMES_PER_HBA_VMD 24 /* Attributes supported. This should map to the * attributes in the MPB. Also, lower 16 bits * should match/duplicate RLC bits above. @@ -182,7 +188,13 @@ static inline int imsm_orom_is_enterprise(const struct imsm_orom *orom) static inline int imsm_orom_is_nvme(const struct imsm_orom *orom) { return memcmp(orom->signature, IMSM_NVME_OROM_COMPAT_SIGNATURE, - sizeof(orom->signature)) == 0; + sizeof(orom->signature)) == 0; +} + +static inline int imsm_orom_is_vmd_without_efi(const struct imsm_orom *orom) +{ + return memcmp(orom->signature, IMSM_VMD_OROM_COMPAT_SIGNATURE, + sizeof(orom->signature)) == 0; } static inline int imsm_orom_has_tpv_support(const struct imsm_orom *orom) @@ -229,7 +241,7 @@ extern struct orom_entry *orom_entries; static inline char *guid_str(char *buf, struct efi_guid guid) { - sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + snprintf(buf, GUID_STR_MAX, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid.b[3], guid.b[2], guid.b[1], guid.b[0], guid.b[5], guid.b[4], guid.b[7], guid.b[6], guid.b[8], guid.b[9], guid.b[10], guid.b[11], diff --git a/super-ddf.c b/super-ddf.c index 7213284..c524265 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -2364,8 +2364,7 @@ static int init_super_ddf(struct supertype *st, * Remaining 16 are serial number.... maybe a hostname would do? */ memcpy(ddf->controller.guid, T10, sizeof(T10)); - gethostname(hostname, sizeof(hostname)); - hostname[sizeof(hostname) - 1] = 0; + s_gethostname(hostname, sizeof(hostname)); hostlen = strlen(hostname); memcpy(ddf->controller.guid + 24 - hostlen, hostname, hostlen); for (i = strlen(T10) ; i+hostlen < 24; i++) diff --git a/super-intel.c b/super-intel.c index ae0f4a8..77b0066 100644 --- a/super-intel.c +++ b/super-intel.c @@ -499,8 +499,15 @@ struct intel_disk { struct intel_disk *next; }; +/** + * struct extent - reserved space details. + * @start: start offset. + * @size: size of reservation, set to 0 for metadata reservation. + * @vol: index of the volume, meaningful if &size is set. + */ struct extent { unsigned long long start, size; + int vol; }; /* definitions of reshape process types */ @@ -650,6 +657,11 @@ static int check_no_platform(void) char *l = conf_line(fp); char *w = l; + if (l == NULL) { + fclose(fp); + return 0; + } + do { if (strcmp(w, search) == 0) no_platform = 1; @@ -1534,9 +1546,10 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl, int get_minimal_reservation) { /* find a list of used extents on the given physical device */ - struct extent *rv, *e; - int i; int memberships = count_memberships(dl, super); + struct extent *rv = xcalloc(memberships + 1, sizeof(struct extent)); + struct extent *e = rv; + int i; __u32 reservation; /* trim the reserved area for spares, so they can join any array @@ -1548,9 +1561,6 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl, else reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS; - rv = xcalloc(sizeof(struct extent), (memberships + 1)); - e = rv; - for (i = 0; i < super->anchor->num_raid_devs; i++) { struct imsm_dev *dev = get_imsm_dev(super, i); struct imsm_map *map = get_imsm_map(dev, MAP_0); @@ -1558,6 +1568,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl, if (get_imsm_disk_slot(map, dl->index) >= 0) { e->start = pba_of_lba0(map); e->size = per_dev_array_size(map); + e->vol = i; e++; } } @@ -1639,17 +1650,29 @@ static int is_journal(struct imsm_disk *disk) return (disk->status & JOURNAL_DISK) == JOURNAL_DISK; } -/* round array size down to closest MB and ensure it splits evenly - * between members +/** + * round_member_size_to_mb()- Round given size to closest MiB. + * @size: size to round in sectors. */ -static unsigned long long round_size_to_mb(unsigned long long size, unsigned int - disk_count) +static inline unsigned long long round_member_size_to_mb(unsigned long long size) { - size /= disk_count; - size = (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT; - size *= disk_count; + return (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT; +} - return size; +/** + * round_size_to_mb()- Round given size. + * @array_size: size to round in sectors. + * @disk_count: count of data members. + * + * Get size per each data member and round it to closest MiB to ensure that data + * splits evenly between members. + * + * Return: Array size, rounded down. + */ +static inline unsigned long long round_size_to_mb(unsigned long long array_size, + unsigned int disk_count) +{ + return round_member_size_to_mb(array_size / disk_count) * disk_count; } static int able_to_resync(int raid_level, int missing_disks) @@ -2649,9 +2672,14 @@ static void print_imsm_capability(const struct imsm_orom *orom) 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); + if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) { + if (imsm_orom_is_vmd_without_efi(orom)) + printf(" Version : %d.%d\n", orom->major_ver, + orom->minor_ver); + else + 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" : "", @@ -6877,20 +6905,35 @@ static unsigned long long find_size(struct extent *e, int *idx, int num_extents) return end - base_start; } -static unsigned long long merge_extents(struct intel_super *super, int sum_extents) +/** merge_extents() - analyze extents and get free size. + * @super: Intel metadata, not NULL. + * @expanding: if set, we are expanding &super->current_vol. + * + * Build a composite disk with all known extents and generate a size given the + * "all disks in an array must share a common start offset" constraint. + * If a volume is expanded, then return free space after the volume. + * + * Return: Free space or 0 on failure. + */ +static unsigned long long merge_extents(struct intel_super *super, const bool expanding) { - /* build a composite disk with all known extents and generate a new - * 'maxsize' given the "all disks in an array must share a common start - * offset" constraint - */ - struct extent *e = xcalloc(sum_extents, sizeof(*e)); + struct extent *e; struct dl *dl; - int i, j; - int start_extent; - unsigned long long pos; + int i, j, pos_vol_idx = -1; + int extent_idx = 0; + int sum_extents = 0; + unsigned long long pos = 0; unsigned long long start = 0; - unsigned long long maxsize; - unsigned long reserve; + unsigned long long free_size = 0; + + unsigned long pre_reservation = 0; + unsigned long post_reservation = IMSM_RESERVED_SECTORS; + unsigned long reservation_size; + + for (dl = super->disks; dl; dl = dl->next) + if (dl->e) + sum_extents += dl->extent_cnt; + e = xcalloc(sum_extents, sizeof(struct extent)); /* coalesce and sort all extents. also, check to see if we need to * reserve space between member arrays @@ -6909,50 +6952,57 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten j = 0; while (i < sum_extents) { e[j].start = e[i].start; + e[j].vol = e[i].vol; e[j].size = find_size(e, &i, sum_extents); j++; if (e[j-1].size == 0) break; } - pos = 0; - maxsize = 0; - start_extent = 0; i = 0; do { - unsigned long long esize; + unsigned long long esize = e[i].start - pos; - esize = e[i].start - pos; - if (esize >= maxsize) { - maxsize = esize; + if (expanding ? pos_vol_idx == super->current_vol : esize >= free_size) { + free_size = esize; start = pos; - start_extent = i; + extent_idx = i; } + pos = e[i].start + e[i].size; + pos_vol_idx = e[i].vol; + i++; } while (e[i-1].size); - free(e); - if (maxsize == 0) + if (free_size == 0) { + dprintf("imsm: Cannot find free size.\n"); + free(e); return 0; + } - /* FIXME assumes volume at offset 0 is the first volume in a - * container - */ - if (start_extent > 0) - reserve = IMSM_RESERVED_SECTORS; /* gap between raid regions */ - else - reserve = 0; + if (!expanding && extent_idx != 0) + /* + * Not a real first volume in a container is created, pre_reservation is needed. + */ + pre_reservation = IMSM_RESERVED_SECTORS; - if (maxsize < reserve) - return 0; + if (e[extent_idx].size == 0) + /* + * extent_idx points to the metadata, post_reservation is allready done. + */ + post_reservation = 0; + free(e); - super->create_offset = ~((unsigned long long) 0); - if (start + reserve > super->create_offset) - return 0; /* start overflows create_offset */ - super->create_offset = start + reserve; + reservation_size = pre_reservation + post_reservation; + + if (free_size < reservation_size) { + dprintf("imsm: Reservation size is greater than free space.\n"); + return 0; + } - return maxsize - reserve; + super->create_offset = start + pre_reservation; + return free_size - reservation_size; } static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks) @@ -6998,7 +7048,7 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist, int fd = -1; while (dev && !is_fd_valid(fd)) { char *path = xmalloc(strlen(dev->name) + strlen("/dev/") + 1); - num = sprintf(path, "%s%s", "/dev/", dev->name); + num = snprintf(path, PATH_MAX, "%s%s", "/dev/", dev->name); if (num > 0) fd = open(path, O_RDONLY, 0); if (num <= 0 || !is_fd_valid(fd)) { @@ -7550,13 +7600,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, return 0; } - /* count total number of extents for merge */ - i = 0; - for (dl = super->disks; dl; dl = dl->next) - if (dl->e) - i += dl->extent_cnt; - - maxsize = merge_extents(super, i); + maxsize = merge_extents(super, false); if (mpb->num_raid_devs > 0 && size && size != maxsize) pr_err("attempting to create a second volume with size less then remaining space.\n"); @@ -7591,7 +7635,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, * @super: &intel_super pointer, not NULL. * @raiddisks: number of raid disks. * @size: requested size, could be 0 (means max size). - * @chunk: requested chunk. + * @chunk: requested chunk size in KiB. * @freesize: pointer for returned size value. * * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR. @@ -7605,22 +7649,22 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, const int raiddisks, unsigned long long size, const int chunk, - unsigned long long *freesize) + unsigned long long *freesize, + bool expanding) { struct imsm_super *mpb = super->anchor; struct dl *dl; int i; - int extent_cnt; struct extent *e; + int cnt = 0; + int used = 0; unsigned long long maxsize; - unsigned long long minsize; - int cnt; - int used; + unsigned long long minsize = size; + + if (minsize == 0) + minsize = chunk * 2; /* find the largest common start free region of the possible disks */ - used = 0; - extent_cnt = 0; - cnt = 0; for (dl = super->disks; dl; dl = dl->next) { dl->raiddisk = -1; @@ -7640,19 +7684,18 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, ; dl->e = e; dl->extent_cnt = i; - extent_cnt += i; cnt++; } - maxsize = merge_extents(super, extent_cnt); - minsize = size; - if (size == 0) - /* chunk is in K */ - minsize = chunk * 2; + maxsize = merge_extents(super, expanding); + if (maxsize < minsize) { + pr_err("imsm: Free space is %llu but must be equal or larger than %llu.\n", + maxsize, minsize); + return IMSM_STATUS_ERROR; + } - if (cnt < raiddisks || (super->orom && used && used != raiddisks) || - maxsize < minsize || maxsize == 0) { - pr_err("not enough devices with space to create array.\n"); + if (cnt < raiddisks || (super->orom && used && used != raiddisks)) { + pr_err("imsm: Not enough devices with space to create array.\n"); return IMSM_STATUS_ERROR; } @@ -7702,7 +7745,7 @@ static imsm_status_t autolayout_imsm(struct intel_super *super, int vol_cnt = super->anchor->num_raid_devs; imsm_status_t rv; - rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize); + rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize, false); if (rv != IMSM_STATUS_OK) return IMSM_STATUS_ERROR; @@ -7897,7 +7940,7 @@ static int kill_subarray_imsm(struct supertype *st, char *subarray_id) if (i < current_vol) continue; - sprintf(subarray, "%u", i); + snprintf(subarray, sizeof(subarray), "%u", 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); @@ -11270,7 +11313,7 @@ static const char *imsm_get_disk_controller_domain(const char *path) char *drv=NULL; struct stat st; - strcpy(disk_path, disk_by_path); + strncpy(disk_path, disk_by_path, PATH_MAX); strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1); if (stat(disk_path, &st) == 0) { struct sys_dev* hba; @@ -11624,6 +11667,96 @@ static void imsm_update_metadata_locally(struct supertype *st, } } +/** + * imsm_analyze_expand() - check expand properties and calculate new size. + * @st: imsm supertype. + * @geo: new geometry params. + * @array: array info. + * @direction: reshape direction. + * + * Obtain free space after the &array and verify if expand to requested size is + * possible. If geo->size is set to %MAX_SIZE, assume that max free size is + * requested. + * + * Return: + * On success %IMSM_STATUS_OK is returned, geo->size and geo->raid_disks are + * updated. + * On error, %IMSM_STATUS_ERROR is returned. + */ +static imsm_status_t imsm_analyze_expand(struct supertype *st, + struct geo_params *geo, + struct mdinfo *array, + int direction) +{ + struct intel_super *super = st->sb; + struct imsm_dev *dev = get_imsm_dev(super, super->current_vol); + struct imsm_map *map = get_imsm_map(dev, MAP_0); + int data_disks = imsm_num_data_members(map); + + unsigned long long current_size; + unsigned long long free_size; + unsigned long long new_size; + unsigned long long max_size; + + const int chunk_kib = geo->chunksize / 1024; + imsm_status_t rv; + + if (direction == ROLLBACK_METADATA_CHANGES) { + /** + * Accept size for rollback only. + */ + new_size = geo->size * 2; + goto success; + } + + if (data_disks == 0) { + pr_err("imsm: Cannot retrieve data disks.\n"); + return IMSM_STATUS_ERROR; + } + current_size = array->custom_array_size / data_disks; + + rv = imsm_get_free_size(super, dev->vol.map->num_members, 0, chunk_kib, &free_size, true); + if (rv != IMSM_STATUS_OK) { + pr_err("imsm: Cannot find free space for expand.\n"); + return IMSM_STATUS_ERROR; + } + max_size = round_member_size_to_mb(free_size + current_size); + + if (geo->size == MAX_SIZE) + new_size = max_size; + else + new_size = round_member_size_to_mb(geo->size * 2); + + if (new_size == 0) { + pr_err("imsm: Rounded requested size is 0.\n"); + return IMSM_STATUS_ERROR; + } + + if (new_size > max_size) { + pr_err("imsm: Rounded requested size (%llu) is larger than free space available (%llu).\n", + new_size, max_size); + return IMSM_STATUS_ERROR; + } + + if (new_size == current_size) { + pr_err("imsm: Rounded requested size (%llu) is same as current size (%llu).\n", + new_size, current_size); + return IMSM_STATUS_ERROR; + } + + if (new_size < current_size) { + pr_err("imsm: Size reduction is not supported, rounded requested size (%llu) is smaller than current (%llu).\n", + new_size, current_size); + return IMSM_STATUS_ERROR; + } + +success: + dprintf("imsm: New size per member is %llu.\n", new_size); + geo->size = data_disks * new_size; + geo->raid_disks = dev->vol.map->num_members; + return IMSM_STATUS_OK; +} + /*************************************************************************** * Function: imsm_analyze_change * Description: Function analyze change for single volume @@ -11644,13 +11777,6 @@ 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 imsm_map *map; - struct intel_super *super; - unsigned long long current_size; - unsigned long long free_size; - unsigned long long max_size; imsm_status_t rv; getinfo_super_imsm_volume(st, &info, NULL); @@ -11733,95 +11859,20 @@ 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); - map = get_imsm_map(dev, MAP_0); - data_disks = imsm_num_data_members(map); - /* 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_alignment_check( - get_imsm_raid_level(dev->vol.map), - chunk * 1024, super->sector_size, - 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 (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(super, dev->vol.map->num_members, - 0, chunk, &free_size); + rv = imsm_analyze_expand(st, geo, &info, direction); if (rv != IMSM_STATUS_OK) - /* Cannot find maximum available space - */ - max_size = 0; - else { - max_size = free_size + current_size; - /* align component size - */ - max_size = imsm_component_size_alignment_check( - get_imsm_raid_level(dev->vol.map), - chunk * 1024, super->sector_size, - 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; + goto analyse_change_exit; change = CH_ARRAY_SIZE; } + + chunk = geo->chunksize / 1024; if (!validate_geometry_imsm(st, geo->level, imsm_layout, -- cgit v1.2.3