diff --git a/0013-mdmon-Stop-parsing-duplicate-options.patch b/0013-mdmon-Stop-parsing-duplicate-options.patch new file mode 100644 index 0000000..fed1740 --- /dev/null +++ b/0013-mdmon-Stop-parsing-duplicate-options.patch @@ -0,0 +1,122 @@ +From 1066ab83dbe9a4cc20f7db44a40aa2cbb9d5eed6 Mon Sep 17 00:00:00 2001 +From: Lukasz Florczak +Date: Fri, 13 May 2022 09:19:42 +0200 +Subject: [PATCH 13/52] mdmon: Stop parsing duplicate options + +Introduce new function is_duplicate_opt() to check if given option +was already used and prevent setting it again along with an error +message. + +Move parsing above in_initrd() check to be able to detect --offroot +option duplicates. + +Now help option is executed after parsing to prevent executing commands +like: 'mdmon --help --ndlksnlksajndfjksndafasj'. + +Signed-off-by: Lukasz Florczak +Signed-off-by: Jes Sorensen +--- + mdmon.c | 44 +++++++++++++++++++++++++++++++++++--------- + 1 file changed, 35 insertions(+), 9 deletions(-) + +diff --git a/mdmon.c b/mdmon.c +index 5570574b..c057da63 100644 +--- a/mdmon.c ++++ b/mdmon.c +@@ -288,6 +288,15 @@ void usage(void) + exit(2); + } + ++static bool is_duplicate_opt(const int opt, const int set_val, const char *long_name) ++{ ++ if (opt == set_val) { ++ pr_err("--%s option duplicated!\n", long_name); ++ return true; ++ } ++ return false; ++} ++ + static int mdmon(char *devnm, int must_fork, int takeover); + + int main(int argc, char *argv[]) +@@ -299,6 +308,7 @@ int main(int argc, char *argv[]) + int all = 0; + int takeover = 0; + int dofork = 1; ++ bool help = false; + static struct option options[] = { + {"all", 0, NULL, 'a'}, + {"takeover", 0, NULL, 't'}, +@@ -308,37 +318,50 @@ int main(int argc, char *argv[]) + {NULL, 0, NULL, 0} + }; + +- if (in_initrd()) { +- /* +- * set first char of argv[0] to @. This is used by +- * systemd to signal that the task was launched from +- * initrd/initramfs and should be preserved during shutdown +- */ +- argv[0][0] = '@'; +- } +- + while ((opt = getopt_long(argc, argv, "thaF", options, NULL)) != -1) { + switch (opt) { + case 'a': ++ if (is_duplicate_opt(all, 1, "all")) ++ exit(1); + container_name = argv[optind-1]; + all = 1; + break; + case 't': ++ if (is_duplicate_opt(takeover, 1, "takeover")) ++ exit(1); + takeover = 1; + break; + case 'F': ++ if (is_duplicate_opt(dofork, 0, "foreground")) ++ exit(1); + dofork = 0; + break; + case OffRootOpt: ++ if (is_duplicate_opt(argv[0][0], '@', "offroot")) ++ exit(1); + argv[0][0] = '@'; + break; + case 'h': ++ if (is_duplicate_opt(help, true, "help")) ++ exit(1); ++ help = true; ++ break; + default: + usage(); + break; + } + } + ++ ++ if (in_initrd()) { ++ /* ++ * set first char of argv[0] to @. This is used by ++ * systemd to signal that the task was launched from ++ * initrd/initramfs and should be preserved during shutdown ++ */ ++ argv[0][0] = '@'; ++ } ++ + if (all == 0 && container_name == NULL) { + if (argv[optind]) + container_name = argv[optind]; +@@ -353,6 +376,9 @@ int main(int argc, char *argv[]) + if (strcmp(container_name, "/proc/mdstat") == 0) + all = 1; + ++ if (help) ++ usage(); ++ + if (all) { + struct mdstat_ent *mdstat, *e; + int container_len = strlen(container_name); +-- +2.31.1 + diff --git a/0014-Grow-block-n-on-external-volumes.patch b/0014-Grow-block-n-on-external-volumes.patch new file mode 100644 index 0000000..25ffac1 --- /dev/null +++ b/0014-Grow-block-n-on-external-volumes.patch @@ -0,0 +1,41 @@ +From 20e114e334ed6ed3280c37a9a08fb95578393d1a Mon Sep 17 00:00:00 2001 +From: Mateusz Kusiak +Date: Thu, 19 May 2022 09:16:08 +0200 +Subject: [PATCH 14/52] Grow: block -n on external volumes. + +Performing --raid-devices on external metadata volume should be blocked +as it causes unwanted behaviour. + +Eg. Performing +mdadm -G /dev/md/volume -l10 -n4 +on r0_d2 inside 4 disk container, returns +mdadm: Need 2 spares to avoid degraded array, only have 0. + +Signed-off-by: Mateusz Kusiak +Signed-off-by: Jes Sorensen +--- + Grow.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/Grow.c b/Grow.c +index 8a242b0f..f6efbc48 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -1892,6 +1892,14 @@ int Grow_reshape(char *devname, int fd, + + if (retval) { + pr_err("Cannot read superblock for %s\n", devname); ++ close(cfd); ++ free(subarray); ++ return 1; ++ } ++ ++ if (s->raiddisks && subarray) { ++ pr_err("--raid-devices operation can be performed on a container only\n"); ++ close(cfd); + free(subarray); + return 1; + } +-- +2.31.1 + diff --git a/0015-Incremental-Fix-possible-memory-and-resource-leaks.patch b/0015-Incremental-Fix-possible-memory-and-resource-leaks.patch new file mode 100644 index 0000000..42fa773 --- /dev/null +++ b/0015-Incremental-Fix-possible-memory-and-resource-leaks.patch @@ -0,0 +1,90 @@ +From de064c93e3819d72720e4fba6575265ba10e1553 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Mon, 13 Jun 2022 12:11:25 +0200 +Subject: [PATCH 15/52] Incremental: Fix possible memory and resource leaks + +map allocated through map_by_uuid() is not freed if mdfd is invalid. +In addition mdfd is not closed, and mdinfo list is not freed too. + +Signed-off-by: Mateusz Grzonka +Change-Id: I25e726f0e2502cf7e8ce80c2bd7944b3b1e2b9dc +Signed-off-by: Jes Sorensen +--- + Incremental.c | 32 +++++++++++++++++++++++--------- + 1 file changed, 23 insertions(+), 9 deletions(-) + +diff --git a/Incremental.c b/Incremental.c +index a57fc323..4d0cd9d6 100644 +--- a/Incremental.c ++++ b/Incremental.c +@@ -1499,7 +1499,7 @@ static int Incremental_container(struct supertype *st, char *devname, + return 0; + } + for (ra = list ; ra ; ra = ra->next) { +- int mdfd; ++ int mdfd = -1; + char chosen_name[1024]; + struct map_ent *mp; + struct mddev_ident *match = NULL; +@@ -1514,6 +1514,12 @@ static int Incremental_container(struct supertype *st, char *devname, + + if (mp) { + mdfd = open_dev(mp->devnm); ++ if (!is_fd_valid(mdfd)) { ++ pr_err("failed to open %s: %s.\n", ++ mp->devnm, strerror(errno)); ++ rv = 2; ++ goto release; ++ } + if (mp->path) + strcpy(chosen_name, mp->path); + else +@@ -1573,21 +1579,25 @@ static int Incremental_container(struct supertype *st, char *devname, + c->autof, + trustworthy, + chosen_name, 0); ++ ++ if (!is_fd_valid(mdfd)) { ++ pr_err("create_mddev failed with chosen name %s: %s.\n", ++ chosen_name, strerror(errno)); ++ rv = 2; ++ goto release; ++ } + } +- if (only && (!mp || strcmp(mp->devnm, only) != 0)) +- continue; + +- if (mdfd < 0) { +- pr_err("failed to open %s: %s.\n", +- chosen_name, strerror(errno)); +- return 2; ++ if (only && (!mp || strcmp(mp->devnm, only) != 0)) { ++ close_fd(&mdfd); ++ continue; + } + + assemble_container_content(st, mdfd, ra, c, + chosen_name, &result); + map_free(map); + map = NULL; +- close(mdfd); ++ close_fd(&mdfd); + } + if (c->export && result) { + char sep = '='; +@@ -1610,7 +1620,11 @@ static int Incremental_container(struct supertype *st, char *devname, + } + printf("\n"); + } +- return 0; ++ ++release: ++ map_free(map); ++ sysfs_free(list); ++ return rv; + } + + static void run_udisks(char *arg1, char *arg2) +-- +2.31.1 + diff --git a/0016-Mdmonitor-Fix-segfault.patch b/0016-Mdmonitor-Fix-segfault.patch new file mode 100644 index 0000000..05c7fb4 --- /dev/null +++ b/0016-Mdmonitor-Fix-segfault.patch @@ -0,0 +1,98 @@ +From e702f392959d1c2ad2089e595b52235ed97b4e18 Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Mon, 6 Jun 2022 12:32:12 +0200 +Subject: [PATCH 16/52] Mdmonitor: Fix segfault + +Mdadm with "--monitor" parameter requires md device +as an argument to be monitored. If given argument is +not a md device, error shall be returned. Previously +it was not checked and invalid argument caused +segmentation fault. This commit adds checking +that devices passed to mdmonitor are md devices. + +Signed-off-by: Kinga Tanska +Signed-off-by: Jes Sorensen +--- + Monitor.c | 10 +++++++++- + mdadm.h | 1 + + mdopen.c | 17 +++++++++++++++++ + 3 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/Monitor.c b/Monitor.c +index c0ab5412..4e5802b5 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -182,6 +182,7 @@ int Monitor(struct mddev_dev *devlist, + continue; + if (strcasecmp(mdlist->devname, "") == 0) + continue; ++ + st = xcalloc(1, sizeof *st); + if (mdlist->devname[0] == '/') + st->devname = xstrdup(mdlist->devname); +@@ -190,6 +191,8 @@ int Monitor(struct mddev_dev *devlist, + strcpy(strcpy(st->devname, "/dev/md/"), + mdlist->devname); + } ++ if (!is_mddev(mdlist->devname)) ++ return 1; + st->next = statelist; + st->devnm[0] = 0; + st->percent = RESYNC_UNKNOWN; +@@ -203,7 +206,12 @@ int Monitor(struct mddev_dev *devlist, + struct mddev_dev *dv; + + for (dv = devlist; dv; dv = dv->next) { +- struct state *st = xcalloc(1, sizeof *st); ++ struct state *st; ++ ++ if (!is_mddev(dv->devname)) ++ return 1; ++ ++ st = xcalloc(1, sizeof *st); + mdlist = conf_get_ident(dv->devname); + st->devname = xstrdup(dv->devname); + st->next = statelist; +diff --git a/mdadm.h b/mdadm.h +index 09915a00..d53df169 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1636,6 +1636,7 @@ extern int create_mddev(char *dev, char *name, int autof, int trustworthy, + #define FOREIGN 2 + #define METADATA 3 + extern int open_mddev(char *dev, int report_errors); ++extern int is_mddev(char *dev); + extern int open_container(int fd); + extern int metadata_container_matches(char *metadata, char *devnm); + extern int metadata_subdev_matches(char *metadata, char *devnm); +diff --git a/mdopen.c b/mdopen.c +index 245be537..d18c9319 100644 +--- a/mdopen.c ++++ b/mdopen.c +@@ -475,6 +475,23 @@ int open_mddev(char *dev, int report_errors) + return mdfd; + } + ++/** ++ * is_mddev() - check that file name passed is an md device. ++ * @dev: file name that has to be checked. ++ * Return: 1 if file passed is an md device, 0 if not. ++ */ ++int is_mddev(char *dev) ++{ ++ int fd = open_mddev(dev, 1); ++ ++ if (fd >= 0) { ++ close(fd); ++ return 1; ++ } ++ ++ return 0; ++} ++ + char *find_free_devnm(int use_partitions) + { + static char devnm[32]; +-- +2.31.1 + diff --git a/0017-Mdmonitor-Improve-logging-method.patch b/0017-Mdmonitor-Improve-logging-method.patch new file mode 100644 index 0000000..f00b8b3 --- /dev/null +++ b/0017-Mdmonitor-Improve-logging-method.patch @@ -0,0 +1,61 @@ +From f5ff2988761625b43eb15555993f2797af29f166 Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Mon, 6 Jun 2022 12:32:13 +0200 +Subject: [PATCH 17/52] Mdmonitor: Improve logging method + +Change logging, and as a result, mdmonitor in verbose +mode will report its configuration. + +Signed-off-by: Kinga Tanska +Signed-off-by: Oleksandr Shchirskyi +Signed-off-by: Jes Sorensen +--- + Monitor.c | 25 ++++++++++++++----------- + 1 file changed, 14 insertions(+), 11 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index 4e5802b5..6ca1ebe5 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -136,24 +136,27 @@ int Monitor(struct mddev_dev *devlist, + struct mddev_ident *mdlist; + int delay_for_event = c->delay; + +- if (!mailaddr) { ++ if (!mailaddr) + mailaddr = conf_get_mailaddr(); +- if (mailaddr && ! c->scan) +- pr_err("Monitor using email address \"%s\" from config file\n", +- mailaddr); +- } +- mailfrom = conf_get_mailfrom(); + +- if (!alert_cmd) { ++ if (!alert_cmd) + alert_cmd = conf_get_program(); +- if (alert_cmd && !c->scan) +- pr_err("Monitor using program \"%s\" from config file\n", +- alert_cmd); +- } ++ ++ mailfrom = conf_get_mailfrom(); ++ + if (c->scan && !mailaddr && !alert_cmd && !dosyslog) { + pr_err("No mail address or alert command - not monitoring.\n"); + return 1; + } ++ ++ if (c->verbose) { ++ pr_err("Monitor is started with delay %ds\n", c->delay); ++ if (mailaddr) ++ pr_err("Monitor using email address %s\n", mailaddr); ++ if (alert_cmd) ++ pr_err("Monitor using program %s\n", alert_cmd); ++ } ++ + info.alert_cmd = alert_cmd; + info.mailaddr = mailaddr; + info.mailfrom = mailfrom; +-- +2.31.1 + diff --git a/0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch b/0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch new file mode 100644 index 0000000..a5e9351 --- /dev/null +++ b/0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch @@ -0,0 +1,73 @@ +From 626bc45396c4959f2c4685c2faa7c4f553f4efdf Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Mon, 13 Jun 2022 11:59:34 +0200 +Subject: [PATCH 18/52] Fix possible NULL ptr dereferences and memory leaks + +In Assemble there was a NULL check for sra variable, +which effectively didn't stop the execution in every case. +That might have resulted in a NULL pointer dereference. + +Also in super-ddf, mu variable was set to NULL for some condition, +and then immidiately dereferenced. +Additionally some memory wasn't freed as well. + +Signed-off-by: Mateusz Grzonka +Signed-off-by: Jes Sorensen +--- + Assemble.c | 7 ++++++- + super-ddf.c | 9 +++++++-- + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/Assemble.c b/Assemble.c +index 9eac9ce0..4b213560 100644 +--- a/Assemble.c ++++ b/Assemble.c +@@ -1982,7 +1982,12 @@ int assemble_container_content(struct supertype *st, int mdfd, + } + + sra = sysfs_read(mdfd, NULL, GET_VERSION|GET_DEVS); +- if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0) { ++ if (sra == NULL) { ++ pr_err("Failed to read sysfs parameters\n"); ++ return 1; ++ } ++ ++ if (strcmp(sra->text_version, content->text_version) != 0) { + if (content->array.major_version == -1 && + content->array.minor_version == -2 && + c->readonly && +diff --git a/super-ddf.c b/super-ddf.c +index 8cda23a7..abbc8b09 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -5125,13 +5125,16 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a, + */ + vc = find_vdcr(ddf, a->info.container_member, rv->disk.raid_disk, + &n_bvd, &vcl); +- if (vc == NULL) ++ if (vc == NULL) { ++ free(rv); + return NULL; ++ } + + mu = xmalloc(sizeof(*mu)); + if (posix_memalign(&mu->space, 512, sizeof(struct vcl)) != 0) { + free(mu); +- mu = NULL; ++ free(rv); ++ return NULL; + } + + mu->len = ddf->conf_rec_len * 512 * vcl->conf.sec_elmnt_count; +@@ -5161,6 +5164,8 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a, + pr_err("BUG: can't find disk %d (%d/%d)\n", + di->disk.raid_disk, + di->disk.major, di->disk.minor); ++ free(mu); ++ free(rv); + return NULL; + } + vc->phys_refnum[i_prim] = ddf->phys->entries[dl->pdnum].refnum; +-- +2.31.1 + diff --git a/0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch b/0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch new file mode 100644 index 0000000..87b6db6 --- /dev/null +++ b/0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch @@ -0,0 +1,301 @@ +From 756a15f32338fdf0c562678694bc8991ad6afb90 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Mon, 13 Jun 2022 12:00:09 +0200 +Subject: [PATCH 19/52] imsm: Remove possibility for get_imsm_dev to return + NULL + +Returning NULL from get_imsm_dev or __get_imsm_dev will cause segfault. +Guarantee that it never happens. + +Signed-off-by: Mateusz Grzonka +Signed-off-by: Jes Sorensen +--- + super-intel.c | 153 +++++++++++++++++++++++++------------------------- + 1 file changed, 78 insertions(+), 75 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index ba3bd41f..3788feb9 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -851,6 +851,21 @@ static struct disk_info *get_disk_info(struct imsm_update_create_array *update) + return inf; + } + ++/** ++ * __get_imsm_dev() - Get device with index from imsm_super. ++ * @mpb: &imsm_super pointer, not NULL. ++ * @index: Device index. ++ * ++ * Function works as non-NULL, aborting in such a case, ++ * when NULL would be returned. ++ * ++ * Device index should be in range 0 up to num_raid_devs. ++ * Function assumes the index was already verified. ++ * Index must be valid, otherwise abort() is called. ++ * ++ * Return: Pointer to corresponding imsm_dev. ++ * ++ */ + static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index) + { + int offset; +@@ -858,30 +873,47 @@ static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index) + void *_mpb = mpb; + + if (index >= mpb->num_raid_devs) +- return NULL; ++ goto error; + + /* devices start after all disks */ + offset = ((void *) &mpb->disk[mpb->num_disks]) - _mpb; + +- for (i = 0; i <= index; i++) ++ for (i = 0; i <= index; i++, offset += sizeof_imsm_dev(_mpb + offset, 0)) + if (i == index) + return _mpb + offset; +- else +- offset += sizeof_imsm_dev(_mpb + offset, 0); +- +- return NULL; ++error: ++ pr_err("cannot find imsm_dev with index %u in imsm_super\n", index); ++ abort(); + } + ++/** ++ * get_imsm_dev() - Get device with index from intel_super. ++ * @super: &intel_super pointer, not NULL. ++ * @index: Device index. ++ * ++ * Function works as non-NULL, aborting in such a case, ++ * when NULL would be returned. ++ * ++ * Device index should be in range 0 up to num_raid_devs. ++ * Function assumes the index was already verified. ++ * Index must be valid, otherwise abort() is called. ++ * ++ * Return: Pointer to corresponding imsm_dev. ++ * ++ */ + static struct imsm_dev *get_imsm_dev(struct intel_super *super, __u8 index) + { + struct intel_dev *dv; + + if (index >= super->anchor->num_raid_devs) +- return NULL; ++ goto error; ++ + for (dv = super->devlist; dv; dv = dv->next) + if (dv->index == index) + return dv->dev; +- return NULL; ++error: ++ pr_err("cannot find imsm_dev with index %u in intel_super\n", index); ++ abort(); + } + + static inline unsigned long long __le48_to_cpu(const struct bbm_log_block_addr +@@ -4364,8 +4396,7 @@ int check_mpb_migr_compatibility(struct intel_super *super) + for (i = 0; i < super->anchor->num_raid_devs; i++) { + struct imsm_dev *dev_iter = __get_imsm_dev(super->anchor, i); + +- if (dev_iter && +- dev_iter->vol.migr_state == 1 && ++ if (dev_iter->vol.migr_state == 1 && + dev_iter->vol.migr_type == MIGR_GEN_MIGR) { + /* This device is migrating */ + map0 = get_imsm_map(dev_iter, MAP_0); +@@ -4514,8 +4545,6 @@ static void clear_hi(struct intel_super *super) + } + 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) +@@ -5836,7 +5865,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, + struct imsm_dev *_dev = __get_imsm_dev(mpb, 0); + + _disk = __get_imsm_disk(mpb, dl->index); +- if (!_dev || !_disk) { ++ if (!_disk) { + pr_err("BUG mpb setup error\n"); + return 1; + } +@@ -6171,10 +6200,10 @@ static int write_super_imsm(struct supertype *st, int doclose) + for (i = 0; i < mpb->num_raid_devs; i++) { + struct imsm_dev *dev = __get_imsm_dev(mpb, i); + struct imsm_dev *dev2 = get_imsm_dev(super, i); +- if (dev && dev2) { +- imsm_copy_dev(dev, dev2); +- mpb_size += sizeof_imsm_dev(dev, 0); +- } ++ ++ imsm_copy_dev(dev, dev2); ++ mpb_size += sizeof_imsm_dev(dev, 0); ++ + if (is_gen_migration(dev2)) + clear_migration_record = 0; + } +@@ -9033,29 +9062,26 @@ static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed) + __u8 state; + + dev2 = get_imsm_dev(cont->sb, dev_idx); +- if (dev2) { +- state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0); +- if (state == IMSM_T_STATE_FAILED) { +- map = get_imsm_map(dev2, MAP_0); +- if (!map) +- return 1; +- for (slot = 0; slot < map->num_members; slot++) { +- /* +- * Check if failed disks are deleted from intel +- * disk list or are marked to be deleted +- */ +- idx = get_imsm_disk_idx(dev2, slot, MAP_X); +- idisk = get_imsm_dl_disk(cont->sb, idx); +- /* +- * Do not rebuild the array if failed disks +- * from failed sub-array are not removed from +- * container. +- */ +- if (idisk && +- is_failed(&idisk->disk) && +- (idisk->action != DISK_REMOVE)) +- return 0; +- } ++ ++ state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0); ++ if (state == IMSM_T_STATE_FAILED) { ++ map = get_imsm_map(dev2, MAP_0); ++ for (slot = 0; slot < map->num_members; slot++) { ++ /* ++ * Check if failed disks are deleted from intel ++ * disk list or are marked to be deleted ++ */ ++ idx = get_imsm_disk_idx(dev2, slot, MAP_X); ++ idisk = get_imsm_dl_disk(cont->sb, idx); ++ /* ++ * Do not rebuild the array if failed disks ++ * from failed sub-array are not removed from ++ * container. ++ */ ++ if (idisk && ++ is_failed(&idisk->disk) && ++ (idisk->action != DISK_REMOVE)) ++ return 0; + } + } + return 1; +@@ -10089,7 +10115,6 @@ static void imsm_process_update(struct supertype *st, + int victim = u->dev_idx; + struct active_array *a; + struct intel_dev **dp; +- struct imsm_dev *dev; + + /* sanity check that we are not affecting the uuid of + * active arrays, or deleting an active array +@@ -10105,8 +10130,7 @@ static void imsm_process_update(struct supertype *st, + * is active in the container, so checking + * mpb->num_raid_devs is just extra paranoia + */ +- dev = get_imsm_dev(super, victim); +- if (a || !dev || mpb->num_raid_devs == 1) { ++ if (a || mpb->num_raid_devs == 1 || victim >= super->anchor->num_raid_devs) { + dprintf("failed to delete subarray-%d\n", victim); + break; + } +@@ -10140,7 +10164,7 @@ static void imsm_process_update(struct supertype *st, + if (a->info.container_member == target) + break; + dev = get_imsm_dev(super, u->dev_idx); +- if (a || !dev || !check_name(super, name, 1)) { ++ if (a || !check_name(super, name, 1)) { + dprintf("failed to rename subarray-%d\n", target); + break; + } +@@ -10169,10 +10193,6 @@ static void imsm_process_update(struct supertype *st, + struct imsm_update_rwh_policy *u = (void *)update->buf; + int target = u->dev_idx; + struct imsm_dev *dev = get_imsm_dev(super, target); +- if (!dev) { +- dprintf("could not find subarray-%d\n", target); +- break; +- } + + if (dev->rwh_policy != u->new_policy) { + dev->rwh_policy = u->new_policy; +@@ -11397,8 +11417,10 @@ static int imsm_create_metadata_update_for_migration( + { + struct intel_super *super = st->sb; + int update_memory_size; ++ int current_chunk_size; + struct imsm_update_reshape_migration *u; +- struct imsm_dev *dev; ++ struct imsm_dev *dev = get_imsm_dev(super, super->current_vol); ++ struct imsm_map *map = get_imsm_map(dev, MAP_0); + int previous_level = -1; + + dprintf("(enter) New Level = %i\n", geo->level); +@@ -11415,23 +11437,15 @@ static int imsm_create_metadata_update_for_migration( + u->new_disks[0] = -1; + u->new_chunksize = -1; + +- dev = get_imsm_dev(super, u->subdev); +- if (dev) { +- struct imsm_map *map; ++ current_chunk_size = __le16_to_cpu(map->blocks_per_strip) / 2; + +- map = get_imsm_map(dev, MAP_0); +- if (map) { +- int current_chunk_size = +- __le16_to_cpu(map->blocks_per_strip) / 2; +- +- if (geo->chunksize != current_chunk_size) { +- u->new_chunksize = geo->chunksize / 1024; +- dprintf("imsm: chunk size change from %i to %i\n", +- current_chunk_size, u->new_chunksize); +- } +- previous_level = map->raid_level; +- } ++ if (geo->chunksize != current_chunk_size) { ++ u->new_chunksize = geo->chunksize / 1024; ++ dprintf("imsm: chunk size change from %i to %i\n", ++ current_chunk_size, u->new_chunksize); + } ++ previous_level = map->raid_level; ++ + if (geo->level == 5 && previous_level == 0) { + struct mdinfo *spares = NULL; + +@@ -12519,9 +12533,6 @@ static int validate_internal_bitmap_imsm(struct supertype *st) + unsigned long long offset; + struct dl *d; + +- if (!dev) +- return -1; +- + if (dev->rwh_policy != RWH_BITMAP) + return 0; + +@@ -12567,16 +12578,8 @@ static int add_internal_bitmap_imsm(struct supertype *st, int *chunkp, + return -1; + + dev = get_imsm_dev(super, vol_idx); +- +- if (!dev) { +- dprintf("cannot find the device for volume index %d\n", +- vol_idx); +- return -1; +- } + dev->rwh_policy = RWH_BITMAP; +- + *chunkp = calculate_bitmap_chunksize(st, dev); +- + return 0; + } + +-- +2.31.1 + diff --git a/0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch b/0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch new file mode 100644 index 0000000..107ac28 --- /dev/null +++ b/0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch @@ -0,0 +1,85 @@ +From 190dc029b141c423e724566cbed5d5afbb10b05a Mon Sep 17 00:00:00 2001 +From: Nigel Croxon +Date: Mon, 18 Apr 2022 13:44:23 -0400 +Subject: [PATCH 20/52] Revert "mdadm: fix coredump of mdadm --monitor -r" + +This reverts commit 546047688e1c64638f462147c755b58119cabdc8. + +The change from commit mdadm: fix coredump of mdadm +--monitor -r broke the printing of the return message when +passing -r to mdadm --manage, the removal of a device from +an array. + +If the current code reverts this commit, both issues are +still fixed. + +The original problem reported that the fix tried to address +was: The --monitor -r option requires a parameter, +otherwise a null pointer will be manipulated when +converting to integer data, and a core dump will appear. + +The original problem was really fixed with: +60815698c0a Refactor parse_num and use it to parse optarg. +Which added a check for NULL in 'optarg' before moving it +to the 'increments' variable. + +New issue: When trying to remove a device using the short +argument -r, instead of the long argument --remove, the +output is empty. The problem started when commit +546047688e1c was added. + +Steps to Reproduce: +1. create/assemble /dev/md0 device +2. mdadm --manage /dev/md0 -r /dev/vdxx + +Actual results: +Nothing, empty output, nothing happens, the device is still +connected to the array. + +The output should have stated "mdadm: hot remove failed +for /dev/vdxx: Device or resource busy", if the device was +still active. Or it should remove the device and print +a message: + +mdadm: set /dev/vdd faulty in /dev/md0 +mdadm: hot removed /dev/vdd from /dev/md0 + +The following commit should be reverted as it breaks +mdadm --manage -r. + +commit 546047688e1c64638f462147c755b58119cabdc8 +Author: Wu Guanghao +Date: Mon Aug 16 15:24:51 2021 +0800 +mdadm: fix coredump of mdadm --monitor -r + +-Nigel + +Signed-off-by: Nigel Croxon +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + ReadMe.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ReadMe.c b/ReadMe.c +index 8f873c48..bec1be9a 100644 +--- a/ReadMe.c ++++ b/ReadMe.c +@@ -81,11 +81,11 @@ char Version[] = "mdadm - v" VERSION " - " VERS_DATE EXTRAVERSION "\n"; + * found, it is started. + */ + +-char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:r:n:x:u:c:d:z:U:N:safRSow1tye:k"; ++char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:"; + char short_bitmap_options[]= +- "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sarfRSow1tye:k:"; ++ "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:"; + char short_bitmap_auto_options[]= +- "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:"; ++ "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:"; + + struct option long_options[] = { + {"manage", 0, 0, ManageOpt}, +-- +2.31.1 + diff --git a/0021-util-replace-ioctl-use-with-function.patch b/0021-util-replace-ioctl-use-with-function.patch new file mode 100644 index 0000000..3833674 --- /dev/null +++ b/0021-util-replace-ioctl-use-with-function.patch @@ -0,0 +1,31 @@ +From 953cc7e5a485a91ddec7312c7a5d7779749fad5f Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Tue, 21 Jun 2022 00:10:39 +0800 +Subject: [PATCH 21/52] util: replace ioctl use with function + +Replace using of ioctl calling to get md array info with +special function prepared to it. + +Signed-off-by: Kinga Tanska +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util.c b/util.c +index cc94f96e..38f0420e 100644 +--- a/util.c ++++ b/util.c +@@ -267,7 +267,7 @@ int md_array_active(int fd) + * GET_ARRAY_INFO doesn't provide access to the proper state + * information, so fallback to a basic check for raid_disks != 0 + */ +- ret = ioctl(fd, GET_ARRAY_INFO, &array); ++ ret = md_get_array_info(fd, &array); + } + + return !ret; +-- +2.31.1 + diff --git a/0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch b/0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch new file mode 100644 index 0000000..360ec6e --- /dev/null +++ b/0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch @@ -0,0 +1,110 @@ +From 63902857b98c37c8ac4b837bb01d006b327a4532 Mon Sep 17 00:00:00 2001 +From: Heming Zhao +Date: Tue, 21 Jun 2022 00:10:40 +0800 +Subject: [PATCH 22/52] mdadm/super1: restore commit 45a87c2f31335 to fix + clustered slot issue + +Commit 9d67f6496c71 ("mdadm:check the nodes when operate clustered +array") modified assignment logic for st->nodes in write_bitmap1(), +which introduced bitmap slot issue: + +load_super1 didn't set up supertype.nodes, which made spare disk only +have one slot info. Then it triggered kernel md_bitmap_load_sb to get +wrong bitmap slot data. + +For fixing this issue, there are two methods: + +1> revert the related code of commit 9d67f6496c71. and restore the code + from former commit 45a87c2f31335 ("super1: add more checks for + NodeNumUpdate option"). + st->nodes value would be 0 & 1 under current code logic. i.e. + When adding a spare disk, there is no place to init st->nodes, and + the value is ZERO. + +2> keep 9d67f6496c71, add additional ->nodes handling in load_super1(), + let load_super1 to set st->nodes when bitmap is BITMAP_MAJOR_CLUSTERED. + Under current mdadm code logic, load_super1 will be called many + times, any new code in load_super1 will cost mdadm running more time. + And more reason is I prefer as much as possible to limit clustered + code spreading in every corner. + +So I used method <1> to fix this issue. + +How to trigger: + +dd if=/dev/zero bs=1M count=1 oflag=direct of=/dev/sda +dd if=/dev/zero bs=1M count=1 oflag=direct of=/dev/sdb +dd if=/dev/zero bs=1M count=1 oflag=direct of=/dev/sdc +mdadm -C /dev/md0 -b clustered -e 1.2 -n 2 -l mirror /dev/sda /dev/sdb +mdadm -a /dev/md0 /dev/sdc +mdadm /dev/md0 --fail /dev/sda +mdadm /dev/md0 --remove /dev/sda +mdadm -Ss +mdadm -A /dev/md0 /dev/sdb /dev/sdc + +the output of current "mdadm -X /dev/sdc": +(there should be (by default) 4 slot info for correct output) +``` + Filename : /dev/sdc + Magic : 6d746962 + Version : 5 + UUID : a74642f8:a6b1fba8:58e1f8db:cfe7b082 + Events : 29 + Events Cleared : 0 + State : OK + Chunksize : 64 MB + Daemon : 5s flush period + Write Mode : Normal + Sync Size : 306176 (299.00 MiB 313.52 MB) + Bitmap : 5 bits (chunks), 5 dirty (100.0%) +``` + +And mdadm later operations will trigger kernel output error message: +(triggered by "mdadm -A /dev/md0 /dev/sdb /dev/sdc") +``` +kernel: md0: invalid bitmap file superblock: bad magic +kernel: md_bitmap_copy_from_slot can't get bitmap from slot 1 +kernel: md-cluster: Could not gather bitmaps from slot 1 +kernel: md0: invalid bitmap file superblock: bad magic +kernel: md_bitmap_copy_from_slot can't get bitmap from slot 2 +kernel: md-cluster: Could not gather bitmaps from slot 2 +kernel: md0: invalid bitmap file superblock: bad magic +kernel: md_bitmap_copy_from_slot can't get bitmap from slot 3 +kernel: md-cluster: Could not gather bitmaps from slot 3 +kernel: md-cluster: failed to gather all resyn infos +kernel: md0: detected capacity change from 0 to 612352 +``` + +Acked-by: Coly Li +Signed-off-by: Heming Zhao +Signed-off-by: Jes Sorensen +--- + super1.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/super1.c b/super1.c +index e3e2f954..3a0c69fd 100644 +--- a/super1.c ++++ b/super1.c +@@ -2674,7 +2674,17 @@ static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update + } + + if (bms->version == BITMAP_MAJOR_CLUSTERED) { +- if (__cpu_to_le32(st->nodes) < bms->nodes) { ++ if (st->nodes == 1) { ++ /* the parameter for nodes is not valid */ ++ pr_err("Warning: cluster-md at least needs two nodes\n"); ++ return -EINVAL; ++ } else if (st->nodes == 0) { ++ /* ++ * parameter "--nodes" is not specified, (eg, add a disk to ++ * clustered raid) ++ */ ++ break; ++ } else if (__cpu_to_le32(st->nodes) < bms->nodes) { + /* + * Since the nodes num is not increased, no + * need to check the space enough or not, +-- +2.31.1 + diff --git a/0023-imsm-introduce-get_disk_slot_in_dev.patch b/0023-imsm-introduce-get_disk_slot_in_dev.patch new file mode 100644 index 0000000..d979cc5 --- /dev/null +++ b/0023-imsm-introduce-get_disk_slot_in_dev.patch @@ -0,0 +1,122 @@ +From 76c152ca9851e9fcdf52e8f6e7e6c09b936bdd14 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Tue, 21 Jun 2022 00:10:41 +0800 +Subject: [PATCH 23/52] imsm: introduce get_disk_slot_in_dev() + +The routine was added to remove unnecessary get_imsm_dev() and +get_imsm_map() calls, used only to determine disk slot. + +Additionally, enum for IMSM return statues was added for further usage. + +Signed-off-by: Mariusz Tkaczyk +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + super-intel.c | 47 ++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 36 insertions(+), 11 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index 3788feb9..cd1f1e3d 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -366,6 +366,18 @@ struct migr_record { + }; + ASSERT_SIZE(migr_record, 128) + ++/** ++ * enum imsm_status - internal IMSM return values representation. ++ * @STATUS_OK: function succeeded. ++ * @STATUS_ERROR: General error ocurred (not specified). ++ * ++ * Typedefed to imsm_status_t. ++ */ ++typedef enum imsm_status { ++ IMSM_STATUS_ERROR = -1, ++ IMSM_STATUS_OK = 0, ++} imsm_status_t; ++ + struct md_list { + /* usage marker: + * 1: load metadata +@@ -1183,7 +1195,7 @@ static void set_imsm_ord_tbl_ent(struct imsm_map *map, int slot, __u32 ord) + map->disk_ord_tbl[slot] = __cpu_to_le32(ord); + } + +-static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx) ++static int get_imsm_disk_slot(struct imsm_map *map, const unsigned int idx) + { + int slot; + __u32 ord; +@@ -1194,7 +1206,7 @@ static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx) + return slot; + } + +- return -1; ++ return IMSM_STATUS_ERROR; + } + + static int get_imsm_raid_level(struct imsm_map *map) +@@ -1209,6 +1221,23 @@ static int get_imsm_raid_level(struct imsm_map *map) + return map->raid_level; + } + ++/** ++ * get_disk_slot_in_dev() - retrieve disk slot from &imsm_dev. ++ * @super: &intel_super pointer, not NULL. ++ * @dev_idx: imsm device index. ++ * @idx: disk index. ++ * ++ * Return: Slot on success, IMSM_STATUS_ERROR otherwise. ++ */ ++static int get_disk_slot_in_dev(struct intel_super *super, const __u8 dev_idx, ++ const unsigned int idx) ++{ ++ struct imsm_dev *dev = get_imsm_dev(super, dev_idx); ++ struct imsm_map *map = get_imsm_map(dev, MAP_0); ++ ++ return get_imsm_disk_slot(map, idx); ++} ++ + static int cmp_extent(const void *av, const void *bv) + { + const struct extent *a = av; +@@ -1225,13 +1254,9 @@ static int count_memberships(struct dl *dl, struct intel_super *super) + int memberships = 0; + int i; + +- 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); +- +- if (get_imsm_disk_slot(map, dl->index) >= 0) ++ for (i = 0; i < super->anchor->num_raid_devs; i++) ++ if (get_disk_slot_in_dev(super, i, dl->index) >= 0) + memberships++; +- } + + return memberships; + } +@@ -1941,6 +1966,7 @@ void examine_migr_rec_imsm(struct intel_super *super) + + /* first map under migration */ + map = get_imsm_map(dev, MAP_0); ++ + if (map) + slot = get_imsm_disk_slot(map, super->disks->index); + if (map == NULL || slot > 1 || slot < 0) { +@@ -9655,10 +9681,9 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u, + /* count arrays using the victim in the metadata */ + found = 0; + for (a = active_array; a ; a = a->next) { +- dev = get_imsm_dev(super, a->info.container_member); +- map = get_imsm_map(dev, MAP_0); ++ int dev_idx = a->info.container_member; + +- if (get_imsm_disk_slot(map, victim) >= 0) ++ if (get_disk_slot_in_dev(super, dev_idx, victim) >= 0) + found++; + } + +-- +2.31.1 + diff --git a/0024-imsm-use-same-slot-across-container.patch b/0024-imsm-use-same-slot-across-container.patch new file mode 100644 index 0000000..31348e4 --- /dev/null +++ b/0024-imsm-use-same-slot-across-container.patch @@ -0,0 +1,252 @@ +From 6d4d9ab295de165e57b5c30e044028dbffb8f297 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Tue, 21 Jun 2022 00:10:42 +0800 +Subject: [PATCH 24/52] imsm: use same slot across container + +Autolayout relies on drives order on super->disks list, but +it is not quaranted by readdir() in sysfs_read(). As a result +drive could be put in different slot in second volume. + +Make it consistent by reffering to first volume, if exists. + +Use enum imsm_status to unify error handling. + +Signed-off-by: Mariusz Tkaczyk +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + super-intel.c | 169 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 108 insertions(+), 61 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index cd1f1e3d..deef7c87 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -7522,11 +7522,27 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, + return 1; + } + +-static int imsm_get_free_size(struct supertype *st, int raiddisks, +- unsigned long long size, int chunk, +- unsigned long long *freesize) ++/** ++ * imsm_get_free_size() - get the biggest, common free space from members. ++ * @super: &intel_super pointer, not NULL. ++ * @raiddisks: number of raid disks. ++ * @size: requested size, could be 0 (means max size). ++ * @chunk: requested chunk. ++ * @freesize: pointer for returned size value. ++ * ++ * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR. ++ * ++ * @freesize is set to meaningful value, this can be @size, or calculated ++ * max free size. ++ * super->create_offset value is modified and set appropriately in ++ * merge_extends() for further creation. ++ */ ++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) + { +- struct intel_super *super = st->sb; + struct imsm_super *mpb = super->anchor; + struct dl *dl; + int i; +@@ -7570,12 +7586,10 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks, + /* chunk is in K */ + minsize = chunk * 2; + +- if (cnt < raiddisks || +- (super->orom && used && used != raiddisks) || +- maxsize < minsize || +- maxsize == 0) { ++ if (cnt < raiddisks || (super->orom && used && used != raiddisks) || ++ maxsize < minsize || maxsize == 0) { + pr_err("not enough devices with space to create array.\n"); +- return 0; /* No enough free spaces large enough */ ++ return IMSM_STATUS_ERROR; + } + + if (size == 0) { +@@ -7588,37 +7602,69 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks, + } + if (mpb->num_raid_devs > 0 && size && size != maxsize) + pr_err("attempting to create a second volume with size less then remaining space.\n"); +- cnt = 0; +- for (dl = super->disks; dl; dl = dl->next) +- if (dl->e) +- dl->raiddisk = cnt++; +- + *freesize = size; + + dprintf("imsm: imsm_get_free_size() returns : %llu\n", size); + +- return 1; ++ return IMSM_STATUS_OK; + } + +-static int reserve_space(struct supertype *st, int raiddisks, +- unsigned long long size, int chunk, +- unsigned long long *freesize) ++/** ++ * autolayout_imsm() - automatically layout a new volume. ++ * @super: &intel_super pointer, not NULL. ++ * @raiddisks: number of raid disks. ++ * @size: requested size, could be 0 (means max size). ++ * @chunk: requested chunk. ++ * @freesize: pointer for returned size value. ++ * ++ * We are being asked to automatically layout a new volume based on the current ++ * contents of the container. If the parameters can be satisfied autolayout_imsm ++ * will record the disks, start offset, and will return size of the volume to ++ * be created. See imsm_get_free_size() for details. ++ * add_to_super() and getinfo_super() detect when autolayout is in progress. ++ * If first volume exists, slots are set consistently to it. ++ * ++ * Return: &IMSM_STATUS_OK on success, &IMSM_STATUS_ERROR otherwise. ++ * ++ * Disks are marked for creation via dl->raiddisk. ++ */ ++static imsm_status_t autolayout_imsm(struct intel_super *super, ++ const int raiddisks, ++ unsigned long long size, const int chunk, ++ unsigned long long *freesize) + { +- struct intel_super *super = st->sb; +- struct dl *dl; +- int cnt; +- int rv = 0; ++ int curr_slot = 0; ++ struct dl *disk; ++ int vol_cnt = super->anchor->num_raid_devs; ++ imsm_status_t rv; + +- 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; ++ rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize); ++ if (rv != IMSM_STATUS_OK) ++ return IMSM_STATUS_ERROR; ++ ++ for (disk = super->disks; disk; disk = disk->next) { ++ if (!disk->e) ++ continue; ++ ++ if (curr_slot == raiddisks) ++ break; ++ ++ if (vol_cnt == 0) { ++ disk->raiddisk = curr_slot; ++ } else { ++ int _slot = get_disk_slot_in_dev(super, 0, disk->index); ++ ++ if (_slot == -1) { ++ pr_err("Disk %s is not used in first volume, aborting\n", ++ disk->devname); ++ return IMSM_STATUS_ERROR; ++ } ++ disk->raiddisk = _slot; ++ } ++ curr_slot++; + } + +- return rv; ++ return IMSM_STATUS_OK; + } + + static int validate_geometry_imsm(struct supertype *st, int level, int layout, +@@ -7654,35 +7700,35 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout, + } + + if (!dev) { +- if (st->sb) { +- struct intel_super *super = st->sb; +- if (!validate_geometry_imsm_orom(st->sb, level, layout, +- raiddisks, chunk, size, +- verbose)) ++ struct intel_super *super = st->sb; ++ ++ /* ++ * Autolayout mode, st->sb and freesize must be set. ++ */ ++ if (!super || !freesize) { ++ pr_vrb("freesize and superblock must be set for autolayout, aborting\n"); ++ return 1; ++ } ++ ++ if (!validate_geometry_imsm_orom(st->sb, level, layout, ++ raiddisks, chunk, size, ++ verbose)) ++ return 0; ++ ++ if (super->orom) { ++ imsm_status_t rv; ++ int count = count_volumes(super->hba, 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; +- /* we are being asked to automatically layout a +- * new volume based on the current contents of +- * the container. If the the parameters can be +- * satisfied reserve_space will record the disks, +- * start offset, and size of the volume to be +- * created. add_to_super and getinfo_super +- * detect when autolayout is in progress. +- */ +- /* assuming that freesize is always given when array is +- created */ +- if (super->orom && freesize) { +- int count; +- count = count_volumes(super->hba, +- 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, freesize); ++ ++ rv = autolayout_imsm(super, raiddisks, size, *chunk, ++ freesize); ++ if (rv != IMSM_STATUS_OK) ++ return 0; + } + return 1; + } +@@ -11538,7 +11584,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, + unsigned long long current_size; + unsigned long long free_size; + unsigned long long max_size; +- int rv; ++ imsm_status_t rv; + + getinfo_super_imsm_volume(st, &info, NULL); + if (geo->level != info.array.level && geo->level >= 0 && +@@ -11657,9 +11703,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, + } + /* check the maximum available size + */ +- rv = imsm_get_free_size(st, dev->vol.map->num_members, +- 0, chunk, &free_size); +- if (rv == 0) ++ rv = imsm_get_free_size(super, dev->vol.map->num_members, ++ 0, chunk, &free_size); ++ ++ if (rv != IMSM_STATUS_OK) + /* Cannot find maximum available space + */ + max_size = 0; +-- +2.31.1 + diff --git a/0025-imsm-block-changing-slots-during-creation.patch b/0025-imsm-block-changing-slots-during-creation.patch new file mode 100644 index 0000000..6de11e1 --- /dev/null +++ b/0025-imsm-block-changing-slots-during-creation.patch @@ -0,0 +1,122 @@ +From 9a7df595bbe360132cb37c8b39aa1fd9ac24b43f Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Tue, 21 Jun 2022 00:10:43 +0800 +Subject: [PATCH 25/52] imsm: block changing slots during creation + +If user specifies drives for array creation, then slot order across +volumes is not preserved. +Ideally, it should be checked in validate_geometry() but it is not +possible in current implementation (order is determined later). +Add verification in add_to_super_imsm_volume() and throw error if +mismatch is detected. +IMSM allows to use only same members within container. +This is not hardware dependency but metadata limitation. +Therefore, 09-imsm-overlap test is removed. Testing it is pointless. +After this patch, creation in this scenario is blocked. Offset +verification is covered in other tests. + +Signed-off-by: Mariusz Tkaczyk +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + super-intel.c | 33 ++++++++++++++++++++++----------- + tests/09imsm-overlap | 28 ---------------------------- + 2 files changed, 22 insertions(+), 39 deletions(-) + delete mode 100644 tests/09imsm-overlap + +diff --git a/super-intel.c b/super-intel.c +index deef7c87..8ffe485c 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -5789,6 +5789,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, + struct imsm_map *map; + struct dl *dl, *df; + int slot; ++ int autolayout = 0; ++ ++ if (!is_fd_valid(fd)) ++ autolayout = 1; + + dev = get_imsm_dev(super, super->current_vol); + map = get_imsm_map(dev, MAP_0); +@@ -5799,25 +5803,32 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk, + return 1; + } + +- if (!is_fd_valid(fd)) { +- /* we're doing autolayout so grab the pre-marked (in +- * validate_geometry) raid_disk +- */ +- for (dl = super->disks; dl; dl = dl->next) ++ for (dl = super->disks; dl ; dl = dl->next) { ++ if (autolayout) { + if (dl->raiddisk == dk->raid_disk) + break; +- } else { +- for (dl = super->disks; dl ; dl = dl->next) +- if (dl->major == dk->major && +- dl->minor == dk->minor) +- break; ++ } else if (dl->major == dk->major && dl->minor == dk->minor) ++ break; + } + + if (!dl) { +- pr_err("%s is not a member of the same container\n", devname); ++ if (!autolayout) ++ pr_err("%s is not a member of the same container.\n", ++ devname); + return 1; + } + ++ if (!autolayout && super->current_vol > 0) { ++ int _slot = get_disk_slot_in_dev(super, 0, dl->index); ++ ++ if (_slot != dk->raid_disk) { ++ pr_err("Member %s is in %d slot for the first volume, but is in %d slot for a new volume.\n", ++ dl->devname, _slot, dk->raid_disk); ++ pr_err("Raid members are in different order than for the first volume, aborting.\n"); ++ return 1; ++ } ++ } ++ + if (mpb->num_disks == 0) + if (!get_dev_sector_size(dl->fd, dl->devname, + &super->sector_size)) +diff --git a/tests/09imsm-overlap b/tests/09imsm-overlap +deleted file mode 100644 +index ff5d2093..00000000 +--- a/tests/09imsm-overlap ++++ /dev/null +@@ -1,28 +0,0 @@ +- +-. tests/env-imsm-template +- +-# create raid arrays with varying degress of overlap +-mdadm -CR $container -e imsm -n 6 $dev0 $dev1 $dev2 $dev3 $dev4 $dev5 +-imsm_check container 6 +- +-size=1024 +-level=1 +-num_disks=2 +-mdadm -CR $member0 $dev0 $dev1 -n $num_disks -l $level -z $size +-mdadm -CR $member1 $dev1 $dev2 -n $num_disks -l $level -z $size +-mdadm -CR $member2 $dev2 $dev3 -n $num_disks -l $level -z $size +-mdadm -CR $member3 $dev3 $dev4 -n $num_disks -l $level -z $size +-mdadm -CR $member4 $dev4 $dev5 -n $num_disks -l $level -z $size +- +-udevadm settle +- +-offset=0 +-imsm_check member $member0 $num_disks $level $size 1024 $offset +-offset=$((offset+size+4096)) +-imsm_check member $member1 $num_disks $level $size 1024 $offset +-offset=$((offset+size+4096)) +-imsm_check member $member2 $num_disks $level $size 1024 $offset +-offset=$((offset+size+4096)) +-imsm_check member $member3 $num_disks $level $size 1024 $offset +-offset=$((offset+size+4096)) +-imsm_check member $member4 $num_disks $level $size 1024 $offset +-- +2.31.1 + diff --git a/0026-mdadm-block-update-ppl-for-non-raid456-levels.patch b/0026-mdadm-block-update-ppl-for-non-raid456-levels.patch new file mode 100644 index 0000000..5e9e87f --- /dev/null +++ b/0026-mdadm-block-update-ppl-for-non-raid456-levels.patch @@ -0,0 +1,177 @@ +From 70f1ff4291b0388adca1f4c91918ce1175e8b360 Mon Sep 17 00:00:00 2001 +From: Lukasz Florczak +Date: Wed, 15 Jun 2022 14:28:39 +0200 +Subject: [PATCH 26/52] mdadm: block update=ppl for non raid456 levels + +Option ppl should be used only for raid levels 4, 5 and 6. Cancel update +for other levels. + +Applied globally for imsm and ddf format. + +Additionally introduce is_level456() helper function. + +Signed-off-by: Lukasz Florczak +Signed-off-by: Jes Sorensen +--- + Assemble.c | 11 +++++------ + Grow.c | 2 +- + Manage.c | 14 ++++++++++++-- + mdadm.h | 11 +++++++++++ + super0.c | 2 +- + super1.c | 3 +-- + 6 files changed, 31 insertions(+), 12 deletions(-) + +diff --git a/Assemble.c b/Assemble.c +index 4b213560..6df6bfbc 100644 +--- a/Assemble.c ++++ b/Assemble.c +@@ -906,8 +906,7 @@ static int force_array(struct mdinfo *content, + * devices in RAID4 or last devices in RAID4/5/6. + */ + delta = devices[j].i.delta_disks; +- if (devices[j].i.array.level >= 4 && +- devices[j].i.array.level <= 6 && ++ if (is_level456(devices[j].i.array.level) && + i/2 >= content->array.raid_disks - delta) + /* OK */; + else if (devices[j].i.array.level == 4 && +@@ -1226,8 +1225,7 @@ static int start_array(int mdfd, + fprintf(stderr, ".\n"); + } + if (content->reshape_active && +- content->array.level >= 4 && +- content->array.level <= 6) { ++ is_level456(content->array.level)) { + /* might need to increase the size + * of the stripe cache - default is 256 + */ +@@ -1974,7 +1972,8 @@ int assemble_container_content(struct supertype *st, int mdfd, + int start_reshape; + char *avail; + int err; +- int is_raid456, is_clean, all_disks; ++ int is_clean, all_disks; ++ bool is_raid456; + + if (sysfs_init(content, mdfd, NULL)) { + pr_err("Unable to initialize sysfs\n"); +@@ -2107,7 +2106,7 @@ int assemble_container_content(struct supertype *st, int mdfd, + content->array.state |= 1; + } + +- is_raid456 = (content->array.level >= 4 && content->array.level <= 6); ++ is_raid456 = is_level456(content->array.level); + is_clean = content->array.state & 1; + + if (enough(content->array.level, content->array.raid_disks, +diff --git a/Grow.c b/Grow.c +index f6efbc48..8c520d42 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -2944,7 +2944,7 @@ static int impose_level(int fd, int level, char *devname, int verbose) + } + + md_get_array_info(fd, &array); +- if (level == 0 && (array.level >= 4 && array.level <= 6)) { ++ if (level == 0 && is_level456(array.level)) { + /* To convert to RAID0 we need to fail and + * remove any non-data devices. */ + int found = 0; +diff --git a/Manage.c b/Manage.c +index f789e0c1..e5e6abe4 100644 +--- a/Manage.c ++++ b/Manage.c +@@ -307,7 +307,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) + * - unfreeze reshape + * - wait on 'sync_completed' for that point to be reached. + */ +- if (mdi && (mdi->array.level >= 4 && mdi->array.level <= 6) && ++ if (mdi && is_level456(mdi->array.level) && + sysfs_attribute_available(mdi, NULL, "sync_action") && + sysfs_attribute_available(mdi, NULL, "reshape_direction") && + sysfs_get_str(mdi, NULL, "sync_action", buf, 20) > 0 && +@@ -1679,6 +1679,7 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident + { + struct supertype supertype, *st = &supertype; + int fd, rv = 2; ++ struct mdinfo *info = NULL; + + memset(st, 0, sizeof(*st)); + +@@ -1696,6 +1697,13 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident + if (mdmon_running(st->devnm)) + st->update_tail = &st->updates; + ++ info = st->ss->container_content(st, subarray); ++ ++ if (strncmp(update, "ppl", 3) == 0 && !is_level456(info->array.level)) { ++ pr_err("RWH policy ppl is supported only for raid4, raid5 and raid6.\n"); ++ goto free_super; ++ } ++ + rv = st->ss->update_subarray(st, subarray, update, ident); + + if (rv) { +@@ -1711,7 +1719,9 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident + pr_err("Updated subarray-%s name from %s, UUIDs may have changed\n", + subarray, dev); + +- free_super: ++free_super: ++ if (info) ++ free(info); + st->ss->free_super(st); + close(fd); + +diff --git a/mdadm.h b/mdadm.h +index d53df169..974415b9 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -796,6 +796,17 @@ static inline int is_fd_valid(int fd) + return (fd > -1); + } + ++/** ++ * is_level456() - check whether given level is between inclusive 4 and 6. ++ * @level: level to check. ++ * ++ * Return: true if condition is met, false otherwise ++ */ ++static inline bool is_level456(int level) ++{ ++ return (level >= 4 && level <= 6); ++} ++ + /** + * close_fd() - verify, close and unset file descriptor. + * @fd: pointer to file descriptor. +diff --git a/super0.c b/super0.c +index 61c9ec1d..37f595ed 100644 +--- a/super0.c ++++ b/super0.c +@@ -683,7 +683,7 @@ static int update_super0(struct supertype *st, struct mdinfo *info, + int parity = sb->level == 6 ? 2 : 1; + rv = 0; + +- if (sb->level >= 4 && sb->level <= 6 && ++ if (is_level456(sb->level) && + sb->reshape_position % ( + sb->new_chunk/512 * + (sb->raid_disks - sb->delta_disks - parity))) { +diff --git a/super1.c b/super1.c +index 3a0c69fd..71af860c 100644 +--- a/super1.c ++++ b/super1.c +@@ -1530,8 +1530,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info, + * So we reject a revert-reshape unless the + * alignment is good. + */ +- if (__le32_to_cpu(sb->level) >= 4 && +- __le32_to_cpu(sb->level) <= 6) { ++ if (is_level456(__le32_to_cpu(sb->level))) { + reshape_sectors = + __le64_to_cpu(sb->reshape_position); + reshape_chunk = __le32_to_cpu(sb->new_chunk); +-- +2.31.1 + diff --git a/0027-mdadm-Fix-array-size-mismatch-after-grow.patch b/0027-mdadm-Fix-array-size-mismatch-after-grow.patch new file mode 100644 index 0000000..cd3e93a --- /dev/null +++ b/0027-mdadm-Fix-array-size-mismatch-after-grow.patch @@ -0,0 +1,30 @@ +From 42e02e613fb0b4a2c0c0d984b9e6e2933875bb44 Mon Sep 17 00:00:00 2001 +From: Lukasz Florczak +Date: Fri, 22 Jul 2022 08:43:47 +0200 +Subject: [PATCH 27/52] mdadm: Fix array size mismatch after grow + +imsm_fix_size_mismatch() is invoked to fix the problem, but it couldn't +proceed due to migration check. This patch allows for intended behavior. + +Signed-off-by: Lukasz Florczak +Signed-off-by: Jes Sorensen +--- + super-intel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/super-intel.c b/super-intel.c +index 8ffe485c..76b947f5 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -11854,7 +11854,7 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index) + unsigned long long d_size = imsm_dev_size(dev); + int u_size; + +- if (calc_size == d_size || dev->vol.migr_type == MIGR_GEN_MIGR) ++ if (calc_size == d_size) + continue; + + /* There is a difference, confirm that imsm_dev_size is +-- +2.31.1 + diff --git a/0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch b/0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch new file mode 100644 index 0000000..4fde0c9 --- /dev/null +++ b/0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch @@ -0,0 +1,34 @@ +From 751757620afb25a4c02746bf8368a7b5f22352ec Mon Sep 17 00:00:00 2001 +From: Lukasz Florczak +Date: Fri, 22 Jul 2022 08:43:48 +0200 +Subject: [PATCH 28/52] mdadm: Remove dead code in imsm_fix_size_mismatch + +imsm_create_metadata_update_for_size_change() that returns u_size value +could return 0 in the past. As its behavior changed, and returned value +is always the size of imsm_update_size_change structure, check for +u_size is no longer needed. + +Signed-off-by: Lukasz Florczak +Signed-off-by: Jes Sorensen +--- + super-intel.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index 76b947f5..4ddfcf94 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -11869,10 +11869,6 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index) + geo.size = d_size; + u_size = imsm_create_metadata_update_for_size_change(st, &geo, + &update); +- if (u_size < 1) { +- dprintf("imsm: Cannot prepare size change update\n"); +- goto exit; +- } + imsm_update_metadata_locally(st, update, u_size); + if (st->update_tail) { + append_metadata_update(st, update, u_size); +-- +2.31.1 + diff --git a/0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch b/0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch new file mode 100644 index 0000000..c7d871d --- /dev/null +++ b/0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch @@ -0,0 +1,40 @@ +From c8d1c398505b62d9129a4e711f17e4469f4327ff Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Thu, 14 Jul 2022 09:02:10 +0200 +Subject: [PATCH 29/52] Monitor: use devname as char array instead of pointer + +Device name wasn't filled properly due to incorrect use of strcpy. +Strcpy was used twice. Firstly to fill devname with "/dev/md/" +and then to add chosen name. First strcpy result was overwritten by +second one (as a result instead of "/dev/md/" +was assigned). This commit changes this implementation to use snprintf +and devname with fixed size. + +Signed-off-by: Kinga Tanska +Signed-off-by: Jes Sorensen +--- + Monitor.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index 6ca1ebe5..a5b11ae2 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -190,9 +190,11 @@ int Monitor(struct mddev_dev *devlist, + if (mdlist->devname[0] == '/') + st->devname = xstrdup(mdlist->devname); + else { +- st->devname = xmalloc(8+strlen(mdlist->devname)+1); +- strcpy(strcpy(st->devname, "/dev/md/"), +- mdlist->devname); ++ /* length of "/dev/md/" + device name + terminating byte */ ++ size_t _len = sizeof("/dev/md/") + strnlen(mdlist->devname, PATH_MAX); ++ ++ st->devname = xcalloc(_len, sizeof(char)); ++ snprintf(st->devname, _len, "/dev/md/%s", mdlist->devname); + } + if (!is_mddev(mdlist->devname)) + return 1; +-- +2.31.1 + diff --git a/0030-Monitor-use-snprintf-to-fill-device-name.patch b/0030-Monitor-use-snprintf-to-fill-device-name.patch new file mode 100644 index 0000000..83543cb --- /dev/null +++ b/0030-Monitor-use-snprintf-to-fill-device-name.patch @@ -0,0 +1,133 @@ +From 84d969be8f6d8a345b75f558fad26e4f62a558f6 Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Thu, 14 Jul 2022 09:02:11 +0200 +Subject: [PATCH 30/52] Monitor: use snprintf to fill device name + +Safe string functions are propagated in Monitor.c. + +Signed-off-by: Kinga Tanska +Signed-off-by: Jes Sorensen +--- + Monitor.c | 37 ++++++++++++++----------------------- + 1 file changed, 14 insertions(+), 23 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index a5b11ae2..93f36ac0 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -33,8 +33,8 @@ + #endif + + struct state { +- char *devname; +- char devnm[32]; /* to sync with mdstat info */ ++ char devname[MD_NAME_MAX + sizeof("/dev/md/")]; /* length of "/dev/md/" + device name + terminating byte*/ ++ char devnm[MD_NAME_MAX]; /* to sync with mdstat info */ + unsigned int utime; + int err; + char *spare_group; +@@ -45,9 +45,9 @@ struct state { + int devstate[MAX_DISKS]; + dev_t devid[MAX_DISKS]; + int percent; +- char parent_devnm[32]; /* For subarray, devnm of parent. +- * For others, "" +- */ ++ char parent_devnm[MD_NAME_MAX]; /* For subarray, devnm of parent. ++ * For others, "" ++ */ + struct supertype *metadata; + struct state *subarray;/* for a container it is a link to first subarray + * for a subarray it is a link to next subarray +@@ -187,15 +187,8 @@ int Monitor(struct mddev_dev *devlist, + continue; + + st = xcalloc(1, sizeof *st); +- if (mdlist->devname[0] == '/') +- st->devname = xstrdup(mdlist->devname); +- else { +- /* length of "/dev/md/" + device name + terminating byte */ +- size_t _len = sizeof("/dev/md/") + strnlen(mdlist->devname, PATH_MAX); +- +- st->devname = xcalloc(_len, sizeof(char)); +- snprintf(st->devname, _len, "/dev/md/%s", mdlist->devname); +- } ++ snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), ++ "/dev/md/%s", basename(mdlist->devname)); + if (!is_mddev(mdlist->devname)) + return 1; + st->next = statelist; +@@ -218,7 +211,7 @@ int Monitor(struct mddev_dev *devlist, + + st = xcalloc(1, sizeof *st); + mdlist = conf_get_ident(dv->devname); +- st->devname = xstrdup(dv->devname); ++ snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", dv->devname); + st->next = statelist; + st->devnm[0] = 0; + st->percent = RESYNC_UNKNOWN; +@@ -301,7 +294,6 @@ int Monitor(struct mddev_dev *devlist, + for (stp = &statelist; (st = *stp) != NULL; ) { + if (st->from_auto && st->err > 5) { + *stp = st->next; +- free(st->devname); + free(st->spare_group); + free(st); + } else +@@ -554,7 +546,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + goto disappeared; + + if (st->devnm[0] == 0) +- strcpy(st->devnm, fd2devnm(fd)); ++ snprintf(st->devnm, MD_NAME_MAX, "%s", fd2devnm(fd)); + + for (mse2 = mdstat; mse2; mse2 = mse2->next) + if (strcmp(mse2->devnm, st->devnm) == 0) { +@@ -684,7 +676,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + strncmp(mse->metadata_version, "external:", 9) == 0 && + is_subarray(mse->metadata_version+9)) { + char *sl; +- strcpy(st->parent_devnm, mse->metadata_version + 10); ++ snprintf(st->parent_devnm, MD_NAME_MAX, "%s", mse->metadata_version + 10); + sl = strchr(st->parent_devnm, '/'); + if (sl) + *sl = 0; +@@ -772,14 +764,13 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist, + continue; + } + +- st->devname = xstrdup(name); ++ snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", name); + if ((fd = open(st->devname, O_RDONLY)) < 0 || + md_get_array_info(fd, &array) < 0) { + /* no such array */ + if (fd >= 0) + close(fd); + put_md_name(st->devname); +- free(st->devname); + if (st->metadata) { + st->metadata->ss->free_super(st->metadata); + free(st->metadata); +@@ -791,7 +782,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist, + st->next = *statelist; + st->err = 1; + st->from_auto = 1; +- strcpy(st->devnm, mse->devnm); ++ snprintf(st->devnm, MD_NAME_MAX, "%s", mse->devnm); + st->percent = RESYNC_UNKNOWN; + st->expected_spares = -1; + if (mse->metadata_version && +@@ -799,8 +790,8 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist, + "external:", 9) == 0 && + is_subarray(mse->metadata_version+9)) { + char *sl; +- strcpy(st->parent_devnm, +- mse->metadata_version+10); ++ snprintf(st->parent_devnm, MD_NAME_MAX, ++ "%s", mse->metadata_version + 10); + sl = strchr(st->parent_devnm, '/'); + *sl = 0; + } else +-- +2.31.1 + diff --git a/0031-Makefile-Don-t-build-static-build-with-everything-an.patch b/0031-Makefile-Don-t-build-static-build-with-everything-an.patch new file mode 100644 index 0000000..8922281 --- /dev/null +++ b/0031-Makefile-Don-t-build-static-build-with-everything-an.patch @@ -0,0 +1,42 @@ +From 14ae4c37bce9a53da08d59d6c2d7e0946e9c9f47 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:06 -0600 +Subject: [PATCH 31/52] Makefile: Don't build static build with everything and + everything-test + +Running the test suite requires building everything, but it seems to be +difficult to build the static version of mdadm now seeing there +is no readily available static udev library. + +The test suite doesn't need the static binary so just don't build it +with the everything or everything-test targets. + +Leave the mdadm.static and install-static targets in place in case +someone still has a use case for the static binary. + +Signed-off-by: Logan Gunthorpe +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Makefile b/Makefile +index bf126033..ec1f99ed 100644 +--- a/Makefile ++++ b/Makefile +@@ -182,9 +182,9 @@ check_rundir: + echo "***** or set CHECK_RUN_DIR=0"; exit 1; \ + fi + +-everything: all mdadm.static swap_super test_stripe raid6check \ ++everything: all swap_super test_stripe raid6check \ + mdadm.Os mdadm.O2 man +-everything-test: all mdadm.static swap_super test_stripe \ ++everything-test: all swap_super test_stripe \ + mdadm.Os mdadm.O2 man + # mdadm.uclibc doesn't work on x86-64 + # mdadm.tcc doesn't work.. +-- +2.31.1 + diff --git a/0032-DDF-Cleanup-validate_geometry_ddf_container.patch b/0032-DDF-Cleanup-validate_geometry_ddf_container.patch new file mode 100644 index 0000000..99e2e6b --- /dev/null +++ b/0032-DDF-Cleanup-validate_geometry_ddf_container.patch @@ -0,0 +1,141 @@ +From 679bd9508a30b2a0a1baecc9a21dd6c7d8d8d7dc Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:07 -0600 +Subject: [PATCH 32/52] DDF: Cleanup validate_geometry_ddf_container() + +Move the function up so that the function declaration is not necessary +and remove the unused arguments to the function. + +No functional changes are intended but will help with a bug fix in the +next patch. + +Signed-off-by: Logan Gunthorpe +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-ddf.c | 88 ++++++++++++++++++++++++----------------------------- + 1 file changed, 39 insertions(+), 49 deletions(-) + +diff --git a/super-ddf.c b/super-ddf.c +index abbc8b09..9d867f69 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -503,13 +503,6 @@ struct ddf_super { + static int load_super_ddf_all(struct supertype *st, int fd, + void **sbp, char *devname); + static int get_svd_state(const struct ddf_super *, const struct vcl *); +-static int +-validate_geometry_ddf_container(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); + + static int validate_geometry_ddf_bvd(struct supertype *st, + int level, int layout, int raiddisks, +@@ -3322,6 +3315,42 @@ static int reserve_space(struct supertype *st, int raiddisks, + return 1; + } + ++static int ++validate_geometry_ddf_container(struct supertype *st, ++ int level, int raiddisks, ++ unsigned long long data_offset, ++ char *dev, unsigned long long *freesize, ++ int verbose) ++{ ++ int fd; ++ unsigned long long ldsize; ++ ++ if (level != LEVEL_CONTAINER) ++ return 0; ++ if (!dev) ++ return 1; ++ ++ fd = dev_open(dev, O_RDONLY|O_EXCL); ++ if (fd < 0) { ++ if (verbose) ++ pr_err("ddf: Cannot open %s: %s\n", ++ dev, strerror(errno)); ++ return 0; ++ } ++ if (!get_dev_size(fd, dev, &ldsize)) { ++ close(fd); ++ return 0; ++ } ++ close(fd); ++ if (freesize) { ++ *freesize = avail_size_ddf(st, ldsize >> 9, INVALID_SECTORS); ++ if (*freesize == 0) ++ return 0; ++ } ++ ++ return 1; ++} ++ + static int validate_geometry_ddf(struct supertype *st, + int level, int layout, int raiddisks, + int *chunk, unsigned long long size, +@@ -3347,11 +3376,9 @@ static int validate_geometry_ddf(struct supertype *st, + level = LEVEL_CONTAINER; + if (level == LEVEL_CONTAINER) { + /* Must be a fresh device to add to a container */ +- return validate_geometry_ddf_container(st, level, layout, +- raiddisks, *chunk, +- size, data_offset, dev, +- freesize, +- verbose); ++ return validate_geometry_ddf_container(st, level, raiddisks, ++ data_offset, dev, ++ freesize, verbose); + } + + if (!dev) { +@@ -3449,43 +3476,6 @@ static int validate_geometry_ddf(struct supertype *st, + return 1; + } + +-static int +-validate_geometry_ddf_container(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) +-{ +- int fd; +- unsigned long long ldsize; +- +- if (level != LEVEL_CONTAINER) +- return 0; +- if (!dev) +- return 1; +- +- fd = dev_open(dev, O_RDONLY|O_EXCL); +- if (fd < 0) { +- if (verbose) +- pr_err("ddf: Cannot open %s: %s\n", +- dev, strerror(errno)); +- return 0; +- } +- if (!get_dev_size(fd, dev, &ldsize)) { +- close(fd); +- return 0; +- } +- close(fd); +- if (freesize) { +- *freesize = avail_size_ddf(st, ldsize >> 9, INVALID_SECTORS); +- if (*freesize == 0) +- return 0; +- } +- +- return 1; +-} +- + static int validate_geometry_ddf_bvd(struct supertype *st, + int level, int layout, int raiddisks, + int *chunk, unsigned long long size, +-- +2.31.1 + diff --git a/0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch b/0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch new file mode 100644 index 0000000..3be71e7 --- /dev/null +++ b/0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch @@ -0,0 +1,49 @@ +From 2b93288a5650bb811932836f67f30d63c5ddcfbd Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:08 -0600 +Subject: [PATCH 33/52] DDF: Fix NULL pointer dereference in + validate_geometry_ddf() + +A relatively recent patch added a call to validate_geometry() in +Manage_add() that has level=LEVEL_CONTAINER and chunk=NULL. + +This causes some ddf tests to segfault which aborts the test suite. + +To fix this, avoid dereferencing chunk when the level is +LEVEL_CONTAINER or LEVEL_NONE. + +Fixes: 1f5d54a06df0 ("Manage: Call validate_geometry when adding drive to external container") +Signed-off-by: Logan Gunthorpe +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-ddf.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/super-ddf.c b/super-ddf.c +index 9d867f69..949e7d15 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -3369,9 +3369,6 @@ static int validate_geometry_ddf(struct supertype *st, + * If given BVDs, we make an SVD, changing all the GUIDs in the process. + */ + +- if (*chunk == UnSet) +- *chunk = DEFAULT_CHUNK; +- + if (level == LEVEL_NONE) + level = LEVEL_CONTAINER; + if (level == LEVEL_CONTAINER) { +@@ -3381,6 +3378,9 @@ static int validate_geometry_ddf(struct supertype *st, + freesize, verbose); + } + ++ if (*chunk == UnSet) ++ *chunk = DEFAULT_CHUNK; ++ + if (!dev) { + mdu_array_info_t array = { + .level = level, +-- +2.31.1 + diff --git a/0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch b/0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch new file mode 100644 index 0000000..849a475 --- /dev/null +++ b/0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch @@ -0,0 +1,85 @@ +From 548e9b916f86c06e2cdb50d8f49633f9bec66c7e Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:09 -0600 +Subject: [PATCH 34/52] mdadm/Grow: Fix use after close bug by closing after + fork + +The test 07reshape-grow fails most of the time. But it succeeds around +1 in 5 times. When it does succeed, it causes the tests to die because +mdadm has segfaulted. + +The segfault was caused by mdadm attempting to repoen a file +descriptor that was already closed. The backtrace of the segfault +was: + + #0 __strncmp_avx2 () at ../sysdeps/x86_64/multiarch/strcmp-avx2.S:101 + #1 0x000056146e31d44b in devnm2devid (devnm=0x0) at util.c:956 + #2 0x000056146e31dab4 in open_dev_flags (devnm=0x0, flags=0) + at util.c:1072 + #3 0x000056146e31db22 in open_dev (devnm=0x0) at util.c:1079 + #4 0x000056146e3202e8 in reopen_mddev (mdfd=4) at util.c:2244 + #5 0x000056146e329f36 in start_array (mdfd=4, + mddev=0x7ffc55342450 "/dev/md0", content=0x7ffc55342860, + st=0x56146fc78660, ident=0x7ffc55342f70, best=0x56146fc6f5d0, + bestcnt=10, chosen_drive=0, devices=0x56146fc706b0, okcnt=5, + sparecnt=0, rebuilding_cnt=0, journalcnt=0, c=0x7ffc55342e90, + clean=1, avail=0x56146fc78720 "\001\001\001\001\001", + start_partial_ok=0, err_ok=0, was_forced=0) + at Assemble.c:1206 + #6 0x000056146e32c36e in Assemble (st=0x56146fc78660, + mddev=0x7ffc55342450 "/dev/md0", ident=0x7ffc55342f70, + devlist=0x56146fc6e2d0, c=0x7ffc55342e90) + at Assemble.c:1914 + #7 0x000056146e312ac9 in main (argc=11, argv=0x7ffc55343238) + at mdadm.c:1510 + +The file descriptor was closed early in Grow_continue(). The noted commit +moved the close() call to close the fd above the fork which caused the +parent process to return with a closed fd. + +This meant reshape_array() and Grow_continue() would return in the parent +with the fd forked. The fd would eventually be passed to reopen_mddev() +which returned an unhandled NULL from fd2devnm() which would then be +dereferenced in devnm2devid. + +Fix this by moving the close() call below the fork. This appears to +fix the 07revert-grow test. While we're at it, switch to using +close_fd() to invalidate the file descriptor. + +Fixes: 77b72fa82813 ("mdadm/Grow: prevent md's fd from being occupied during delayed time") +Cc: Alex Wu +Cc: BingJing Chang +Cc: Danny Shih +Cc: ChangSyun Peng +Signed-off-by: Logan Gunthorpe +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Grow.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/Grow.c b/Grow.c +index 8c520d42..97f22c75 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -3514,7 +3514,6 @@ started: + return 0; + } + +- close(fd); + /* Now we just need to kick off the reshape and watch, while + * handling backups of the data... + * This is all done by a forked background process. +@@ -3535,6 +3534,9 @@ started: + break; + } + ++ /* Close unused file descriptor in the forked process */ ++ close_fd(&fd); ++ + /* If another array on the same devices is busy, the + * reshape will wait for them. This would mean that + * the first section that we suspend will stay suspended +-- +2.31.1 + diff --git a/0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch b/0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch new file mode 100644 index 0000000..c19c1e4 --- /dev/null +++ b/0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch @@ -0,0 +1,36 @@ +From 9ae62977b51dab0f4bb46b1c8ea5ebd1705b2f4d Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:10 -0600 +Subject: [PATCH 35/52] monitor: Avoid segfault when calling NULL + get_bad_blocks + +Not all struct superswitch implement a get_bad_blocks() function, +yet mdmon seems to call it without checking for NULL and thus +occasionally segfaults in the test 10ddf-geometry. + +Fix this by checking for NULL before calling it. + +Signed-off-by: Logan Gunthorpe +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + monitor.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/monitor.c b/monitor.c +index b877e595..820a93d0 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -311,6 +311,9 @@ static int check_for_cleared_bb(struct active_array *a, struct mdinfo *mdi) + struct md_bb *bb; + int i; + ++ if (!ss->get_bad_blocks) ++ return -1; ++ + /* + * Get a list of bad blocks for an array, then read list of + * acknowledged bad blocks from kernel and compare it against metadata +-- +2.31.1 + diff --git a/0036-mdadm-Fix-mdadm-r-remove-option-regression.patch b/0036-mdadm-Fix-mdadm-r-remove-option-regression.patch new file mode 100644 index 0000000..8bcf0c9 --- /dev/null +++ b/0036-mdadm-Fix-mdadm-r-remove-option-regression.patch @@ -0,0 +1,78 @@ +From 6c9d9260633f2c8491985b0782cf0fbd7e51651b Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:11 -0600 +Subject: [PATCH 36/52] mdadm: Fix mdadm -r remove option regression + +The commit noted below globally adds a parameter to the -r option but missed +the fact that -r is used for another purpose: --remove. + +After that commit, a command such as: + + mdadm /dev/md0 -r /dev/loop0 + +will do nothing seeing the device parameter will be consumed as a +argument to the -r option; thus, there will only be one device +seen one the command line, devs_found will only be 1 and nothing will +happen. + +This caused the 01r5integ and 01raid6integ tests to hang indefinitely +as mdadm did not remove the failed device. With the device not removed, +it would not be readded. Then the loop waiting for the array status to +change would loop forever. + +This commit was recently reverted, but the legitimate fix for the +monitor operations was still not fixed. So add specific monitor +short ops to re-fix the --monitor -r option. + +Fixes: 546047688e1c ("mdadm: fix coredump of mdadm --monitor -r") +Fixes: 190dc029b141 ("Revert "mdadm: fix coredump of mdadm --monitor -r"") +Cc: Wu Guanghao +Cc: Mariusz Tkaczyk +Signed-off-by: Logan Gunthorpe +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + ReadMe.c | 1 + + mdadm.c | 1 + + mdadm.h | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/ReadMe.c b/ReadMe.c +index bec1be9a..7518a32a 100644 +--- a/ReadMe.c ++++ b/ReadMe.c +@@ -82,6 +82,7 @@ char Version[] = "mdadm - v" VERSION " - " VERS_DATE EXTRAVERSION "\n"; + */ + + char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:"; ++char short_monitor_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:r:n:x:u:c:d:z:U:N:safRSow1tye:k:"; + char short_bitmap_options[]= + "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:"; + char short_bitmap_auto_options[]= +diff --git a/mdadm.c b/mdadm.c +index be40686c..d0c5e6de 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -227,6 +227,7 @@ int main(int argc, char *argv[]) + shortopt = short_bitmap_auto_options; + break; + case 'F': newmode = MONITOR; ++ shortopt = short_monitor_options; + break; + case 'G': newmode = GROW; + shortopt = short_bitmap_options; +diff --git a/mdadm.h b/mdadm.h +index 974415b9..163f4a49 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -419,6 +419,7 @@ enum mode { + }; + + extern char short_options[]; ++extern char short_monitor_options[]; + extern char short_bitmap_options[]; + extern char short_bitmap_auto_options[]; + extern struct option long_options[]; +-- +2.31.1 + diff --git a/0037-mdadm-Fix-optional-write-behind-parameter.patch b/0037-mdadm-Fix-optional-write-behind-parameter.patch new file mode 100644 index 0000000..c10712a --- /dev/null +++ b/0037-mdadm-Fix-optional-write-behind-parameter.patch @@ -0,0 +1,42 @@ +From 41edf6f45895193f4a523cb0a08d639c9ff9ccc9 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:12 -0600 +Subject: [PATCH 37/52] mdadm: Fix optional --write-behind parameter + +The commit noted below changed the behaviour of --write-behind to +require an argument. This broke the 06wrmostly test with the error: + + mdadm: Invalid value for maximum outstanding write-behind writes: (null). + Must be between 0 and 16383. + +To fix this, check if optarg is NULL before parising it, as the origial +code did. + +Fixes: 60815698c0ac ("Refactor parse_num and use it to parse optarg.") +Cc: Mateusz Grzonka +Signed-off-by: Logan Gunthorpe +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + mdadm.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/mdadm.c b/mdadm.c +index d0c5e6de..56722ed9 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -1201,8 +1201,9 @@ int main(int argc, char *argv[]) + case O(BUILD, WriteBehind): + case O(CREATE, WriteBehind): + s.write_behind = DEFAULT_MAX_WRITE_BEHIND; +- if (parse_num(&s.write_behind, optarg) != 0 || +- s.write_behind < 0 || s.write_behind > 16383) { ++ if (optarg && ++ (parse_num(&s.write_behind, optarg) != 0 || ++ s.write_behind < 0 || s.write_behind > 16383)) { + pr_err("Invalid value for maximum outstanding write-behind writes: %s.\n\tMust be between 0 and 16383.\n", + optarg); + exit(2); +-- +2.31.1 + diff --git a/0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch b/0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch new file mode 100644 index 0000000..e934bed --- /dev/null +++ b/0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch @@ -0,0 +1,38 @@ +From 7539254342bc591717b0051734cc6c09c1b88640 Mon Sep 17 00:00:00 2001 +From: Sudhakar Panneerselvam +Date: Wed, 22 Jun 2022 14:25:13 -0600 +Subject: [PATCH 38/52] tests/00raid0: add a test that validates raid0 with + layout fails for 0.9 + +329dfc28debb disallows the creation of raid0 with layouts for 0.9 +metadata. This test confirms the new behavior. + +Signed-off-by: Sudhakar Panneerselvam +Signed-off-by: Himanshu Madhani +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + tests/00raid0 | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/tests/00raid0 b/tests/00raid0 +index 8bc18985..e6b21cc4 100644 +--- a/tests/00raid0 ++++ b/tests/00raid0 +@@ -6,11 +6,9 @@ check raid0 + testdev $md0 3 $mdsize2_l 512 + mdadm -S $md0 + +-# now with version-0.90 superblock ++# verify raid0 with layouts fail for 0.90 + mdadm -CR $md0 -e0.90 -l0 -n4 $dev0 $dev1 $dev2 $dev3 +-check raid0 +-testdev $md0 4 $mdsize0 512 +-mdadm -S $md0 ++check opposite_result + + # now with no superblock + mdadm -B $md0 -l0 -n5 $dev0 $dev1 $dev2 $dev3 $dev4 +-- +2.31.1 + diff --git a/0039-tests-fix-raid0-tests-for-0.90-metadata.patch b/0039-tests-fix-raid0-tests-for-0.90-metadata.patch new file mode 100644 index 0000000..ace5fbe --- /dev/null +++ b/0039-tests-fix-raid0-tests-for-0.90-metadata.patch @@ -0,0 +1,99 @@ +From 14c2161edb77d7294199e8aa7daa9f9d1d0ad5d7 Mon Sep 17 00:00:00 2001 +From: Sudhakar Panneerselvam +Date: Wed, 22 Jun 2022 14:25:14 -0600 +Subject: [PATCH 39/52] tests: fix raid0 tests for 0.90 metadata + +Some of the test cases fail because raid0 creation fails with the error, +"0.90 metadata does not support layouts for RAID0" added by commit, +329dfc28debb. Fix some of the test cases by switching from raid0 to +linear level for 0.9 metadata where possible. + +Signed-off-by: Sudhakar Panneerselvam +Signed-off-by: Himanshu Madhani +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + tests/00raid0 | 4 ++-- + tests/00readonly | 4 ++++ + tests/03r0assem | 6 +++--- + tests/04r0update | 4 ++-- + tests/04update-metadata | 2 +- + 5 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/tests/00raid0 b/tests/00raid0 +index e6b21cc4..9b8896cb 100644 +--- a/tests/00raid0 ++++ b/tests/00raid0 +@@ -20,8 +20,8 @@ mdadm -S $md0 + # now same again with different chunk size + for chunk in 4 32 256 + do +- mdadm -CR $md0 -e0.90 -l raid0 --chunk $chunk -n3 $dev0 $dev1 $dev2 +- check raid0 ++ mdadm -CR $md0 -e0.90 -l linear --chunk $chunk -n3 $dev0 $dev1 $dev2 ++ check linear + testdev $md0 3 $mdsize0 $chunk + mdadm -S $md0 + +diff --git a/tests/00readonly b/tests/00readonly +index 28b0fa13..39202487 100644 +--- a/tests/00readonly ++++ b/tests/00readonly +@@ -4,6 +4,10 @@ for metadata in 0.9 1.0 1.1 1.2 + do + for level in linear raid0 raid1 raid4 raid5 raid6 raid10 + do ++ if [[ $metadata == "0.9" && $level == "raid0" ]]; ++ then ++ continue ++ fi + mdadm -CR $md0 -l $level -n 4 --metadata=$metadata \ + $dev1 $dev2 $dev3 $dev4 --assume-clean + check nosync +diff --git a/tests/03r0assem b/tests/03r0assem +index 6744e322..44df0645 100644 +--- a/tests/03r0assem ++++ b/tests/03r0assem +@@ -68,9 +68,9 @@ mdadm -S $md2 + ### Now for version 0... + + mdadm --zero-superblock $dev0 $dev1 $dev2 +-mdadm -CR $md2 -l0 --metadata=0.90 -n3 $dev0 $dev1 $dev2 +-check raid0 +-tst="testdev $md2 3 $mdsize0 512" ++mdadm -CR $md2 -llinear --metadata=0.90 -n3 $dev0 $dev1 $dev2 ++check linear ++tst="testdev $md2 3 $mdsize0 1" + $tst + + uuid=`mdadm -Db $md2 | sed 's/.*UUID=//'` +diff --git a/tests/04r0update b/tests/04r0update +index 73ee3b9f..b95efb06 100644 +--- a/tests/04r0update ++++ b/tests/04r0update +@@ -1,7 +1,7 @@ + + # create a raid0, re-assemble with a different super-minor +-mdadm -CR -e 0.90 $md0 -l0 -n3 $dev0 $dev1 $dev2 +-testdev $md0 3 $mdsize0 512 ++mdadm -CR -e 0.90 $md0 -llinear -n3 $dev0 $dev1 $dev2 ++testdev $md0 3 $mdsize0 1 + minor1=`mdadm -E $dev0 | sed -n -e 's/.*Preferred Minor : //p'` + mdadm -S /dev/md0 + +diff --git a/tests/04update-metadata b/tests/04update-metadata +index 232fc1ff..08c14af7 100644 +--- a/tests/04update-metadata ++++ b/tests/04update-metadata +@@ -8,7 +8,7 @@ set -xe + + dlist="$dev0 $dev1 $dev2 $dev3" + +-for ls in raid0/4 linear/4 raid1/1 raid5/3 raid6/2 ++for ls in linear/4 raid1/1 raid5/3 raid6/2 + do + s=${ls#*/} l=${ls%/*} + mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist +-- +2.31.1 + diff --git a/0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch b/0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch new file mode 100644 index 0000000..76a7586 --- /dev/null +++ b/0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch @@ -0,0 +1,39 @@ +From de045db607b1ac4b70fc2a8878463e029c2ab1dc Mon Sep 17 00:00:00 2001 +From: Sudhakar Panneerselvam +Date: Wed, 22 Jun 2022 14:25:15 -0600 +Subject: [PATCH 40/52] tests/04update-metadata: avoid passing chunk size to + raid1 + +'04update-metadata' test fails with error, "specifying chunk size is +forbidden for this level" added by commit, 5b30a34aa4b5e. Hence, +correcting the test to ignore passing chunk size to raid1. + +Signed-off-by: Sudhakar Panneerselvam +Signed-off-by: Himanshu Madhani +[logang@deltatee.com: fix if/then style and dropped unrelated hunk] +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + tests/04update-metadata | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/tests/04update-metadata b/tests/04update-metadata +index 08c14af7..2b72a303 100644 +--- a/tests/04update-metadata ++++ b/tests/04update-metadata +@@ -11,7 +11,11 @@ dlist="$dev0 $dev1 $dev2 $dev3" + for ls in linear/4 raid1/1 raid5/3 raid6/2 + do + s=${ls#*/} l=${ls%/*} +- mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist ++ if [[ $l == 'raid1' ]]; then ++ mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 $dlist ++ else ++ mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist ++ fi + testdev $md0 $s 19904 64 + mdadm -S $md0 + mdadm -A $md0 --update=metadata $dlist +-- +2.31.1 + diff --git a/0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch b/0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch new file mode 100644 index 0000000..00c9367 --- /dev/null +++ b/0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch @@ -0,0 +1,31 @@ +From a2c832465fc75202e244327b2081231dfa974617 Mon Sep 17 00:00:00 2001 +From: Sudhakar Panneerselvam +Date: Wed, 22 Jun 2022 14:25:16 -0600 +Subject: [PATCH 41/52] tests/02lineargrow: clear the superblock at every + iteration + +This fixes 02lineargrow test as prior metadata causes --add operation +to misbehave. + +Signed-off-by: Sudhakar Panneerselvam +Signed-off-by: Himanshu Madhani +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + tests/02lineargrow | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tests/02lineargrow b/tests/02lineargrow +index e05c219d..595bf9f2 100644 +--- a/tests/02lineargrow ++++ b/tests/02lineargrow +@@ -20,4 +20,6 @@ do + testdev $md0 3 $sz 1 + + mdadm -S $md0 ++ mdadm --zero /dev/loop2 ++ mdadm --zero /dev/loop3 + done +-- +2.31.1 + diff --git a/0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch b/0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch new file mode 100644 index 0000000..288ca2c --- /dev/null +++ b/0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch @@ -0,0 +1,88 @@ +From a7bfcc716e235664dfb3b6c5a9590273e611ac72 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:17 -0600 +Subject: [PATCH 42/52] mdadm/test: Add a mode to repeat specified tests + +Many tests fail infrequently or rarely. To help find these, add +an option to run the tests multiple times by specifying --loop=N. + +If --loop=0 is specified, the test will be looped forever. + +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + test | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/test b/test +index 711a3c7a..da6db5e0 100755 +--- a/test ++++ b/test +@@ -10,6 +10,7 @@ devlist= + + savelogs=0 + exitonerror=1 ++loop=1 + prefix='[0-9][0-9]' + + # use loop devices by default if doesn't specify --dev +@@ -117,6 +118,7 @@ do_help() { + --logdir=directory Directory to save all logfiles in + --save-logs Usually use with --logdir together + --keep-going | --no-error Don't stop on error, ie. run all tests ++ --loop=N Run tests N times (0 to run forever) + --dev=loop|lvm|ram|disk Use loop devices (default), LVM, RAM or disk + --disks= Provide a bunch of physical devices for test + --volgroup=name LVM volume group for LVM test +@@ -211,6 +213,9 @@ parse_args() { + --keep-going | --no-error ) + exitonerror=0 + ;; ++ --loop=* ) ++ loop="${i##*=}" ++ ;; + --disable-multipath ) + unset MULTIPATH + ;; +@@ -263,19 +268,26 @@ main() { + echo "Testing on linux-$(uname -r) kernel" + [ "$savelogs" == "1" ] && + echo "Saving logs to $logdir" +- if [ "x$TESTLIST" != "x" ] +- then +- for script in ${TESTLIST[@]} +- do +- do_test $testdir/$script +- done +- else +- for script in $testdir/$prefix $testdir/$prefix*[^~] +- do +- do_test $script +- done +- fi + ++ while true; do ++ if [ "x$TESTLIST" != "x" ] ++ then ++ for script in ${TESTLIST[@]} ++ do ++ do_test $testdir/$script ++ done ++ else ++ for script in $testdir/$prefix $testdir/$prefix*[^~] ++ do ++ do_test $script ++ done ++ fi ++ ++ let loop=$loop-1 ++ if [ "$loop" == "0" ]; then ++ break ++ fi ++ done + exit 0 + } + +-- +2.31.1 + diff --git a/0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch b/0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch new file mode 100644 index 0000000..5585173 --- /dev/null +++ b/0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch @@ -0,0 +1,120 @@ +From 28520bf114b3b0515a48ff44fff4ecbe9ed6dfad Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:18 -0600 +Subject: [PATCH 43/52] mdadm/test: Mark and ignore broken test failures + +Add functionality to continue if a test marked as broken fails. + +To mark a test as broken, a file with the same name but with the suffix +'.broken' should exist. The first line in the file will be printed with +a KNOWN BROKEN message; the rest of the file can describe the how the +test is broken. + +Also adds --skip-broken and --skip-always-broken to skip all the tests +that have a .broken file or to skip all tests whose .broken file's first +line contains the keyword always. + +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + test | 37 +++++++++++++++++++++++++++++++++++-- + 1 file changed, 35 insertions(+), 2 deletions(-) + +diff --git a/test b/test +index da6db5e0..61d9ee83 100755 +--- a/test ++++ b/test +@@ -10,6 +10,8 @@ devlist= + + savelogs=0 + exitonerror=1 ++ctrl_c_error=0 ++skipbroken=0 + loop=1 + prefix='[0-9][0-9]' + +@@ -36,6 +38,7 @@ die() { + + ctrl_c() { + exitonerror=1 ++ ctrl_c_error=1 + } + + # mdadm always adds --quiet, and we want to see any unexpected messages +@@ -80,8 +83,21 @@ mdadm() { + do_test() { + _script=$1 + _basename=`basename $_script` ++ _broken=0 ++ + if [ -f "$_script" ] + then ++ if [ -f "${_script}.broken" ]; then ++ _broken=1 ++ _broken_msg=$(head -n1 "${_script}.broken" | tr -d '\n') ++ if [ "$skipbroken" == "all" ]; then ++ return ++ elif [ "$skipbroken" == "always" ] && ++ [[ "$_broken_msg" == *always* ]]; then ++ return ++ fi ++ fi ++ + rm -f $targetdir/stderr + # this might have been reset: restore the default. + echo 2000 > /proc/sys/dev/raid/speed_limit_max +@@ -98,10 +114,15 @@ do_test() { + else + save_log fail + _fail=1 ++ if [ "$_broken" == "1" ]; then ++ echo " (KNOWN BROKEN TEST: $_broken_msg)" ++ fi + fi + [ "$savelogs" == "1" ] && + mv -f $targetdir/log $logdir/$_basename.log +- [ "$_fail" == "1" -a "$exitonerror" == "1" ] && exit 1 ++ [ "$ctrl_c_error" == "1" ] && exit 1 ++ [ "$_fail" == "1" -a "$exitonerror" == "1" \ ++ -a "$_broken" == "0" ] && exit 1 + fi + } + +@@ -119,6 +140,8 @@ do_help() { + --save-logs Usually use with --logdir together + --keep-going | --no-error Don't stop on error, ie. run all tests + --loop=N Run tests N times (0 to run forever) ++ --skip-broken Skip tests that are known to be broken ++ --skip-always-broken Skip tests that are known to always fail + --dev=loop|lvm|ram|disk Use loop devices (default), LVM, RAM or disk + --disks= Provide a bunch of physical devices for test + --volgroup=name LVM volume group for LVM test +@@ -216,6 +239,12 @@ parse_args() { + --loop=* ) + loop="${i##*=}" + ;; ++ --skip-broken ) ++ skipbroken=all ++ ;; ++ --skip-always-broken ) ++ skipbroken=always ++ ;; + --disable-multipath ) + unset MULTIPATH + ;; +@@ -279,7 +308,11 @@ main() { + else + for script in $testdir/$prefix $testdir/$prefix*[^~] + do +- do_test $script ++ case $script in ++ *.broken) ;; ++ *) ++ do_test $script ++ esac + done + fi + +-- +2.31.1 + diff --git a/0044-tests-Add-broken-files-for-all-broken-tests.patch b/0044-tests-Add-broken-files-for-all-broken-tests.patch new file mode 100644 index 0000000..643bf3f --- /dev/null +++ b/0044-tests-Add-broken-files-for-all-broken-tests.patch @@ -0,0 +1,447 @@ +From daa86d6634761796ada1f535c13e47fdd3cc95eb Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 22 Jun 2022 14:25:19 -0600 +Subject: [PATCH 44/52] tests: Add broken files for all broken tests + +Each broken file contains the rough frequency of brokeness as well +as a brief explanation of what happens when it breaks. Estimates +of failure rates are not statistically significant and can vary +run to run. + +This is really just a view from my window. Tests were done on a +small VM with the default loop devices, not real hardware. We've +seen different kernel configurations can cause bugs to appear as well +(ie. different block schedulers). It may also be that different race +conditions will be seen on machines with different performance +characteristics. + +These annotations were done with the kernel currently in md/md-next: + + facef3b96c5b ("md: Notify sysfs sync_completed in md_reap_sync_thread()") + +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + tests/01r5integ.broken | 7 ++++ + tests/01raid6integ.broken | 7 ++++ + tests/04r5swap.broken | 7 ++++ + tests/07autoassemble.broken | 8 ++++ + tests/07autodetect.broken | 5 +++ + tests/07changelevelintr.broken | 9 +++++ + tests/07changelevels.broken | 9 +++++ + tests/07reshape5intr.broken | 45 ++++++++++++++++++++++ + tests/07revert-grow.broken | 31 +++++++++++++++ + tests/07revert-shrink.broken | 9 +++++ + tests/07testreshape5.broken | 12 ++++++ + tests/09imsm-assemble.broken | 6 +++ + tests/09imsm-create-fail-rebuild.broken | 5 +++ + tests/09imsm-overlap.broken | 7 ++++ + tests/10ddf-assemble-missing.broken | 6 +++ + tests/10ddf-fail-create-race.broken | 7 ++++ + tests/10ddf-fail-two-spares.broken | 5 +++ + tests/10ddf-incremental-wrong-order.broken | 9 +++++ + tests/14imsm-r1_2d-grow-r1_3d.broken | 5 +++ + tests/14imsm-r1_2d-takeover-r0_2d.broken | 6 +++ + tests/18imsm-r10_4d-takeover-r0_2d.broken | 5 +++ + tests/18imsm-r1_2d-takeover-r0_1d.broken | 6 +++ + tests/19raid6auto-repair.broken | 5 +++ + tests/19raid6repair.broken | 5 +++ + 24 files changed, 226 insertions(+) + create mode 100644 tests/01r5integ.broken + create mode 100644 tests/01raid6integ.broken + create mode 100644 tests/04r5swap.broken + create mode 100644 tests/07autoassemble.broken + create mode 100644 tests/07autodetect.broken + create mode 100644 tests/07changelevelintr.broken + create mode 100644 tests/07changelevels.broken + create mode 100644 tests/07reshape5intr.broken + create mode 100644 tests/07revert-grow.broken + create mode 100644 tests/07revert-shrink.broken + create mode 100644 tests/07testreshape5.broken + create mode 100644 tests/09imsm-assemble.broken + create mode 100644 tests/09imsm-create-fail-rebuild.broken + create mode 100644 tests/09imsm-overlap.broken + create mode 100644 tests/10ddf-assemble-missing.broken + create mode 100644 tests/10ddf-fail-create-race.broken + create mode 100644 tests/10ddf-fail-two-spares.broken + create mode 100644 tests/10ddf-incremental-wrong-order.broken + create mode 100644 tests/14imsm-r1_2d-grow-r1_3d.broken + create mode 100644 tests/14imsm-r1_2d-takeover-r0_2d.broken + create mode 100644 tests/18imsm-r10_4d-takeover-r0_2d.broken + create mode 100644 tests/18imsm-r1_2d-takeover-r0_1d.broken + create mode 100644 tests/19raid6auto-repair.broken + create mode 100644 tests/19raid6repair.broken + +diff --git a/tests/01r5integ.broken b/tests/01r5integ.broken +new file mode 100644 +index 00000000..20737637 +--- /dev/null ++++ b/tests/01r5integ.broken +@@ -0,0 +1,7 @@ ++fails rarely ++ ++Fails about 1 in every 30 runs with a sha mismatch error: ++ ++ c49ab26e1b01def7874af9b8a6d6d0c29fdfafe6 /dev/md0 does not match ++ 15dc2f73262f811ada53c65e505ceec9cf025cb9 /dev/md0 with /dev/loop3 ++ missing +diff --git a/tests/01raid6integ.broken b/tests/01raid6integ.broken +new file mode 100644 +index 00000000..1df735f0 +--- /dev/null ++++ b/tests/01raid6integ.broken +@@ -0,0 +1,7 @@ ++fails infrequently ++ ++Fails about 1 in 5 with a sha mismatch: ++ ++ 8286c2bc045ae2cfe9f8b7ae3a898fa25db6926f /dev/md0 does not match ++ a083a0738b58caab37fd568b91b177035ded37df /dev/md0 with /dev/loop2 and ++ /dev/loop3 missing +diff --git a/tests/04r5swap.broken b/tests/04r5swap.broken +new file mode 100644 +index 00000000..e38987db +--- /dev/null ++++ b/tests/04r5swap.broken +@@ -0,0 +1,7 @@ ++always fails ++ ++Fails with errors: ++ ++ mdadm: /dev/loop0 has no superblock - assembly aborted ++ ++ ERROR: no recovery happening +diff --git a/tests/07autoassemble.broken b/tests/07autoassemble.broken +new file mode 100644 +index 00000000..8be09407 +--- /dev/null ++++ b/tests/07autoassemble.broken +@@ -0,0 +1,8 @@ ++always fails ++ ++Prints lots of messages, but the array doesn't assemble. Error ++possibly related to: ++ ++ mdadm: /dev/md/1 is busy - skipping ++ mdadm: no recogniseable superblock on /dev/md/testing:0 ++ mdadm: /dev/md/2 is busy - skipping +diff --git a/tests/07autodetect.broken b/tests/07autodetect.broken +new file mode 100644 +index 00000000..294954a1 +--- /dev/null ++++ b/tests/07autodetect.broken +@@ -0,0 +1,5 @@ ++always fails ++ ++Fails with error: ++ ++ ERROR: no resync happening +diff --git a/tests/07changelevelintr.broken b/tests/07changelevelintr.broken +new file mode 100644 +index 00000000..284b4906 +--- /dev/null ++++ b/tests/07changelevelintr.broken +@@ -0,0 +1,9 @@ ++always fails ++ ++Fails with errors: ++ ++ mdadm: this change will reduce the size of the array. ++ use --grow --array-size first to truncate array. ++ e.g. mdadm --grow /dev/md0 --array-size 56832 ++ ++ ERROR: no reshape happening +diff --git a/tests/07changelevels.broken b/tests/07changelevels.broken +new file mode 100644 +index 00000000..9b930d93 +--- /dev/null ++++ b/tests/07changelevels.broken +@@ -0,0 +1,9 @@ ++always fails ++ ++Fails with errors: ++ ++ mdadm: /dev/loop0 is smaller than given size. 18976K < 19968K + metadata ++ mdadm: /dev/loop1 is smaller than given size. 18976K < 19968K + metadata ++ mdadm: /dev/loop2 is smaller than given size. 18976K < 19968K + metadata ++ ++ ERROR: /dev/md0 isn't a block device. +diff --git a/tests/07reshape5intr.broken b/tests/07reshape5intr.broken +new file mode 100644 +index 00000000..efe52a66 +--- /dev/null ++++ b/tests/07reshape5intr.broken +@@ -0,0 +1,45 @@ ++always fails ++ ++This patch, recently added to md-next causes the test to always fail: ++ ++7e6ba434cc60 ("md: don't unregister sync_thread with reconfig_mutex ++held") ++ ++The new error is simply: ++ ++ ERROR: no reshape happening ++ ++Before the patch, the error seen is below. ++ ++-- ++ ++fails infrequently ++ ++Fails roughly 1 in 4 runs with errors: ++ ++ mdadm: Merging with already-assembled /dev/md/0 ++ mdadm: cannot re-read metadata from /dev/loop6 - aborting ++ ++ ERROR: no reshape happening ++ ++Also have seen a random deadlock: ++ ++ INFO: task mdadm:109702 blocked for more than 30 seconds. ++ Not tainted 5.18.0-rc3-eid-vmlocalyes-dbg-00095-g3c2b5427979d #2040 ++ "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. ++ task:mdadm state:D stack: 0 pid:109702 ppid: 1 flags:0x00004000 ++ Call Trace: ++ ++ __schedule+0x67e/0x13b0 ++ schedule+0x82/0x110 ++ mddev_suspend+0x2e1/0x330 ++ suspend_lo_store+0xbd/0x140 ++ md_attr_store+0xcb/0x130 ++ sysfs_kf_write+0x89/0xb0 ++ kernfs_fop_write_iter+0x202/0x2c0 ++ new_sync_write+0x222/0x330 ++ vfs_write+0x3bc/0x4d0 ++ ksys_write+0xd9/0x180 ++ __x64_sys_write+0x43/0x50 ++ do_syscall_64+0x3b/0x90 ++ entry_SYSCALL_64_after_hwframe+0x44/0xae +diff --git a/tests/07revert-grow.broken b/tests/07revert-grow.broken +new file mode 100644 +index 00000000..9b6db86f +--- /dev/null ++++ b/tests/07revert-grow.broken +@@ -0,0 +1,31 @@ ++always fails ++ ++This patch, recently added to md-next causes the test to always fail: ++ ++7e6ba434cc60 ("md: don't unregister sync_thread with reconfig_mutex held") ++ ++The errors are: ++ ++ mdadm: No active reshape to revert on /dev/loop0 ++ ERROR: active raid5 not found ++ ++Before the patch, the error seen is below. ++ ++-- ++ ++fails rarely ++ ++Fails about 1 in every 30 runs with errors: ++ ++ mdadm: Merging with already-assembled /dev/md/0 ++ mdadm: backup file /tmp/md-backup inaccessible: No such file or directory ++ mdadm: failed to add /dev/loop1 to /dev/md/0: Invalid argument ++ mdadm: failed to add /dev/loop2 to /dev/md/0: Invalid argument ++ mdadm: failed to add /dev/loop3 to /dev/md/0: Invalid argument ++ mdadm: failed to add /dev/loop0 to /dev/md/0: Invalid argument ++ mdadm: /dev/md/0 assembled from 1 drive - need all 5 to start it ++ (use --run to insist). ++ ++ grep: /sys/block/md*/md/sync_action: No such file or directory ++ ++ ERROR: active raid5 not found +diff --git a/tests/07revert-shrink.broken b/tests/07revert-shrink.broken +new file mode 100644 +index 00000000..c33c39ec +--- /dev/null ++++ b/tests/07revert-shrink.broken +@@ -0,0 +1,9 @@ ++always fails ++ ++Fails with errors: ++ ++ mdadm: this change will reduce the size of the array. ++ use --grow --array-size first to truncate array. ++ e.g. mdadm --grow /dev/md0 --array-size 53760 ++ ++ ERROR: active raid5 not found +diff --git a/tests/07testreshape5.broken b/tests/07testreshape5.broken +new file mode 100644 +index 00000000..a8ce03e4 +--- /dev/null ++++ b/tests/07testreshape5.broken +@@ -0,0 +1,12 @@ ++always fails ++ ++Test seems to run 'test_stripe' at $dir directory, but $dir is never ++set. If $dir is adjusted to $PWD, the test still fails with: ++ ++ mdadm: /dev/loop2 is not suitable for this array. ++ mdadm: create aborted ++ ++ return 1 ++ ++ cmp -s -n 8192 /dev/md0 /tmp/RandFile ++ ++ echo cmp failed ++ cmp failed ++ ++ exit 2 +diff --git a/tests/09imsm-assemble.broken b/tests/09imsm-assemble.broken +new file mode 100644 +index 00000000..a6d4d5cf +--- /dev/null ++++ b/tests/09imsm-assemble.broken +@@ -0,0 +1,6 @@ ++fails infrequently ++ ++Fails roughly 1 in 10 runs with errors: ++ ++ mdadm: /dev/loop2 is still in use, cannot remove. ++ /dev/loop2 removal from /dev/md/container should have succeeded +diff --git a/tests/09imsm-create-fail-rebuild.broken b/tests/09imsm-create-fail-rebuild.broken +new file mode 100644 +index 00000000..40c4b294 +--- /dev/null ++++ b/tests/09imsm-create-fail-rebuild.broken +@@ -0,0 +1,5 @@ ++always fails ++ ++Fails with error: ++ ++ **Error**: Array size mismatch - expected 3072, actual 16384 +diff --git a/tests/09imsm-overlap.broken b/tests/09imsm-overlap.broken +new file mode 100644 +index 00000000..e7ccab76 +--- /dev/null ++++ b/tests/09imsm-overlap.broken +@@ -0,0 +1,7 @@ ++always fails ++ ++Fails with errors: ++ ++ **Error**: Offset mismatch - expected 15360, actual 0 ++ **Error**: Offset mismatch - expected 15360, actual 0 ++ /dev/md/vol3 failed check +diff --git a/tests/10ddf-assemble-missing.broken b/tests/10ddf-assemble-missing.broken +new file mode 100644 +index 00000000..bfd8d103 +--- /dev/null ++++ b/tests/10ddf-assemble-missing.broken +@@ -0,0 +1,6 @@ ++always fails ++ ++Fails with errors: ++ ++ ERROR: /dev/md/vol0 has unexpected state on /dev/loop10 ++ ERROR: unexpected number of online disks on /dev/loop10 +diff --git a/tests/10ddf-fail-create-race.broken b/tests/10ddf-fail-create-race.broken +new file mode 100644 +index 00000000..6c0df023 +--- /dev/null ++++ b/tests/10ddf-fail-create-race.broken +@@ -0,0 +1,7 @@ ++usually fails ++ ++Fails about 9 out of 10 times with many errors: ++ ++ mdadm: cannot open MISSING: No such file or directory ++ ERROR: non-degraded array found ++ ERROR: disk 0 not marked as failed in meta data +diff --git a/tests/10ddf-fail-two-spares.broken b/tests/10ddf-fail-two-spares.broken +new file mode 100644 +index 00000000..eeea56d9 +--- /dev/null ++++ b/tests/10ddf-fail-two-spares.broken +@@ -0,0 +1,5 @@ ++fails infrequently ++ ++Fails roughly 1 in 3 with error: ++ ++ ERROR: /dev/md/vol1 should be optimal in meta data +diff --git a/tests/10ddf-incremental-wrong-order.broken b/tests/10ddf-incremental-wrong-order.broken +new file mode 100644 +index 00000000..a5af3bab +--- /dev/null ++++ b/tests/10ddf-incremental-wrong-order.broken +@@ -0,0 +1,9 @@ ++always fails ++ ++Fails with errors: ++ ERROR: sha1sum of /dev/md/vol0 has changed ++ ERROR: /dev/md/vol0 has unexpected state on /dev/loop10 ++ ERROR: unexpected number of online disks on /dev/loop10 ++ ERROR: /dev/md/vol0 has unexpected state on /dev/loop8 ++ ERROR: unexpected number of online disks on /dev/loop8 ++ ERROR: sha1sum of /dev/md/vol0 has changed +diff --git a/tests/14imsm-r1_2d-grow-r1_3d.broken b/tests/14imsm-r1_2d-grow-r1_3d.broken +new file mode 100644 +index 00000000..4ef1d406 +--- /dev/null ++++ b/tests/14imsm-r1_2d-grow-r1_3d.broken +@@ -0,0 +1,5 @@ ++always fails ++ ++Fails with error: ++ ++ mdadm/tests/func.sh: line 325: dvsize/chunk: division by 0 (error token is "chunk") +diff --git a/tests/14imsm-r1_2d-takeover-r0_2d.broken b/tests/14imsm-r1_2d-takeover-r0_2d.broken +new file mode 100644 +index 00000000..89cd4e57 +--- /dev/null ++++ b/tests/14imsm-r1_2d-takeover-r0_2d.broken +@@ -0,0 +1,6 @@ ++always fails ++ ++Fails with error: ++ ++ tests/func.sh: line 325: dvsize/chunk: division by 0 (error token ++ is "chunk") +diff --git a/tests/18imsm-r10_4d-takeover-r0_2d.broken b/tests/18imsm-r10_4d-takeover-r0_2d.broken +new file mode 100644 +index 00000000..a27399f5 +--- /dev/null ++++ b/tests/18imsm-r10_4d-takeover-r0_2d.broken +@@ -0,0 +1,5 @@ ++fails rarely ++ ++Fails about 1 run in 100 with message: ++ ++ ERROR: size is wrong for /dev/md/vol0: 2 * 5120 (chunk=128) = 20480, not 0 +diff --git a/tests/18imsm-r1_2d-takeover-r0_1d.broken b/tests/18imsm-r1_2d-takeover-r0_1d.broken +new file mode 100644 +index 00000000..aa1982e6 +--- /dev/null ++++ b/tests/18imsm-r1_2d-takeover-r0_1d.broken +@@ -0,0 +1,6 @@ ++always fails ++ ++Fails with error: ++ ++ tests/func.sh: line 325: dvsize/chunk: division by 0 (error token ++ is "chunk") +diff --git a/tests/19raid6auto-repair.broken b/tests/19raid6auto-repair.broken +new file mode 100644 +index 00000000..e91a1425 +--- /dev/null ++++ b/tests/19raid6auto-repair.broken +@@ -0,0 +1,5 @@ ++always fails ++ ++Fails with: ++ ++ "should detect errors" +diff --git a/tests/19raid6repair.broken b/tests/19raid6repair.broken +new file mode 100644 +index 00000000..e91a1425 +--- /dev/null ++++ b/tests/19raid6repair.broken +@@ -0,0 +1,5 @@ ++always fails ++ ++Fails with: ++ ++ "should detect errors" +-- +2.31.1 + diff --git a/0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch b/0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch new file mode 100644 index 0000000..44b6d7c --- /dev/null +++ b/0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch @@ -0,0 +1,316 @@ +From 239b3cc0b5da87e966746533b1873c439db54b16 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Fri, 12 Aug 2022 16:36:02 +0200 +Subject: [PATCH 45/52] mdadm: Replace obsolete usleep with nanosleep + +According to POSIX.1-2001, usleep is considered obsolete. +Replace it with a wrapper that uses nanosleep, as recommended in man. +Add handy macros for conversions between msec, usec and nsec. + +Signed-off-by: Mateusz Grzonka +Signed-off-by: Jes Sorensen +--- + Assemble.c | 2 +- + Grow.c | 4 ++-- + Manage.c | 10 +++++----- + managemon.c | 8 ++++---- + mdadm.h | 4 ++++ + mdmon.c | 4 ++-- + super-intel.c | 6 +++--- + util.c | 42 +++++++++++++++++++++++++++++++++--------- + 8 files changed, 54 insertions(+), 26 deletions(-) + +diff --git a/Assemble.c b/Assemble.c +index 6df6bfbc..be2160b4 100644 +--- a/Assemble.c ++++ b/Assemble.c +@@ -1947,7 +1947,7 @@ out: + break; + close(mdfd); + } +- usleep(usecs); ++ sleep_for(0, USEC_TO_NSEC(usecs), true); + usecs <<= 1; + } + } +diff --git a/Grow.c b/Grow.c +index 97f22c75..5780635a 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -954,7 +954,7 @@ int start_reshape(struct mdinfo *sra, int already_running, + err = sysfs_set_str(sra, NULL, "sync_action", + "reshape"); + if (err) +- sleep(1); ++ sleep_for(1, 0, true); + } while (err && errno == EBUSY && cnt-- > 0); + } + return err; +@@ -5058,7 +5058,7 @@ int Grow_continue_command(char *devname, int fd, + } + st->ss->getinfo_super(st, content, NULL); + if (!content->reshape_active) +- sleep(3); ++ sleep_for(3, 0, true); + else + break; + } while (cnt-- > 0); +diff --git a/Manage.c b/Manage.c +index e5e6abe4..a142f8bd 100644 +--- a/Manage.c ++++ b/Manage.c +@@ -244,7 +244,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) + "array_state", + "inactive")) < 0 && + errno == EBUSY) { +- usleep(200000); ++ sleep_for(0, MSEC_TO_NSEC(200), true); + count--; + } + if (err) { +@@ -328,7 +328,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) + sysfs_get_ll(mdi, NULL, "sync_max", &old_sync_max) == 0) { + /* must be in the critical section - wait a bit */ + delay -= 1; +- usleep(100000); ++ sleep_for(0, MSEC_TO_NSEC(100), true); + } + + if (sysfs_set_str(mdi, NULL, "sync_action", "frozen") != 0) +@@ -405,7 +405,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) + * quite started yet. Wait a bit and + * check 'sync_action' to see. + */ +- usleep(10000); ++ sleep_for(0, MSEC_TO_NSEC(10), true); + sysfs_get_str(mdi, NULL, "sync_action", buf, sizeof(buf)); + if (strncmp(buf, "reshape", 7) != 0) + break; +@@ -447,7 +447,7 @@ done: + count = 25; err = 0; + while (count && fd >= 0 && + (err = ioctl(fd, STOP_ARRAY, NULL)) < 0 && errno == EBUSY) { +- usleep(200000); ++ sleep_for(0, MSEC_TO_NSEC(200), true); + count --; + } + if (fd >= 0 && err) { +@@ -1105,7 +1105,7 @@ int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv, + ret = sysfs_unique_holder(devnm, rdev); + if (ret < 2) + break; +- usleep(100 * 1000); /* 100ms */ ++ sleep_for(0, MSEC_TO_NSEC(100), true); + } while (--count > 0); + + if (ret == 0) { +diff --git a/managemon.c b/managemon.c +index 0e9bdf00..a7bfa8f6 100644 +--- a/managemon.c ++++ b/managemon.c +@@ -207,7 +207,7 @@ static void replace_array(struct supertype *container, + remove_old(); + while (pending_discard) { + while (discard_this == NULL) +- sleep(1); ++ sleep_for(1, 0, true); + remove_old(); + } + pending_discard = old; +@@ -568,7 +568,7 @@ static void manage_member(struct mdstat_ent *mdstat, + updates = NULL; + while (update_queue_pending || update_queue) { + check_update_queue(container); +- usleep(15*1000); ++ sleep_for(0, MSEC_TO_NSEC(15), true); + } + replace_array(container, a, newa); + if (sysfs_set_str(&a->info, NULL, +@@ -822,7 +822,7 @@ static void handle_message(struct supertype *container, struct metadata_update * + if (msg->len <= 0) + while (update_queue_pending || update_queue) { + check_update_queue(container); +- usleep(15*1000); ++ sleep_for(0, MSEC_TO_NSEC(15), true); + } + + if (msg->len == 0) { /* ping_monitor */ +@@ -836,7 +836,7 @@ static void handle_message(struct supertype *container, struct metadata_update * + wakeup_monitor(); + + while (monitor_loop_cnt - cnt < 0) +- usleep(10 * 1000); ++ sleep_for(0, MSEC_TO_NSEC(10), true); + } else if (msg->len == -1) { /* ping_manager */ + struct mdstat_ent *mdstat = mdstat_read(1, 0); + +diff --git a/mdadm.h b/mdadm.h +index 163f4a49..add9c0b6 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1720,6 +1720,10 @@ extern int cluster_get_dlmlock(void); + extern int cluster_release_dlmlock(void); + extern void set_dlm_hooks(void); + ++#define MSEC_TO_NSEC(msec) ((msec) * 1000000) ++#define USEC_TO_NSEC(usec) ((usec) * 1000) ++extern void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt); ++ + #define _ROUND_UP(val, base) (((val) + (base) - 1) & ~(base - 1)) + #define ROUND_UP(val, base) _ROUND_UP(val, (typeof(val))(base)) + #define ROUND_UP_PTR(ptr, base) ((typeof(ptr)) \ +diff --git a/mdmon.c b/mdmon.c +index c057da63..e9d035eb 100644 +--- a/mdmon.c ++++ b/mdmon.c +@@ -99,7 +99,7 @@ static int clone_monitor(struct supertype *container) + if (rc) + return rc; + while (mon_tid == -1) +- usleep(10); ++ sleep_for(0, USEC_TO_NSEC(10), true); + pthread_attr_destroy(&attr); + + mgr_tid = syscall(SYS_gettid); +@@ -209,7 +209,7 @@ static void try_kill_monitor(pid_t pid, char *devname, int sock) + rv = kill(pid, SIGUSR1); + if (rv < 0) + break; +- usleep(200000); ++ sleep_for(0, MSEC_TO_NSEC(200), true); + } + } + +diff --git a/super-intel.c b/super-intel.c +index 4ddfcf94..4d82af3d 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -5275,7 +5275,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d + /* 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); ++ sleep_for(0, MSEC_TO_NSEC(3), true); + err = load_and_parse_mpb(dfd, s, NULL, keep_fd); + if (err != 3) + break; +@@ -5377,7 +5377,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname) + + if (mdstat && mdmon_running(mdstat->devnm) && getpid() != mdmon_pid(mdstat->devnm)) { + for (retry = 0; retry < 3; retry++) { +- usleep(3000); ++ sleep_for(0, MSEC_TO_NSEC(3), true); + rv = load_and_parse_mpb(fd, super, devname, 0); + if (rv != 3) + break; +@@ -12084,7 +12084,7 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata) + close(fd); + return 1; + } +- usleep(30000); ++ sleep_for(0, MSEC_TO_NSEC(30), true); + } else + break; + } while (retry--); +diff --git a/util.c b/util.c +index 38f0420e..ca48d976 100644 +--- a/util.c ++++ b/util.c +@@ -166,7 +166,7 @@ retry: + pr_err("error %d when get PW mode on lock %s\n", errno, str); + /* let's try several times if EAGAIN happened */ + if (dlm_lock_res->lksb.sb_status == EAGAIN && retry_count < 10) { +- sleep(10); ++ sleep_for(10, 0, true); + retry_count++; + goto retry; + } +@@ -1085,7 +1085,7 @@ int open_dev_excl(char *devnm) + int i; + int flags = O_RDWR; + dev_t devid = devnm2devid(devnm); +- long delay = 1000; ++ unsigned int delay = 1; // miliseconds + + sprintf(buf, "%d:%d", major(devid), minor(devid)); + for (i = 0; i < 25; i++) { +@@ -1098,8 +1098,8 @@ int open_dev_excl(char *devnm) + } + if (errno != EBUSY) + return fd; +- usleep(delay); +- if (delay < 200000) ++ sleep_for(0, MSEC_TO_NSEC(delay), true); ++ if (delay < 200) + delay *= 2; + } + return -1; +@@ -1123,7 +1123,7 @@ void wait_for(char *dev, int fd) + { + int i; + struct stat stb_want; +- long delay = 1000; ++ unsigned int delay = 1; // miliseconds + + if (fstat(fd, &stb_want) != 0 || + (stb_want.st_mode & S_IFMT) != S_IFBLK) +@@ -1135,8 +1135,8 @@ void wait_for(char *dev, int fd) + (stb.st_mode & S_IFMT) == S_IFBLK && + (stb.st_rdev == stb_want.st_rdev)) + return; +- usleep(delay); +- if (delay < 200000) ++ sleep_for(0, MSEC_TO_NSEC(delay), true); ++ if (delay < 200) + delay *= 2; + } + if (i == 25) +@@ -1821,7 +1821,7 @@ int hot_remove_disk(int mdfd, unsigned long dev, int force) + while ((ret = ioctl(mdfd, HOT_REMOVE_DISK, dev)) == -1 && + errno == EBUSY && + cnt-- > 0) +- usleep(10000); ++ sleep_for(0, MSEC_TO_NSEC(10), true); + + return ret; + } +@@ -1834,7 +1834,7 @@ int sys_hot_remove_disk(int statefd, int force) + while ((ret = write(statefd, "remove", 6)) == -1 && + errno == EBUSY && + cnt-- > 0) +- usleep(10000); ++ sleep_for(0, MSEC_TO_NSEC(10), true); + return ret == 6 ? 0 : -1; + } + +@@ -2375,3 +2375,27 @@ out: + close(fd_zero); + return ret; + } ++ ++/** ++ * sleep_for() - Sleeps for specified time. ++ * @sec: Seconds to sleep for. ++ * @nsec: Nanoseconds to sleep for, has to be less than one second. ++ * @wake_after_interrupt: If set, wake up if interrupted. ++ * ++ * Function immediately returns if error different than EINTR occurs. ++ */ ++void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt) ++{ ++ struct timespec delay = {.tv_sec = sec, .tv_nsec = nsec}; ++ ++ assert(nsec < MSEC_TO_NSEC(1000)); ++ ++ do { ++ errno = 0; ++ nanosleep(&delay, &delay); ++ if (errno != 0 && errno != EINTR) { ++ pr_err("Error sleeping for %us %ldns: %s\n", sec, nsec, strerror(errno)); ++ return; ++ } ++ } while (!wake_after_interrupt && errno == EINTR); ++} +-- +2.31.1 + diff --git a/0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch b/0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch new file mode 100644 index 0000000..34f81dd --- /dev/null +++ b/0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch @@ -0,0 +1,36 @@ +From 39b381252c32275079344d30de18b76fda4bba26 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 27 Jul 2022 15:52:45 -0600 +Subject: [PATCH 46/52] tests/00readonly: Run udevadm settle before setting ro + +In some recent kernel versions, 00readonly fails with: + + mdadm: failed to set readonly for /dev/md0: Device or resource busy + ERROR: array is not read-only! + +This was traced down to a race condition with udev holding a reference +to the block device at the same time as trying to set it read only. + +To fix this, call udevadm settle before setting the array read only. + +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + tests/00readonly | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/00readonly b/tests/00readonly +index 39202487..afe243b3 100644 +--- a/tests/00readonly ++++ b/tests/00readonly +@@ -12,6 +12,7 @@ do + $dev1 $dev2 $dev3 $dev4 --assume-clean + check nosync + check $level ++ udevadm settle + mdadm -ro $md0 + check readonly + state=$(cat /sys/block/md0/md/array_state) +-- +2.31.1 + diff --git a/0047-tests-add-test-for-names.patch b/0047-tests-add-test-for-names.patch new file mode 100644 index 0000000..b1dee23 --- /dev/null +++ b/0047-tests-add-test-for-names.patch @@ -0,0 +1,119 @@ +From b7671c82010ffc04dfaecff2dd19ef8b2283e2b6 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Tue, 19 Jul 2022 14:48:21 +0200 +Subject: [PATCH 47/52] tests: add test for names + +Current behavior is not documented and tested. This test is a base for +future improvements. It is enough to test it only with native metadata, +because it is generic code. Generated properties are passed to metadata +handler. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + tests/00createnames | 93 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 93 insertions(+) + create mode 100644 tests/00createnames + +diff --git a/tests/00createnames b/tests/00createnames +new file mode 100644 +index 00000000..64b81b92 +--- /dev/null ++++ b/tests/00createnames +@@ -0,0 +1,93 @@ ++set -x -e ++ ++# Test how and --name= are handled for create mode. ++# We need to check three properties, generated from those parameters: ++# - devnode name ++# - link in /dev/md/ (MD_DEVNAME property from --detail --export) ++# - name in metadata (MD_NAME property from --examine --export) ++ ++function _verify() { ++ local DEVNODE_NAME="$1" ++ local WANTED_LINK="$2" ++ local WANTED_NAME="$3" ++ ++ local RES="$(mdadm -D --export $DEVNODE_NAME | grep MD_DEVNAME)" ++ if [[ "$?" != "0" ]]; then ++ echo "Cannot get details for $DEVNODE_NAME - unexpected devnode." ++ exit 1 ++ fi ++ ++ if [[ "$WANTED_LINK" != "empty" ]]; then ++ local EXPECTED="MD_DEVNAME=$WANTED_LINK" ++ if [[ "$RES" != "$EXPECTED" ]]; then ++ echo "$RES doesn't match $EXPECTED." ++ exit 1 ++ fi ++ fi ++ ++ ++ local RES="$(mdadm -E --export $dev0 | grep MD_NAME)" ++ if [[ "$?" != "0" ]]; then ++ echo "Cannot get metadata from $dev0." ++ exit 1 ++ fi ++ ++ local EXPECTED="MD_NAME=$(hostname):$WANTED_NAME" ++ if [[ "$RES" != "$EXPECTED" ]]; then ++ echo "$RES doesn't match $EXPECTED." ++ exit 1 ++ fi ++} ++ ++function _create() { ++ local DEVNAME=$1 ++ local NAME=$2 ++ ++ if [[ -z "$NAME" ]]; then ++ mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force ++ else ++ mdadm -CR "$DEVNAME" --name="$NAME" -l0 -n 1 $dev0 --force ++ fi ++ ++ if [[ "$?" != "0" ]]; then ++ echo "Cannot create device." ++ exit 1 ++ fi ++} ++ ++# The most trivial case. ++_create "/dev/md/name" ++_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++_create "name" ++_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# Use 'mdX' as name. ++_create "/dev/md/md0" ++_verify "/dev/md127" "md0" "md0" ++mdadm -S "/dev/md127" ++ ++_create "md0" ++_verify "/dev/md127" "md0" "md0" ++mdadm -S "/dev/md127" ++ ++# is used to create MD_DEVNAME but, name is used to create MD_NAME. ++_create "/dev/md/devnode" "name" ++_verify "/dev/md127" "devnode" "name" ++mdadm -S "/dev/md127" ++ ++_create "devnode" "name" ++_verify "/dev/md127" "devnode" "name" ++mdadm -S "/dev/md127" ++ ++# Devnode points to /dev/ directory. MD_DEVNAME doesn't exist. ++_create "/dev/md0" ++_verify "/dev/md0" "empty" "0" ++mdadm -S "/dev/md0" ++ ++# Devnode points to /dev/ directory and name is set. ++_create "/dev/md0" "name" ++_verify "/dev/md0" "empty" "name" ++mdadm -S "/dev/md0" +-- +2.31.1 + diff --git a/0048-mdadm-remove-symlink-option.patch b/0048-mdadm-remove-symlink-option.patch new file mode 100644 index 0000000..13f67ad --- /dev/null +++ b/0048-mdadm-remove-symlink-option.patch @@ -0,0 +1,176 @@ +From e4a030a0d3a953b8e74c118200e58dc83c2fc608 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Tue, 19 Jul 2022 14:48:22 +0200 +Subject: [PATCH 48/52] mdadm: remove symlink option + +The option is not used. Remove it from code. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + ReadMe.c | 1 - + config.c | 7 +------ + mdadm.8.in | 9 --------- + mdadm.c | 20 -------------------- + mdadm.conf.5.in | 15 --------------- + mdadm.h | 2 -- + 6 files changed, 1 insertion(+), 53 deletions(-) + +diff --git a/ReadMe.c b/ReadMe.c +index 7518a32a..7f94847e 100644 +--- a/ReadMe.c ++++ b/ReadMe.c +@@ -147,7 +147,6 @@ struct option long_options[] = { + {"nofailfast",0, 0, NoFailFast}, + {"re-add", 0, 0, ReAdd}, + {"homehost", 1, 0, HomeHost}, +- {"symlinks", 1, 0, Symlinks}, + {"data-offset",1, 0, DataOffset}, + {"nodes",1, 0, Nodes}, /* also for --assemble */ + {"home-cluster",1, 0, ClusterName}, +diff --git a/config.c b/config.c +index 9c725457..dc1620c1 100644 +--- a/config.c ++++ b/config.c +@@ -194,7 +194,6 @@ struct mddev_dev *load_containers(void) + + struct createinfo createinfo = { + .autof = 2, /* by default, create devices with standard names */ +- .symlinks = 1, + .names = 0, /* By default, stick with numbered md devices. */ + .bblist = 1, /* Use a bad block list by default */ + #ifdef DEBIAN +@@ -310,11 +309,7 @@ static void createline(char *line) + if (!createinfo.supertype) + pr_err("metadata format %s unknown, ignoring\n", + w+9); +- } else if (strncasecmp(w, "symlinks=yes", 12) == 0) +- createinfo.symlinks = 1; +- else if (strncasecmp(w, "symlinks=no", 11) == 0) +- createinfo.symlinks = 0; +- else if (strncasecmp(w, "names=yes", 12) == 0) ++ } else if (strncasecmp(w, "names=yes", 12) == 0) + createinfo.names = 1; + else if (strncasecmp(w, "names=no", 11) == 0) + createinfo.names = 0; +diff --git a/mdadm.8.in b/mdadm.8.in +index 0be02e4a..f2736226 100644 +--- a/mdadm.8.in ++++ b/mdadm.8.in +@@ -1048,11 +1048,6 @@ simultaneously. If not specified, this defaults to 4. + Specify journal device for the RAID-4/5/6 array. The journal device + should be a SSD with reasonable lifetime. + +-.TP +-.BR \-\-symlinks +-Auto creation of symlinks in /dev to /dev/md, option --symlinks must +-be 'no' or 'yes' and work with --create and --build. +- + .TP + .BR \-k ", " \-\-consistency\-policy= + Specify how the array maintains consistency in case of unexpected shutdown. +@@ -1405,10 +1400,6 @@ Reshape can be continued later using the + .B \-\-continue + option for the grow command. + +-.TP +-.BR \-\-symlinks +-See this option under Create and Build options. +- + .SH For Manage mode: + + .TP +diff --git a/mdadm.c b/mdadm.c +index 56722ed9..180f7a9c 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -59,7 +59,6 @@ int main(int argc, char *argv[]) + struct mddev_dev *dv; + mdu_array_info_t array; + int devs_found = 0; +- char *symlinks = NULL; + int grow_continue = 0; + /* autof indicates whether and how to create device node. + * bottom 3 bits are style. Rest (when shifted) are number of parts +@@ -663,13 +662,6 @@ int main(int argc, char *argv[]) + case O(ASSEMBLE,Auto): /* auto-creation of device node */ + c.autof = parse_auto(optarg, "--auto flag", 0); + continue; +- +- case O(CREATE,Symlinks): +- case O(BUILD,Symlinks): +- case O(ASSEMBLE,Symlinks): /* auto creation of symlinks in /dev to /dev/md */ +- symlinks = optarg; +- continue; +- + case O(BUILD,'f'): /* force honouring '-n 1' */ + case O(BUILD,Force): /* force honouring '-n 1' */ + case O(GROW,'f'): /* ditto */ +@@ -1325,18 +1317,6 @@ int main(int argc, char *argv[]) + exit(2); + } + +- if (symlinks) { +- struct createinfo *ci = conf_get_create_info(); +- +- if (strcasecmp(symlinks, "yes") == 0) +- ci->symlinks = 1; +- else if (strcasecmp(symlinks, "no") == 0) +- ci->symlinks = 0; +- else { +- pr_err("option --symlinks must be 'no' or 'yes'\n"); +- exit(2); +- } +- } + /* Ok, got the option parsing out of the way + * hopefully it's mostly right but there might be some stuff + * missing +diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in +index cd4e6a9d..bc2295c2 100644 +--- a/mdadm.conf.5.in ++++ b/mdadm.conf.5.in +@@ -338,21 +338,6 @@ missing device entries should be created. + The name of the metadata format to use if none is explicitly given. + This can be useful to impose a system-wide default of version-1 superblocks. + +-.TP +-.B symlinks=no +-Normally when creating devices in +-.B /dev/md/ +-.I mdadm +-will create a matching symlink from +-.B /dev/ +-with a name starting +-.B md +-or +-.BR md_ . +-Give +-.B symlinks=no +-to suppress this symlink creation. +- + .TP + .B names=yes + Since Linux 2.6.29 it has been possible to create +diff --git a/mdadm.h b/mdadm.h +index add9c0b6..93e72786 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -394,7 +394,6 @@ struct createinfo { + int gid; + int autof; + int mode; +- int symlinks; + int names; + int bblist; + struct supertype *supertype; +@@ -442,7 +441,6 @@ enum special_options { + BackupFile, + HomeHost, + AutoHomeHost, +- Symlinks, + AutoDetect, + Waitclean, + DetailPlatform, +-- +2.31.1 + diff --git a/0049-mdadm-move-data_offset-to-struct-shape.patch b/0049-mdadm-move-data_offset-to-struct-shape.patch new file mode 100644 index 0000000..9613654 --- /dev/null +++ b/0049-mdadm-move-data_offset-to-struct-shape.patch @@ -0,0 +1,232 @@ +From ae5dfc56b7a96805d5a0b50eaf93b9fec8604298 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Tue, 19 Jul 2022 14:48:23 +0200 +Subject: [PATCH 49/52] mdadm: move data_offset to struct shape + +Data offset is a shape property so move it there to remove additional +parameter from some functions. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Create.c | 16 ++++++++-------- + Grow.c | 7 +++---- + mdadm.c | 20 +++++++++----------- + mdadm.h | 5 ++--- + 4 files changed, 22 insertions(+), 26 deletions(-) + +diff --git a/Create.c b/Create.c +index c84c1ac8..e06ec2ae 100644 +--- a/Create.c ++++ b/Create.c +@@ -95,7 +95,7 @@ int Create(struct supertype *st, char *mddev, + char *name, int *uuid, + int subdevs, struct mddev_dev *devlist, + struct shape *s, +- struct context *c, unsigned long long data_offset) ++ struct context *c) + { + /* + * Create a new raid array. +@@ -288,7 +288,7 @@ int Create(struct supertype *st, char *mddev, + newsize = s->size * 2; + if (st && ! st->ss->validate_geometry(st, s->level, s->layout, s->raiddisks, + &s->chunk, s->size*2, +- data_offset, NULL, ++ s->data_offset, NULL, + &newsize, s->consistency_policy, + c->verbose >= 0)) + return 1; +@@ -323,10 +323,10 @@ int Create(struct supertype *st, char *mddev, + info.array.working_disks = 0; + dnum = 0; + for (dv = devlist; dv; dv = dv->next) +- if (data_offset == VARIABLE_OFFSET) ++ if (s->data_offset == VARIABLE_OFFSET) + dv->data_offset = INVALID_SECTORS; + else +- dv->data_offset = data_offset; ++ dv->data_offset = s->data_offset; + + for (dv=devlist; dv && !have_container; dv=dv->next, dnum++) { + char *dname = dv->devname; +@@ -342,7 +342,7 @@ int Create(struct supertype *st, char *mddev, + missing_disks ++; + continue; + } +- if (data_offset == VARIABLE_OFFSET) { ++ if (s->data_offset == VARIABLE_OFFSET) { + doff = strchr(dname, ':'); + if (doff) { + *doff++ = 0; +@@ -350,7 +350,7 @@ int Create(struct supertype *st, char *mddev, + } else + dv->data_offset = INVALID_SECTORS; + } else +- dv->data_offset = data_offset; ++ dv->data_offset = s->data_offset; + + dfd = open(dname, O_RDONLY); + if (dfd < 0) { +@@ -535,7 +535,7 @@ int Create(struct supertype *st, char *mddev, + if (!st->ss->validate_geometry(st, s->level, s->layout, + s->raiddisks, + &s->chunk, minsize*2, +- data_offset, ++ s->data_offset, + NULL, NULL, + s->consistency_policy, 0)) { + pr_err("devices too large for RAID level %d\n", s->level); +@@ -754,7 +754,7 @@ int Create(struct supertype *st, char *mddev, + } + } + if (!st->ss->init_super(st, &info.array, s, name, c->homehost, uuid, +- data_offset)) ++ s->data_offset)) + goto abort_locked; + + total_slots = info.array.nr_disks; +diff --git a/Grow.c b/Grow.c +index 5780635a..868bdc3a 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -1775,7 +1775,6 @@ static int reshape_container(char *container, char *devname, + + int Grow_reshape(char *devname, int fd, + struct mddev_dev *devlist, +- unsigned long long data_offset, + struct context *c, struct shape *s) + { + /* Make some changes in the shape of an array. +@@ -1821,7 +1820,7 @@ int Grow_reshape(char *devname, int fd, + return 1; + } + +- if (data_offset != INVALID_SECTORS && array.level != 10 && ++ if (s->data_offset != INVALID_SECTORS && array.level != 10 && + (array.level < 4 || array.level > 6)) { + pr_err("--grow --data-offset not yet supported\n"); + return 1; +@@ -2179,7 +2178,7 @@ size_change_error: + if ((s->level == UnSet || s->level == array.level) && + (s->layout_str == NULL) && + (s->chunk == 0 || s->chunk == array.chunk_size) && +- data_offset == INVALID_SECTORS && ++ s->data_offset == INVALID_SECTORS && + (s->raiddisks == 0 || s->raiddisks == array.raid_disks)) { + /* Nothing more to do */ + if (!changed && c->verbose >= 0) +@@ -2379,7 +2378,7 @@ size_change_error: + } + sync_metadata(st); + rv = reshape_array(container, fd, devname, st, &info, c->force, +- devlist, data_offset, c->backup_file, ++ devlist, s->data_offset, c->backup_file, + c->verbose, 0, 0, 0); + frozen = 0; + } +diff --git a/mdadm.c b/mdadm.c +index 180f7a9c..845e4466 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -49,7 +49,6 @@ int main(int argc, char *argv[]) + int i; + + unsigned long long array_size = 0; +- unsigned long long data_offset = INVALID_SECTORS; + struct mddev_ident ident; + char *configfile = NULL; + int devmode = 0; +@@ -79,6 +78,7 @@ int main(int argc, char *argv[]) + .layout = UnSet, + .bitmap_chunk = UnSet, + .consistency_policy = CONSISTENCY_POLICY_UNKNOWN, ++ .data_offset = INVALID_SECTORS, + }; + + char sys_hostname[256]; +@@ -479,15 +479,15 @@ int main(int argc, char *argv[]) + + case O(CREATE,DataOffset): + case O(GROW,DataOffset): +- if (data_offset != INVALID_SECTORS) { ++ if (s.data_offset != INVALID_SECTORS) { + pr_err("data-offset may only be specified one. Second value is %s.\n", optarg); + exit(2); + } + if (mode == CREATE && strcmp(optarg, "variable") == 0) +- data_offset = VARIABLE_OFFSET; ++ s.data_offset = VARIABLE_OFFSET; + else +- data_offset = parse_size(optarg); +- if (data_offset == INVALID_SECTORS) { ++ s.data_offset = parse_size(optarg); ++ if (s.data_offset == INVALID_SECTORS) { + pr_err("invalid data-offset: %s\n", + optarg); + exit(2); +@@ -1416,7 +1416,7 @@ int main(int argc, char *argv[]) + exit(1); + } + +- if (c.backup_file && data_offset != INVALID_SECTORS) { ++ if (c.backup_file && s.data_offset != INVALID_SECTORS) { + pr_err("--backup-file and --data-offset are incompatible\n"); + exit(2); + } +@@ -1587,8 +1587,7 @@ int main(int argc, char *argv[]) + + rv = Create(ss, devlist->devname, + ident.name, ident.uuid_set ? ident.uuid : NULL, +- devs_found-1, devlist->next, +- &s, &c, data_offset); ++ devs_found - 1, devlist->next, &s, &c); + break; + case MISC: + if (devmode == 'E') { +@@ -1706,10 +1705,9 @@ int main(int argc, char *argv[]) + c.verbose); + else if (s.size > 0 || s.raiddisks || s.layout_str || + s.chunk != 0 || s.level != UnSet || +- data_offset != INVALID_SECTORS) { ++ s.data_offset != INVALID_SECTORS) { + rv = Grow_reshape(devlist->devname, mdfd, +- devlist->next, +- data_offset, &c, &s); ++ devlist->next, &c, &s); + } else if (s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN) { + rv = Grow_consistency_policy(devlist->devname, mdfd, &c, &s); + } else if (array_size == 0) +diff --git a/mdadm.h b/mdadm.h +index 93e72786..adb7cdaa 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -595,6 +595,7 @@ struct shape { + int assume_clean; + int write_behind; + unsigned long long size; ++ unsigned long long data_offset; + int consistency_policy; + }; + +@@ -1431,7 +1432,6 @@ extern int Grow_addbitmap(char *devname, int fd, + struct context *c, struct shape *s); + extern int Grow_reshape(char *devname, int fd, + struct mddev_dev *devlist, +- unsigned long long data_offset, + struct context *c, struct shape *s); + extern int Grow_restart(struct supertype *st, struct mdinfo *info, + int *fdlist, int cnt, char *backup_file, int verbose); +@@ -1462,8 +1462,7 @@ extern int Create(struct supertype *st, char *mddev, + char *name, int *uuid, + int subdevs, struct mddev_dev *devlist, + struct shape *s, +- struct context *c, +- unsigned long long data_offset); ++ struct context *c); + + extern int Detail(char *dev, struct context *c); + extern int Detail_Platform(struct superswitch *ss, int scan, int verbose, int export, char *controller_path); +-- +2.31.1 + diff --git a/0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch b/0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch new file mode 100644 index 0000000..a28efa4 --- /dev/null +++ b/0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch @@ -0,0 +1,162 @@ +From 27ad4900501c615b7c6b266bf23948e5606dba53 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 27 Jul 2022 15:52:46 -0600 +Subject: [PATCH 50/52] mdadm: Don't open md device for CREATE and ASSEMBLE + +The mdadm command tries to open the md device for most modes, first +thing, no matter what. When running to create or assemble an array, +in most cases, the md device will not exist, the open call will fail +and everything will proceed correctly. + +However, when running tests, a create or assembly command may be run +shortly after stopping an array and the old md device file may still +be around. Then, if create_on_open is set in the kernel, a new md +device will be created when mdadm does its initial open. + +When mdadm gets around to creating the new device with the new_array +parameter it issues this error: + + mdadm: Fail to create md0 when using + /sys/module/md_mod/parameters/new_array, fallback to creation via node + +This is because an mddev was already created by the kernel with the +earlier open() call and thus the new one being created will fail with +EEXIST. The mdadm command will still successfully be created due to +falling back to the node creation method. However, the error message +itself will fail any test that's running it. + +This issue is a race condition that is very rare, but a recent change +in the kernel caused this to happen more frequently: about 1 in 50 +times. + +To fix this, don't bother trying to open the md device for CREATE, +ASSEMBLE and BUILD commands, as the file descriptor will never be used +anyway even if it is successfully openned. The mdfd has not been used +for these commands since: + + 7f91af49ad09 ("Delay creation of array devices for assemble/build/create") + +The checks that were done on the open device can be changed to being +done with stat. + +Side note: it would be nice to disable create_on_open as well to help +solve this, but it seems the work for this was never finished. By default, +mdadm will create using the old node interface when a name is specified +unless the user specifically puts names=yes in a config file, which +doesn't seem to be common or desirable to require this.. + +Signed-off-by: Logan Gunthorpe +Signed-off-by: Jes Sorensen +--- + lib.c | 12 ++++++++++++ + mdadm.c | 40 ++++++++++++++++++++-------------------- + mdadm.h | 1 + + 3 files changed, 33 insertions(+), 20 deletions(-) + +diff --git a/lib.c b/lib.c +index 7e3e3d47..e395b28d 100644 +--- a/lib.c ++++ b/lib.c +@@ -164,6 +164,18 @@ char *stat2devnm(struct stat *st) + return devid2devnm(st->st_rdev); + } + ++bool stat_is_md_dev(struct stat *st) ++{ ++ if ((S_IFMT & st->st_mode) != S_IFBLK) ++ return false; ++ if (major(st->st_rdev) == MD_MAJOR) ++ return true; ++ if (major(st->st_rdev) == (unsigned)get_mdp_major()) ++ return true; ++ ++ return false; ++} ++ + char *fd2devnm(int fd) + { + struct stat stb; +diff --git a/mdadm.c b/mdadm.c +index 845e4466..972adb52 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -1329,6 +1329,9 @@ int main(int argc, char *argv[]) + + if (mode == MANAGE || mode == BUILD || mode == CREATE || + mode == GROW || (mode == ASSEMBLE && ! c.scan)) { ++ struct stat stb; ++ int ret; ++ + if (devs_found < 1) { + pr_err("an md device must be given in this mode\n"); + exit(2); +@@ -1341,6 +1344,12 @@ int main(int argc, char *argv[]) + mdfd = open_mddev(devlist->devname, 1); + if (mdfd < 0) + exit(1); ++ ++ ret = fstat(mdfd, &stb); ++ if (ret) { ++ pr_err("fstat failed on %s.\n", devlist->devname); ++ exit(1); ++ } + } else { + char *bname = basename(devlist->devname); + +@@ -1348,30 +1357,21 @@ int main(int argc, char *argv[]) + pr_err("Name %s is too long.\n", devlist->devname); + exit(1); + } +- /* non-existent device is OK */ +- mdfd = open_mddev(devlist->devname, 0); +- } +- if (mdfd == -2) { +- pr_err("device %s exists but is not an md array.\n", devlist->devname); +- exit(1); +- } +- if ((int)ident.super_minor == -2) { +- struct stat stb; +- if (mdfd < 0) { ++ ++ ret = stat(devlist->devname, &stb); ++ if (ident.super_minor == -2 && ret != 0) { + pr_err("--super-minor=dev given, and listed device %s doesn't exist.\n", +- devlist->devname); ++ devlist->devname); ++ exit(1); ++ } ++ ++ if (!ret && !stat_is_md_dev(&stb)) { ++ pr_err("device %s exists but is not an md array.\n", devlist->devname); + exit(1); + } +- fstat(mdfd, &stb); +- ident.super_minor = minor(stb.st_rdev); +- } +- if (mdfd >= 0 && mode != MANAGE && mode != GROW) { +- /* We don't really want this open yet, we just might +- * have wanted to check some things +- */ +- close(mdfd); +- mdfd = -1; + } ++ if (ident.super_minor == -2) ++ ident.super_minor = minor(stb.st_rdev); + } + + if (s.raiddisks) { +diff --git a/mdadm.h b/mdadm.h +index adb7cdaa..8208b81e 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1672,6 +1672,7 @@ void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0 + extern char *stat2kname(struct stat *st); + extern char *fd2kname(int fd); + extern char *stat2devnm(struct stat *st); ++bool stat_is_md_dev(struct stat *st); + extern char *fd2devnm(int fd); + extern void udev_block(char *devnm); + extern void udev_unblock(void); +-- +2.31.1 + diff --git a/0051-Grow-Split-Grow_reshape-into-helper-function.patch b/0051-Grow-Split-Grow_reshape-into-helper-function.patch new file mode 100644 index 0000000..2b5aaaf --- /dev/null +++ b/0051-Grow-Split-Grow_reshape-into-helper-function.patch @@ -0,0 +1,231 @@ +From 7211116c295ba1f9e1fcbdc2dd2d3762855062e1 Mon Sep 17 00:00:00 2001 +From: Mateusz Kusiak +Date: Thu, 28 Jul 2022 20:20:53 +0800 +Subject: [PATCH 51/52] Grow: Split Grow_reshape into helper function + +Grow_reshape should be split into helper functions given its size. +- Add helper function for preparing reshape on external metadata. +- Close cfd file descriptor. + +Signed-off-by: Mateusz Kusiak +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Grow.c | 125 ++++++++++++++++++++++++++++++-------------------------- + mdadm.h | 1 + + util.c | 14 +++++++ + 3 files changed, 81 insertions(+), 59 deletions(-) + +diff --git a/Grow.c b/Grow.c +index 868bdc3a..0f07a894 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -1773,6 +1773,65 @@ static int reshape_container(char *container, char *devname, + char *backup_file, int verbose, + int forked, int restart, int freeze_reshape); + ++/** ++ * prepare_external_reshape() - prepares update on external metadata if supported. ++ * @devname: Device name. ++ * @subarray: Subarray. ++ * @st: Supertype. ++ * @container: Container. ++ * @cfd: Container file descriptor. ++ * ++ * Function checks that the requested reshape is supported on external metadata, ++ * and performs an initial check that the container holds the pre-requisite ++ * spare devices (mdmon owns final validation). ++ * ++ * Return: 0 on success, else 1 ++ */ ++static int prepare_external_reshape(char *devname, char *subarray, ++ struct supertype *st, char *container, ++ const int cfd) ++{ ++ struct mdinfo *cc = NULL; ++ struct mdinfo *content = NULL; ++ ++ if (st->ss->load_container(st, cfd, NULL)) { ++ pr_err("Cannot read superblock for %s\n", devname); ++ return 1; ++ } ++ ++ if (!st->ss->container_content) ++ return 1; ++ ++ cc = st->ss->container_content(st, subarray); ++ for (content = cc; content ; content = content->next) { ++ /* ++ * check if reshape is allowed based on metadata ++ * indications stored in content.array.status ++ */ ++ if (is_bit_set(&content->array.state, MD_SB_BLOCK_VOLUME) || ++ is_bit_set(&content->array.state, MD_SB_BLOCK_CONTAINER_RESHAPE)) { ++ pr_err("Cannot reshape arrays in container with unsupported metadata: %s(%s)\n", ++ devname, container); ++ goto error; ++ } ++ if (content->consistency_policy == CONSISTENCY_POLICY_PPL) { ++ pr_err("Operation not supported when ppl consistency policy is enabled\n"); ++ goto error; ++ } ++ if (content->consistency_policy == CONSISTENCY_POLICY_BITMAP) { ++ pr_err("Operation not supported when write-intent bitmap consistency policy is enabled\n"); ++ goto error; ++ } ++ } ++ sysfs_free(cc); ++ if (mdmon_running(container)) ++ st->update_tail = &st->updates; ++ return 0; ++error: ++ sysfs_free(cc); ++ return 1; ++} ++ + int Grow_reshape(char *devname, int fd, + struct mddev_dev *devlist, + struct context *c, struct shape *s) +@@ -1799,7 +1858,7 @@ int Grow_reshape(char *devname, int fd, + struct supertype *st; + char *subarray = NULL; + +- int frozen; ++ int frozen = 0; + int changed = 0; + char *container = NULL; + int cfd = -1; +@@ -1808,7 +1867,7 @@ int Grow_reshape(char *devname, int fd, + int added_disks; + + struct mdinfo info; +- struct mdinfo *sra; ++ struct mdinfo *sra = NULL; + + if (md_get_array_info(fd, &array) < 0) { + pr_err("%s is not an active md array - aborting\n", +@@ -1865,13 +1924,7 @@ int Grow_reshape(char *devname, int fd, + } + } + +- /* in the external case we need to check that the requested reshape is +- * supported, and perform an initial check that the container holds the +- * pre-requisite spare devices (mdmon owns final validation) +- */ + if (st->ss->external) { +- int retval; +- + if (subarray) { + container = st->container_devnm; + cfd = open_dev_excl(st->container_devnm); +@@ -1887,13 +1940,12 @@ int Grow_reshape(char *devname, int fd, + return 1; + } + +- retval = st->ss->load_container(st, cfd, NULL); +- +- if (retval) { +- pr_err("Cannot read superblock for %s\n", devname); +- close(cfd); ++ rv = prepare_external_reshape(devname, subarray, st, ++ container, cfd); ++ if (rv > 0) { + free(subarray); +- return 1; ++ close(cfd); ++ goto release; + } + + if (s->raiddisks && subarray) { +@@ -1902,51 +1954,6 @@ int Grow_reshape(char *devname, int fd, + free(subarray); + return 1; + } +- +- /* check if operation is supported for metadata handler */ +- if (st->ss->container_content) { +- struct mdinfo *cc = NULL; +- struct mdinfo *content = NULL; +- +- cc = st->ss->container_content(st, subarray); +- for (content = cc; content ; content = content->next) { +- int allow_reshape = 1; +- +- /* check if reshape is allowed based on metadata +- * indications stored in content.array.status +- */ +- if (content->array.state & +- (1 << MD_SB_BLOCK_VOLUME)) +- allow_reshape = 0; +- if (content->array.state & +- (1 << MD_SB_BLOCK_CONTAINER_RESHAPE)) +- allow_reshape = 0; +- if (!allow_reshape) { +- pr_err("cannot reshape arrays in container with unsupported metadata: %s(%s)\n", +- devname, container); +- sysfs_free(cc); +- free(subarray); +- return 1; +- } +- if (content->consistency_policy == +- CONSISTENCY_POLICY_PPL) { +- pr_err("Operation not supported when ppl consistency policy is enabled\n"); +- sysfs_free(cc); +- free(subarray); +- return 1; +- } +- if (content->consistency_policy == +- CONSISTENCY_POLICY_BITMAP) { +- pr_err("Operation not supported when write-intent bitmap is enabled\n"); +- sysfs_free(cc); +- free(subarray); +- return 1; +- } +- } +- sysfs_free(cc); +- } +- if (mdmon_running(container)) +- st->update_tail = &st->updates; + } + + added_disks = 0; +diff --git a/mdadm.h b/mdadm.h +index 8208b81e..941a5f38 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1539,6 +1539,7 @@ extern int stat_is_blkdev(char *devname, dev_t *rdev); + extern bool is_dev_alive(char *path); + extern int get_mdp_major(void); + extern int get_maj_min(char *dev, int *major, int *minor); ++extern bool is_bit_set(int *val, unsigned char index); + extern int dev_open(char *dev, int flags); + extern int open_dev(char *devnm); + extern void reopen_mddev(int mdfd); +diff --git a/util.c b/util.c +index ca48d976..26ffdcea 100644 +--- a/util.c ++++ b/util.c +@@ -1027,6 +1027,20 @@ int get_maj_min(char *dev, int *major, int *minor) + *e == 0); + } + ++/** ++ * is_bit_set() - get bit value by index. ++ * @val: value. ++ * @index: index of the bit (LSB numbering). ++ * ++ * Return: bit value. ++ */ ++bool is_bit_set(int *val, unsigned char index) ++{ ++ if ((*val) & (1 << index)) ++ return true; ++ return false; ++} ++ + int dev_open(char *dev, int flags) + { + /* like 'open', but if 'dev' matches %d:%d, create a temp +-- +2.31.1 + diff --git a/0052-Assemble-check-if-device-is-container-before-schedul.patch b/0052-Assemble-check-if-device-is-container-before-schedul.patch new file mode 100644 index 0000000..4c4c323 --- /dev/null +++ b/0052-Assemble-check-if-device-is-container-before-schedul.patch @@ -0,0 +1,36 @@ +From 5c3c3df646dd3b7e8df81152f08e9ac4ddccc671 Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Fri, 19 Aug 2022 02:55:46 +0200 +Subject: [PATCH 52/52] Assemble: check if device is container before + scheduling force-clean update + +Up to now using assemble with force flag making each array as clean. +Force-clean should not be done for the container. This commit add +check if device is different than container before cleaning. + +Signed-off-by: Kinga Tanska +Signed-off-by: Jes Sorensen +--- + Assemble.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/Assemble.c b/Assemble.c +index be2160b4..1dd82a8c 100644 +--- a/Assemble.c ++++ b/Assemble.c +@@ -1809,10 +1809,9 @@ try_again: + } + #endif + } +- if (c->force && !clean && ++ if (c->force && !clean && content->array.level != LEVEL_CONTAINER && + !enough(content->array.level, content->array.raid_disks, +- content->array.layout, clean, +- avail)) { ++ content->array.layout, clean, avail)) { + change += st->ss->update_super(st, content, "force-array", + devices[chosen_drive].devname, c->verbose, + 0, NULL); +-- +2.31.1 + diff --git a/Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch b/Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch deleted file mode 100644 index 08b6900..0000000 --- a/Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 7e92ef334af165a5e50b33ddff98e18f1c8a18d0 Mon Sep 17 00:00:00 2001 -From: Xiao Ni -Date: Thu, 24 Feb 2022 11:37:34 +0800 -Subject: [PATCH 1/1] Revert "mdadm: fix coredump of mdadm --monitor -r" - -This reverts commit 546047688e1c64638f462147c755b58119cabdc8. - -This is a rhel ony patch. We have sent patch to upstream. But -it hasn't been merged. We will remove this patch once upstream -merges our patch. - -Signed-off-by: Xiao Ni ---- - ReadMe.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/ReadMe.c b/ReadMe.c -index 81399765..ee457a54 100644 ---- a/ReadMe.c -+++ b/ReadMe.c -@@ -81,11 +81,11 @@ char Version[] = "mdadm - v" VERSION " - " VERS_DATE EXTRAVERSION "\n"; - * found, it is started. - */ - --char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:r:n:x:u:c:d:z:U:N:safRSow1tye:k"; -+char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:"; - char short_bitmap_options[]= -- "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sarfRSow1tye:k:"; -+ "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:"; - char short_bitmap_auto_options[]= -- "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:"; -+ "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:"; - - struct option long_options[] = { - {"manage", 0, 0, ManageOpt}, --- -2.31.1 - diff --git a/mdadm.spec b/mdadm.spec index 8f53f14..543e1a2 100644 --- a/mdadm.spec +++ b/mdadm.spec @@ -2,7 +2,7 @@ Summary: The mdadm program controls Linux md devices (software RAID arrays) Name: mdadm Version: 4.2 # extraversion is used to define rhel internal version -%define extraversion 4 +%define extraversion 5 Release: %{extraversion}%{?dist} Source: http://www.kernel.org/pub/linux/utils/raid/mdadm/mdadm-%{version}%{?subversion:-%{subversion}}.tar.xz Source1: mdmonitor.init @@ -17,18 +17,57 @@ Source9: mdcheck Source10: mdadm_env.sh Patch000: disable-Werror.patch -Patch001: Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch -Patch002: 0001-Unify-error-message.patch -Patch003: 0002-mdadm-Fix-double-free.patch -Patch004: 0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch -Patch005: 0004-udev-adapt-rules-to-systemd-v247.patch -Patch006: 0005-Replace-error-prone-signal-with-sigaction.patch -Patch007: 0006-mdadm-Respect-config-file-location-in-man.patch -Patch008: 0007-mdadm-Update-ReadMe.patch -Patch009: 0008-mdadm-Update-config-man-regarding-default-files-and-.patch -Patch010: 0009-mdadm-Update-config-manual.patch -Patch011: 0010-Create-Build-use-default_layout.patch -Patch012: 0011-mdadm-add-map_num_s.patch +Patch001: 0001-Unify-error-message.patch +Patch002: 0002-mdadm-Fix-double-free.patch +Patch003: 0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch +Patch004: 0004-udev-adapt-rules-to-systemd-v247.patch +Patch005: 0005-Replace-error-prone-signal-with-sigaction.patch +Patch006: 0006-mdadm-Respect-config-file-location-in-man.patch +Patch007: 0007-mdadm-Update-ReadMe.patch +Patch008: 0008-mdadm-Update-config-man-regarding-default-files-and-.patch +Patch009: 0009-mdadm-Update-config-manual.patch +Patch010: 0010-Create-Build-use-default_layout.patch +Patch011: 0011-mdadm-add-map_num_s.patch +Patch012: 0013-mdmon-Stop-parsing-duplicate-options.patch +Patch013: 0014-Grow-block-n-on-external-volumes.patch +Patch014: 0015-Incremental-Fix-possible-memory-and-resource-leaks.patch +Patch015: 0016-Mdmonitor-Fix-segfault.patch +Patch016: 0017-Mdmonitor-Improve-logging-method.patch +Patch017: 0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch +Patch018: 0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch +Patch019: 0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch +Patch020: 0021-util-replace-ioctl-use-with-function.patch +Patch021: 0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch +Patch022: 0023-imsm-introduce-get_disk_slot_in_dev.patch +Patch023: 0024-imsm-use-same-slot-across-container.patch +Patch024: 0025-imsm-block-changing-slots-during-creation.patch +Patch025: 0026-mdadm-block-update-ppl-for-non-raid456-levels.patch +Patch026: 0027-mdadm-Fix-array-size-mismatch-after-grow.patch +Patch027: 0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch +Patch028: 0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch +Patch029: 0030-Monitor-use-snprintf-to-fill-device-name.patch +Patch030: 0031-Makefile-Don-t-build-static-build-with-everything-an.patch +Patch031: 0032-DDF-Cleanup-validate_geometry_ddf_container.patch +Patch032: 0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch +Patch033: 0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch +Patch034: 0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch +Patch035: 0036-mdadm-Fix-mdadm-r-remove-option-regression.patch +Patch036: 0037-mdadm-Fix-optional-write-behind-parameter.patch +Patch037: 0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch +Patch038: 0039-tests-fix-raid0-tests-for-0.90-metadata.patch +Patch039: 0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch +Patch040: 0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch +Patch041: 0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch +Patch042: 0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch +Patch043: 0044-tests-Add-broken-files-for-all-broken-tests.patch +Patch044: 0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch +Patch045: 0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch +Patch046: 0047-tests-add-test-for-names.patch +Patch047: 0048-mdadm-remove-symlink-option.patch +Patch048: 0049-mdadm-move-data_offset-to-struct-shape.patch +Patch049: 0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch +Patch050: 0051-Grow-Split-Grow_reshape-into-helper-function.patch +Patch051: 0052-Assemble-check-if-device-is-container-before-schedul.patch # RHEL customization patches Patch200: mdadm-3.3-udev.patch @@ -60,18 +99,57 @@ file can be used to help with some common tasks. %setup -q -n %{name}-%{version}%{?subversion:_%{subversion}} %patch000 -p1 -b .disable -%patch001 -p1 -b .Revert -%patch002 -p1 -b .0001 -%patch003 -p1 -b .0002 -%patch004 -p1 -b .0003 -%patch005 -p1 -b .0004 -%patch006 -p1 -b .0005 -%patch007 -p1 -b .0006 -%patch008 -p1 -b .0007 -%patch009 -p1 -b .0008 -%patch010 -p1 -b .0009 -%patch011 -p1 -b .0010 -%patch012 -p1 -b .0011 +%patch001 -p1 -b .0001 +%patch002 -p1 -b .0002 +%patch003 -p1 -b .0003 +%patch004 -p1 -b .0004 +%patch005 -p1 -b .0005 +%patch006 -p1 -b .0006 +%patch007 -p1 -b .0007 +%patch008 -p1 -b .0008 +%patch009 -p1 -b .0009 +%patch010 -p1 -b .0010 +%patch011 -p1 -b .0011 +%patch012 -p1 -b .0013 +%patch013 -p1 -b .0014 +%patch014 -p1 -b .0015 +%patch015 -p1 -b .0016 +%patch016 -p1 -b .0017 +%patch017 -p1 -b .0018 +%patch018 -p1 -b .0019 +%patch019 -p1 -b .0020 +%patch020 -p1 -b .0021 +%patch021 -p1 -b .0022 +%patch022 -p1 -b .0023 +%patch023 -p1 -b .0024 +%patch024 -p1 -b .0025 +%patch025 -p1 -b .0026 +%patch026 -p1 -b .0027 +%patch027 -p1 -b .0028 +%patch028 -p1 -b .0029 +%patch029 -p1 -b .0030 +%patch030 -p1 -b .0031 +%patch031 -p1 -b .0032 +%patch032 -p1 -b .0033 +%patch033 -p1 -b .0034 +%patch034 -p1 -b .0035 +%patch035 -p1 -b .0036 +%patch036 -p1 -b .0037 +%patch037 -p1 -b .0038 +%patch038 -p1 -b .0039 +%patch039 -p1 -b .0040 +%patch040 -p1 -b .0041 +%patch041 -p1 -b .0042 +%patch042 -p1 -b .0043 +%patch043 -p1 -b .0044 +%patch044 -p1 -b .0045 +%patch045 -p1 -b .0046 +%patch046 -p1 -b .0047 +%patch047 -p1 -b .0048 +%patch048 -p1 -b .0049 +%patch049 -p1 -b .0050 +%patch050 -p1 -b .0051 +%patch051 -p1 -b .0052 # RHEL customization patches %patch200 -p1 -b .udev @@ -143,6 +221,10 @@ rm -rf %{buildroot} /usr/lib/mdadm/mdadm_env.sh %changelog +* Thu Aug 25 2022 Xiao Ni - 4.2-5 +- Update mdadm to latest upstream +- Resolves rhbz#2092326 + * Sun Aug 07 2022 Xiao Ni - 4.2-4 - Add KillMode=none to mdmon systemd service again - Resolves rhbz#2109397