diff --git a/SOURCES/0012-mdadm-systemd-remove-KillMode-none-from-service-file.patch b/SOURCES/0012-mdadm-systemd-remove-KillMode-none-from-service-file.patch new file mode 100644 index 0000000..088b803 --- /dev/null +++ b/SOURCES/0012-mdadm-systemd-remove-KillMode-none-from-service-file.patch @@ -0,0 +1,69 @@ +From 52c67fcdd6dadc4138ecad73e65599551804d445 Mon Sep 17 00:00:00 2001 +From: Coly Li +Date: Tue, 15 Feb 2022 21:34:15 +0800 +Subject: [PATCH 012/125] mdadm/systemd: remove KillMode=none from service file + +For mdadm's systemd configuration, current systemd KillMode is "none" in +following service files, +- mdadm-grow-continue@.service +- mdmon@.service + +This "none" mode is strongly againsted by systemd developers (see man 5 +systemd.kill for "KillMode=" section), and is considering to remove in +future systemd version. + +As systemd developer explained in disuccsion, the systemd kill process +is, +1. send the signal specified by KillSignal= to the list of processes (if + any), TERM is the default +2. wait until either the target of process(es) exit or a timeout expires +3. if the timeout expires send the signal specified by FinalKillSignal=, + KILL is the default + +For "control-group", all remaining processes will receive the SIGTERM +signal (by default) and if there are still processes after a period f +time, they will get the SIGKILL signal. + +For "mixed", only the main process will receive the SIGTERM signal, and +if there are still processes after a period of time, all remaining +processes (including the main one) will receive the SIGKILL signal. + +From the above comment, currently KillMode=control-group is a proper +kill mode. Since control-gropu is the default kill mode, the fix can be +simply removing KillMode=none line from the service file, then the +default mode will take effect. + +Signed-off-by: Coly Li +Cc: Benjamin Brunner +Cc: Franck Bui +Cc: Jes Sorensen +Cc: Mariusz Tkaczyk +Cc: Neil Brown +Cc: Xiao Ni +Signed-off-by: Jes Sorensen +--- + systemd/mdadm-grow-continue@.service | 1 - + systemd/mdmon@.service | 1 - + 2 files changed, 2 deletions(-) + +diff --git a/systemd/mdadm-grow-continue@.service b/systemd/mdadm-grow-continue@.service +index 5c667d2a..9fdc8ec7 100644 +--- a/systemd/mdadm-grow-continue@.service ++++ b/systemd/mdadm-grow-continue@.service +@@ -14,4 +14,3 @@ ExecStart=BINDIR/mdadm --grow --continue /dev/%I + StandardInput=null + StandardOutput=null + StandardError=null +-KillMode=none +diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service +index 85a3a7c5..77533958 100644 +--- a/systemd/mdmon@.service ++++ b/systemd/mdmon@.service +@@ -25,4 +25,3 @@ Type=forking + # it out) and systemd will remove it when transitioning from + # initramfs to rootfs. + #PIDFile=/run/mdadm/%I.pid +-KillMode=none +-- +2.38.1 + diff --git a/SOURCES/0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch b/SOURCES/0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch new file mode 100644 index 0000000..493a0e9 --- /dev/null +++ b/SOURCES/0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch @@ -0,0 +1,54 @@ +From 28a083955c6f58f8e582734c8c82aff909a7d461 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 2 Feb 2023 08:56:31 +0100 +Subject: [PATCH 084/125] Revert "mdadm/systemd: remove KillMode=none from + service file" + +This reverts commit 52c67fcdd6dadc4138ecad73e65599551804d445. + +The functionality is marked as deprecated but we don't have alternative +solution yet. Shutdown hangs if OS is installed on external array: + +task:umount state:D stack: 0 pid: 6285 ppid: flags:0x00004084 +Call Trace: +__schedule+0x2d1/0x830 +? finish_wait+0x80/0x80 +schedule+0x35/0xa0 +md_write_start+0x14b/0x220 +? finish_wait+0x80/0x80 +raid1_make_request+0x3c/0x90 [raid1] +md_handle_request+0x128/0x1b0 +md_make_request+0x5b/0xb0 +generic_make_request_no_check+0x202/0x330 +submit_bio+0x3c/0x160 + +Use it until new solution is implemented. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + systemd/mdadm-grow-continue@.service | 1 + + systemd/mdmon@.service | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/systemd/mdadm-grow-continue@.service b/systemd/mdadm-grow-continue@.service +index 64b8254a..9ccadca3 100644 +--- a/systemd/mdadm-grow-continue@.service ++++ b/systemd/mdadm-grow-continue@.service +@@ -15,3 +15,4 @@ ExecStart=BINDIR/mdadm --grow --continue /dev/%I + StandardInput=null + StandardOutput=null + StandardError=null ++KillMode=none +diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service +index 97a1acd9..cb6482d9 100644 +--- a/systemd/mdmon@.service ++++ b/systemd/mdmon@.service +@@ -26,3 +26,4 @@ Type=forking + # it out) and systemd will remove it when transitioning from + # initramfs to rootfs. + #PIDFile=/run/mdadm/%I.pid ++KillMode=none +-- +2.38.1 + diff --git a/SOURCES/0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch b/SOURCES/0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch new file mode 100644 index 0000000..d0ff1ff --- /dev/null +++ b/SOURCES/0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch @@ -0,0 +1,45 @@ +From d07e561810a2e33b667a8a9476edaff42eb119b9 Mon Sep 17 00:00:00 2001 +From: Heming Zhao +Date: Thu, 23 Feb 2023 22:39:39 +0800 +Subject: [PATCH 085/125] Grow: fix can't change bitmap type from none to + clustered. + +Commit a042210648ed ("disallow create or grow clustered bitmap with +writemostly set") introduced this bug. We should use 'true' logic not +'== 0' to deny setting up clustered array under WRITEMOSTLY condition. + +How to trigger + +``` +~/mdadm # ./mdadm -Ss && ./mdadm --zero-superblock /dev/sd{a,b} +~/mdadm # ./mdadm -C /dev/md0 -l mirror -b clustered -e 1.2 -n 2 \ +/dev/sda /dev/sdb --assume-clean +mdadm: array /dev/md0 started. +~/mdadm # ./mdadm --grow /dev/md0 --bitmap=none +~/mdadm # ./mdadm --grow /dev/md0 --bitmap=clustered +mdadm: /dev/md0 disks marked write-mostly are not supported with clustered bitmap +``` + +Signed-off-by: Heming Zhao +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Grow.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Grow.c b/Grow.c +index 8f5cf07d..bb5fe45c 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -429,7 +429,7 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s) + dv = map_dev(disk.major, disk.minor, 1); + if (!dv) + continue; +- if (((disk.state & (1 << MD_DISK_WRITEMOSTLY)) == 0) && ++ if ((disk.state & (1 << MD_DISK_WRITEMOSTLY)) && + (strcmp(s->bitmap_file, "clustered") == 0)) { + pr_err("%s disks marked write-mostly are not supported with clustered bitmap\n",devname); + free(mdi); +-- +2.38.1 + diff --git a/SOURCES/0086-Fix-NULL-dereference-in-super_by_fd.patch b/SOURCES/0086-Fix-NULL-dereference-in-super_by_fd.patch new file mode 100644 index 0000000..766874b --- /dev/null +++ b/SOURCES/0086-Fix-NULL-dereference-in-super_by_fd.patch @@ -0,0 +1,76 @@ +From f1f3ef7d2de5e3a726c27b9f9bb20e270a100dab Mon Sep 17 00:00:00 2001 +From: Li Xiao Keng +Date: Mon, 27 Feb 2023 11:12:07 +0800 +Subject: [PATCH 086/125] Fix NULL dereference in super_by_fd + +When we create 100 partitions (major is 259 not 254) in a raid device, +mdadm may coredump: + +Core was generated by `/usr/sbin/mdadm --detail --export /dev/md1p7'. +Program terminated with signal SIGSEGV, Segmentation fault. +#0 __strlen_avx2_rtm () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:74 +74 VPCMPEQ (%rdi), %ymm0, %ymm1 +(gdb) bt +#0 __strlen_avx2_rtm () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:74 +#1 0x00007fbb9a7e4139 in __strcpy_chk (dest=dest@entry=0x55d55d6a13ac "", src=0x0, destlen=destlen@entry=32) at strcpy_chk.c:28 +#2 0x000055d55ba1766d in strcpy (__src=, __dest=0x55d55d6a13ac "") at /usr/include/bits/string_fortified.h:79 +#3 super_by_fd (fd=fd@entry=3, subarrayp=subarrayp@entry=0x7fff44dfcc48) at util.c:1289 +#4 0x000055d55ba273a6 in Detail (dev=0x7fff44dfef0b "/dev/md1p7", c=0x7fff44dfe440) at Detail.c:101 +#5 0x000055d55ba0de61 in misc_list (c=, ss=, dump_directory=, ident=, devlist=) at mdadm.c:1959 +#6 main (argc=, argv=) at mdadm.c:1629 + +The direct cause is fd2devnm returning NULL, so add a check. + +Signed-off-by: Li Xiao Keng +Signed-off-by: Wu Guang Hao +Acked-by: Coly Li +Acked-by: Coly Li > +Signed-off-by: Jes Sorensen +--- + mapfile.c | 4 ++++ + util.c | 7 ++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/mapfile.c b/mapfile.c +index 6b2207dd..ac351768 100644 +--- a/mapfile.c ++++ b/mapfile.c +@@ -292,6 +292,10 @@ struct map_ent *map_by_uuid(struct map_ent **map, int uuid[4]) + struct map_ent *map_by_devnm(struct map_ent **map, char *devnm) + { + struct map_ent *mp; ++ ++ if (!devnm) ++ return NULL; ++ + if (!*map) + map_read(map); + +diff --git a/util.c b/util.c +index 9cd89fa4..8c7f3fd5 100644 +--- a/util.c ++++ b/util.c +@@ -1160,6 +1160,11 @@ struct supertype *super_by_fd(int fd, char **subarrayp) + int i; + char *subarray = NULL; + char container[32] = ""; ++ char *devnm = NULL; ++ ++ devnm = fd2devnm(fd); ++ if (!devnm) ++ return NULL; + + sra = sysfs_read(fd, NULL, GET_VERSION); + +@@ -1205,7 +1210,7 @@ struct supertype *super_by_fd(int fd, char **subarrayp) + if (subarrayp) + *subarrayp = subarray; + strcpy(st->container_devnm, container); +- strcpy(st->devnm, fd2devnm(fd)); ++ strncpy(st->devnm, devnm, MD_NAME_MAX - 1); + } else + free(subarray); + +-- +2.38.1 + diff --git a/SOURCES/0087-Mdmonitor-Make-alert_info-global.patch b/SOURCES/0087-Mdmonitor-Make-alert_info-global.patch new file mode 100644 index 0000000..6819fba --- /dev/null +++ b/SOURCES/0087-Mdmonitor-Make-alert_info-global.patch @@ -0,0 +1,369 @@ +From b301516615c441bd3cc4b512fae73fc066d227f1 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Thu, 2 Feb 2023 12:26:59 +0100 +Subject: [PATCH 087/125] Mdmonitor: Make alert_info global + +Move information about --test flag and hostname into alert_info. + +Signed-off-by: Mateusz Grzonka +Signed-off-by: Jes Sorensen +--- + Monitor.c | 124 +++++++++++++++++++++++++++--------------------------- + 1 file changed, 61 insertions(+), 63 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index 188cb8be..9ef4dab8 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -58,21 +58,20 @@ struct state { + }; + + struct alert_info { ++ char hostname[HOST_NAME_MAX]; + char *mailaddr; + char *mailfrom; + char *alert_cmd; + int dosyslog; +-}; ++ int test; ++} info; + static int make_daemon(char *pidfile); + static int check_one_sharer(int scan); + static void write_autorebuild_pid(void); +-static void alert(const char *event, const char *dev, const char *disc, struct alert_info *info); +-static int check_array(struct state *st, struct mdstat_ent *mdstat, +- int test, struct alert_info *info, +- int increments, char *prefer); +-static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist, +- int test, struct alert_info *info); +-static void try_spare_migration(struct state *statelist, struct alert_info *info); ++static void alert(const char *event, const char *dev, const char *disc); ++static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer); ++static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist); ++static void try_spare_migration(struct state *statelist); + static void link_containers_with_subarrays(struct state *list); + static void free_statelist(struct state *statelist); + #ifndef NO_LIBUDEV +@@ -132,7 +131,6 @@ int Monitor(struct mddev_dev *devlist, + int finished = 0; + struct mdstat_ent *mdstat = NULL; + char *mailfrom; +- struct alert_info info; + struct mddev_ident *mdlist; + int delay_for_event = c->delay; + +@@ -166,6 +164,13 @@ int Monitor(struct mddev_dev *devlist, + info.mailaddr = mailaddr; + info.mailfrom = mailfrom; + info.dosyslog = dosyslog; ++ info.test = c->test; ++ ++ if (gethostname(info.hostname, sizeof(info.hostname)) != 0) { ++ pr_err("Cannot get hostname.\n"); ++ return 1; ++ } ++ info.hostname[sizeof(info.hostname) - 1] = '\0'; + + if (share){ + if (check_one_sharer(c->scan)) +@@ -241,8 +246,7 @@ int Monitor(struct mddev_dev *devlist, + mdstat = mdstat_read(oneshot ? 0 : 1, 0); + + for (st = statelist; st; st = st->next) { +- if (check_array(st, mdstat, c->test, &info, +- increments, c->prefer)) ++ if (check_array(st, mdstat, increments, c->prefer)) + anydegraded = 1; + /* for external arrays, metadata is filled for + * containers only +@@ -255,15 +259,14 @@ int Monitor(struct mddev_dev *devlist, + + /* now check if there are any new devices found in mdstat */ + if (c->scan) +- new_found = add_new_arrays(mdstat, &statelist, c->test, +- &info); ++ new_found = add_new_arrays(mdstat, &statelist); + + /* If an array has active < raid && spare == 0 && spare_group != NULL + * Look for another array with spare > 0 and active == raid and same spare_group + * if found, choose a device and hotremove/hotadd + */ + if (share && anydegraded) +- try_spare_migration(statelist, &info); ++ try_spare_migration(statelist); + if (!new_found) { + if (oneshot) + break; +@@ -294,7 +297,7 @@ int Monitor(struct mddev_dev *devlist, + mdstat_close(); + } + } +- c->test = 0; ++ info.test = 0; + + for (stp = &statelist; (st = *stp) != NULL; ) { + if (st->from_auto && st->err > 5) { +@@ -412,7 +415,7 @@ static void write_autorebuild_pid() + } + } + +-static void execute_alert_cmd(const char *event, const char *dev, const char *disc, struct alert_info *info) ++static void execute_alert_cmd(const char *event, const char *dev, const char *disc) + { + int pid = fork(); + +@@ -424,15 +427,14 @@ static void execute_alert_cmd(const char *event, const char *dev, const char *di + pr_err("Cannot fork to execute alert command"); + break; + case 0: +- execl(info->alert_cmd, info->alert_cmd, event, dev, disc, NULL); ++ execl(info.alert_cmd, info.alert_cmd, event, dev, disc, NULL); + exit(2); + } + } + +-static void send_event_email(const char *event, const char *dev, const char *disc, struct alert_info *info) ++static void send_event_email(const char *event, const char *dev, const char *disc) + { + FILE *mp, *mdstat; +- char hname[256]; + char buf[BUFSIZ]; + int n; + +@@ -442,14 +444,13 @@ static void send_event_email(const char *event, const char *dev, const char *dis + return; + } + +- gethostname(hname, sizeof(hname)); + signal(SIGPIPE, SIG_IGN); +- if (info->mailfrom) +- fprintf(mp, "From: %s\n", info->mailfrom); ++ if (info.mailfrom) ++ fprintf(mp, "From: %s\n", info.mailfrom); + else + fprintf(mp, "From: %s monitoring \n", Name); +- fprintf(mp, "To: %s\n", info->mailaddr); +- fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, hname); ++ fprintf(mp, "To: %s\n", info.mailaddr); ++ fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, info.hostname); + fprintf(mp, "This is an automatically generated mail message. \n"); + fprintf(mp, "A %s event had been detected on md device %s.\n\n", event, dev); + +@@ -501,37 +502,36 @@ static void log_event_to_syslog(const char *event, const char *dev, const char * + syslog(priority, "%s event detected on md device %s", event, dev); + } + +-static void alert(const char *event, const char *dev, const char *disc, struct alert_info *info) ++static void alert(const char *event, const char *dev, const char *disc) + { +- if (!info->alert_cmd && !info->mailaddr && !info->dosyslog) { ++ if (!info.alert_cmd && !info.mailaddr && !info.dosyslog) { + time_t now = time(0); + + printf("%1.15s: %s on %s %s\n", ctime(&now) + 4, + event, dev, disc?disc:"unknown device"); + } +- if (info->alert_cmd) +- execute_alert_cmd(event, dev, disc, info); ++ if (info.alert_cmd) ++ execute_alert_cmd(event, dev, disc); + +- if (info->mailaddr && (strncmp(event, "Fail", 4) == 0 || ++ if (info.mailaddr && (strncmp(event, "Fail", 4) == 0 || + strncmp(event, "Test", 4) == 0 || + strncmp(event, "Spares", 6) == 0 || + strncmp(event, "Degrade", 7) == 0)) { +- send_event_email(event, dev, disc, info); ++ send_event_email(event, dev, disc); + } + +- if (info->dosyslog) ++ if (info.dosyslog) + log_event_to_syslog(event, dev, disc); + } + + static int check_array(struct state *st, struct mdstat_ent *mdstat, +- int test, struct alert_info *ainfo, + int increments, char *prefer) + { + /* Update the state 'st' to reflect any changes shown in mdstat, + * or found by directly examining the array, and return + * '1' if the array is degraded, or '0' if it is optimal (or dead). + */ +- struct { int state, major, minor; } info[MAX_DISKS]; ++ struct { int state, major, minor; } disks_info[MAX_DISKS]; + struct mdinfo *sra = NULL; + mdu_array_info_t array; + struct mdstat_ent *mse = NULL, *mse2; +@@ -545,8 +545,8 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + int is_container = 0; + unsigned long redundancy_only_flags = 0; + +- if (test) +- alert("TestMessage", dev, NULL, ainfo); ++ if (info.test) ++ alert("TestMessage", dev, NULL); + + retval = 0; + +@@ -595,7 +595,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + */ + if (sra->array.level == 0 || sra->array.level == -1) { + if (!st->err && !st->from_config) +- alert("DeviceDisappeared", dev, " Wrong-Level", ainfo); ++ alert("DeviceDisappeared", dev, " Wrong-Level"); + st->err++; + goto out; + } +@@ -612,7 +612,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + st->percent = RESYNC_NONE; + new_array = 1; + if (!is_container) +- alert("NewArray", st->devname, NULL, ainfo); ++ alert("NewArray", st->devname, NULL); + } + + if (st->utime == array.utime && st->failed == sra->array.failed_disks && +@@ -625,14 +625,14 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + } + if (st->utime == 0 && /* new array */ + mse->pattern && strchr(mse->pattern, '_') /* degraded */) +- alert("DegradedArray", dev, NULL, ainfo); ++ alert("DegradedArray", dev, NULL); + + if (st->utime == 0 && /* new array */ st->expected_spares > 0 && + sra->array.spare_disks < st->expected_spares) +- alert("SparesMissing", dev, NULL, ainfo); ++ alert("SparesMissing", dev, NULL); + if (st->percent < 0 && st->percent != RESYNC_UNKNOWN && + mse->percent >= 0) +- alert("RebuildStarted", dev, NULL, ainfo); ++ alert("RebuildStarted", dev, NULL); + if (st->percent >= 0 && mse->percent >= 0 && + (mse->percent / increments) > (st->percent / increments)) { + char percentalert[18]; +@@ -647,7 +647,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + snprintf(percentalert, sizeof(percentalert), + "Rebuild%02d", mse->percent); + +- alert(percentalert, dev, NULL, ainfo); ++ alert(percentalert, dev, NULL); + } + + if (mse->percent == RESYNC_NONE && st->percent >= 0) { +@@ -660,9 +660,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + snprintf(cnt, sizeof(cnt), + " mismatches found: %d (on raid level %d)", + sra->mismatch_cnt, sra->array.level); +- alert("RebuildFinished", dev, cnt, ainfo); ++ alert("RebuildFinished", dev, cnt); + } else +- alert("RebuildFinished", dev, NULL, ainfo); ++ alert("RebuildFinished", dev, NULL); + } + st->percent = mse->percent; + +@@ -671,13 +671,13 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + mdu_disk_info_t disc; + disc.number = i; + if (md_get_disk_info(fd, &disc) >= 0) { +- info[i].state = disc.state; +- info[i].major = disc.major; +- info[i].minor = disc.minor; ++ disks_info[i].state = disc.state; ++ disks_info[i].major = disc.major; ++ disks_info[i].minor = disc.minor; + if (disc.major || disc.minor) + remaining_disks --; + } else +- info[i].major = info[i].minor = 0; ++ disks_info[i].major = disks_info[i].minor = 0; + } + last_disk = i; + +@@ -700,13 +700,13 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + int change; + char *dv = NULL; + disc.number = i; +- if (i < last_disk && (info[i].major || info[i].minor)) { +- newstate = info[i].state; +- dv = map_dev_preferred(info[i].major, info[i].minor, 1, ++ if (i < last_disk && (disks_info[i].major || disks_info[i].minor)) { ++ newstate = disks_info[i].state; ++ dv = map_dev_preferred(disks_info[i].major, disks_info[i].minor, 1, + prefer); + disc.state = newstate; +- disc.major = info[i].major; +- disc.minor = info[i].minor; ++ disc.major = disks_info[i].major; ++ disc.minor = disks_info[i].minor; + } else + newstate = (1 << MD_DISK_REMOVED); + +@@ -716,14 +716,14 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + change = newstate ^ st->devstate[i]; + if (st->utime && change && !st->err && !new_array) { + if ((st->devstate[i]&change) & (1 << MD_DISK_SYNC)) +- alert("Fail", dev, dv, ainfo); ++ alert("Fail", dev, dv); + else if ((newstate & (1 << MD_DISK_FAULTY)) && + (disc.major || disc.minor) && + st->devid[i] == makedev(disc.major, + disc.minor)) +- alert("FailSpare", dev, dv, ainfo); ++ alert("FailSpare", dev, dv); + else if ((newstate&change) & (1 << MD_DISK_SYNC)) +- alert("SpareActive", dev, dv, ainfo); ++ alert("SpareActive", dev, dv); + } + st->devstate[i] = newstate; + st->devid[i] = makedev(disc.major, disc.minor); +@@ -747,13 +747,12 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + + disappeared: + if (!st->err && !is_container) +- alert("DeviceDisappeared", dev, NULL, ainfo); ++ alert("DeviceDisappeared", dev, NULL); + st->err++; + goto out; + } + +-static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist, +- int test, struct alert_info *info) ++static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist) + { + struct mdstat_ent *mse; + int new_found = 0; +@@ -806,8 +805,8 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist, + } else + st->parent_devnm[0] = 0; + *statelist = st; +- if (test) +- alert("TestMessage", st->devname, NULL, info); ++ if (info.test) ++ alert("TestMessage", st->devname, NULL); + new_found = 1; + } + return new_found; +@@ -971,7 +970,7 @@ static dev_t container_choose_spare(struct state *from, struct state *to, + return dev; + } + +-static void try_spare_migration(struct state *statelist, struct alert_info *info) ++static void try_spare_migration(struct state *statelist) + { + struct state *from; + struct state *st; +@@ -1030,8 +1029,7 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info + if (devid > 0 && + move_spare(from->devname, to->devname, + devid)) { +- alert("MoveSpare", to->devname, +- from->devname, info); ++ alert("MoveSpare", to->devname, from->devname); + break; + } + } +-- +2.38.1 + diff --git a/SOURCES/0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch b/SOURCES/0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch new file mode 100644 index 0000000..770d3d1 --- /dev/null +++ b/SOURCES/0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch @@ -0,0 +1,313 @@ +From 50232a6ec4a5c46c608181d72d0c633831a03134 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Thu, 2 Feb 2023 12:27:00 +0100 +Subject: [PATCH 088/125] Mdmonitor: Pass events to alert() using enums instead + of strings + +Add events enum, and mapping_t struct, that maps them to strings, so +that enums are passed around instead of strings. + +Signed-off-by: Mateusz Grzonka +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Monitor.c | 136 +++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 83 insertions(+), 53 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index 9ef4dab8..029e9efd 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -32,6 +32,8 @@ + #include + #endif + ++#define EVENT_NAME_MAX 32 ++ + struct state { + 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 */ +@@ -65,10 +67,43 @@ struct alert_info { + int dosyslog; + int test; + } info; ++ ++enum event { ++ EVENT_SPARE_ACTIVE = 0, ++ EVENT_NEW_ARRAY, ++ EVENT_MOVE_SPARE, ++ EVENT_TEST_MESSAGE, ++ EVENT_REBUILD_STARTED, ++ EVENT_REBUILD, ++ EVENT_REBUILD_FINISHED, ++ EVENT_SPARES_MISSING, ++ EVENT_DEVICE_DISAPPEARED, ++ EVENT_FAIL, ++ EVENT_FAIL_SPARE, ++ EVENT_DEGRADED_ARRAY, ++ EVENT_UNKNOWN ++}; ++ ++mapping_t events_map[] = { ++ {"SpareActive", EVENT_SPARE_ACTIVE}, ++ {"NewArray", EVENT_NEW_ARRAY}, ++ {"MoveSpare", EVENT_MOVE_SPARE}, ++ {"TestMessage", EVENT_TEST_MESSAGE}, ++ {"RebuildStarted", EVENT_REBUILD_STARTED}, ++ {"Rebuild", EVENT_REBUILD}, ++ {"RebuildFinished", EVENT_REBUILD_FINISHED}, ++ {"SparesMissing", EVENT_SPARES_MISSING}, ++ {"DeviceDisappeared", EVENT_DEVICE_DISAPPEARED}, ++ {"Fail", EVENT_FAIL}, ++ {"FailSpare", EVENT_FAIL_SPARE}, ++ {"DegradedArray", EVENT_DEGRADED_ARRAY}, ++ {NULL, EVENT_UNKNOWN} ++}; ++ + static int make_daemon(char *pidfile); + static int check_one_sharer(int scan); + static void write_autorebuild_pid(void); +-static void alert(const char *event, const char *dev, const char *disc); ++static void alert(const enum event event_enum, const unsigned int progress, const char *dev, const char *disc); + static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer); + static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist); + static void try_spare_migration(struct state *statelist); +@@ -415,7 +450,7 @@ static void write_autorebuild_pid() + } + } + +-static void execute_alert_cmd(const char *event, const char *dev, const char *disc) ++static void execute_alert_cmd(const char *event_name, const char *dev, const char *disc) + { + int pid = fork(); + +@@ -427,12 +462,12 @@ static void execute_alert_cmd(const char *event, const char *dev, const char *di + pr_err("Cannot fork to execute alert command"); + break; + case 0: +- execl(info.alert_cmd, info.alert_cmd, event, dev, disc, NULL); ++ execl(info.alert_cmd, info.alert_cmd, event_name, dev, disc, NULL); + exit(2); + } + } + +-static void send_event_email(const char *event, const char *dev, const char *disc) ++static void send_event_email(const char *event_name, const char *dev, const char *disc) + { + FILE *mp, *mdstat; + char buf[BUFSIZ]; +@@ -450,9 +485,9 @@ static void send_event_email(const char *event, const char *dev, const char *dis + else + fprintf(mp, "From: %s monitoring \n", Name); + fprintf(mp, "To: %s\n", info.mailaddr); +- fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, info.hostname); ++ fprintf(mp, "Subject: %s event on %s:%s\n\n", event_name, dev, info.hostname); + fprintf(mp, "This is an automatically generated mail message. \n"); +- fprintf(mp, "A %s event had been detected on md device %s.\n\n", event, dev); ++ fprintf(mp, "A %s event had been detected on md device %s.\n\n", event_name, dev); + + if (disc && disc[0] != ' ') + fprintf(mp, +@@ -474,20 +509,20 @@ static void send_event_email(const char *event, const char *dev, const char *dis + pclose(mp); + } + +-static void log_event_to_syslog(const char *event, const char *dev, const char *disc) ++static void log_event_to_syslog(const enum event event_enum, const char *event_name, const char *dev, const char *disc) + { + int priority; + /* Log at a different severity depending on the event. + * + * These are the critical events: */ +- if (strncmp(event, "Fail", 4) == 0 || +- strncmp(event, "Degrade", 7) == 0 || +- strncmp(event, "DeviceDisappeared", 17) == 0) ++ if (event_enum == EVENT_FAIL || ++ event_enum == EVENT_DEGRADED_ARRAY || ++ event_enum == EVENT_DEVICE_DISAPPEARED) + priority = LOG_CRIT; + /* Good to know about, but are not failures: */ +- else if (strncmp(event, "Rebuild", 7) == 0 || +- strncmp(event, "MoveSpare", 9) == 0 || +- strncmp(event, "Spares", 6) != 0) ++ else if (event_enum == EVENT_REBUILD || ++ event_enum == EVENT_MOVE_SPARE || ++ event_enum == EVENT_SPARES_MISSING) + priority = LOG_WARNING; + /* Everything else: */ + else +@@ -495,33 +530,37 @@ static void log_event_to_syslog(const char *event, const char *dev, const char * + + if (disc && disc[0] != ' ') + syslog(priority, +- "%s event detected on md device %s, component device %s", event, dev, disc); ++ "%s event detected on md device %s, component device %s", ++ event_name, dev, disc); + else if (disc) +- syslog(priority, "%s event detected on md device %s: %s", event, dev, disc); ++ syslog(priority, "%s event detected on md device %s: %s", event_name, dev, disc); + else +- syslog(priority, "%s event detected on md device %s", event, dev); ++ syslog(priority, "%s event detected on md device %s", event_name, dev); + } + +-static void alert(const char *event, const char *dev, const char *disc) ++static void alert(const enum event event_enum, const unsigned int progress, const char *dev, const char *disc) + { +- if (!info.alert_cmd && !info.mailaddr && !info.dosyslog) { +- time_t now = time(0); ++ char event_name[EVENT_NAME_MAX]; + +- printf("%1.15s: %s on %s %s\n", ctime(&now) + 4, +- event, dev, disc?disc:"unknown device"); ++ if (event_enum == EVENT_REBUILD) { ++ snprintf(event_name, sizeof(event_name), "%s%02d", ++ map_num_s(events_map, EVENT_REBUILD), progress); ++ } else { ++ snprintf(event_name, sizeof(event_name), "%s", map_num_s(events_map, event_enum)); + } ++ + if (info.alert_cmd) +- execute_alert_cmd(event, dev, disc); ++ execute_alert_cmd(event_name, dev, disc); + +- if (info.mailaddr && (strncmp(event, "Fail", 4) == 0 || +- strncmp(event, "Test", 4) == 0 || +- strncmp(event, "Spares", 6) == 0 || +- strncmp(event, "Degrade", 7) == 0)) { +- send_event_email(event, dev, disc); ++ if (info.mailaddr && (event_enum == EVENT_FAIL || ++ event_enum == EVENT_TEST_MESSAGE || ++ event_enum == EVENT_SPARES_MISSING || ++ event_enum == EVENT_DEGRADED_ARRAY)) { ++ send_event_email(event_name, dev, disc); + } + + if (info.dosyslog) +- log_event_to_syslog(event, dev, disc); ++ log_event_to_syslog(event_enum, event_name, dev, disc); + } + + static int check_array(struct state *st, struct mdstat_ent *mdstat, +@@ -546,7 +585,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + unsigned long redundancy_only_flags = 0; + + if (info.test) +- alert("TestMessage", dev, NULL); ++ alert(EVENT_TEST_MESSAGE, 0, dev, NULL); + + retval = 0; + +@@ -595,7 +634,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + */ + if (sra->array.level == 0 || sra->array.level == -1) { + if (!st->err && !st->from_config) +- alert("DeviceDisappeared", dev, " Wrong-Level"); ++ alert(EVENT_DEVICE_DISAPPEARED, 0, dev, " Wrong-Level"); + st->err++; + goto out; + } +@@ -612,7 +651,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + st->percent = RESYNC_NONE; + new_array = 1; + if (!is_container) +- alert("NewArray", st->devname, NULL); ++ alert(EVENT_NEW_ARRAY, 0, st->devname, NULL); + } + + if (st->utime == array.utime && st->failed == sra->array.failed_disks && +@@ -625,29 +664,20 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + } + if (st->utime == 0 && /* new array */ + mse->pattern && strchr(mse->pattern, '_') /* degraded */) +- alert("DegradedArray", dev, NULL); ++ alert(EVENT_DEGRADED_ARRAY, 0, dev, NULL); + + if (st->utime == 0 && /* new array */ st->expected_spares > 0 && + sra->array.spare_disks < st->expected_spares) +- alert("SparesMissing", dev, NULL); ++ alert(EVENT_SPARES_MISSING, 0, dev, NULL); + if (st->percent < 0 && st->percent != RESYNC_UNKNOWN && + mse->percent >= 0) +- alert("RebuildStarted", dev, NULL); ++ alert(EVENT_REBUILD_STARTED, 0, dev, NULL); + if (st->percent >= 0 && mse->percent >= 0 && + (mse->percent / increments) > (st->percent / increments)) { +- char percentalert[18]; +- /* +- * "RebuildNN" (10 chars) or "RebuildStarted" (15 chars) +- */ +- + if((mse->percent / increments) == 0) +- snprintf(percentalert, sizeof(percentalert), +- "RebuildStarted"); ++ alert(EVENT_REBUILD_STARTED, 0, dev, NULL); + else +- snprintf(percentalert, sizeof(percentalert), +- "Rebuild%02d", mse->percent); +- +- alert(percentalert, dev, NULL); ++ alert(EVENT_REBUILD, mse->percent, dev, NULL); + } + + if (mse->percent == RESYNC_NONE && st->percent >= 0) { +@@ -660,9 +690,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + snprintf(cnt, sizeof(cnt), + " mismatches found: %d (on raid level %d)", + sra->mismatch_cnt, sra->array.level); +- alert("RebuildFinished", dev, cnt); ++ alert(EVENT_REBUILD_FINISHED, 0, dev, cnt); + } else +- alert("RebuildFinished", dev, NULL); ++ alert(EVENT_REBUILD_FINISHED, 0, dev, NULL); + } + st->percent = mse->percent; + +@@ -716,14 +746,14 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + change = newstate ^ st->devstate[i]; + if (st->utime && change && !st->err && !new_array) { + if ((st->devstate[i]&change) & (1 << MD_DISK_SYNC)) +- alert("Fail", dev, dv); ++ alert(EVENT_FAIL, 0, dev, dv); + else if ((newstate & (1 << MD_DISK_FAULTY)) && + (disc.major || disc.minor) && + st->devid[i] == makedev(disc.major, + disc.minor)) +- alert("FailSpare", dev, dv); ++ alert(EVENT_FAIL_SPARE, 0, dev, dv); + else if ((newstate&change) & (1 << MD_DISK_SYNC)) +- alert("SpareActive", dev, dv); ++ alert(EVENT_SPARE_ACTIVE, 0, dev, dv); + } + st->devstate[i] = newstate; + st->devid[i] = makedev(disc.major, disc.minor); +@@ -747,7 +777,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + + disappeared: + if (!st->err && !is_container) +- alert("DeviceDisappeared", dev, NULL); ++ alert(EVENT_DEVICE_DISAPPEARED, 0, dev, NULL); + st->err++; + goto out; + } +@@ -806,7 +836,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist) + st->parent_devnm[0] = 0; + *statelist = st; + if (info.test) +- alert("TestMessage", st->devname, NULL); ++ alert(EVENT_TEST_MESSAGE, 0, st->devname, NULL); + new_found = 1; + } + return new_found; +@@ -1029,7 +1059,7 @@ static void try_spare_migration(struct state *statelist) + if (devid > 0 && + move_spare(from->devname, to->devname, + devid)) { +- alert("MoveSpare", to->devname, from->devname); ++ alert(EVENT_MOVE_SPARE, 0, to->devname, from->devname); + break; + } + } +-- +2.38.1 + diff --git a/SOURCES/0089-Mdmonitor-Add-helper-functions.patch b/SOURCES/0089-Mdmonitor-Add-helper-functions.patch new file mode 100644 index 0000000..930b63a --- /dev/null +++ b/SOURCES/0089-Mdmonitor-Add-helper-functions.patch @@ -0,0 +1,406 @@ +From cc3df167c599d2ee0c132149c86fc0ad70d9f14e Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Thu, 2 Feb 2023 12:27:01 +0100 +Subject: [PATCH 089/125] Mdmonitor: Add helper functions + +Add functions: +- is_email_event(), +- get_syslog_event_priority(), +- sprint_event_message(), +with kernel style comments containing more detailed descriptions. + +Also update event syslog priorities to be consistent with man. MoveSpare event was described in man as priority info, while implemented as warning. Move event data into a struct, so that it is passed between different functions if needed. +Sort function declarations alphabetically and remove redundant alert() declaration. + +Signed-off-by: Mateusz Grzonka +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Monitor.c | 228 +++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 158 insertions(+), 70 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index 029e9efd..39598ba0 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -73,10 +73,12 @@ enum event { + EVENT_NEW_ARRAY, + EVENT_MOVE_SPARE, + EVENT_TEST_MESSAGE, ++ __SYSLOG_PRIORITY_WARNING, + EVENT_REBUILD_STARTED, + EVENT_REBUILD, + EVENT_REBUILD_FINISHED, + EVENT_SPARES_MISSING, ++ __SYSLOG_PRIORITY_CRITICAL, + EVENT_DEVICE_DISAPPEARED, + EVENT_FAIL, + EVENT_FAIL_SPARE, +@@ -100,18 +102,31 @@ mapping_t events_map[] = { + {NULL, EVENT_UNKNOWN} + }; + +-static int make_daemon(char *pidfile); +-static int check_one_sharer(int scan); +-static void write_autorebuild_pid(void); +-static void alert(const enum event event_enum, const unsigned int progress, const char *dev, const char *disc); +-static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer); ++struct event_data { ++ enum event event_enum; ++ /* ++ * @event_name: Rebuild event name must be in form "RebuildXX", where XX is rebuild progress. ++ */ ++ char event_name[EVENT_NAME_MAX]; ++ char message[BUFSIZ]; ++ const char *description; ++ const char *dev; ++ const char *disc; ++}; ++ + static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist); + static void try_spare_migration(struct state *statelist); + static void link_containers_with_subarrays(struct state *list); + static void free_statelist(struct state *statelist); ++static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer); ++static int check_one_sharer(int scan); + #ifndef NO_LIBUDEV + static int check_udev_activity(void); + #endif ++static void link_containers_with_subarrays(struct state *list); ++static int make_daemon(char *pidfile); ++static void try_spare_migration(struct state *statelist); ++static void write_autorebuild_pid(void); + + int Monitor(struct mddev_dev *devlist, + char *mailaddr, char *alert_cmd, +@@ -450,7 +465,80 @@ static void write_autorebuild_pid() + } + } + +-static void execute_alert_cmd(const char *event_name, const char *dev, const char *disc) ++#define BASE_MESSAGE "%s event detected on md device %s" ++#define COMPONENT_DEVICE_MESSAGE ", component device %s" ++#define DESCRIPTION_MESSAGE ": %s" ++/* ++ * sprint_event_message() - Writes basic message about detected event to destination ptr. ++ * @dest: message destination, should be at least the size of BUFSIZ ++ * @data: event data ++ * ++ * Return: 0 on success, 1 on error ++ */ ++static int sprint_event_message(char *dest, const struct event_data *data) ++{ ++ if (!dest || !data) ++ return 1; ++ ++ if (data->disc && data->description) ++ snprintf(dest, BUFSIZ, BASE_MESSAGE COMPONENT_DEVICE_MESSAGE DESCRIPTION_MESSAGE, ++ data->event_name, data->dev, data->disc, data->description); ++ else if (data->disc) ++ snprintf(dest, BUFSIZ, BASE_MESSAGE COMPONENT_DEVICE_MESSAGE, ++ data->event_name, data->dev, data->disc); ++ else if (data->description) ++ snprintf(dest, BUFSIZ, BASE_MESSAGE DESCRIPTION_MESSAGE, ++ data->event_name, data->dev, data->description); ++ else ++ snprintf(dest, BUFSIZ, BASE_MESSAGE, data->event_name, data->dev); ++ ++ return 0; ++} ++ ++/* ++ * get_syslog_event_priority() - Determines event priority. ++ * @event_enum: event to be checked ++ * ++ * Return: LOG_CRIT, LOG_WARNING or LOG_INFO ++ */ ++static int get_syslog_event_priority(const enum event event_enum) ++{ ++ if (event_enum > __SYSLOG_PRIORITY_CRITICAL) ++ return LOG_CRIT; ++ if (event_enum > __SYSLOG_PRIORITY_WARNING) ++ return LOG_WARNING; ++ return LOG_INFO; ++} ++ ++/* ++ * is_email_event() - Determines whether email for event should be sent or not. ++ * @event_enum: event to be checked ++ * ++ * Return: true if email should be sent, false otherwise ++ */ ++static bool is_email_event(const enum event event_enum) ++{ ++ static const enum event email_events[] = { ++ EVENT_FAIL, ++ EVENT_FAIL_SPARE, ++ EVENT_DEGRADED_ARRAY, ++ EVENT_SPARES_MISSING, ++ EVENT_TEST_MESSAGE ++ }; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(email_events); ++i) { ++ if (event_enum == email_events[i]) ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * execute_alert_cmd() - Forks and executes command provided as alert_cmd. ++ * @data: event data ++ */ ++static void execute_alert_cmd(const struct event_data *data) + { + int pid = fork(); + +@@ -462,12 +550,16 @@ static void execute_alert_cmd(const char *event_name, const char *dev, const cha + pr_err("Cannot fork to execute alert command"); + break; + case 0: +- execl(info.alert_cmd, info.alert_cmd, event_name, dev, disc, NULL); ++ execl(info.alert_cmd, info.alert_cmd, data->event_name, data->dev, data->disc, NULL); + exit(2); + } + } + +-static void send_event_email(const char *event_name, const char *dev, const char *disc) ++/* ++ * send_event_email() - Sends an email about event detected by monitor. ++ * @data: event data ++ */ ++static void send_event_email(const struct event_data *data) + { + FILE *mp, *mdstat; + char buf[BUFSIZ]; +@@ -485,15 +577,9 @@ static void send_event_email(const char *event_name, const char *dev, const char + else + fprintf(mp, "From: %s monitoring \n", Name); + fprintf(mp, "To: %s\n", info.mailaddr); +- fprintf(mp, "Subject: %s event on %s:%s\n\n", event_name, dev, info.hostname); +- fprintf(mp, "This is an automatically generated mail message. \n"); +- fprintf(mp, "A %s event had been detected on md device %s.\n\n", event_name, dev); +- +- if (disc && disc[0] != ' ') +- fprintf(mp, +- "It could be related to component device %s.\n\n", disc); +- if (disc && disc[0] == ' ') +- fprintf(mp, "Extra information:%s.\n\n", disc); ++ fprintf(mp, "Subject: %s event on %s:%s\n\n", data->event_name, data->dev, info.hostname); ++ fprintf(mp, "This is an automatically generated mail message.\n"); ++ fprintf(mp, "%s\n", data->message); + + mdstat = fopen("/proc/mdstat", "r"); + if (!mdstat) { +@@ -509,58 +595,60 @@ static void send_event_email(const char *event_name, const char *dev, const char + pclose(mp); + } + +-static void log_event_to_syslog(const enum event event_enum, const char *event_name, const char *dev, const char *disc) ++/* ++ * log_event_to_syslog() - Logs an event into syslog. ++ * @data: event data ++ */ ++static void log_event_to_syslog(const struct event_data *data) + { + int priority; +- /* Log at a different severity depending on the event. +- * +- * These are the critical events: */ +- if (event_enum == EVENT_FAIL || +- event_enum == EVENT_DEGRADED_ARRAY || +- event_enum == EVENT_DEVICE_DISAPPEARED) +- priority = LOG_CRIT; +- /* Good to know about, but are not failures: */ +- else if (event_enum == EVENT_REBUILD || +- event_enum == EVENT_MOVE_SPARE || +- event_enum == EVENT_SPARES_MISSING) +- priority = LOG_WARNING; +- /* Everything else: */ +- else +- priority = LOG_INFO; +- +- if (disc && disc[0] != ' ') +- syslog(priority, +- "%s event detected on md device %s, component device %s", +- event_name, dev, disc); +- else if (disc) +- syslog(priority, "%s event detected on md device %s: %s", event_name, dev, disc); +- else +- syslog(priority, "%s event detected on md device %s", event_name, dev); ++ ++ priority = get_syslog_event_priority(data->event_enum); ++ ++ syslog(priority, "%s\n", data->message); + } + +-static void alert(const enum event event_enum, const unsigned int progress, const char *dev, const char *disc) ++/* ++ * alert() - Alerts about the monitor event. ++ * @event_enum: event to be sent ++ * @description: event description ++ * @progress: rebuild progress ++ * @dev: md device name ++ * @disc: component device ++ * ++ * If needed function executes alert command, sends an email or logs event to syslog. ++ */ ++static void alert(const enum event event_enum, const char *description, const uint8_t progress, ++ const char *dev, const char *disc) + { +- char event_name[EVENT_NAME_MAX]; ++ struct event_data data = {.dev = dev, .disc = disc, .description = description}; ++ ++ if (!dev) ++ return; + + if (event_enum == EVENT_REBUILD) { +- snprintf(event_name, sizeof(event_name), "%s%02d", ++ snprintf(data.event_name, sizeof(data.event_name), "%s%02d", + map_num_s(events_map, EVENT_REBUILD), progress); + } else { +- snprintf(event_name, sizeof(event_name), "%s", map_num_s(events_map, event_enum)); ++ snprintf(data.event_name, sizeof(data.event_name), "%s", map_num_s(events_map, event_enum)); + } + +- if (info.alert_cmd) +- execute_alert_cmd(event_name, dev, disc); ++ data.event_enum = event_enum; + +- if (info.mailaddr && (event_enum == EVENT_FAIL || +- event_enum == EVENT_TEST_MESSAGE || +- event_enum == EVENT_SPARES_MISSING || +- event_enum == EVENT_DEGRADED_ARRAY)) { +- send_event_email(event_name, dev, disc); ++ if (sprint_event_message(data.message, &data) != 0) { ++ pr_err("Cannot create event message.\n"); ++ return; + } ++ pr_err("%s\n", data.message); ++ ++ if (info.alert_cmd) ++ execute_alert_cmd(&data); ++ ++ if (info.mailaddr && is_email_event(event_enum)) ++ send_event_email(&data); + + if (info.dosyslog) +- log_event_to_syslog(event_enum, event_name, dev, disc); ++ log_event_to_syslog(&data); + } + + static int check_array(struct state *st, struct mdstat_ent *mdstat, +@@ -585,7 +673,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + unsigned long redundancy_only_flags = 0; + + if (info.test) +- alert(EVENT_TEST_MESSAGE, 0, dev, NULL); ++ alert(EVENT_TEST_MESSAGE, NULL, 0, dev, NULL); + + retval = 0; + +@@ -634,7 +722,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + */ + if (sra->array.level == 0 || sra->array.level == -1) { + if (!st->err && !st->from_config) +- alert(EVENT_DEVICE_DISAPPEARED, 0, dev, " Wrong-Level"); ++ alert(EVENT_DEVICE_DISAPPEARED, "Wrong-Level", 0, dev, NULL); + st->err++; + goto out; + } +@@ -651,7 +739,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + st->percent = RESYNC_NONE; + new_array = 1; + if (!is_container) +- alert(EVENT_NEW_ARRAY, 0, st->devname, NULL); ++ alert(EVENT_NEW_ARRAY, NULL, 0, st->devname, NULL); + } + + if (st->utime == array.utime && st->failed == sra->array.failed_disks && +@@ -664,20 +752,20 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + } + if (st->utime == 0 && /* new array */ + mse->pattern && strchr(mse->pattern, '_') /* degraded */) +- alert(EVENT_DEGRADED_ARRAY, 0, dev, NULL); ++ alert(EVENT_DEGRADED_ARRAY, NULL, 0, dev, NULL); + + if (st->utime == 0 && /* new array */ st->expected_spares > 0 && + sra->array.spare_disks < st->expected_spares) +- alert(EVENT_SPARES_MISSING, 0, dev, NULL); ++ alert(EVENT_SPARES_MISSING, NULL, 0, dev, NULL); + if (st->percent < 0 && st->percent != RESYNC_UNKNOWN && + mse->percent >= 0) +- alert(EVENT_REBUILD_STARTED, 0, dev, NULL); ++ alert(EVENT_REBUILD_STARTED, NULL, 0, dev, NULL); + if (st->percent >= 0 && mse->percent >= 0 && + (mse->percent / increments) > (st->percent / increments)) { + if((mse->percent / increments) == 0) +- alert(EVENT_REBUILD_STARTED, 0, dev, NULL); ++ alert(EVENT_REBUILD_STARTED, NULL, 0, dev, NULL); + else +- alert(EVENT_REBUILD, mse->percent, dev, NULL); ++ alert(EVENT_REBUILD, NULL, mse->percent, dev, NULL); + } + + if (mse->percent == RESYNC_NONE && st->percent >= 0) { +@@ -690,9 +778,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + snprintf(cnt, sizeof(cnt), + " mismatches found: %d (on raid level %d)", + sra->mismatch_cnt, sra->array.level); +- alert(EVENT_REBUILD_FINISHED, 0, dev, cnt); ++ alert(EVENT_REBUILD_FINISHED, NULL, 0, dev, cnt); + } else +- alert(EVENT_REBUILD_FINISHED, 0, dev, NULL); ++ alert(EVENT_REBUILD_FINISHED, NULL, 0, dev, NULL); + } + st->percent = mse->percent; + +@@ -746,14 +834,14 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + change = newstate ^ st->devstate[i]; + if (st->utime && change && !st->err && !new_array) { + if ((st->devstate[i]&change) & (1 << MD_DISK_SYNC)) +- alert(EVENT_FAIL, 0, dev, dv); ++ alert(EVENT_FAIL, NULL, 0, dev, dv); + else if ((newstate & (1 << MD_DISK_FAULTY)) && + (disc.major || disc.minor) && + st->devid[i] == makedev(disc.major, + disc.minor)) +- alert(EVENT_FAIL_SPARE, 0, dev, dv); ++ alert(EVENT_FAIL_SPARE, NULL, 0, dev, dv); + else if ((newstate&change) & (1 << MD_DISK_SYNC)) +- alert(EVENT_SPARE_ACTIVE, 0, dev, dv); ++ alert(EVENT_SPARE_ACTIVE, NULL, 0, dev, dv); + } + st->devstate[i] = newstate; + st->devid[i] = makedev(disc.major, disc.minor); +@@ -777,7 +865,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat, + + disappeared: + if (!st->err && !is_container) +- alert(EVENT_DEVICE_DISAPPEARED, 0, dev, NULL); ++ alert(EVENT_DEVICE_DISAPPEARED, NULL, 0, dev, NULL); + st->err++; + goto out; + } +@@ -836,7 +924,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist) + st->parent_devnm[0] = 0; + *statelist = st; + if (info.test) +- alert(EVENT_TEST_MESSAGE, 0, st->devname, NULL); ++ alert(EVENT_TEST_MESSAGE, NULL, 0, st->devname, NULL); + new_found = 1; + } + return new_found; +@@ -1059,7 +1147,7 @@ static void try_spare_migration(struct state *statelist) + if (devid > 0 && + move_spare(from->devname, to->devname, + devid)) { +- alert(EVENT_MOVE_SPARE, 0, to->devname, from->devname); ++ alert(EVENT_MOVE_SPARE, NULL, 0, to->devname, from->devname); + break; + } + } +-- +2.38.1 + diff --git a/SOURCES/0090-Add-helpers-to-determine-whether-directories-or-file.patch b/SOURCES/0090-Add-helpers-to-determine-whether-directories-or-file.patch new file mode 100644 index 0000000..294f8af --- /dev/null +++ b/SOURCES/0090-Add-helpers-to-determine-whether-directories-or-file.patch @@ -0,0 +1,83 @@ +From ee9dcf9549e8cbfeb51123812776cc87016c95b0 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Thu, 2 Feb 2023 12:27:02 +0100 +Subject: [PATCH 090/125] Add helpers to determine whether directories or files + are soft links + +Signed-off-by: Mateusz Grzonka +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + mdadm.h | 2 ++ + util.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 47 insertions(+) + +diff --git a/mdadm.h b/mdadm.h +index 13f8b4cb..1674ce13 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1777,6 +1777,8 @@ 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); ++extern bool is_directory(const char *path); ++extern bool is_file(const char *path); + + #define _ROUND_UP(val, base) (((val) + (base) - 1) & ~(base - 1)) + #define ROUND_UP(val, base) _ROUND_UP(val, (typeof(val))(base)) +diff --git a/util.c b/util.c +index 8c7f3fd5..7fc881bf 100644 +--- a/util.c ++++ b/util.c +@@ -2401,3 +2401,48 @@ void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt) + } + } while (!wake_after_interrupt && errno == EINTR); + } ++ ++/* is_directory() - Checks if directory provided by path is indeed a regular directory. ++ * @path: directory path to be checked ++ * ++ * Doesn't accept symlinks. ++ * ++ * Return: true if is a directory, false if not ++ */ ++bool is_directory(const char *path) ++{ ++ struct stat st; ++ ++ if (lstat(path, &st) != 0) { ++ pr_err("%s: %s\n", strerror(errno), path); ++ return false; ++ } ++ ++ if (!S_ISDIR(st.st_mode)) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * is_file() - Checks if file provided by path is indeed a regular file. ++ * @path: file path to be checked ++ * ++ * Doesn't accept symlinks. ++ * ++ * Return: true if is a file, false if not ++ */ ++bool is_file(const char *path) ++{ ++ struct stat st; ++ ++ if (lstat(path, &st) != 0) { ++ pr_err("%s: %s\n", strerror(errno), path); ++ return false; ++ } ++ ++ if (!S_ISREG(st.st_mode)) ++ return false; ++ ++ return true; ++} +-- +2.38.1 + diff --git a/SOURCES/0091-Mdmonitor-Refactor-write_autorebuild_pid.patch b/SOURCES/0091-Mdmonitor-Refactor-write_autorebuild_pid.patch new file mode 100644 index 0000000..84b4e63 --- /dev/null +++ b/SOURCES/0091-Mdmonitor-Refactor-write_autorebuild_pid.patch @@ -0,0 +1,110 @@ +From b6a84d4e92f876acd120d3062a8302db5dd2498c Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Thu, 2 Feb 2023 12:27:03 +0100 +Subject: [PATCH 091/125] Mdmonitor: Refactor write_autorebuild_pid() + +Add better error handling and check for symlinks when opening MDMON_DIR. + +Signed-off-by: Mateusz Grzonka +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Monitor.c | 55 ++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 36 insertions(+), 19 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index 39598ba0..14a2dfe5 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -33,6 +33,7 @@ + #endif + + #define EVENT_NAME_MAX 32 ++#define AUTOREBUILD_PID_PATH MDMON_DIR "/autorebuild.pid" + + struct state { + char devname[MD_NAME_MAX + sizeof("/dev/md/")]; /* length of "/dev/md/" + device name + terminating byte*/ +@@ -126,7 +127,7 @@ static int check_udev_activity(void); + static void link_containers_with_subarrays(struct state *list); + static int make_daemon(char *pidfile); + static void try_spare_migration(struct state *statelist); +-static void write_autorebuild_pid(void); ++static int write_autorebuild_pid(void); + + int Monitor(struct mddev_dev *devlist, + char *mailaddr, char *alert_cmd, +@@ -234,7 +235,8 @@ int Monitor(struct mddev_dev *devlist, + } + + if (share) +- write_autorebuild_pid(); ++ if (write_autorebuild_pid() != 0) ++ return 1; + + if (devlist == NULL) { + mdlist = conf_get_ident(NULL); +@@ -440,29 +442,44 @@ static int check_one_sharer(int scan) + return 0; + } + +-static void write_autorebuild_pid() ++/* ++ * write_autorebuild_pid() - Writes pid to autorebuild.pid file. ++ * ++ * Return: 0 on success, 1 on error ++ */ ++static int write_autorebuild_pid(void) + { +- char path[PATH_MAX]; +- int pid; +- FILE *fp = NULL; +- sprintf(path, "%s/autorebuild.pid", MDMON_DIR); ++ FILE *fp; ++ int fd; + + if (mkdir(MDMON_DIR, 0700) < 0 && errno != EEXIST) { +- pr_err("Can't create autorebuild.pid file\n"); +- } else { +- int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0700); ++ pr_err("%s: %s\n", strerror(errno), MDMON_DIR); ++ return 1; ++ } + +- if (fd >= 0) +- fp = fdopen(fd, "w"); ++ if (!is_directory(MDMON_DIR)) { ++ pr_err("%s is not a regular directory.\n", MDMON_DIR); ++ return 1; ++ } + +- if (!fp) +- pr_err("Can't create autorebuild.pid file\n"); +- else { +- pid = getpid(); +- fprintf(fp, "%d\n", pid); +- fclose(fp); +- } ++ fd = open(AUTOREBUILD_PID_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0700); ++ ++ if (fd < 0) { ++ pr_err("Error opening %s file.\n", AUTOREBUILD_PID_PATH); ++ return 1; + } ++ ++ fp = fdopen(fd, "w"); ++ ++ if (!fp) { ++ pr_err("Error opening fd for %s file.\n", AUTOREBUILD_PID_PATH); ++ return 1; ++ } ++ ++ fprintf(fp, "%d\n", getpid()); ++ ++ fclose(fp); ++ return 0; + } + + #define BASE_MESSAGE "%s event detected on md device %s" +-- +2.38.1 + diff --git a/SOURCES/0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch b/SOURCES/0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch new file mode 100644 index 0000000..f8708a1 --- /dev/null +++ b/SOURCES/0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch @@ -0,0 +1,139 @@ +From 0a07dea8d3b78a22a59f4604a5e8da15690f28e3 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Thu, 2 Feb 2023 12:27:04 +0100 +Subject: [PATCH 092/125] Mdmonitor: Refactor check_one_sharer() for better + error handling + +Also check if autorebuild.pid is a symlink, which we shouldn't accept. + +Signed-off-by: Mateusz Grzonka +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Monitor.c | 89 ++++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 62 insertions(+), 27 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index 14a2dfe5..44918184 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -32,6 +32,7 @@ + #include + #endif + ++#define TASK_COMM_LEN 16 + #define EVENT_NAME_MAX 32 + #define AUTOREBUILD_PID_PATH MDMON_DIR "/autorebuild.pid" + +@@ -224,7 +225,7 @@ int Monitor(struct mddev_dev *devlist, + info.hostname[sizeof(info.hostname) - 1] = '\0'; + + if (share){ +- if (check_one_sharer(c->scan)) ++ if (check_one_sharer(c->scan) == 2) + return 1; + } + +@@ -406,39 +407,73 @@ static int make_daemon(char *pidfile) + return -1; + } + ++/* ++ * check_one_sharer() - Checks for other mdmon processes running. ++ * ++ * Return: ++ * 0 - no other processes running, ++ * 1 - warning, ++ * 2 - error, or when scan mode is enabled, and one mdmon process already exists ++ */ + static int check_one_sharer(int scan) + { + int pid; +- FILE *comm_fp; +- FILE *fp; ++ FILE *fp, *comm_fp; + char comm_path[PATH_MAX]; +- char path[PATH_MAX]; +- char comm[20]; +- +- sprintf(path, "%s/autorebuild.pid", MDMON_DIR); +- fp = fopen(path, "r"); +- if (fp) { +- if (fscanf(fp, "%d", &pid) != 1) +- pid = -1; +- snprintf(comm_path, sizeof(comm_path), +- "/proc/%d/comm", pid); +- comm_fp = fopen(comm_path, "r"); +- if (comm_fp) { +- if (fscanf(comm_fp, "%19s", comm) && +- strncmp(basename(comm), Name, strlen(Name)) == 0) { +- if (scan) { +- pr_err("Only one autorebuild process allowed in scan mode, aborting\n"); +- fclose(comm_fp); +- fclose(fp); +- return 1; +- } else { +- pr_err("Warning: One autorebuild process already running.\n"); +- } +- } ++ char comm[TASK_COMM_LEN]; ++ ++ if (!is_directory(MDMON_DIR)) { ++ pr_err("%s is not a regular directory.\n", MDMON_DIR); ++ return 2; ++ } ++ ++ if (access(AUTOREBUILD_PID_PATH, F_OK) != 0) ++ return 0; ++ ++ if (!is_file(AUTOREBUILD_PID_PATH)) { ++ pr_err("%s is not a regular file.\n", AUTOREBUILD_PID_PATH); ++ return 2; ++ } ++ ++ fp = fopen(AUTOREBUILD_PID_PATH, "r"); ++ if (!fp) { ++ pr_err("Cannot open %s file.\n", AUTOREBUILD_PID_PATH); ++ return 2; ++ } ++ ++ if (fscanf(fp, "%d", &pid) != 1) { ++ pr_err("Cannot read pid from %s file.\n", AUTOREBUILD_PID_PATH); ++ fclose(fp); ++ return 2; ++ } ++ ++ snprintf(comm_path, sizeof(comm_path), "/proc/%d/comm", pid); ++ ++ comm_fp = fopen(comm_path, "r"); ++ if (!comm_fp) { ++ dprintf("Warning: Cannot open %s, continuing\n", comm_path); ++ fclose(fp); ++ return 1; ++ } ++ ++ if (fscanf(comm_fp, "%15s", comm) == 0) { ++ dprintf("Warning: Cannot read comm from %s, continuing\n", comm_path); ++ fclose(comm_fp); ++ fclose(fp); ++ return 1; ++ } ++ ++ if (strncmp(basename(comm), Name, strlen(Name)) == 0) { ++ if (scan) { ++ pr_err("Only one autorebuild process allowed in scan mode, aborting\n"); + fclose(comm_fp); ++ fclose(fp); ++ return 2; + } +- fclose(fp); ++ pr_err("Warning: One autorebuild process already running.\n"); + } ++ fclose(comm_fp); ++ fclose(fp); + return 0; + } + +-- +2.38.1 + diff --git a/SOURCES/0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch b/SOURCES/0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch new file mode 100644 index 0000000..dee708a --- /dev/null +++ b/SOURCES/0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch @@ -0,0 +1,41 @@ +From a0151041642dffff2421c22e18fb7b02b58787d9 Mon Sep 17 00:00:00 2001 +From: Coly Li +Date: Sat, 4 Mar 2023 00:21:30 +0800 +Subject: [PATCH 093/125] util.c: reorder code lines in parse_layout_faulty() + +Resort the code lines in parse_layout_faulty() to make it more +comfortable, no logic change. + +Signed-off-by: Coly Li +Reviewed-by: Paul Menzel +Signed-off-by: Jes Sorensen +--- + util.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/util.c b/util.c +index 7fc881bf..b0b7aec4 100644 +--- a/util.c ++++ b/util.c +@@ -421,12 +421,15 @@ int parse_layout_10(char *layout) + + int parse_layout_faulty(char *layout) + { ++ int ln, mode; ++ char *m; ++ + if (!layout) + return -1; ++ + /* Parse the layout string for 'faulty' */ +- int ln = strcspn(layout, "0123456789"); +- char *m = xstrdup(layout); +- int mode; ++ ln = strcspn(layout, "0123456789"); ++ m = xstrdup(layout); + m[ln] = 0; + mode = map_name(faultylayout, m); + if (mode == UnSet) +-- +2.38.1 + diff --git a/SOURCES/0094-util.c-fix-memleak-in-parse_layout_faulty.patch b/SOURCES/0094-util.c-fix-memleak-in-parse_layout_faulty.patch new file mode 100644 index 0000000..255d195 --- /dev/null +++ b/SOURCES/0094-util.c-fix-memleak-in-parse_layout_faulty.patch @@ -0,0 +1,32 @@ +From 06ef619582b47af89eb094c164fc5effd46d6048 Mon Sep 17 00:00:00 2001 +From: Wu Guanghao +Date: Sat, 4 Mar 2023 00:21:31 +0800 +Subject: [PATCH 094/125] util.c: fix memleak in parse_layout_faulty() + +char *m is allocated by xstrdup but not free() before return, will cause +a memory leak + +Signed-off-by: Wu Guanghao +Acked-by: Mariusz Tkaczyk +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + util.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/util.c b/util.c +index b0b7aec4..9f1e1f7c 100644 +--- a/util.c ++++ b/util.c +@@ -432,6 +432,8 @@ int parse_layout_faulty(char *layout) + m = xstrdup(layout); + m[ln] = 0; + mode = map_name(faultylayout, m); ++ free(m); ++ + if (mode == UnSet) + return -1; + +-- +2.38.1 + diff --git a/SOURCES/0095-Detail.c-fix-memleak-in-Detail.patch b/SOURCES/0095-Detail.c-fix-memleak-in-Detail.patch new file mode 100644 index 0000000..f3d9846 --- /dev/null +++ b/SOURCES/0095-Detail.c-fix-memleak-in-Detail.patch @@ -0,0 +1,31 @@ +From dac0b5121dd77bf1659b95248423445f932dfae4 Mon Sep 17 00:00:00 2001 +From: Wu Guanghao +Date: Sat, 4 Mar 2023 00:21:32 +0800 +Subject: [PATCH 095/125] Detail.c: fix memleak in Detail() + +char *sysdev = xstrdup() but not free() in for loop, will cause memory +leak + +Signed-off-by: Wu Guanghao +Acked-by: Mariusz Tkaczyk +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Detail.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Detail.c b/Detail.c +index ce7a8445..4ef26460 100644 +--- a/Detail.c ++++ b/Detail.c +@@ -303,6 +303,7 @@ int Detail(char *dev, struct context *c) + if (path) + printf("MD_DEVICE_%s_DEV=%s\n", + sysdev, path); ++ free(sysdev); + } + } + goto out; +-- +2.38.1 + diff --git a/SOURCES/0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch b/SOURCES/0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch new file mode 100644 index 0000000..2561c51 --- /dev/null +++ b/SOURCES/0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch @@ -0,0 +1,63 @@ +From 50cd06b484bb99bfacdd4f9d2f8ee5e52bfc7bd3 Mon Sep 17 00:00:00 2001 +From: Wu Guanghao +Date: Sat, 4 Mar 2023 00:21:33 +0800 +Subject: [PATCH 096/125] isuper-intel.c: fix double free in load_imsm_mpb() + +In load_imsm_mpb() there is potential double free issue on super->buf. + +The first location to free super->buf is from get_super_block() <== +load_and_parse_mpb() <== load_imsm_mpb(): + 4514 if (posix_memalign(&super->migr_rec_buf, MAX_SECTOR_SIZE, + 4515 MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) { + 4516 pr_err("could not allocate migr_rec buffer\n"); + 4517 free(super->buf); + 4518 return 2; + 4519 } + +If the above error condition happens, super->buf is freed and value 2 +is returned to get_super_block() eventually. Then in the following code +block inside load_imsm_mpb(), + 5289 error: + 5290 if (!err) { + 5291 s->next = *super_list; + 5292 *super_list = s; + 5293 } else { + 5294 if (s) + 5295 free_imsm(s); + 5296 close_fd(&dfd); + 5297 } +at line 5295 when free_imsm() is called, super->buf is freed again from +the call chain free_imsm() <== __free_imsm(), in following code block, + 4651 if (super->buf) { + 4652 free(super->buf); + 4653 super->buf = NULL; + 4654 } + +This patch sets super->buf as NULL after line 4517 in load_imsm_mpb() +to avoid the potential double free(). + +(Coly Li helps to re-compose the commit log) + +Signed-off-by: Wu Guanghao +Reviewed-by: Mariusz Tkaczyk +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + super-intel.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/super-intel.c b/super-intel.c +index 89fac626..4a3da847 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -4515,6 +4515,7 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname) + MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) { + pr_err("could not allocate migr_rec buffer\n"); + free(super->buf); ++ super->buf = NULL; + return 2; + } + super->clean_migration_record_by_mdmon = 0; +-- +2.38.1 + diff --git a/SOURCES/0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch b/SOURCES/0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch new file mode 100644 index 0000000..dbd5eeb --- /dev/null +++ b/SOURCES/0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch @@ -0,0 +1,39 @@ +From 5d2434d18b6bc71bd16678b1a6d1cc3a92f1d415 Mon Sep 17 00:00:00 2001 +From: Wu Guanghao +Date: Sat, 4 Mar 2023 00:21:34 +0800 +Subject: [PATCH 097/125] super-intel.c: fix memleak in + find_disk_attached_hba() + +If disk_path = diskfd_to_devpath(), we need free(disk_path) before +return, otherwise there will be a memory leak + +Signed-off-by: Wu Guanghao +Reviewed-by: Mariusz Tkaczyk +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + super-intel.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index 4a3da847..e155a8ae 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -713,12 +713,12 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname) + + for (elem = list; elem; elem = elem->next) + if (path_attached_to_hba(disk_path, elem->path)) +- return elem; ++ break; + + if (disk_path != devname) + free(disk_path); + +- return NULL; ++ return elem; + } + + static int find_intel_hba_capability(int fd, struct intel_super *super, +-- +2.38.1 + diff --git a/SOURCES/0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch b/SOURCES/0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch new file mode 100644 index 0000000..d31b162 --- /dev/null +++ b/SOURCES/0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch @@ -0,0 +1,46 @@ +From 68b90794adf8287fa534cc8f35efb09772b133d0 Mon Sep 17 00:00:00 2001 +From: Wu Guanghao +Date: Sat, 4 Mar 2023 00:21:35 +0800 +Subject: [PATCH 098/125] super-ddf.c: fix memleak in get_vd_num_of_subarray() + +sra = sysfs_read() should be free before return in +get_vd_num_of_subarray() + +Signed-off-by: Wu Guanghao +Acked-by: Mariusz Tkaczyk +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + super-ddf.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/super-ddf.c b/super-ddf.c +index 309812df..b86c6acd 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -1592,15 +1592,20 @@ static unsigned int get_vd_num_of_subarray(struct supertype *st) + sra = sysfs_read(-1, st->devnm, GET_VERSION); + if (!sra || sra->array.major_version != -1 || + sra->array.minor_version != -2 || +- !is_subarray(sra->text_version)) ++ !is_subarray(sra->text_version)) { ++ if (sra) ++ sysfs_free(sra); + return DDF_NOTFOUND; ++ } + + sub = strchr(sra->text_version + 1, '/'); + if (sub != NULL) + vcnum = strtoul(sub + 1, &end, 10); + if (sub == NULL || *sub == '\0' || *end != '\0' || +- vcnum >= be16_to_cpu(ddf->active->max_vd_entries)) ++ vcnum >= be16_to_cpu(ddf->active->max_vd_entries)) { ++ sysfs_free(sra); + return DDF_NOTFOUND; ++ } + + return vcnum; + } +-- +2.38.1 + diff --git a/SOURCES/0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch b/SOURCES/0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch new file mode 100644 index 0000000..dacf428 --- /dev/null +++ b/SOURCES/0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch @@ -0,0 +1,36 @@ +From ba867e2ebaead20e3d9a7e62ef8fd940176c3110 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 1 Mar 2023 13:41:29 -0700 +Subject: [PATCH 099/125] Create: goto abort_locked instead of return 1 in + error path + +The return 1 after the fstat_is_blkdev() check should be replaced +with an error return that goes through the error path to unlock +resources locked by this function. + +Signed-off-by: Logan Gunthorpe +Acked-by: Kinga Tanska +Reviewed-by: Xiao Ni +Reviewed-by: Chaitanya Kulkarni +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Create.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Create.c b/Create.c +index 953e7372..2e8203ec 100644 +--- a/Create.c ++++ b/Create.c +@@ -939,7 +939,7 @@ int Create(struct supertype *st, char *mddev, + goto abort_locked; + } + if (!fstat_is_blkdev(fd, dv->devname, &rdev)) +- return 1; ++ goto abort_locked; + inf->disk.major = major(rdev); + inf->disk.minor = minor(rdev); + } +-- +2.38.1 + diff --git a/SOURCES/0100-Create-remove-safe_mode_delay-local-variable.patch b/SOURCES/0100-Create-remove-safe_mode_delay-local-variable.patch new file mode 100644 index 0000000..a813d87 --- /dev/null +++ b/SOURCES/0100-Create-remove-safe_mode_delay-local-variable.patch @@ -0,0 +1,64 @@ +From fb2c0f6183e29b014608e5e1aa4d53cb55887326 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 1 Mar 2023 13:41:30 -0700 +Subject: [PATCH 100/125] Create: remove safe_mode_delay local variable + +All .getinfo_super() call sets the info.safe_mode_delay variables +to a constant value, so no matter what the current state is +that function will always set it to the same value. + +Create() calls .getinfo_super() multiple times while creating the array. +The value is stored in a local variable for every disk in the loop +to add disks (so the last disc call takes precedence). The local +variable is then used in the call to sysfs_set_safemode(). + +This can be simplified by using info.safe_mode_delay directly. The info +variable had .getinfo_super() called on it early in the function so, by the +reasoning above, it will have the same value as the local variable which +can thus be removed. + +Doing this allows for factoring out code from Create() in a subsequent +patch. + +Signed-off-by: Logan Gunthorpe +Acked-by: Kinga Tanska +Reviewed-by: Xiao Ni +Reviewed-by: Chaitanya Kulkarni +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Create.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/Create.c b/Create.c +index 2e8203ec..8ded81dc 100644 +--- a/Create.c ++++ b/Create.c +@@ -137,7 +137,6 @@ int Create(struct supertype *st, char *mddev, + int did_default = 0; + int do_default_layout = 0; + int do_default_chunk = 0; +- unsigned long safe_mode_delay = 0; + char chosen_name[1024]; + struct map_ent *map = NULL; + unsigned long long newsize; +@@ -952,7 +951,6 @@ int Create(struct supertype *st, char *mddev, + goto abort_locked; + } + st->ss->getinfo_super(st, inf, NULL); +- safe_mode_delay = inf->safe_mode_delay; + + if (have_container && c->verbose > 0) + pr_err("Using %s for device %d\n", +@@ -1065,7 +1063,7 @@ int Create(struct supertype *st, char *mddev, + "readonly"); + break; + } +- sysfs_set_safemode(&info, safe_mode_delay); ++ sysfs_set_safemode(&info, info.safe_mode_delay); + if (err) { + pr_err("failed to activate array.\n"); + ioctl(mdfd, STOP_ARRAY, NULL); +-- +2.38.1 + diff --git a/SOURCES/0101-Create-Factor-out-add_disks-helpers.patch b/SOURCES/0101-Create-Factor-out-add_disks-helpers.patch new file mode 100644 index 0000000..6546497 --- /dev/null +++ b/SOURCES/0101-Create-Factor-out-add_disks-helpers.patch @@ -0,0 +1,452 @@ +From 8a4ce2c053866ac97feb436c4c85a54446ee0016 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 1 Mar 2023 13:41:31 -0700 +Subject: [PATCH 101/125] Create: Factor out add_disks() helpers + +The Create function is massive with a very large number of variables. +Reading and understanding the function is almost impossible. To help +with this, factor out the two pass loop that adds the disks to the array. + +This moves about 160 lines into three new helper functions and removes +a bunch of local variables from the main Create function. The main new +helper function add_disks() does the two pass loop and calls into +add_disk_to_super() and update_metadata(). Factoring out the +latter two helpers also helps to reduce a ton of indentation. + +No functional changes intended. + +Signed-off-by: Logan Gunthorpe +Acked-by: Kinga Tanska +Reviewed-by: Xiao Ni +Reviewed-by: Chaitanya Kulkarni +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Create.c | 382 +++++++++++++++++++++++++++++++------------------------ + 1 file changed, 213 insertions(+), 169 deletions(-) + +diff --git a/Create.c b/Create.c +index 8ded81dc..6a044664 100644 +--- a/Create.c ++++ b/Create.c +@@ -91,6 +91,214 @@ int default_layout(struct supertype *st, int level, int verbose) + return layout; + } + ++static int add_disk_to_super(int mdfd, struct shape *s, struct context *c, ++ struct supertype *st, struct mddev_dev *dv, ++ struct mdinfo *info, int have_container, int major_num) ++{ ++ dev_t rdev; ++ int fd; ++ ++ if (dv->disposition == 'j') { ++ info->disk.raid_disk = MD_DISK_ROLE_JOURNAL; ++ info->disk.state = (1<disk.raid_disk < s->raiddisks) { ++ info->disk.state = (1<disk.state = 0; ++ } ++ ++ if (dv->writemostly == FlagSet) { ++ if (major_num == BITMAP_MAJOR_CLUSTERED) { ++ pr_err("Can not set %s --write-mostly with a clustered bitmap\n",dv->devname); ++ return 1; ++ } else { ++ info->disk.state |= (1<failfast == FlagSet) ++ info->disk.state |= (1<ss->external && st->container_devnm[0]) ++ fd = open(dv->devname, O_RDWR); ++ else ++ fd = open(dv->devname, O_RDWR|O_EXCL); ++ ++ if (fd < 0) { ++ pr_err("failed to open %s after earlier success - aborting\n", ++ dv->devname); ++ return 1; ++ } ++ if (!fstat_is_blkdev(fd, dv->devname, &rdev)) ++ return 1; ++ info->disk.major = major(rdev); ++ info->disk.minor = minor(rdev); ++ } ++ if (fd >= 0) ++ remove_partitions(fd); ++ if (st->ss->add_to_super(st, &info->disk, fd, dv->devname, ++ dv->data_offset)) { ++ ioctl(mdfd, STOP_ARRAY, NULL); ++ return 1; ++ } ++ st->ss->getinfo_super(st, info, NULL); ++ ++ if (have_container && c->verbose > 0) ++ pr_err("Using %s for device %d\n", ++ map_dev(info->disk.major, info->disk.minor, 0), ++ info->disk.number); ++ ++ if (!have_container) { ++ /* getinfo_super might have lost these ... */ ++ info->disk.major = major(rdev); ++ info->disk.minor = minor(rdev); ++ } ++ ++ return 0; ++} ++ ++static int update_metadata(int mdfd, struct shape *s, struct supertype *st, ++ struct map_ent **map, struct mdinfo *info, ++ char *chosen_name) ++{ ++ struct mdinfo info_new; ++ struct map_ent *me = NULL; ++ ++ /* check to see if the uuid has changed due to these ++ * metadata changes, and if so update the member array ++ * and container uuid. Note ->write_init_super clears ++ * the subarray cursor such that ->getinfo_super once ++ * again returns container info. ++ */ ++ st->ss->getinfo_super(st, &info_new, NULL); ++ if (st->ss->external && is_container(s->level) && ++ !same_uuid(info_new.uuid, info->uuid, 0)) { ++ map_update(map, fd2devnm(mdfd), ++ info_new.text_version, ++ info_new.uuid, chosen_name); ++ me = map_by_devnm(map, st->container_devnm); ++ } ++ ++ if (st->ss->write_init_super(st)) { ++ st->ss->free_super(st); ++ return 1; ++ } ++ ++ /* ++ * Before activating the array, perform extra steps ++ * required to configure the internal write-intent ++ * bitmap. ++ */ ++ if (info_new.consistency_policy == CONSISTENCY_POLICY_BITMAP && ++ st->ss->set_bitmap && st->ss->set_bitmap(st, info)) { ++ st->ss->free_super(st); ++ return 1; ++ } ++ ++ /* update parent container uuid */ ++ if (me) { ++ char *path = xstrdup(me->path); ++ ++ st->ss->getinfo_super(st, &info_new, NULL); ++ map_update(map, st->container_devnm, info_new.text_version, ++ info_new.uuid, path); ++ free(path); ++ } ++ ++ flush_metadata_updates(st); ++ st->ss->free_super(st); ++ ++ return 0; ++} ++ ++static int add_disks(int mdfd, struct mdinfo *info, struct shape *s, ++ struct context *c, struct supertype *st, ++ struct map_ent **map, struct mddev_dev *devlist, ++ int total_slots, int have_container, int insert_point, ++ int major_num, char *chosen_name) ++{ ++ struct mddev_dev *moved_disk = NULL; ++ int pass, raid_disk_num, dnum; ++ struct mddev_dev *dv; ++ struct mdinfo *infos; ++ int ret = 0; ++ ++ infos = xmalloc(sizeof(*infos) * total_slots); ++ enable_fds(total_slots); ++ for (pass = 1; pass <= 2; pass++) { ++ for (dnum = 0, raid_disk_num = 0, dv = devlist; dv; ++ dv = (dv->next) ? (dv->next) : moved_disk, dnum++) { ++ if (dnum >= total_slots) ++ abort(); ++ if (dnum == insert_point) { ++ raid_disk_num += 1; ++ moved_disk = dv; ++ continue; ++ } ++ if (strcasecmp(dv->devname, "missing") == 0) { ++ raid_disk_num += 1; ++ continue; ++ } ++ if (have_container) ++ moved_disk = NULL; ++ if (have_container && dnum < total_slots - 1) ++ /* repeatedly use the container */ ++ moved_disk = dv; ++ ++ switch(pass) { ++ case 1: ++ infos[dnum] = *info; ++ infos[dnum].disk.number = dnum; ++ infos[dnum].disk.raid_disk = raid_disk_num++; ++ ++ if (dv->disposition == 'j') ++ raid_disk_num--; ++ ++ ret = add_disk_to_super(mdfd, s, c, st, dv, ++ &infos[dnum], have_container, ++ major_num); ++ if (ret) ++ goto out; ++ ++ break; ++ case 2: ++ infos[dnum].errors = 0; ++ ++ ret = add_disk(mdfd, st, info, &infos[dnum]); ++ if (ret) { ++ pr_err("ADD_NEW_DISK for %s failed: %s\n", ++ dv->devname, strerror(errno)); ++ if (errno == EINVAL && ++ info->array.level == 0) { ++ pr_err("Possibly your kernel doesn't support RAID0 layouts.\n"); ++ pr_err("Either upgrade, or use --layout=dangerous\n"); ++ } ++ goto out; ++ } ++ break; ++ } ++ if (!have_container && ++ dv == moved_disk && dnum != insert_point) break; ++ } ++ ++ if (pass == 1) { ++ ret = update_metadata(mdfd, s, st, map, info, ++ chosen_name); ++ if (ret) ++ goto out; ++ } ++ } ++ ++out: ++ free(infos); ++ return ret; ++} ++ + int Create(struct supertype *st, char *mddev, + char *name, int *uuid, + int subdevs, struct mddev_dev *devlist, +@@ -117,7 +325,7 @@ int Create(struct supertype *st, char *mddev, + unsigned long long minsize = 0, maxsize = 0; + char *mindisc = NULL; + char *maxdisc = NULL; +- int dnum, raid_disk_num; ++ int dnum; + struct mddev_dev *dv; + dev_t rdev; + int fail = 0, warn = 0; +@@ -126,14 +334,13 @@ int Create(struct supertype *st, char *mddev, + int missing_disks = 0; + int insert_point = subdevs * 2; /* where to insert a missing drive */ + int total_slots; +- int pass; + int rv; + int bitmap_fd; + int have_container = 0; + int container_fd = -1; + int need_mdmon = 0; + unsigned long long bitmapsize; +- struct mdinfo info, *infos; ++ struct mdinfo info; + int did_default = 0; + int do_default_layout = 0; + int do_default_chunk = 0; +@@ -869,174 +1076,11 @@ int Create(struct supertype *st, char *mddev, + } + } + +- infos = xmalloc(sizeof(*infos) * total_slots); +- enable_fds(total_slots); +- for (pass = 1; pass <= 2; pass++) { +- struct mddev_dev *moved_disk = NULL; /* the disk that was moved out of the insert point */ +- +- for (dnum = 0, raid_disk_num = 0, dv = devlist; dv; +- dv = (dv->next) ? (dv->next) : moved_disk, dnum++) { +- int fd; +- struct mdinfo *inf = &infos[dnum]; +- +- if (dnum >= total_slots) +- abort(); +- if (dnum == insert_point) { +- raid_disk_num += 1; +- moved_disk = dv; +- continue; +- } +- if (strcasecmp(dv->devname, "missing") == 0) { +- raid_disk_num += 1; +- continue; +- } +- if (have_container) +- moved_disk = NULL; +- if (have_container && dnum < info.array.raid_disks - 1) +- /* repeatedly use the container */ +- moved_disk = dv; +- +- switch(pass) { +- case 1: +- *inf = info; +- +- inf->disk.number = dnum; +- inf->disk.raid_disk = raid_disk_num++; +- +- if (dv->disposition == 'j') { +- inf->disk.raid_disk = MD_DISK_ROLE_JOURNAL; +- inf->disk.state = (1<disk.raid_disk < s->raiddisks) +- inf->disk.state = (1<disk.state = 0; +- +- if (dv->writemostly == FlagSet) { +- if (major_num == BITMAP_MAJOR_CLUSTERED) { +- pr_err("Can not set %s --write-mostly with a clustered bitmap\n",dv->devname); +- goto abort_locked; +- } else +- inf->disk.state |= (1<failfast == FlagSet) +- inf->disk.state |= (1<ss->external && +- st->container_devnm[0]) +- fd = open(dv->devname, O_RDWR); +- else +- fd = open(dv->devname, O_RDWR|O_EXCL); +- +- if (fd < 0) { +- pr_err("failed to open %s after earlier success - aborting\n", +- dv->devname); +- goto abort_locked; +- } +- if (!fstat_is_blkdev(fd, dv->devname, &rdev)) +- goto abort_locked; +- inf->disk.major = major(rdev); +- inf->disk.minor = minor(rdev); +- } +- if (fd >= 0) +- remove_partitions(fd); +- if (st->ss->add_to_super(st, &inf->disk, +- fd, dv->devname, +- dv->data_offset)) { +- ioctl(mdfd, STOP_ARRAY, NULL); +- goto abort_locked; +- } +- st->ss->getinfo_super(st, inf, NULL); +- +- if (have_container && c->verbose > 0) +- pr_err("Using %s for device %d\n", +- map_dev(inf->disk.major, +- inf->disk.minor, +- 0), dnum); +- +- if (!have_container) { +- /* getinfo_super might have lost these ... */ +- inf->disk.major = major(rdev); +- inf->disk.minor = minor(rdev); +- } +- break; +- case 2: +- inf->errors = 0; +- +- rv = add_disk(mdfd, st, &info, inf); +- +- if (rv) { +- pr_err("ADD_NEW_DISK for %s failed: %s\n", +- dv->devname, strerror(errno)); +- if (errno == EINVAL && +- info.array.level == 0) { +- pr_err("Possibly your kernel doesn't support RAID0 layouts.\n"); +- pr_err("Either upgrade, or use --layout=dangerous\n"); +- } +- goto abort_locked; +- } +- break; +- } +- if (!have_container && +- dv == moved_disk && dnum != insert_point) break; +- } +- if (pass == 1) { +- struct mdinfo info_new; +- struct map_ent *me = NULL; +- +- /* check to see if the uuid has changed due to these +- * metadata changes, and if so update the member array +- * and container uuid. Note ->write_init_super clears +- * the subarray cursor such that ->getinfo_super once +- * again returns container info. +- */ +- st->ss->getinfo_super(st, &info_new, NULL); +- if (st->ss->external && !is_container(s->level) && +- !same_uuid(info_new.uuid, info.uuid, 0)) { +- map_update(&map, fd2devnm(mdfd), +- info_new.text_version, +- info_new.uuid, chosen_name); +- me = map_by_devnm(&map, st->container_devnm); +- } +- +- if (st->ss->write_init_super(st)) { +- st->ss->free_super(st); +- goto abort_locked; +- } +- /* +- * Before activating the array, perform extra steps +- * required to configure the internal write-intent +- * bitmap. +- */ +- if (info_new.consistency_policy == +- CONSISTENCY_POLICY_BITMAP && +- st->ss->set_bitmap && +- st->ss->set_bitmap(st, &info)) { +- st->ss->free_super(st); +- goto abort_locked; +- } +- +- /* update parent container uuid */ +- if (me) { +- char *path = xstrdup(me->path); +- +- st->ss->getinfo_super(st, &info_new, NULL); +- map_update(&map, st->container_devnm, +- info_new.text_version, +- info_new.uuid, path); +- free(path); +- } ++ if (add_disks(mdfd, &info, s, c, st, &map, devlist, total_slots, ++ have_container, insert_point, major_num, chosen_name)) ++ goto abort_locked; + +- flush_metadata_updates(st); +- st->ss->free_super(st); +- } +- } + map_unlock(&map); +- free(infos); + + if (is_container(s->level)) { + /* No need to start. But we should signal udev to +-- +2.38.1 + diff --git a/SOURCES/0102-mdadm-Introduce-pr_info.patch b/SOURCES/0102-mdadm-Introduce-pr_info.patch new file mode 100644 index 0000000..4059e20 --- /dev/null +++ b/SOURCES/0102-mdadm-Introduce-pr_info.patch @@ -0,0 +1,72 @@ +From 9364dbfb264e89ab9467dfc0d2b813033e320640 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 1 Mar 2023 13:41:32 -0700 +Subject: [PATCH 102/125] mdadm: Introduce pr_info() + +Feedback was given to avoid informational pr_err() calls that print +to stderr, even though that's done all through out the code. + +Using printf() directly doesn't maintain the same format (an "mdadm" +prefix on every line. + +So introduce pr_info() which prints to stdout with the same format +and use it for a couple informational pr_err() calls in Create(). + +Future work can make this call used in more cases. + +Signed-off-by: Logan Gunthorpe +Acked-by: Kinga Tanska +Reviewed-by: Xiao Ni +Reviewed-by: Chaitanya Kulkarni +Acked-by: Coly Li +Acked-by: Paul Menzel +Signed-off-by: Jes Sorensen +--- + Create.c | 7 ++++--- + mdadm.h | 2 ++ + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/Create.c b/Create.c +index 6a044664..4acda30c 100644 +--- a/Create.c ++++ b/Create.c +@@ -984,11 +984,12 @@ int Create(struct supertype *st, char *mddev, + + mdi = sysfs_read(-1, devnm, GET_VERSION); + +- pr_err("Creating array inside %s container %s\n", ++ pr_info("Creating array inside %s container %s\n", + mdi?mdi->text_version:"managed", devnm); + sysfs_free(mdi); + } else +- pr_err("Defaulting to version %s metadata\n", info.text_version); ++ pr_info("Defaulting to version %s metadata\n", ++ info.text_version); + } + + map_update(&map, fd2devnm(mdfd), info.text_version, +@@ -1145,7 +1146,7 @@ int Create(struct supertype *st, char *mddev, + ioctl(mdfd, RESTART_ARRAY_RW, NULL); + } + if (c->verbose >= 0) +- pr_err("array %s started.\n", mddev); ++ pr_info("array %s started.\n", mddev); + if (st->ss->external && st->container_devnm[0]) { + if (need_mdmon) + start_mdmon(st->container_devnm); +diff --git a/mdadm.h b/mdadm.h +index 1674ce13..4336be4d 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1854,6 +1854,8 @@ static inline int xasprintf(char **strp, const char *fmt, ...) { + #endif + #define cont_err(fmt ...) fprintf(stderr, " " fmt) + ++#define pr_info(fmt, args...) printf("%s: "fmt, Name, ##args) ++ + void *xmalloc(size_t len); + void *xrealloc(void *ptr, size_t len); + void *xcalloc(size_t num, size_t size); +-- +2.38.1 + diff --git a/SOURCES/0103-mdadm-Add-write-zeros-option-for-Create.patch b/SOURCES/0103-mdadm-Add-write-zeros-option-for-Create.patch new file mode 100644 index 0000000..2f39174 --- /dev/null +++ b/SOURCES/0103-mdadm-Add-write-zeros-option-for-Create.patch @@ -0,0 +1,346 @@ +From 577fd10486d8d1472a6b559066f344ac30a3a391 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 1 Mar 2023 13:41:33 -0700 +Subject: [PATCH 103/125] mdadm: Add --write-zeros option for Create + +Add the --write-zeros option for Create which will send a write zeros +request to all the disks before assembling the array. After zeroing +the array, the disks will be in a known clean state and the initial +sync may be skipped. + +Writing zeroes is best used when there is a hardware offload method +to zero the data. But even still, zeroing can take several minutes on +a large device. Because of this, all disks are zeroed in parallel using +their own forked process and a message is printed to the user. The main +process will proceed only after all the zeroing processes have completed +successfully. + +Signed-off-by: Logan Gunthorpe +Acked-by: Kinga Tanska +Reviewed-by: Xiao Ni +Reviewed-by: Chaitanya Kulkarni +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + Create.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- + ReadMe.c | 2 + + mdadm.c | 9 +++ + mdadm.h | 5 ++ + 4 files changed, 190 insertions(+), 2 deletions(-) + +diff --git a/Create.c b/Create.c +index 4acda30c..bbe9e13d 100644 +--- a/Create.c ++++ b/Create.c +@@ -26,6 +26,10 @@ + #include "md_u.h" + #include "md_p.h" + #include ++#include ++#include ++#include ++#include + + static int round_size_and_verify(unsigned long long *size, int chunk) + { +@@ -91,9 +95,149 @@ int default_layout(struct supertype *st, int level, int verbose) + return layout; + } + ++static pid_t write_zeroes_fork(int fd, struct shape *s, struct supertype *st, ++ struct mddev_dev *dv) ++ ++{ ++ const unsigned long long req_size = 1 << 30; ++ unsigned long long offset_bytes, size_bytes, sz; ++ sigset_t sigset; ++ int ret = 0; ++ pid_t pid; ++ ++ size_bytes = KIB_TO_BYTES(s->size); ++ ++ /* ++ * If size_bytes is zero, this is a zoned raid array where ++ * each disk is of a different size and uses its full ++ * disk. Thus zero the entire disk. ++ */ ++ if (!size_bytes && !get_dev_size(fd, dv->devname, &size_bytes)) ++ return -1; ++ ++ if (dv->data_offset != INVALID_SECTORS) ++ offset_bytes = SEC_TO_BYTES(dv->data_offset); ++ else ++ offset_bytes = SEC_TO_BYTES(st->data_offset); ++ ++ pr_info("zeroing data from %lld to %lld on: %s\n", ++ offset_bytes, size_bytes, dv->devname); ++ ++ pid = fork(); ++ if (pid < 0) { ++ pr_err("Could not fork to zero disks: %s\n", strerror(errno)); ++ return pid; ++ } else if (pid != 0) { ++ return pid; ++ } ++ ++ sigemptyset(&sigset); ++ sigaddset(&sigset, SIGINT); ++ sigprocmask(SIG_UNBLOCK, &sigset, NULL); ++ ++ while (size_bytes) { ++ /* ++ * Split requests to the kernel into 1GB chunks seeing the ++ * fallocate() call is not interruptible and blocking a ++ * ctrl-c for several minutes is not desirable. ++ * ++ * 1GB is chosen as a compromise: the user may still have ++ * to wait several seconds if they ctrl-c on devices that ++ * zero slowly, but will reduce the number of requests ++ * required and thus the overhead on devices that perform ++ * better. ++ */ ++ sz = size_bytes; ++ if (sz >= req_size) ++ sz = req_size; ++ ++ if (fallocate(fd, FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE, ++ offset_bytes, sz)) { ++ pr_err("zeroing %s failed: %s\n", dv->devname, ++ strerror(errno)); ++ ret = 1; ++ break; ++ } ++ ++ offset_bytes += sz; ++ size_bytes -= sz; ++ } ++ ++ exit(ret); ++} ++ ++static int wait_for_zero_forks(int *zero_pids, int count) ++{ ++ int wstatus, ret = 0, i, sfd, wait_count = 0; ++ struct signalfd_siginfo fdsi; ++ bool interrupted = false; ++ sigset_t sigset; ++ ssize_t s; ++ ++ for (i = 0; i < count; i++) ++ if (zero_pids[i]) ++ wait_count++; ++ if (!wait_count) ++ return 0; ++ ++ sigemptyset(&sigset); ++ sigaddset(&sigset, SIGINT); ++ sigaddset(&sigset, SIGCHLD); ++ sigprocmask(SIG_BLOCK, &sigset, NULL); ++ ++ sfd = signalfd(-1, &sigset, 0); ++ if (sfd < 0) { ++ pr_err("Unable to create signalfd: %s\n", strerror(errno)); ++ return 1; ++ } ++ ++ while (1) { ++ s = read(sfd, &fdsi, sizeof(fdsi)); ++ if (s != sizeof(fdsi)) { ++ pr_err("Invalid signalfd read: %s\n", strerror(errno)); ++ close(sfd); ++ return 1; ++ } ++ ++ if (fdsi.ssi_signo == SIGINT) { ++ printf("\n"); ++ pr_info("Interrupting zeroing processes, please wait...\n"); ++ interrupted = true; ++ } else if (fdsi.ssi_signo == SIGCHLD) { ++ if (!--wait_count) ++ break; ++ } ++ } ++ ++ close(sfd); ++ ++ for (i = 0; i < count; i++) { ++ if (!zero_pids[i]) ++ continue; ++ ++ waitpid(zero_pids[i], &wstatus, 0); ++ zero_pids[i] = 0; ++ if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) ++ ret = 1; ++ } ++ ++ if (interrupted) { ++ pr_err("zeroing interrupted!\n"); ++ return 1; ++ } ++ ++ if (ret) ++ pr_err("zeroing failed!\n"); ++ else ++ pr_info("zeroing finished\n"); ++ ++ return ret; ++} ++ + static int add_disk_to_super(int mdfd, struct shape *s, struct context *c, + struct supertype *st, struct mddev_dev *dv, +- struct mdinfo *info, int have_container, int major_num) ++ struct mdinfo *info, int have_container, int major_num, ++ int *zero_pid) + { + dev_t rdev; + int fd; +@@ -148,6 +292,14 @@ static int add_disk_to_super(int mdfd, struct shape *s, struct context *c, + } + st->ss->getinfo_super(st, info, NULL); + ++ if (fd >= 0 && s->write_zeroes) { ++ *zero_pid = write_zeroes_fork(fd, s, st, dv); ++ if (*zero_pid <= 0) { ++ ioctl(mdfd, STOP_ARRAY, NULL); ++ return 1; ++ } ++ } ++ + if (have_container && c->verbose > 0) + pr_err("Using %s for device %d\n", + map_dev(info->disk.major, info->disk.minor, 0), +@@ -224,10 +376,23 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s, + { + struct mddev_dev *moved_disk = NULL; + int pass, raid_disk_num, dnum; ++ int zero_pids[total_slots]; + struct mddev_dev *dv; + struct mdinfo *infos; ++ sigset_t sigset, orig_sigset; + int ret = 0; + ++ /* ++ * Block SIGINT so the main thread will always wait for the ++ * zeroing processes when being interrupted. Otherwise the ++ * zeroing processes will finish their work in the background ++ * keeping the disk busy. ++ */ ++ sigemptyset(&sigset); ++ sigaddset(&sigset, SIGINT); ++ sigprocmask(SIG_BLOCK, &sigset, &orig_sigset); ++ memset(zero_pids, 0, sizeof(zero_pids)); ++ + infos = xmalloc(sizeof(*infos) * total_slots); + enable_fds(total_slots); + for (pass = 1; pass <= 2; pass++) { +@@ -261,7 +426,7 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s, + + ret = add_disk_to_super(mdfd, s, c, st, dv, + &infos[dnum], have_container, +- major_num); ++ major_num, &zero_pids[dnum]); + if (ret) + goto out; + +@@ -287,6 +452,10 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s, + } + + if (pass == 1) { ++ ret = wait_for_zero_forks(zero_pids, total_slots); ++ if (ret) ++ goto out; ++ + ret = update_metadata(mdfd, s, st, map, info, + chosen_name); + if (ret) +@@ -295,7 +464,10 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s, + } + + out: ++ if (ret) ++ wait_for_zero_forks(zero_pids, total_slots); + free(infos); ++ sigprocmask(SIG_SETMASK, &orig_sigset, NULL); + return ret; + } + +diff --git a/ReadMe.c b/ReadMe.c +index bd8d50d2..db251ed2 100644 +--- a/ReadMe.c ++++ b/ReadMe.c +@@ -138,6 +138,7 @@ struct option long_options[] = { + {"size", 1, 0, 'z'}, + {"auto", 1, 0, Auto}, /* also for --assemble */ + {"assume-clean",0,0, AssumeClean }, ++ {"write-zeroes",0,0, WriteZeroes }, + {"metadata", 1, 0, 'e'}, /* superblock format */ + {"bitmap", 1, 0, Bitmap}, + {"bitmap-chunk", 1, 0, BitmapChunk}, +@@ -390,6 +391,7 @@ char Help_create[] = + " --write-journal= : Specify journal device for RAID-4/5/6 array\n" + " --consistency-policy= : Specify the policy that determines how the array\n" + " -k : maintains consistency in case of unexpected shutdown.\n" ++" --write-zeroes : Write zeroes to the disks before creating. This will bypass initial sync.\n" + "\n" + ; + +diff --git a/mdadm.c b/mdadm.c +index 57e8e6fa..4685ad6b 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -590,6 +590,10 @@ int main(int argc, char *argv[]) + s.assume_clean = 1; + continue; + ++ case O(CREATE, WriteZeroes): ++ s.write_zeroes = 1; ++ continue; ++ + case O(GROW,'n'): + case O(CREATE,'n'): + case O(BUILD,'n'): /* number of raid disks */ +@@ -1251,6 +1255,11 @@ int main(int argc, char *argv[]) + } + } + ++ if (s.write_zeroes && !s.assume_clean) { ++ pr_info("Disk zeroing requested, setting --assume-clean to skip resync\n"); ++ s.assume_clean = 1; ++ } ++ + if (!mode && devs_found) { + mode = MISC; + devmode = 'Q'; +diff --git a/mdadm.h b/mdadm.h +index 4336be4d..b9127f9a 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -275,6 +275,9 @@ static inline void __put_unaligned32(__u32 val, void *p) + + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + ++#define KIB_TO_BYTES(x) ((x) << 10) ++#define SEC_TO_BYTES(x) ((x) << 9) ++ + extern const char Name[]; + + struct md_bb_entry { +@@ -435,6 +438,7 @@ extern char Version[], Usage[], Help[], OptionHelp[], + */ + enum special_options { + AssumeClean = 300, ++ WriteZeroes, + BitmapChunk, + WriteBehind, + ReAdd, +@@ -640,6 +644,7 @@ struct shape { + int bitmap_chunk; + char *bitmap_file; + int assume_clean; ++ bool write_zeroes; + int write_behind; + unsigned long long size; + unsigned long long data_offset; +-- +2.38.1 + diff --git a/SOURCES/0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch b/SOURCES/0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch new file mode 100644 index 0000000..441aef2 --- /dev/null +++ b/SOURCES/0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch @@ -0,0 +1,44 @@ +From c918cf2af993b55bca9f396c79713e54d3f8b6fb Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 1 Mar 2023 13:41:34 -0700 +Subject: [PATCH 104/125] tests/00raid5-zero: Introduce test to exercise + --write-zeros. + +Attempt to create a raid5 array with --write-zeros. If it is successful +check the array to ensure it is in sync. + +If it is unsuccessful and an unsupported error is printed, skip the +test. + +Signed-off-by: Logan Gunthorpe +Acked-by: Kinga Tanska +Reviewed-by: Xiao Ni +Reviewed-by: Chaitanya Kulkarni +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + tests/00raid5-zero | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + create mode 100644 tests/00raid5-zero + +diff --git a/tests/00raid5-zero b/tests/00raid5-zero +new file mode 100644 +index 00000000..7d0f05a1 +--- /dev/null ++++ b/tests/00raid5-zero +@@ -0,0 +1,12 @@ ++ ++if mdadm -CfR $md0 -l 5 -n3 $dev0 $dev1 $dev2 --write-zeroes ; then ++ check nosync ++ echo check > /sys/block/md0/md/sync_action; ++ check wait ++elif grep "zeroing [^ ]* failed: Operation not supported" \ ++ $targetdir/stderr; then ++ echo "write-zeros not supported, skipping" ++else ++ echo >&2 "ERROR: mdadm return failure without not supported message" ++ exit 1 ++fi +-- +2.38.1 + diff --git a/SOURCES/0105-manpage-Add-write-zeroes-option-to-manpage.patch b/SOURCES/0105-manpage-Add-write-zeroes-option-to-manpage.patch new file mode 100644 index 0000000..16a0e3f --- /dev/null +++ b/SOURCES/0105-manpage-Add-write-zeroes-option-to-manpage.patch @@ -0,0 +1,56 @@ +From 33831d845a48b9a2ac4d1e954c88a3dd8cb15753 Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Wed, 1 Mar 2023 13:41:35 -0700 +Subject: [PATCH 105/125] manpage: Add --write-zeroes option to manpage + +Document the new --write-zeroes option in the manpage. + +Signed-off-by: Logan Gunthorpe +Acked-by: Kinga Tanska +Reviewed-by: Xiao Ni +Reviewed-by: Chaitanya Kulkarni +Acked-by: Coly Li +Signed-off-by: Jes Sorensen +--- + mdadm.8.in | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/mdadm.8.in b/mdadm.8.in +index 64f71ed1..6f0f6c13 100644 +--- a/mdadm.8.in ++++ b/mdadm.8.in +@@ -837,6 +837,22 @@ array is resynced at creation. From Linux version 3.0, + .B \-\-assume\-clean + can be used with that command to avoid the automatic resync. + ++.TP ++.BR \-\-write-zeroes ++When creating an array, send write zeroes requests to all the block ++devices. This should zero the data area on all disks such that the ++initial sync is not necessary and, if successfull, will behave ++as if ++.B \-\-assume\-clean ++was specified. ++.IP ++This is intended for use with devices that have hardware offload for ++zeroing, but despite this zeroing can still take several minutes for ++large disks. Thus a message is printed before and after zeroing and ++each disk is zeroed in parallel with the others. ++.IP ++This is only meaningful with --create. ++ + .TP + .BR \-\-backup\-file= + This is needed when +@@ -1370,7 +1386,7 @@ and + .B layout\-alternate + options are for RAID0 arrays with non-uniform devices size that were in + use before Linux 5.4. If the array was being used with Linux 3.13 or +-earlier, then to assemble the array on a new kernel, ++earlier, then to assemble the array on a new kernel, + .B \-\-update=layout\-original + must be given. If the array was created and used with a kernel from Linux 3.14 to + Linux 5.3, then +-- +2.38.1 + diff --git a/SOURCES/0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch b/SOURCES/0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch new file mode 100644 index 0000000..13765d8 --- /dev/null +++ b/SOURCES/0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch @@ -0,0 +1,53 @@ +From 566844b93e6823a04ed65827ba3e03cb123b3a03 Mon Sep 17 00:00:00 2001 +From: Khem Raj +Date: Wed, 18 Jan 2023 00:32:36 -0800 +Subject: [PATCH 106/125] Define alignof using _Alignof when using C11 or newer + +WG14 N2350 made very clear that it is an UB having type definitions +within "offsetof" [1]. This patch enhances the implementation of macro +alignof_slot to use builtin "_Alignof" to avoid undefined behavior on +when using std=c11 or newer + +clang 16+ has started to flag this [2] + +Fixes build when using -std >= gnu11 and using clang16+ + +Older compilers gcc < 4.9 or clang < 8 has buggy _Alignof even though it +may support C11, exclude those compilers too + +[1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2350.htm +[2] https://reviews.llvm.org/D133574 + +Upstream-Status: Pending +Signed-off-by: Khem Raj +Signed-off-by: Jes Sorensen +--- + sha1.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/sha1.c b/sha1.c +index 89b32f46..1e4ad5d9 100644 +--- a/sha1.c ++++ b/sha1.c +@@ -229,7 +229,17 @@ sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) + if (len >= 64) + { + #if !_STRING_ARCH_unaligned +-# define alignof(type) offsetof (struct { char c; type x; }, x) ++/* GCC releases before GCC 4.9 had a bug in _Alignof. See GCC bug 52023 ++ . ++ clang versions < 8.0.0 have the same bug. */ ++# if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \ ++ || (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \ ++ && !defined __clang__) \ ++ || (defined __clang__ && __clang_major__ < 8)) ++# define alignof(type) offsetof (struct { char c; type x; }, x) ++# else ++# define alignof(type) _Alignof(type) ++# endif + # define UNALIGNED_P(p) (((size_t) p) % alignof (sha1_uint32) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) +-- +2.38.1 + diff --git a/SOURCES/0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch b/SOURCES/0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch new file mode 100644 index 0000000..20f2755 --- /dev/null +++ b/SOURCES/0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch @@ -0,0 +1,41 @@ +From eb45d0add7cf2918f838bec2d93d99cf2d9c662f Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 13 Mar 2023 14:42:58 +1100 +Subject: [PATCH 107/125] Use existence of /etc/initrd-release to detect + initrd. + +Since v183, systemd has used the existence of /etc/initrd-release to +detect if it is running in an initrd, rather than looking at the magic +number of the root filesystem's device. It is time for mdadm to do the +same. + +Signed-off-by: NeilBrown +Signed-off-by: Jes Sorensen +--- + util.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/util.c b/util.c +index 9f1e1f7c..509fb43e 100644 +--- a/util.c ++++ b/util.c +@@ -2227,15 +2227,7 @@ int continue_via_systemd(char *devnm, char *service_name) + + int in_initrd(void) + { +- /* This is based on similar function in systemd. */ +- struct statfs s; +- /* statfs.f_type is signed long on s390x and MIPS, causing all +- sorts of sign extension problems with RAMFS_MAGIC being +- defined as 0x858458f6 */ +- return statfs("/", &s) >= 0 && +- ((unsigned long)s.f_type == TMPFS_MAGIC || +- ((unsigned long)s.f_type & 0xFFFFFFFFUL) == +- ((unsigned long)RAMFS_MAGIC & 0xFFFFFFFFUL)); ++ return access("/etc/initrd-release", F_OK) >= 0; + } + + void reopen_mddev(int mdfd) +-- +2.38.1 + diff --git a/SOURCES/0108-mdmon-don-t-test-both-all-and-container_name.patch b/SOURCES/0108-mdmon-don-t-test-both-all-and-container_name.patch new file mode 100644 index 0000000..0926a9d --- /dev/null +++ b/SOURCES/0108-mdmon-don-t-test-both-all-and-container_name.patch @@ -0,0 +1,47 @@ +From d39fd87e31024804dd7f2c16c03af0379b71f5f1 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 13 Mar 2023 14:42:58 +1100 +Subject: [PATCH 108/125] mdmon: don't test both 'all' and 'container_name'. + +If 'all' is not set, then container_name must be NULL, as nothing else +can set it. So simplify the test to ignore container_name. +This makes the purpose of the code more obvious. + +Signed-off-by: NeilBrown +Signed-off-by: Jes Sorensen +--- + mdmon.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/mdmon.c b/mdmon.c +index 60ba3182..f8fd2f0f 100644 +--- a/mdmon.c ++++ b/mdmon.c +@@ -352,7 +352,6 @@ int main(int argc, char *argv[]) + } + } + +- + if (in_initrd()) { + /* + * set first char of argv[0] to @. This is used by +@@ -362,12 +361,10 @@ int main(int argc, char *argv[]) + argv[0][0] = '@'; + } + +- if (all == 0 && container_name == NULL) { +- if (argv[optind]) { +- container_name = get_md_name(argv[optind]); +- if (!container_name) +- return 1; +- } ++ if (!all && argv[optind]) { ++ container_name = get_md_name(argv[optind]); ++ if (!container_name) ++ return 1; + } + + if (container_name == NULL || argc - optind > 1) +-- +2.38.1 + diff --git a/SOURCES/0109-mdmon-change-systemd-unit-file-to-use-foreground.patch b/SOURCES/0109-mdmon-change-systemd-unit-file-to-use-foreground.patch new file mode 100644 index 0000000..b2822c8 --- /dev/null +++ b/SOURCES/0109-mdmon-change-systemd-unit-file-to-use-foreground.patch @@ -0,0 +1,33 @@ +From 6660e33edde76329bd3b7f03383856c7efee2aa9 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 13 Mar 2023 14:42:58 +1100 +Subject: [PATCH 109/125] mdmon: change systemd unit file to use --foreground + +There is no value in mdmon forking when it is running under systemd - +systemd can still track it anyway. + +So add --foreground option, and remove "Type=forking". + +Signed-off-by: NeilBrown +Signed-off-by: Jes Sorensen +--- + systemd/mdmon@.service | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service +index cb6482d9..bba9b0eb 100644 +--- a/systemd/mdmon@.service ++++ b/systemd/mdmon@.service +@@ -20,8 +20,7 @@ Environment=IMSM_NO_PLATFORM=1 + # 'takeover'. As the '--offroot --takeover' don't hurt when + # not necessary, are are useful with root-on-md in dracut, + # have them always present. +-ExecStart=BINDIR/mdmon --offroot --takeover %I +-Type=forking ++ExecStart=BINDIR/mdmon --foreground --offroot --takeover %I + # Don't set the PIDFile. It isn't necessary (systemd can work + # it out) and systemd will remove it when transitioning from + # initramfs to rootfs. +-- +2.38.1 + diff --git a/SOURCES/0110-mdmon-Remove-need-for-KillMode-none.patch b/SOURCES/0110-mdmon-Remove-need-for-KillMode-none.patch new file mode 100644 index 0000000..d1cde02 --- /dev/null +++ b/SOURCES/0110-mdmon-Remove-need-for-KillMode-none.patch @@ -0,0 +1,55 @@ +From 0f9a4b3e11fbe4f8631d20b1f89cf43e9219db55 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 13 Mar 2023 14:42:58 +1100 +Subject: [PATCH 110/125] mdmon: Remove need for KillMode=none + +mdmon needs to keep running during the switchroot out of (at boot) and +then back into (at shutdown) the initrd. It runs until a new mdmon +takes over. + +Killmode=none is used to achieve this, with the help of --offroot which +sets argv[0][0] to '@' which systemd understands. + +This is needed because mdmon is currently run in system-mdmon.slice +which conflicts with shutdown.target so without Killmode=none mdmon +would get killed early in shutdown when system.mdmon.slice is removed. + +As described in systemd.service(5), this conflict with shutdown can be +resolved by explicitly requesting system.slice, which is a natural +counterpart to DefaultDependencies=no. + +So add that, and also add IgnoreOnIsolate=true to avoid another possible +source of an early death. With these we no longer need KillMode=none +which the systemd developers have marked as "deprecated". + +Signed-off-by: NeilBrown +Signed-off-by: Jes Sorensen +--- + systemd/mdmon@.service | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service +index bba9b0eb..303ad05c 100644 +--- a/systemd/mdmon@.service ++++ b/systemd/mdmon@.service +@@ -10,6 +10,9 @@ Description=MD Metadata Monitor on /dev/%I + DefaultDependencies=no + Before=initrd-switch-root.target + Documentation=man:mdmon(8) ++# Allow mdmon to keep running after switchroot, until a new ++# instance is started. ++IgnoreOnIsolate=true + + [Service] + # mdmon should never complain due to lack of a platform, +@@ -25,4 +28,6 @@ ExecStart=BINDIR/mdmon --foreground --offroot --takeover %I + # it out) and systemd will remove it when transitioning from + # initramfs to rootfs. + #PIDFile=/run/mdadm/%I.pid +-KillMode=none ++# The default slice is system-mdmon.slice which Conflicts ++# with shutdown, causing mdmon to exit early. So use system.slice. ++Slice=system.slice +-- +2.38.1 + diff --git a/SOURCES/0111-mdmon-Improve-switchroot-interactions.patch b/SOURCES/0111-mdmon-Improve-switchroot-interactions.patch new file mode 100644 index 0000000..96fedb3 --- /dev/null +++ b/SOURCES/0111-mdmon-Improve-switchroot-interactions.patch @@ -0,0 +1,166 @@ +From 723d1df4946eb40337bf494f9b2549500c1399b2 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 13 Mar 2023 14:42:58 +1100 +Subject: [PATCH 111/125] mdmon: Improve switchroot interactions. + +We need a new mdmon@mdfoo instance to run in the root filesystem after +switch root, as /sys and /dev are removed from the initrd. + +systemd will not start a new unit with the same name running while the +old unit is still active, and we want the two mdmon processes to overlap +in time to avoid any risk of deadlock, which can happen when a write is +attempted with no mdmon running. + +So we need a different unit name in the initrd than in the root. Apart +from the name, everything else should be the same. + +This is easily achieved using a different instance name as the +mdmon@.service unit file already supports multiple instances (for +different arrays). + +So start "mdmon@mdfoo.service" from root, but +"mdmon@initrd-mdfoo.service" from the initrd. udev can tell which +circumstance is the case by looking for /etc/initrd-release. +continue_from_systemd() is enhanced so that the "initrd-" prefix can be +requested. + +Teach mdmon that a container name like "initrd/foo" should be treated +just like "foo". Note that systemd passes the instance name +"initrd-foo" as "initrd/foo". + +We don't need a similar mechanism at shutdown because dracut runs +"mdmon --takeover --all" when appropriate. + +Signed-off-by: NeilBrown +Signed-off-by: Jes Sorensen +--- + Grow.c | 4 ++-- + mdadm.h | 2 +- + mdmon.c | 7 ++++++- + systemd/mdmon@.service | 2 +- + udev-md-raid-arrays.rules | 3 ++- + util.c | 7 ++++--- + 6 files changed, 16 insertions(+), 9 deletions(-) + +diff --git a/Grow.c b/Grow.c +index bb5fe45c..06001f2d 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -3516,7 +3516,7 @@ started: + + if (!forked) + if (continue_via_systemd(container ?: sra->sys_name, +- GROW_SERVICE)) { ++ GROW_SERVICE, NULL)) { + free(fdlist); + free(offsets); + sysfs_free(sra); +@@ -3714,7 +3714,7 @@ int reshape_container(char *container, char *devname, + ping_monitor(container); + + if (!forked && !freeze_reshape) +- if (continue_via_systemd(container, GROW_SERVICE)) ++ if (continue_via_systemd(container, GROW_SERVICE, NULL)) + return 0; + + switch (forked ? 0 : fork()) { +diff --git a/mdadm.h b/mdadm.h +index b9127f9a..1e518276 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1608,7 +1608,7 @@ extern int same_dev(char *one, char *two); + extern int compare_paths (char* path1,char* path2); + extern void enable_fds(int devices); + extern void manage_fork_fds(int close_all); +-extern int continue_via_systemd(char *devnm, char *service_name); ++extern int continue_via_systemd(char *devnm, char *service_name, char *prefix); + + extern void ident_init(struct mddev_ident *ident); + +diff --git a/mdmon.c b/mdmon.c +index f8fd2f0f..096b4d76 100644 +--- a/mdmon.c ++++ b/mdmon.c +@@ -362,7 +362,12 @@ int main(int argc, char *argv[]) + } + + if (!all && argv[optind]) { +- container_name = get_md_name(argv[optind]); ++ static const char prefix[] = "initrd/"; ++ container_name = argv[optind]; ++ if (strncmp(container_name, prefix, ++ sizeof(prefix) - 1) == 0) ++ container_name += sizeof(prefix)-1; ++ container_name = get_md_name(container_name); + if (!container_name) + return 1; + } +diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service +index 303ad05c..23a375f6 100644 +--- a/systemd/mdmon@.service ++++ b/systemd/mdmon@.service +@@ -6,7 +6,7 @@ + # (at your option) any later version. + + [Unit] +-Description=MD Metadata Monitor on /dev/%I ++Description=MD Metadata Monitor on %I + DefaultDependencies=no + Before=initrd-switch-root.target + Documentation=man:mdmon(8) +diff --git a/udev-md-raid-arrays.rules b/udev-md-raid-arrays.rules +index 2967ace1..4e64b249 100644 +--- a/udev-md-raid-arrays.rules ++++ b/udev-md-raid-arrays.rules +@@ -38,7 +38,8 @@ ENV{MD_LEVEL}=="raid[1-9]*", ENV{SYSTEMD_WANTS}+="mdmonitor.service" + + # Tell systemd to run mdmon for our container, if we need it. + ENV{MD_LEVEL}=="raid[1-9]*", ENV{MD_CONTAINER}=="?*", PROGRAM="/usr/bin/readlink $env{MD_CONTAINER}", ENV{MD_MON_THIS}="%c" +-ENV{MD_MON_THIS}=="?*", PROGRAM="/usr/bin/basename $env{MD_MON_THIS}", ENV{SYSTEMD_WANTS}+="mdmon@%c.service" ++ENV{MD_MON_THIS}=="?*", TEST=="/etc/initrd-release", PROGRAM="/usr/bin/basename $env{MD_MON_THIS}", ENV{SYSTEMD_WANTS}+="mdmon@initrd-%c.service" ++ENV{MD_MON_THIS}=="?*", TEST!="/etc/initrd-release", PROGRAM="/usr/bin/basename $env{MD_MON_THIS}", ENV{SYSTEMD_WANTS}+="mdmon@%c.service" + ENV{RESHAPE_ACTIVE}=="yes", PROGRAM="/usr/bin/basename $env{MD_MON_THIS}", ENV{SYSTEMD_WANTS}+="mdadm-grow-continue@%c.service" + + LABEL="md_end" +diff --git a/util.c b/util.c +index 509fb43e..d70ca43b 100644 +--- a/util.c ++++ b/util.c +@@ -1916,6 +1916,7 @@ int start_mdmon(char *devnm) + int len; + pid_t pid; + int status; ++ char *prefix = in_initrd() ? "initrd-" : ""; + char pathbuf[1024]; + char *paths[4] = { + pathbuf, +@@ -1926,7 +1927,7 @@ int start_mdmon(char *devnm) + + if (check_env("MDADM_NO_MDMON")) + return 0; +- if (continue_via_systemd(devnm, MDMON_SERVICE)) ++ if (continue_via_systemd(devnm, MDMON_SERVICE, prefix)) + return 0; + + /* That failed, try running mdmon directly */ +@@ -2197,7 +2198,7 @@ void manage_fork_fds(int close_all) + * 1- if systemd service has been started + * 0- otherwise + */ +-int continue_via_systemd(char *devnm, char *service_name) ++int continue_via_systemd(char *devnm, char *service_name, char *prefix) + { + int pid, status; + char pathbuf[1024]; +@@ -2209,7 +2210,7 @@ int continue_via_systemd(char *devnm, char *service_name) + case 0: + manage_fork_fds(1); + snprintf(pathbuf, sizeof(pathbuf), +- "%s@%s.service", service_name, devnm); ++ "%s@%s%s.service", service_name, prefix ?: "", devnm); + status = execl("/usr/bin/systemctl", "systemctl", "restart", + pathbuf, NULL); + status = execl("/bin/systemctl", "systemctl", "restart", +-- +2.38.1 + diff --git a/SOURCES/0112-mdopen-always-try-create_named_array.patch b/SOURCES/0112-mdopen-always-try-create_named_array.patch new file mode 100644 index 0000000..6d857ad --- /dev/null +++ b/SOURCES/0112-mdopen-always-try-create_named_array.patch @@ -0,0 +1,40 @@ +From 2e10c46d0906b1a1ec40e8f5005ccb63125dcd9e Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 14 Mar 2023 11:06:25 +1100 +Subject: [PATCH 112/125] mdopen: always try create_named_array() + +mdopen() will use create_named_array() to ask the kernel to create the +given md array, but only if it is given a number or name. +If it is NOT given a name and is required to choose one itself using +find_free_devnm() it does NOT use create_named_array(). + +On kernels with CONFIG_BLOCK_LEGACY_AUTOLOAD not set, this can result in +failure to assemble an array. This can particularly seen when the +"name" of the array begins with a host name different to the name of the +host running the command. + +So add the missing call to create_named_array(). + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217074 +Signed-off-by: NeilBrown +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + mdopen.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/mdopen.c b/mdopen.c +index d18c9319..810f79a3 100644 +--- a/mdopen.c ++++ b/mdopen.c +@@ -370,6 +370,7 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, + } + if (block_udev) + udev_block(devnm); ++ create_named_array(devnm); + } + + sprintf(devname, "/dev/%s", devnm); +-- +2.38.1 + diff --git a/SOURCES/0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch b/SOURCES/0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch new file mode 100644 index 0000000..1a510f1 --- /dev/null +++ b/SOURCES/0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch @@ -0,0 +1,172 @@ +From 420dafcd38c5949c2ddb90ad6873e7edd625db30 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Mon, 20 Mar 2023 14:43:54 +1100 +Subject: [PATCH 113/125] Improvements for IMSM_NO_PLATFORM testing. + +Factor out IMSM_NO_PLATFORM testing into a single function that caches +the result. + +Allow mdmon to explicitly set the result to "1" so that we don't need +the ENV var in the unit file + +Check if the kernel command line contains "mdadm.imsm.test=1" and in +that case assert NO_PLATFORM. This simplifies testing in a virtual +machine. + +Signed-off-by: NeilBrown +Signed-off-by: Jes Sorensen +--- + mdadm.8.in | 5 +++++ + mdadm.h | 2 ++ + mdmon.c | 6 ++++++ + super-intel.c | 45 +++++++++++++++++++++++++++++++++++++++--- + systemd/mdmon@.service | 3 --- + 5 files changed, 55 insertions(+), 6 deletions(-) + +diff --git a/mdadm.8.in b/mdadm.8.in +index 6f0f6c13..b7159509 100644 +--- a/mdadm.8.in ++++ b/mdadm.8.in +@@ -3197,6 +3197,11 @@ environment. This can be useful for testing or for disaster + recovery. You should be aware that interoperability may be + compromised by setting this value. + ++These change can also be suppressed by adding ++.B mdadm.imsm.test=1 ++to the kernel command line. This makes it easy to test IMSM ++code in a virtual machine that doesn't have IMSM virtual hardware. ++ + .TP + .B MDADM_GROW_ALLOW_OLD + If an array is stopped while it is performing a reshape and that +diff --git a/mdadm.h b/mdadm.h +index 1e518276..0d995445 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1263,6 +1263,8 @@ extern struct superswitch super0, super1; + extern struct superswitch super_imsm, super_ddf; + extern struct superswitch mbr, gpt; + ++void imsm_set_no_platform(int v); ++ + struct metadata_update { + int len; + char *buf; +diff --git a/mdmon.c b/mdmon.c +index 096b4d76..cef5bbc8 100644 +--- a/mdmon.c ++++ b/mdmon.c +@@ -318,6 +318,12 @@ int main(int argc, char *argv[]) + {NULL, 0, NULL, 0} + }; + ++ /* ++ * mdmon should never complain due to lack of a platform, ++ * that is mdadm's job if at all. ++ */ ++ imsm_set_no_platform(1); ++ + while ((opt = getopt_long(argc, argv, "thaF", options, NULL)) != -1) { + switch (opt) { + case 'a': +diff --git a/super-intel.c b/super-intel.c +index e155a8ae..a5c86cb2 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -20,6 +20,7 @@ + #define HAVE_STDINT_H 1 + #include "mdadm.h" + #include "mdmon.h" ++#include "dlink.h" + #include "sha1.h" + #include "platform-intel.h" + #include +@@ -629,6 +630,44 @@ static const char *_sys_dev_type[] = { + [SYS_DEV_VMD] = "VMD" + }; + ++static int no_platform = -1; ++ ++static int check_no_platform(void) ++{ ++ static const char search[] = "mdadm.imsm.test=1"; ++ FILE *fp; ++ ++ if (no_platform >= 0) ++ return no_platform; ++ ++ if (check_env("IMSM_NO_PLATFORM")) { ++ no_platform = 1; ++ return 1; ++ } ++ fp = fopen("/proc/cmdline", "r"); ++ if (fp) { ++ char *l = conf_line(fp); ++ char *w = l; ++ ++ do { ++ if (strcmp(w, search) == 0) ++ no_platform = 1; ++ w = dl_next(w); ++ } while (w != l); ++ free_line(l); ++ fclose(fp); ++ if (no_platform >= 0) ++ return no_platform; ++ } ++ no_platform = 0; ++ return 0; ++} ++ ++void imsm_set_no_platform(int v) ++{ ++ no_platform = v; ++} ++ + const char *get_sys_dev_type(enum sys_dev_type type) + { + if (type >= SYS_DEV_MAX) +@@ -2699,7 +2738,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle + int result=1; + + if (enumerate_only) { +- if (check_env("IMSM_NO_PLATFORM")) ++ if (check_no_platform()) + return 0; + list = find_intel_devices(); + if (!list) +@@ -4722,7 +4761,7 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de + devname); + return 1; + } +- if (!is_fd_valid(fd) || check_env("IMSM_NO_PLATFORM")) { ++ if (!is_fd_valid(fd) || check_no_platform()) { + super->orom = NULL; + super->hba = NULL; + return 0; +@@ -10697,7 +10736,7 @@ static int imsm_get_allowed_degradation(int level, int raid_disks, + ******************************************************************************/ + int validate_container_imsm(struct mdinfo *info) + { +- if (check_env("IMSM_NO_PLATFORM")) ++ if (check_no_platform()) + return 0; + + struct sys_dev *idev; +diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service +index 23a375f6..020cc7e1 100644 +--- a/systemd/mdmon@.service ++++ b/systemd/mdmon@.service +@@ -15,9 +15,6 @@ Documentation=man:mdmon(8) + IgnoreOnIsolate=true + + [Service] +-# mdmon should never complain due to lack of a platform, +-# that is mdadm's job if at all. +-Environment=IMSM_NO_PLATFORM=1 + # The mdmon starting in the initramfs (with dracut at least) + # cannot see sysfs after root is mounted, so we will have to + # 'takeover'. As the '--offroot --takeover' don't hurt when +-- +2.38.1 + diff --git a/SOURCES/0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch b/SOURCES/0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch new file mode 100644 index 0000000..4db3370 --- /dev/null +++ b/SOURCES/0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch @@ -0,0 +1,29 @@ +From 9b6e3b43381245cb128ad98bf117a565ce5defe5 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 23 Mar 2023 17:13:18 +0100 +Subject: [PATCH 114/125] Revert "Revert "mdadm/systemd: remove KillMode=none + from service file"" + +This reverts commit 28a083955c6f58f8e582734c8c82aff909a7d461. + +Resolved by commit 723d1df4946e ("mdmon: Improve switchroot +interactions.") We are ready to drop it. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + systemd/mdadm-grow-continue@.service | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/systemd/mdadm-grow-continue@.service b/systemd/mdadm-grow-continue@.service +index 9ccadca3..64b8254a 100644 +--- a/systemd/mdadm-grow-continue@.service ++++ b/systemd/mdadm-grow-continue@.service +@@ -15,4 +15,3 @@ ExecStart=BINDIR/mdadm --grow --continue /dev/%I + StandardInput=null + StandardOutput=null + StandardError=null +-KillMode=none +-- +2.38.1 + diff --git a/SOURCES/0115-Create-Fix-checking-for-container-in-update_metadata.patch b/SOURCES/0115-Create-Fix-checking-for-container-in-update_metadata.patch new file mode 100644 index 0000000..d533d8b --- /dev/null +++ b/SOURCES/0115-Create-Fix-checking-for-container-in-update_metadata.patch @@ -0,0 +1,38 @@ +From ef6236da232e968dcf08b486178cd20d5ea97e2a Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Thu, 23 Mar 2023 12:50:00 +0100 +Subject: [PATCH 115/125] Create: Fix checking for container in update_metadata + +The commit 8a4ce2c05386 ("Create: Factor out add_disks() helpers") +introduced a regression that caused timeouts and udev failing to create +links. + +Steps to reproduce the issue were as following: +$ mdadm -CR imsm -e imsm -n4 /dev/nvme[0-3]n1 +$ mdadm -CR vol -l5 -n4 /dev/nvme[0-3]n1 --assume-clean + +I found the check for container was wrong because negation was missing. + +Fixes: 8a4ce2c05386 ("Create: Factor out add_disks() helpers") +Signed-off-by: Mateusz Grzonka +Signed-off-by: Jes Sorensen +--- + Create.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Create.c b/Create.c +index bbe9e13d..0911bf92 100644 +--- a/Create.c ++++ b/Create.c +@@ -328,7 +328,7 @@ static int update_metadata(int mdfd, struct shape *s, struct supertype *st, + * again returns container info. + */ + st->ss->getinfo_super(st, &info_new, NULL); +- if (st->ss->external && is_container(s->level) && ++ if (st->ss->external && !is_container(s->level) && + !same_uuid(info_new.uuid, info->uuid, 0)) { + map_update(map, fd2devnm(mdfd), + info_new.text_version, +-- +2.38.1 + diff --git a/SOURCES/0116-Fix-null-pointer-for-incremental-in-mdadm.patch b/SOURCES/0116-Fix-null-pointer-for-incremental-in-mdadm.patch new file mode 100644 index 0000000..ca8176c --- /dev/null +++ b/SOURCES/0116-Fix-null-pointer-for-incremental-in-mdadm.patch @@ -0,0 +1,43 @@ +From 890212d6800646153210ac264ce73035cc7dd5cc Mon Sep 17 00:00:00 2001 +From: miaoguanqin +Date: Tue, 4 Apr 2023 19:31:24 +0800 +Subject: [PATCH 116/125] Fix null pointer for incremental in mdadm + +when we excute mdadm --assemble, udev-md-raid-assembly.rules is triggered. +Then we stop array, we found an coredump for mdadm --incremental.func +stack are as follows: + +#0 enough (level=10, raid_disks=4, layout=258, clean=1, + avail=avail@entry=0x0) at util.c:555 +#1 0x0000562170c26965 in Incremental (devlist=, + c=, st=0x5621729b6dc0) at Incremental.c:514 +#2 0x0000562170bfb6ff in main (argc=, + argv=) at mdadm.c:1762 + +func enough() use array avail,avail allocate space in func count_active, +it may not alloc space, causing a coredump.We fix this coredump. + +Signed-off-by: Guanqin Miao +Signed-off-by: lixiaokeng +Signed-off-by: Jes Sorensen +--- + Incremental.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Incremental.c b/Incremental.c +index 09b94b9f..49a71f72 100644 +--- a/Incremental.c ++++ b/Incremental.c +@@ -507,6 +507,9 @@ int Incremental(struct mddev_dev *devlist, struct context *c, + GET_OFFSET | GET_SIZE)); + active_disks = count_active(st, sra, mdfd, &avail, &info); + ++ if (!avail) ++ goto out_unlock; ++ + journal_device_missing = (info.journal_device_required) && (info.journal_clean == 0); + + if (info.consistency_policy == CONSISTENCY_POLICY_PPL) +-- +2.38.1 + diff --git a/SOURCES/0117-super1-fix-truncation-check-for-journal-device.patch b/SOURCES/0117-super1-fix-truncation-check-for-journal-device.patch new file mode 100644 index 0000000..cf61c2d --- /dev/null +++ b/SOURCES/0117-super1-fix-truncation-check-for-journal-device.patch @@ -0,0 +1,33 @@ +From 1c6f2a1dbfe17df14dd5b062fc53a60c5c387e47 Mon Sep 17 00:00:00 2001 +From: Hristo Venev +Date: Sat, 1 Apr 2023 23:01:35 +0300 +Subject: [PATCH 117/125] super1: fix truncation check for journal device + +The journal device can be smaller than the component devices. + +Fixes: 171e9743881e ("super1: report truncated device") +Signed-off-by: Hristo Venev +Signed-off-by: Jes Sorensen +--- + super1.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/super1.c b/super1.c +index f7020320..44d6ecad 100644 +--- a/super1.c ++++ b/super1.c +@@ -2359,8 +2359,9 @@ static int load_super1(struct supertype *st, int fd, char *devname) + + if (st->minor_version >= 1 && + st->ignore_hw_compat == 0 && +- (dsize < (__le64_to_cpu(super->data_offset) + +- __le64_to_cpu(super->size)) ++ ((role_from_sb(super) != MD_DISK_ROLE_JOURNAL && ++ dsize < (__le64_to_cpu(super->data_offset) + ++ __le64_to_cpu(super->size))) + || + dsize < (__le64_to_cpu(super->data_offset) + + __le64_to_cpu(super->data_size)))) { +-- +2.38.1 + diff --git a/SOURCES/0118-Fix-some-cases-eyesore-formatting.patch b/SOURCES/0118-Fix-some-cases-eyesore-formatting.patch new file mode 100644 index 0000000..889471f --- /dev/null +++ b/SOURCES/0118-Fix-some-cases-eyesore-formatting.patch @@ -0,0 +1,433 @@ +From d3bb888d885fc96fc6239fbf6c22c63143eba461 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 10 Apr 2023 11:40:42 -0400 +Subject: [PATCH 118/125] Fix some cases eyesore formatting + +Summary: No functional change .... just make it more readable. + +Signed-off-by: Jes Sorensen +--- + super1.c | 117 ++++++++++++++++++++++++++++--------------------------- + 1 file changed, 60 insertions(+), 57 deletions(-) + +diff --git a/super1.c b/super1.c +index 44d6ecad..1d20ef55 100644 +--- a/super1.c ++++ b/super1.c +@@ -192,7 +192,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) + unsigned int disk_csum, csum; + unsigned long long newcsum; + int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2; +- unsigned int *isuper = (unsigned int*)sb; ++ unsigned int *isuper = (unsigned int *)sb; + + /* make sure I can count... */ + if (offsetof(struct mdp_superblock_1,data_offset) != 128 || +@@ -204,7 +204,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb) + disk_csum = sb->sb_csum; + sb->sb_csum = 0; + newcsum = 0; +- for (; size>=4; size -= 4 ) { ++ for (; size >= 4; size -= 4) { + newcsum += __le32_to_cpu(*isuper); + isuper++; + } +@@ -319,7 +319,7 @@ static inline unsigned int choose_ppl_space(int chunk) + static void examine_super1(struct supertype *st, char *homehost) + { + struct mdp_superblock_1 *sb = st->sb; +- bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE); ++ bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE); + time_t atime; + unsigned int d; + int role; +@@ -343,8 +343,9 @@ static void examine_super1(struct supertype *st, char *homehost) + printf(".0\n"); + printf(" Feature Map : 0x%x\n", __le32_to_cpu(sb->feature_map)); + printf(" Array UUID : "); +- for (i=0; i<16; i++) { +- if ((i&3)==0 && i != 0) printf(":"); ++ for (i = 0; i < 16; i++) { ++ if ((i & 3) == 0 && i != 0) ++ printf(":"); + printf("%02x", sb->set_uuid[i]); + } + printf("\n"); +@@ -416,11 +417,11 @@ static void examine_super1(struct supertype *st, char *homehost) + UINT64_MAX - info.space_after); + } + printf(" State : %s%s\n", +- (__le64_to_cpu(sb->resync_offset)+1) ? "active":"clean", ++ (__le64_to_cpu(sb->resync_offset) + 1) ? "active":"clean", + (info.space_after > INT64_MAX) ? " TRUNCATED DEVICE" : ""); + printf(" Device UUID : "); +- for (i=0; i<16; i++) { +- if ((i&3)==0 && i != 0) ++ for (i = 0; i < 16; i++) { ++ if ((i & 3)==0 && i != 0) + printf(":"); + printf("%02x", sb->device_uuid[i]); + } +@@ -546,7 +547,7 @@ static void examine_super1(struct supertype *st, char *homehost) + #if 0 + /* This turns out to just be confusing */ + printf(" Array Slot : %d (", __le32_to_cpu(sb->dev_number)); +- for (i = __le32_to_cpu(sb->max_dev); i> 0 ; i--) ++ for (i = __le32_to_cpu(sb->max_dev); i > 0 ; i--) + if (__le16_to_cpu(sb->dev_roles[i-1]) != MD_DISK_ROLE_SPARE) + break; + for (d = 0; d < i; d++) { +@@ -597,7 +598,7 @@ static void examine_super1(struct supertype *st, char *homehost) + #if 0 + /* This is confusing too */ + faulty = 0; +- for (i = 0; i< __le32_to_cpu(sb->max_dev); i++) { ++ for (i = 0; i < __le32_to_cpu(sb->max_dev); i++) { + int role = __le16_to_cpu(sb->dev_roles[i]); + if (role == MD_DISK_ROLE_FAULTY) + faulty++; +@@ -616,10 +617,12 @@ static void examine_super1(struct supertype *st, char *homehost) + if (inconsistent) { + printf("WARNING Array state is inconsistent - each number should appear only once\n"); + for (d = 0; d < __le32_to_cpu(sb->max_dev); d++) +- if (__le16_to_cpu(sb->dev_roles[d]) >= MD_DISK_ROLE_FAULTY) ++ if (__le16_to_cpu(sb->dev_roles[d]) >= ++ MD_DISK_ROLE_FAULTY) + printf(" %d:-", d); + else +- printf(" %d:%d", d, __le16_to_cpu(sb->dev_roles[d])); ++ printf(" %d:%d", d, ++ __le16_to_cpu(sb->dev_roles[d])); + printf("\n"); + } + } +@@ -659,7 +662,7 @@ static void brief_examine_super1(struct supertype *st, int verbose) + printf("num-devices=%d ", __le32_to_cpu(sb->raid_disks)); + printf("UUID="); + for (i = 0; i < 16; i++) { +- if ((i&3)==0 && i != 0) ++ if ((i & 3)==0 && i != 0) + printf(":"); + printf("%02x", sb->set_uuid[i]); + } +@@ -713,7 +716,7 @@ static void export_examine_super1(struct supertype *st) + } + printf("MD_UUID="); + for (i = 0; i < 16; i++) { +- if ((i&3) == 0 && i != 0) ++ if ((i & 3) == 0 && i != 0) + printf(":"); + printf("%02x", sb->set_uuid[i]); + } +@@ -722,7 +725,7 @@ static void export_examine_super1(struct supertype *st) + __le64_to_cpu(sb->utime) & 0xFFFFFFFFFFULL); + printf("MD_DEV_UUID="); + for (i = 0; i < 16; i++) { +- if ((i&3) == 0 && i != 0) ++ if ((i & 3) == 0 && i != 0) + printf(":"); + printf("%02x", sb->device_uuid[i]); + } +@@ -812,7 +815,7 @@ static int copy_metadata1(struct supertype *st, int from, int to) + /* have the header, can calculate + * correct bitmap bytes */ + bitmap_super_t *bms; +- bms = (void*)buf; ++ bms = (void *)buf; + bytes = calc_bitmap_size(bms, 512); + if (n > bytes) + n = bytes; +@@ -867,7 +870,7 @@ err: + static void detail_super1(struct supertype *st, char *homehost, char *subarray) + { + struct mdp_superblock_1 *sb = st->sb; +- bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE); ++ bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE); + int i; + int l = homehost ? strlen(homehost) : 0; + +@@ -880,7 +883,7 @@ static void detail_super1(struct supertype *st, char *homehost, char *subarray) + printf("\n Cluster Name : %-64s", bms->cluster_name); + printf("\n UUID : "); + for (i = 0; i < 16; i++) { +- if ((i&3) == 0 && i != 0) ++ if ((i & 3) == 0 && i != 0) + printf(":"); + printf("%02x", sb->set_uuid[i]); + } +@@ -939,7 +942,7 @@ static int examine_badblocks_super1(struct supertype *st, int fd, char *devname) + } + + size = __le16_to_cpu(sb->bblog_size)* 512; +- if (posix_memalign((void**)&bbl, 4096, size) != 0) { ++ if (posix_memalign((void **)&bbl, 4096, size) != 0) { + pr_err("could not allocate badblocks list\n"); + return 0; + } +@@ -987,7 +990,7 @@ static int match_home1(struct supertype *st, char *homehost) + static void uuid_from_super1(struct supertype *st, int uuid[4]) + { + struct mdp_superblock_1 *super = st->sb; +- char *cuuid = (char*)uuid; ++ char *cuuid = (char *)uuid; + int i; + for (i = 0; i < 16; i++) + cuuid[i] = super->set_uuid[i]; +@@ -996,9 +999,9 @@ static void uuid_from_super1(struct supertype *st, int uuid[4]) + static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) + { + struct mdp_superblock_1 *sb = st->sb; +- struct bitmap_super_s *bsb = (void*)(((char*)sb)+MAX_SB_SIZE); ++ struct bitmap_super_s *bsb = (void *)(((char *)sb) + MAX_SB_SIZE); + struct misc_dev_info *misc = +- (void*)(((char*)sb)+MAX_SB_SIZE+BM_SUPER_SIZE); ++ (void *)(((char *)sb) + MAX_SB_SIZE+BM_SUPER_SIZE); + int working = 0; + unsigned int i; + unsigned int role; +@@ -1166,7 +1169,7 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map) + info->recovery_blocked = info->reshape_active; + + if (map) +- for (i=0; imax_dev); i++) { + role = __le16_to_cpu(sb->dev_roles[i]); +@@ -1217,7 +1220,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info, + */ + int rv = 0; + struct mdp_superblock_1 *sb = st->sb; +- bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE); ++ bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE); + + if (update == UOPT_HOMEHOST && homehost) { + /* +@@ -1228,9 +1231,10 @@ static int update_super1(struct supertype *st, struct mdinfo *info, + update = UOPT_NAME; + c = strchr(sb->set_name, ':'); + if (c) +- snprintf(info->name, sizeof(info->name), "%s", c+1); ++ snprintf(info->name, sizeof(info->name), "%s", c + 1); + else +- snprintf(info->name, sizeof(info->name), "%s", sb->set_name); ++ snprintf(info->name, sizeof(info->name), "%s", ++ sb->set_name); + } + + switch (update) { +@@ -1331,7 +1335,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info, + sb->dev_number = __cpu_to_le32(i); + + if (i == max) +- sb->max_dev = __cpu_to_le32(max+1); ++ sb->max_dev = __cpu_to_le32(max + 1); + if (i > max) + return -2; + +@@ -1350,8 +1354,8 @@ static int update_super1(struct supertype *st, struct mdinfo *info, + sb->data_size = __cpu_to_le64( + ds - __le64_to_cpu(sb->data_offset)); + } else { +- ds -= 8*2; +- ds &= ~(unsigned long long)(4*2-1); ++ ds -= 8 * 2; ++ ds &= ~(unsigned long long)(4 * 2 - 1); + sb->super_offset = __cpu_to_le64(ds); + sb->data_size = __cpu_to_le64( + ds - __le64_to_cpu(sb->data_offset)); +@@ -1367,7 +1371,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info, + if (i > max) + return -2; + if (i == max) +- sb->max_dev = __cpu_to_le32(max+1); ++ sb->max_dev = __cpu_to_le32(max + 1); + sb->raid_disks = __cpu_to_le32(info->array.raid_disks); + sb->dev_roles[info->disk.number] = + __cpu_to_le16(info->disk.raid_disk); +@@ -1645,7 +1649,7 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info, + char defname[10]; + int sbsize; + +- if (posix_memalign((void**)&sb, 4096, SUPER1_SIZE) != 0) { ++ if (posix_memalign((void **)&sb, 4096, SUPER1_SIZE) != 0) { + pr_err("could not allocate superblock\n"); + return 0; + } +@@ -1679,8 +1683,8 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info, + name = defname; + } + if (homehost && +- strchr(name, ':')== NULL && +- strlen(homehost)+1+strlen(name) < 32) { ++ strchr(name, ':') == NULL && ++ strlen(homehost) + 1 + strlen(name) < 32) { + strcpy(sb->set_name, homehost); + strcat(sb->set_name, ":"); + strcat(sb->set_name, name); +@@ -1759,7 +1763,7 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk, + + if (dk->number >= (int)__le32_to_cpu(sb->max_dev) && + __le32_to_cpu(sb->max_dev) < MAX_DEVS) +- sb->max_dev = __cpu_to_le32(dk->number+1); ++ sb->max_dev = __cpu_to_le32(dk->number + 1); + + sb->dev_number = __cpu_to_le32(dk->number); + sb->devflags = 0; /* don't copy another disks flags */ +@@ -1840,8 +1844,8 @@ static int store_super1(struct supertype *st, int fd) + return 4; + + if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) { +- struct bitmap_super_s *bm = (struct bitmap_super_s*) +- (((char*)sb)+MAX_SB_SIZE); ++ struct bitmap_super_s *bm; ++ bm = (struct bitmap_super_s *)(((char *)sb) + MAX_SB_SIZE); + if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) { + locate_bitmap1(st, fd, 0); + if (awrite(&afd, bm, sizeof(*bm)) != sizeof(*bm)) +@@ -1928,7 +1932,7 @@ static int write_empty_r5l_meta_block(struct supertype *st, int fd) + + init_afd(&afd, fd); + +- if (posix_memalign((void**)&mb, 4096, META_BLOCK_SIZE) != 0) { ++ if (posix_memalign((void **)&mb, 4096, META_BLOCK_SIZE) != 0) { + pr_err("Could not allocate memory for the meta block.\n"); + return 1; + } +@@ -2197,7 +2201,7 @@ static int compare_super1(struct supertype *st, struct supertype *tst, + return 1; + + if (!first) { +- if (posix_memalign((void**)&first, 4096, SUPER1_SIZE) != 0) { ++ if (posix_memalign((void **)&first, 4096, SUPER1_SIZE) != 0) { + pr_err("could not allocate superblock\n"); + return 1; + } +@@ -2310,7 +2314,7 @@ static int load_super1(struct supertype *st, int fd, char *devname) + return 1; + } + +- if (posix_memalign((void**)&super, 4096, SUPER1_SIZE) != 0) { ++ if (posix_memalign((void **)&super, 4096, SUPER1_SIZE) != 0) { + pr_err("could not allocate superblock\n"); + return 1; + } +@@ -2349,10 +2353,10 @@ static int load_super1(struct supertype *st, int fd, char *devname) + return 2; + } + +- bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE); ++ bsb = (struct bitmap_super_s *)(((char *)super) + MAX_SB_SIZE); + + misc = (struct misc_dev_info*) +- (((char*)super)+MAX_SB_SIZE+BM_SUPER_SIZE); ++ (((char *)super) + MAX_SB_SIZE+BM_SUPER_SIZE); + misc->device_size = dsize; + if (st->data_offset == INVALID_SECTORS) + st->data_offset = __le64_to_cpu(super->data_offset); +@@ -2360,9 +2364,8 @@ static int load_super1(struct supertype *st, int fd, char *devname) + if (st->minor_version >= 1 && + st->ignore_hw_compat == 0 && + ((role_from_sb(super) != MD_DISK_ROLE_JOURNAL && +- dsize < (__le64_to_cpu(super->data_offset) + +- __le64_to_cpu(super->size))) +- || ++ dsize < (__le64_to_cpu(super->data_offset) + ++ __le64_to_cpu(super->size))) || + dsize < (__le64_to_cpu(super->data_offset) + + __le64_to_cpu(super->data_size)))) { + if (devname) +@@ -2391,8 +2394,8 @@ static int load_super1(struct supertype *st, int fd, char *devname) + return 0; + + no_bitmap: +- super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) +- & ~MD_FEATURE_BITMAP_OFFSET); ++ super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) & ++ ~MD_FEATURE_BITMAP_OFFSET); + return 0; + } + +@@ -2450,7 +2453,7 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize, + if (__le32_to_cpu(super->feature_map) & MD_FEATURE_BITMAP_OFFSET) { + /* hot-add. allow for actual size of bitmap */ + struct bitmap_super_s *bsb; +- bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE); ++ bsb = (struct bitmap_super_s *)(((char *)super) + MAX_SB_SIZE); + bmspace = calc_bitmap_size(bsb, 4096) >> 9; + } else if (md_feature_any_ppl_on(super->feature_map)) { + bmspace = __le16_to_cpu(super->ppl.size); +@@ -2519,7 +2522,7 @@ add_internal_bitmap1(struct supertype *st, + int creating = 0; + int len; + struct mdp_superblock_1 *sb = st->sb; +- bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE); ++ bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE); + int uuid[4]; + + if (__le64_to_cpu(sb->data_size) == 0) +@@ -2607,10 +2610,10 @@ add_internal_bitmap1(struct supertype *st, + max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8; + + min_chunk = 4096; /* sub-page chunks don't work yet.. */ +- bits = (size*512)/min_chunk +1; ++ bits = (size * 512) / min_chunk + 1; + while (bits > max_bits) { + min_chunk *= 2; +- bits = (bits+1)/2; ++ bits = (bits + 1) / 2; + } + if (chunk == UnSet) { + /* For practical purpose, 64Meg is a good +@@ -2628,8 +2631,8 @@ add_internal_bitmap1(struct supertype *st, + /* start bitmap on a 4K boundary with enough space for + * the bitmap + */ +- bits = (size*512) / chunk + 1; +- room = ((bits+7)/8 + sizeof(bitmap_super_t) +4095)/4096; ++ bits = (size * 512) / chunk + 1; ++ room = ((bits + 7) / 8 + sizeof(bitmap_super_t) + 4095) / 4096; + room *= 8; /* convert 4K blocks to sectors */ + offset = -room - bbl_size; + } +@@ -2683,7 +2686,7 @@ static int locate_bitmap1(struct supertype *st, int fd, int node_num) + + offset = __le64_to_cpu(sb->super_offset) + (int32_t)__le32_to_cpu(sb->bitmap_offset); + if (node_num) { +- bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE); ++ bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE); + bm_sectors_per_node = calc_bitmap_size(bms, 4096) >> 9; + offset += bm_sectors_per_node * node_num; + } +@@ -2696,7 +2699,7 @@ static int locate_bitmap1(struct supertype *st, int fd, int node_num) + static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update) + { + struct mdp_superblock_1 *sb = st->sb; +- bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE); ++ bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE); + int rv = 0; + void *buf; + int towrite, n, len; +@@ -2970,16 +2973,16 @@ void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0 + + copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid); + sprintf(sb->set_name, "%d", sb0->md_minor); +- sb->ctime = __cpu_to_le32(info->array.ctime+1); ++ sb->ctime = __cpu_to_le32(info->array.ctime + 1); + sb->level = __cpu_to_le32(info->array.level); + sb->layout = __cpu_to_le32(info->array.layout); + sb->size = __cpu_to_le64(info->component_size); +- sb->chunksize = __cpu_to_le32(info->array.chunk_size/512); ++ sb->chunksize = __cpu_to_le32(info->array.chunk_size / 512); + sb->raid_disks = __cpu_to_le32(info->array.raid_disks); + if (info->array.level > 0) + sb->data_size = sb->size; + else +- sb->data_size = st->ss->avail_size(st, st->devsize/512, 0); ++ sb->data_size = st->ss->avail_size(st, st->devsize / 512, 0); + sb->resync_offset = MaxSector; + sb->max_dev = __cpu_to_le32(MD_SB_DISKS); + sb->dev_number = __cpu_to_le32(info->disk.number); +-- +2.38.1 + diff --git a/SOURCES/0119-Bump-minimum-kernel-version-to-2.6.32.patch b/SOURCES/0119-Bump-minimum-kernel-version-to-2.6.32.patch new file mode 100644 index 0000000..486f799 --- /dev/null +++ b/SOURCES/0119-Bump-minimum-kernel-version-to-2.6.32.patch @@ -0,0 +1,136 @@ +From f8d2c4286a92b7acb7872271a401ad1efe336096 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 10 Apr 2023 11:45:34 -0400 +Subject: [PATCH 119/125] Bump minimum kernel version to 2.6.32 + +Summary: At this point it probably is reasonable to drop support for +anything prior to 3.10. + +Signed-off-by: Jes Sorensen +--- + Create.c | 5 ----- + Grow.c | 16 ---------------- + Manage.c | 17 ----------------- + mdadm.c | 4 ++-- + super1.c | 5 ----- + 5 files changed, 2 insertions(+), 45 deletions(-) + +diff --git a/Create.c b/Create.c +index 0911bf92..aa0472dd 100644 +--- a/Create.c ++++ b/Create.c +@@ -636,11 +636,6 @@ int Create(struct supertype *st, char *mddev, + break; + case LEVEL_LINEAR: + /* a chunksize of zero 0s perfectly valid (and preferred) since 2.6.16 */ +- if (get_linux_version() < 2006016 && s->chunk == 0) { +- s->chunk = 64; +- if (c->verbose > 0) +- pr_err("chunk size defaults to 64K\n"); +- } + break; + case 1: + case LEVEL_FAULTY: +diff --git a/Grow.c b/Grow.c +index 06001f2d..8fa97875 100644 +--- a/Grow.c ++++ b/Grow.c +@@ -1708,14 +1708,6 @@ char *analyse_change(char *devname, struct mdinfo *info, struct reshape *re) + return NULL; + } + +- if (re->after.data_disks == re->before.data_disks && +- get_linux_version() < 2006032) +- return "in-place reshape is not safe before 2.6.32 - sorry."; +- +- if (re->after.data_disks < re->before.data_disks && +- get_linux_version() < 2006030) +- return "reshape to fewer devices is not supported before 2.6.30 - sorry."; +- + re->backup_blocks = compute_backup_blocks( + info->new_chunk, info->array.chunk_size, + re->after.data_disks, re->before.data_disks); +@@ -1895,14 +1887,6 @@ int Grow_reshape(char *devname, int fd, + return 1; + } + +- if (s->raiddisks && s->raiddisks < array.raid_disks && +- array.level > 1 && get_linux_version() < 2006032 && +- !check_env("MDADM_FORCE_FEWER")) { +- pr_err("reducing the number of devices is not safe before Linux 2.6.32\n" +- " Please use a newer kernel\n"); +- return 1; +- } +- + if (array.level > 1 && s->size > 1 && + (unsigned long long) (array.chunk_size / 1024) > s->size) { + pr_err("component size must be larger than chunk size.\n"); +diff --git a/Manage.c b/Manage.c +index fde6aba3..f54de7c6 100644 +--- a/Manage.c ++++ b/Manage.c +@@ -461,17 +461,6 @@ done: + goto out; + } + +- if (get_linux_version() < 2006028) { +- /* prior to 2.6.28, KOBJ_CHANGE was not sent when an md array +- * was stopped, so We'll do it here just to be sure. Drop any +- * partitions as well... +- */ +- if (fd >= 0) +- ioctl(fd, BLKRRPART, 0); +- if (mdi) +- sysfs_uevent(mdi, "change"); +- } +- + if (devnm[0] && use_udev()) { + struct map_ent *mp = map_by_devnm(&map, devnm); + remove_devices(devnm, mp ? mp->path : NULL); +@@ -621,12 +610,6 @@ int attempt_re_add(int fd, int tfd, struct mddev_dev *dv, + * though. + */ + mdu_disk_info_t disc; +- /* re-add doesn't work for version-1 superblocks +- * before 2.6.18 :-( +- */ +- if (array->major_version == 1 && +- get_linux_version() <= 2006018) +- goto skip_re_add; + disc.number = mdi.disk.number; + if (md_get_disk_info(fd, &disc) != 0 || + disc.major != 0 || disc.minor != 0) +diff --git a/mdadm.c b/mdadm.c +index 4685ad6b..2296911d 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -107,8 +107,8 @@ int main(int argc, char *argv[]) + + srandom(time(0) ^ getpid()); + +- if (get_linux_version() < 2006015) { +- pr_err("This version of mdadm does not support kernels older than 2.6.15\n"); ++ if (get_linux_version() < 2006032) { ++ pr_err("This version of mdadm does not support kernels older than 2.6.32\n"); + exit(1); + } + +diff --git a/super1.c b/super1.c +index 1d20ef55..938c3a68 100644 +--- a/super1.c ++++ b/super1.c +@@ -2033,11 +2033,6 @@ static int write_init_super1(struct supertype *st) + /* same array, so preserve events and + * dev_number */ + sb->events = refsb->events; +- /* bugs in 2.6.17 and earlier mean the +- * dev_number chosen in Manage must be preserved +- */ +- if (get_linux_version() >= 2006018) +- sb->dev_number = refsb->dev_number; + } + free_super1(refst); + } +-- +2.38.1 + diff --git a/SOURCES/0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch b/SOURCES/0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch new file mode 100644 index 0000000..4160281 --- /dev/null +++ b/SOURCES/0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch @@ -0,0 +1,42 @@ +From 76c224c6cfc8ff154bd041d30b9551faecd593c1 Mon Sep 17 00:00:00 2001 +From: Xiao Ni +Date: Fri, 7 Apr 2023 08:45:28 +0800 +Subject: [PATCH 120/125] Remove the config files in mdcheck_start|continue + service + +We set MDADM_CHECK_DURATION in the mdcheck_start|continue.service files. +And mdcheck doesn't use any configs from the config file. So we can remove +the dependencies. + +Signed-off-by: Xiao Ni +Signed-off-by: Jes Sorensen +--- + systemd/mdcheck_continue.service | 2 -- + systemd/mdcheck_start.service | 2 -- + 2 files changed, 4 deletions(-) + +diff --git a/systemd/mdcheck_continue.service b/systemd/mdcheck_continue.service +index f5324905..70892a1f 100644 +--- a/systemd/mdcheck_continue.service ++++ b/systemd/mdcheck_continue.service +@@ -13,6 +13,4 @@ Documentation=man:mdadm(8) + [Service] + Type=oneshot + Environment="MDADM_CHECK_DURATION=6 hours" +-EnvironmentFile=-/run/sysconfig/mdadm +-ExecStartPre=-/usr/lib/mdadm/mdadm_env.sh + ExecStart=/usr/share/mdadm/mdcheck --continue --duration ${MDADM_CHECK_DURATION} +diff --git a/systemd/mdcheck_start.service b/systemd/mdcheck_start.service +index 703a6583..fc4fc438 100644 +--- a/systemd/mdcheck_start.service ++++ b/systemd/mdcheck_start.service +@@ -13,6 +13,4 @@ Documentation=man:mdadm(8) + [Service] + Type=oneshot + Environment="MDADM_CHECK_DURATION=6 hours" +-EnvironmentFile=-/run/sysconfig/mdadm +-ExecStartPre=-/usr/lib/mdadm/mdadm_env.sh + ExecStart=/usr/share/mdadm/mdcheck --duration ${MDADM_CHECK_DURATION} +-- +2.38.1 + diff --git a/SOURCES/0121-mdadm-define-DEV_MD_DIR.patch b/SOURCES/0121-mdadm-define-DEV_MD_DIR.patch new file mode 100644 index 0000000..047c45e --- /dev/null +++ b/SOURCES/0121-mdadm-define-DEV_MD_DIR.patch @@ -0,0 +1,347 @@ +From b9ce7ab0218c550488587fdad5708628d6a5ffc2 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 23 Mar 2023 17:50:14 +0100 +Subject: [PATCH 121/125] mdadm: define DEV_MD_DIR + +It is used many times. Additionally define _LEN to avoid repeated +strlen() calls when length is needed. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Create.c | 7 +++---- + Detail.c | 9 ++++----- + Incremental.c | 4 ++-- + Monitor.c | 32 ++++++++++++++++++-------------- + config.c | 10 +++++----- + lib.c | 2 +- + mapfile.c | 12 ++++++------ + mdadm.h | 8 ++++++++ + mdopen.c | 6 +++--- + super-ddf.c | 2 +- + super-intel.c | 2 +- + super1.c | 3 +-- + sysfs.c | 2 +- + 13 files changed, 54 insertions(+), 45 deletions(-) + +diff --git a/Create.c b/Create.c +index aa0472dd..ea6a4745 100644 +--- a/Create.c ++++ b/Create.c +@@ -1024,10 +1024,9 @@ int Create(struct supertype *st, char *mddev, + * it could be in conflict with already existing device + * e.g. container, array + */ +- if (strncmp(chosen_name, "/dev/md/", 8) == 0 && +- map_by_name(&map, chosen_name+8) != NULL) { +- pr_err("Array name %s is in use already.\n", +- chosen_name); ++ if (strncmp(chosen_name, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 && ++ map_by_name(&map, chosen_name + DEV_MD_DIR_LEN)) { ++ pr_err("Array name %s is in use already.\n", chosen_name); + close(mdfd); + map_unlock(&map); + udev_unblock(); +diff --git a/Detail.c b/Detail.c +index 4ef26460..206d88e3 100644 +--- a/Detail.c ++++ b/Detail.c +@@ -254,10 +254,9 @@ int Detail(char *dev, struct context *c) + fname_from_uuid(st, info, nbuf, ':'); + printf("MD_UUID=%s\n", nbuf + 5); + mp = map_by_uuid(&map, info->uuid); +- if (mp && mp->path && +- strncmp(mp->path, "/dev/md/", 8) == 0) { ++ if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) { + printf("MD_DEVNAME="); +- print_escape(mp->path + 8); ++ print_escape(mp->path + DEV_MD_DIR_LEN); + putchar('\n'); + } + +@@ -273,9 +272,9 @@ int Detail(char *dev, struct context *c) + printf("MD_UUID=%s\n", nbuf+5); + } + if (mp && mp->path && +- strncmp(mp->path, "/dev/md/", 8) == 0) { ++ strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) { + printf("MD_DEVNAME="); +- print_escape(mp->path+8); ++ print_escape(mp->path + DEV_MD_DIR_LEN); + putchar('\n'); + } + map_free(map); +diff --git a/Incremental.c b/Incremental.c +index 49a71f72..59b850f1 100644 +--- a/Incremental.c ++++ b/Incremental.c +@@ -460,8 +460,8 @@ int Incremental(struct mddev_dev *devlist, struct context *c, + info.array.working_disks ++; + + } +- if (strncmp(chosen_name, "/dev/md/", 8) == 0) +- md_devname = chosen_name+8; ++ if (strncmp(chosen_name, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) ++ md_devname = chosen_name + DEV_MD_DIR_LEN; + else + md_devname = chosen_name; + if (c->export) { +diff --git a/Monitor.c b/Monitor.c +index 44918184..3273f2fb 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -36,9 +36,18 @@ + #define EVENT_NAME_MAX 32 + #define AUTOREBUILD_PID_PATH MDMON_DIR "/autorebuild.pid" + ++/** ++ * struct state - external array or container properties. ++ * @devname: has length of %DEV_MD_DIR + device name + terminating byte ++ * @devnm: to sync with mdstat info ++ * @parent_devnm: or subarray, devnm of parent, for others, "" ++ * @subarray: for a container it is a link to first subarray, for a subarray it is a link to next ++ * subarray in the same container ++ * @parent: for a subarray it is a link to its container ++ */ + struct state { +- 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 */ ++ char devname[MD_NAME_MAX + sizeof(DEV_MD_DIR)]; ++ char devnm[MD_NAME_MAX]; + unsigned int utime; + int err; + char *spare_group; +@@ -49,15 +58,10 @@ struct state { + int devstate[MAX_DISKS]; + dev_t devid[MAX_DISKS]; + int percent; +- char parent_devnm[MD_NAME_MAX]; /* For subarray, devnm of parent. +- * For others, "" +- */ ++ char parent_devnm[MD_NAME_MAX]; + 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 +- * in the same container */ +- struct state *parent; /* for a subarray it is a link to its container +- */ ++ struct state *subarray; ++ struct state *parent; + struct state *next; + }; + +@@ -252,8 +256,8 @@ int Monitor(struct mddev_dev *devlist, + continue; + + st = xcalloc(1, sizeof *st); +- snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), +- "/dev/md/%s", basename(mdlist->devname)); ++ snprintf(st->devname, MD_NAME_MAX + sizeof(DEV_MD_DIR), DEV_MD_DIR "%s", ++ basename(mdlist->devname)); + st->next = statelist; + st->devnm[0] = 0; + st->percent = RESYNC_UNKNOWN; +@@ -274,7 +278,7 @@ int Monitor(struct mddev_dev *devlist, + + st = xcalloc(1, sizeof *st); + mdlist = conf_get_ident(dv->devname); +- snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", dv->devname); ++ snprintf(st->devname, MD_NAME_MAX + sizeof(DEV_MD_DIR), "%s", dv->devname); + st->next = statelist; + st->devnm[0] = 0; + st->percent = RESYNC_UNKNOWN; +@@ -942,7 +946,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist) + continue; + } + +- snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", name); ++ snprintf(st->devname, MD_NAME_MAX + sizeof(DEV_MD_DIR), "%s", name); + if ((fd = open(st->devname, O_RDONLY)) < 0 || + md_get_array_info(fd, &array) < 0) { + /* no such array */ +diff --git a/config.c b/config.c +index eeedd0c6..59d5bfb6 100644 +--- a/config.c ++++ b/config.c +@@ -405,7 +405,7 @@ void arrayline(char *line) + * or anything that doesn't start '/' or '<' + */ + if (strcasecmp(w, "") == 0 || +- strncmp(w, "/dev/md/", 8) == 0 || ++ strncmp(w, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 || + (w[0] != '/' && w[0] != '<') || + (strncmp(w, "/dev/md", 7) == 0 && + is_number(w + 7)) || +@@ -1102,13 +1102,13 @@ int devname_matches(char *name, char *match) + * mdNN with NN + * then just strcmp + */ +- if (strncmp(name, "/dev/md/", 8) == 0) +- name += 8; ++ if (strncmp(name, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) ++ name += DEV_MD_DIR_LEN; + else if (strncmp(name, "/dev/", 5) == 0) + name += 5; + +- if (strncmp(match, "/dev/md/", 8) == 0) +- match += 8; ++ if (strncmp(match, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) ++ match += DEV_MD_DIR_LEN; + else if (strncmp(match, "/dev/", 5) == 0) + match += 5; + +diff --git a/lib.c b/lib.c +index e395b28d..65ea51e0 100644 +--- a/lib.c ++++ b/lib.c +@@ -313,7 +313,7 @@ char *map_dev_preferred(int major, int minor, int create, + + for (p = devlist; p; p = p->next) + if (p->major == major && p->minor == minor) { +- if (strncmp(p->name, "/dev/md/",8) == 0 || ++ if (strncmp(p->name, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 || + (prefer && strstr(p->name, prefer))) { + if (preferred == NULL || + strlen(p->name) < strlen(preferred)) +diff --git a/mapfile.c b/mapfile.c +index ac351768..34fea179 100644 +--- a/mapfile.c ++++ b/mapfile.c +@@ -320,9 +320,9 @@ struct map_ent *map_by_name(struct map_ent **map, char *name) + for (mp = *map ; mp ; mp = mp->next) { + if (!mp->path) + continue; +- if (strncmp(mp->path, "/dev/md/", 8) != 0) ++ if (strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) != 0) + continue; +- if (strcmp(mp->path+8, name) != 0) ++ if (strcmp(mp->path + DEV_MD_DIR_LEN, name) != 0) + continue; + if (!mddev_busy(mp->devnm)) { + mp->bad = 1; +@@ -413,7 +413,7 @@ void RebuildMap(void) + devid = devnm2devid(md->devnm); + path = map_dev(major(devid), minor(devid), 0); + if (path == NULL || +- strncmp(path, "/dev/md/", 8) != 0) { ++ strncmp(path, DEV_MD_DIR, DEV_MD_DIR_LEN) != 0) { + /* We would really like a name that provides + * an MD_DEVNAME for udev. + * The name needs to be unique both in /dev/md/ +@@ -434,7 +434,7 @@ void RebuildMap(void) + if (match && match->devname && match->devname[0] == '/') { + path = match->devname; + if (path[0] != '/') { +- strcpy(namebuf, "/dev/md/"); ++ strcpy(namebuf, DEV_MD_DIR); + strcat(namebuf, path); + path = namebuf; + } +@@ -478,10 +478,10 @@ void RebuildMap(void) + + while (conflict) { + if (unum >= 0) +- sprintf(namebuf, "/dev/md/%s%s%d", ++ sprintf(namebuf, DEV_MD_DIR "%s%s%d", + name, sep, unum); + else +- sprintf(namebuf, "/dev/md/%s", ++ sprintf(namebuf, DEV_MD_DIR "%s", + name); + unum++; + if (lstat(namebuf, &stb) != 0 && +diff --git a/mdadm.h b/mdadm.h +index 0d995445..67d73f96 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -100,6 +100,14 @@ struct dlm_lksb { + #define DEFAULT_BITMAP_DELAY 5 + #define DEFAULT_MAX_WRITE_BEHIND 256 + ++/* DEV_MD_DIR points to named MD devices directory. ++ * DEV_MD_DIR_LEN is a length with Null byte excluded. ++ */ ++#ifndef DEV_MD_DIR ++#define DEV_MD_DIR "/dev/md/" ++#define DEV_MD_DIR_LEN (sizeof(DEV_MD_DIR) - 1) ++#endif /* DEV_MD_DIR */ ++ + /* MAP_DIR should be somewhere that persists across the pivotroot + * from early boot to late boot. + * /run seems to have emerged as the best standard. +diff --git a/mdopen.c b/mdopen.c +index 810f79a3..6c3bdb6a 100644 +--- a/mdopen.c ++++ b/mdopen.c +@@ -188,12 +188,12 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, + parts = autof >> 3; + autof &= 7; + +- strcpy(chosen, "/dev/md/"); ++ strcpy(chosen, DEV_MD_DIR); + cname = chosen + strlen(chosen); + + if (dev) { +- if (strncmp(dev, "/dev/md/", 8) == 0) { +- strcpy(cname, dev+8); ++ if (strncmp(dev, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) { ++ strcpy(cname, dev + DEV_MD_DIR_LEN); + } else if (strncmp(dev, "/dev/", 5) == 0) { + char *e = dev + strlen(dev); + while (e > dev && isdigit(e[-1])) +diff --git a/super-ddf.c b/super-ddf.c +index b86c6acd..7213284e 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -1648,7 +1648,7 @@ static void brief_examine_subarrays_ddf(struct supertype *st, int verbose) + fname_from_uuid(st, &info, nbuf1, ':'); + _ddf_array_name(namebuf, ddf, i); + printf("ARRAY%s%s container=%s member=%d UUID=%s\n", +- namebuf[0] == '\0' ? "" : " /dev/md/", namebuf, ++ namebuf[0] == '\0' ? "" : " " DEV_MD_DIR, namebuf, + nbuf+5, i, nbuf1+5); + } + } +diff --git a/super-intel.c b/super-intel.c +index a5c86cb2..aaf6659e 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -2309,7 +2309,7 @@ static void brief_examine_subarrays_imsm(struct supertype *st, int verbose) + super->current_vol = i; + getinfo_super_imsm(st, &info, NULL); + fname_from_uuid(st, &info, nbuf1, ':'); +- printf("ARRAY /dev/md/%.16s container=%s member=%d UUID=%s\n", ++ printf("ARRAY " DEV_MD_DIR "%.16s container=%s member=%d UUID=%s\n", + dev->volume, nbuf + 5, i, nbuf1 + 5); + } + } +diff --git a/super1.c b/super1.c +index 938c3a68..856b0208 100644 +--- a/super1.c ++++ b/super1.c +@@ -645,8 +645,7 @@ static void brief_examine_super1(struct supertype *st, int verbose) + + printf("ARRAY "); + if (nm) { +- printf("/dev/md/"); +- print_escape(nm); ++ printf(DEV_MD_DIR "%s", nm); + putchar(' '); + } + if (verbose && c) +diff --git a/sysfs.c b/sysfs.c +index ca1d888f..94d02f53 100644 +--- a/sysfs.c ++++ b/sysfs.c +@@ -1114,7 +1114,7 @@ void sysfsline(char *line) + if (strncasecmp(w, "name=", 5) == 0) { + char *devname = w + 5; + +- if (strncmp(devname, "/dev/md/", 8) == 0) { ++ if (strncmp(devname, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) { + if (sr->devname) + pr_err("Only give one device per SYSFS line: %s\n", + devname); +-- +2.38.1 + diff --git a/SOURCES/0122-mdadm-define-DEV_NUM_PREF.patch b/SOURCES/0122-mdadm-define-DEV_NUM_PREF.patch new file mode 100644 index 0000000..645aa62 --- /dev/null +++ b/SOURCES/0122-mdadm-define-DEV_NUM_PREF.patch @@ -0,0 +1,73 @@ +From 0f8347d4f6588ee6ded55af3e307418cee286a6f Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 23 Mar 2023 17:50:15 +0100 +Subject: [PATCH 122/125] mdadm: define DEV_NUM_PREF + +Use define instead of inlines. Add _LEN define. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + config.c | 4 ++-- + mdadm.h | 8 ++++++++ + mdopen.c | 10 +++++----- + 3 files changed, 15 insertions(+), 7 deletions(-) + +diff --git a/config.c b/config.c +index 59d5bfb6..f44cc1d3 100644 +--- a/config.c ++++ b/config.c +@@ -407,8 +407,8 @@ void arrayline(char *line) + if (strcasecmp(w, "") == 0 || + strncmp(w, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 || + (w[0] != '/' && w[0] != '<') || +- (strncmp(w, "/dev/md", 7) == 0 && +- is_number(w + 7)) || ++ (strncmp(w, DEV_NUM_PREF, DEV_NUM_PREF_LEN) == 0 && ++ is_number(w + DEV_NUM_PREF_LEN)) || + (strncmp(w, "/dev/md_d", 9) == 0 && + is_number(w + 9))) { + /* This is acceptable */; +diff --git a/mdadm.h b/mdadm.h +index 67d73f96..f2e70baa 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -100,6 +100,14 @@ struct dlm_lksb { + #define DEFAULT_BITMAP_DELAY 5 + #define DEFAULT_MAX_WRITE_BEHIND 256 + ++/* DEV_NUM_PREF is a subpath to numbered MD devices, e.g. /dev/md1 or directory name. ++ * DEV_NUM_PREF_LEN is a length with Null byte excluded. ++ */ ++#ifndef DEV_NUM_PREF ++#define DEV_NUM_PREF "/dev/md" ++#define DEV_NUM_PREF_LEN (sizeof(DEV_NUM_PREF) - 1) ++#endif /* DEV_NUM_PREF */ ++ + /* DEV_MD_DIR points to named MD devices directory. + * DEV_MD_DIR_LEN is a length with Null byte excluded. + */ +diff --git a/mdopen.c b/mdopen.c +index 6c3bdb6a..d3022a54 100644 +--- a/mdopen.c ++++ b/mdopen.c +@@ -412,11 +412,11 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, + make_parts(devname, parts); + + if (strcmp(chosen, devname) != 0) { +- if (mkdir("/dev/md",0700) == 0) { +- if (chown("/dev/md", ci->uid, ci->gid)) +- perror("chown /dev/md"); +- if (chmod("/dev/md", ci->mode| ((ci->mode>>2) & 0111))) +- perror("chmod /dev/md"); ++ if (mkdir(DEV_NUM_PREF, 0700) == 0) { ++ if (chown(DEV_NUM_PREF, ci->uid, ci->gid)) ++ perror("chown " DEV_NUM_PREF); ++ if (chmod(DEV_NUM_PREF, ci->mode | ((ci->mode >> 2) & 0111))) ++ perror("chmod " DEV_NUM_PREF); + } + + if (dev && strcmp(chosen, dev) == 0) +-- +2.38.1 + diff --git a/SOURCES/0123-mdadm-define-is_devname_ignore.patch b/SOURCES/0123-mdadm-define-is_devname_ignore.patch new file mode 100644 index 0000000..3526be2 --- /dev/null +++ b/SOURCES/0123-mdadm-define-is_devname_ignore.patch @@ -0,0 +1,133 @@ +From 7b3b691ba69b909ea8c172aae693fa2a6938fd14 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 23 Mar 2023 17:50:16 +0100 +Subject: [PATCH 123/125] mdadm: define is_devname_ignore() + +Use function instead of direct checks across code. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Incremental.c | 6 ++---- + Monitor.c | 2 +- + config.c | 16 ++++++++++++++-- + mdadm.c | 5 ++--- + mdadm.h | 1 + + 5 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/Incremental.c b/Incremental.c +index 59b850f1..f13ce027 100644 +--- a/Incremental.c ++++ b/Incremental.c +@@ -202,8 +202,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c, + if (!match && rv == 2) + goto out; + +- if (match && match->devname && +- strcasecmp(match->devname, "") == 0) { ++ if (match && match->devname && is_devname_ignore(match->devname) == true) { + if (c->verbose >= 0) + pr_err("array containing %s is explicitly ignored by mdadm.conf\n", + devname); +@@ -1567,8 +1566,7 @@ static int Incremental_container(struct supertype *st, char *devname, + break; + } + +- if (match && match->devname && +- strcasecmp(match->devname, "") == 0) { ++ if (match && match->devname && is_devname_ignore(match->devname) == true) { + if (c->verbose > 0) + pr_err("array %s/%s is explicitly ignored by mdadm.conf\n", + match->container, match->member); +diff --git a/Monitor.c b/Monitor.c +index 3273f2fb..66175968 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -250,7 +250,7 @@ int Monitor(struct mddev_dev *devlist, + + if (mdlist->devname == NULL) + continue; +- if (strcasecmp(mdlist->devname, "") == 0) ++ if (is_devname_ignore(mdlist->devname) == true) + continue; + if (!is_mddev(mdlist->devname)) + continue; +diff --git a/config.c b/config.c +index f44cc1d3..e61c0496 100644 +--- a/config.c ++++ b/config.c +@@ -119,6 +119,18 @@ int match_keyword(char *word) + return -1; + } + ++/** ++ * is_devname_ignore() - check if &devname is a special "" keyword. ++ */ ++bool is_devname_ignore(char *devname) ++{ ++ static const char keyword[] = ""; ++ ++ if (strcasecmp(devname, keyword) == 0) ++ return true; ++ return false; ++} ++ + /** + * ident_init() - Set defaults. + * @ident: ident pointer, not NULL. +@@ -404,7 +416,7 @@ void arrayline(char *line) + * + * or anything that doesn't start '/' or '<' + */ +- if (strcasecmp(w, "") == 0 || ++ if (is_devname_ignore(w) == true || + strncmp(w, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 || + (w[0] != '/' && w[0] != '<') || + (strncmp(w, DEV_NUM_PREF, DEV_NUM_PREF_LEN) == 0 && +@@ -571,7 +583,7 @@ void homehostline(char *line) + char *w; + + for (w = dl_next(line); w != line; w = dl_next(w)) { +- if (strcasecmp(w, "") == 0) ++ if (is_devname_ignore(w) == true) + require_homehost = 0; + else if (home_host == NULL) { + if (strcasecmp(w, "") == 0) +diff --git a/mdadm.c b/mdadm.c +index 2296911d..076b45e0 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -154,7 +154,7 @@ int main(int argc, char *argv[]) + continue; + + case HomeHost: +- if (strcasecmp(optarg, "") == 0) ++ if (is_devname_ignore(optarg) == true) + c.require_homehost = 0; + else + c.homehost = optarg; +@@ -1749,8 +1749,7 @@ static int scan_assemble(struct supertype *ss, + int r; + if (a->assembled) + continue; +- if (a->devname && +- strcasecmp(a->devname, "") == 0) ++ if (a->devname && is_devname_ignore(a->devname) == true) + continue; + + r = Assemble(ss, a->devname, +diff --git a/mdadm.h b/mdadm.h +index f2e70baa..0932c2d3 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1650,6 +1650,7 @@ extern void print_escape(char *str); + extern int use_udev(void); + extern unsigned long GCD(unsigned long a, unsigned long b); + extern int conf_name_is_free(char *name); ++extern bool is_devname_ignore(char *devname); + extern int conf_verify_devnames(struct mddev_ident *array_list); + extern int devname_matches(char *name, char *match); + extern struct mddev_ident *conf_match(struct supertype *st, +-- +2.38.1 + diff --git a/SOURCES/0124-mdadm-numbered-names-verification.patch b/SOURCES/0124-mdadm-numbered-names-verification.patch new file mode 100644 index 0000000..a3e94f0 --- /dev/null +++ b/SOURCES/0124-mdadm-numbered-names-verification.patch @@ -0,0 +1,145 @@ +From 25aa7329141c0b28d8811671627f0f5c5dc22273 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 23 Mar 2023 17:50:17 +0100 +Subject: [PATCH 124/125] mdadm: numbered names verification + +New functions added to remove literals and make the code reusable. +Use parse_num() instead of is_numer(). + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + config.c | 17 ++--------------- + lib.c | 2 +- + mdadm.h | 4 +++- + util.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 50 insertions(+), 17 deletions(-) + +diff --git a/config.c b/config.c +index e61c0496..450880e3 100644 +--- a/config.c ++++ b/config.c +@@ -385,17 +385,6 @@ void devline(char *line) + struct mddev_ident *mddevlist = NULL; + struct mddev_ident **mddevlp = &mddevlist; + +-static int is_number(char *w) +-{ +- /* check if there are 1 or more digits and nothing else */ +- int digits = 0; +- while (*w && isdigit(*w)) { +- digits++; +- w++; +- } +- return (digits && ! *w); +-} +- + void arrayline(char *line) + { + char *w; +@@ -419,10 +408,8 @@ void arrayline(char *line) + if (is_devname_ignore(w) == true || + strncmp(w, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 || + (w[0] != '/' && w[0] != '<') || +- (strncmp(w, DEV_NUM_PREF, DEV_NUM_PREF_LEN) == 0 && +- is_number(w + DEV_NUM_PREF_LEN)) || +- (strncmp(w, "/dev/md_d", 9) == 0 && +- is_number(w + 9))) { ++ is_devname_md_numbered(w) == true || ++ is_devname_md_d_numbered(w) == true) { + /* This is acceptable */; + if (mis.devname) + pr_err("only give one device per ARRAY line: %s and %s\n", +diff --git a/lib.c b/lib.c +index 65ea51e0..fe5c8d2c 100644 +--- a/lib.c ++++ b/lib.c +@@ -570,7 +570,7 @@ void free_line(char *line) + * + * Return: 0 on success, 1 otherwise. + */ +-int parse_num(int *dest, char *num) ++int parse_num(int *dest, const char *num) + { + char *c = NULL; + long temp; +diff --git a/mdadm.h b/mdadm.h +index 0932c2d3..83f2cf7f 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1601,7 +1601,7 @@ int default_layout(struct supertype *st, int level, int verbose); + extern int is_near_layout_10(int layout); + extern int parse_layout_10(char *layout); + extern int parse_layout_faulty(char *layout); +-extern int parse_num(int *dest, char *num); ++extern int parse_num(int *dest, const char *num); + extern int parse_cluster_confirm_arg(char *inp, char **devname, int *slot); + extern int check_ext2(int fd, char *name); + extern int check_reiser(int fd, char *name); +@@ -1651,6 +1651,8 @@ extern int use_udev(void); + extern unsigned long GCD(unsigned long a, unsigned long b); + extern int conf_name_is_free(char *name); + extern bool is_devname_ignore(char *devname); ++extern bool is_devname_md_numbered(const char *devname); ++extern bool is_devname_md_d_numbered(const char *devname); + extern int conf_verify_devnames(struct mddev_ident *array_list); + extern int devname_matches(char *name, char *match); + extern struct mddev_ident *conf_match(struct supertype *st, +diff --git a/util.c b/util.c +index d70ca43b..fa378eba 100644 +--- a/util.c ++++ b/util.c +@@ -973,6 +973,50 @@ dev_t devnm2devid(char *devnm) + return 0; + } + ++/** ++ * is_devname_numbered() - helper for numbered devname verification. ++ * @devname: path or name to check. ++ * @pref: expected devname prefix. ++ * @pref_len: prefix len. ++ */ ++static bool is_devname_numbered(const char *devname, const char *pref, const int pref_len) ++{ ++ int val; ++ ++ assert(devname && pref); ++ ++ if (strncmp(devname, pref, pref_len) != 0) ++ return false; ++ ++ if (parse_num(&val, devname + pref_len) != 0) ++ return false; ++ ++ if (val > 127) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * is_devname_md_numbered() - check if &devname is numbered MD device (md). ++ * @devname: path or name to check. ++ */ ++bool is_devname_md_numbered(const char *devname) ++{ ++ return is_devname_numbered(devname, DEV_NUM_PREF, DEV_NUM_PREF_LEN); ++} ++ ++/** ++ * is_devname_md_d_numbered() - check if &devname is secondary numbered MD device (md_d). ++ * @devname: path or name to check. ++ */ ++bool is_devname_md_d_numbered(const char *devname) ++{ ++ static const char d_dev[] = DEV_NUM_PREF "_d"; ++ ++ return is_devname_numbered(devname, d_dev, sizeof(d_dev) - 1); ++} ++ + /** + * get_md_name() - Get main dev node of the md device. + * @devnm: Md device name or path. +-- +2.38.1 + diff --git a/SOURCES/0125-enable-RAID-for-SATA-under-VMD.patch b/SOURCES/0125-enable-RAID-for-SATA-under-VMD.patch new file mode 100644 index 0000000..4866fe3 --- /dev/null +++ b/SOURCES/0125-enable-RAID-for-SATA-under-VMD.patch @@ -0,0 +1,187 @@ +From 75350d87c86001c47076e1f62478079bdc072223 Mon Sep 17 00:00:00 2001 +From: Kevin Friedberg +Date: Wed, 15 Feb 2023 23:41:34 -0500 +Subject: [PATCH 125/125] enable RAID for SATA under VMD + +Detect when a SATA controller has been mapped under Intel Alderlake RST +VMD, so that it can use the VMD controller's RAID capabilities. Create +new device type SYS_DEV_SATA_VMD and list separate controller to prevent +mixing with the NVMe SYS_DEV_VMD devices on the same VMD domain. + +Signed-off-by: Kevin Friedberg +Signed-off-by: Jes Sorensen +--- + platform-intel.c | 21 ++++++++++++++++++--- + platform-intel.h | 1 + + super-intel.c | 28 ++++++++++++++++++---------- + 3 files changed, 37 insertions(+), 13 deletions(-) + +diff --git a/platform-intel.c b/platform-intel.c +index 757f0b1b..914164c0 100644 +--- a/platform-intel.c ++++ b/platform-intel.c +@@ -64,9 +64,10 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) + + if (strcmp(driver, "isci") == 0) + type = SYS_DEV_SAS; +- else if (strcmp(driver, "ahci") == 0) ++ else if (strcmp(driver, "ahci") == 0) { ++ vmd = find_driver_devices("pci", "vmd"); + type = SYS_DEV_SATA; +- else if (strcmp(driver, "nvme") == 0) { ++ } else if (strcmp(driver, "nvme") == 0) { + /* if looking for nvme devs, first look for vmd */ + vmd = find_driver_devices("pci", "vmd"); + type = SYS_DEV_NVME; +@@ -115,6 +116,17 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) + free(rp); + } + ++ /* change sata type if under a vmd controller */ ++ if (type == SYS_DEV_SATA) { ++ struct sys_dev *dev; ++ char *rp = realpath(path, NULL); ++ for (dev = vmd; dev; dev = dev->next) { ++ if ((strncmp(dev->path, rp, strlen(dev->path)) == 0)) ++ type = SYS_DEV_SATA_VMD; ++ } ++ free(rp); ++ } ++ + /* if it's not Intel device or mark as VMD connected - skip it. */ + if (devpath_to_vendor(path) != 0x8086 || skip == 1) + continue; +@@ -166,7 +178,8 @@ struct sys_dev *find_driver_devices(const char *bus, const char *driver) + } + closedir(driver_dir); + +- if (vmd) { ++ /* nvme vmd needs a list separate from sata vmd */ ++ if (vmd && type == SYS_DEV_NVME) { + if (list) + list->next = vmd; + else +@@ -273,6 +286,7 @@ struct sys_dev *find_intel_devices(void) + free_sys_dev(&intel_devices); + + isci = find_driver_devices("pci", "isci"); ++ /* Searching for AHCI will return list of SATA and SATA VMD controllers */ + ahci = find_driver_devices("pci", "ahci"); + /* Searching for NVMe will return list of NVMe and VMD controllers */ + nvme = find_driver_devices("pci", "nvme"); +@@ -638,6 +652,7 @@ const struct imsm_orom *find_imsm_efi(struct sys_dev *hba) + + break; + case SYS_DEV_VMD: ++ case SYS_DEV_SATA_VMD: + for (i = 0; i < ARRAY_SIZE(vmd_efivars); i++) { + if (!read_efi_variable(&orom, sizeof(orom), + vmd_efivars[i], VENDOR_GUID)) +diff --git a/platform-intel.h b/platform-intel.h +index 6238d23f..2c0f4e39 100644 +--- a/platform-intel.h ++++ b/platform-intel.h +@@ -196,6 +196,7 @@ enum sys_dev_type { + SYS_DEV_SATA, + SYS_DEV_NVME, + SYS_DEV_VMD, ++ SYS_DEV_SATA_VMD, + SYS_DEV_MAX + }; + +diff --git a/super-intel.c b/super-intel.c +index aaf6659e..ae0f4a8c 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -627,7 +627,8 @@ static const char *_sys_dev_type[] = { + [SYS_DEV_SAS] = "SAS", + [SYS_DEV_SATA] = "SATA", + [SYS_DEV_NVME] = "NVMe", +- [SYS_DEV_VMD] = "VMD" ++ [SYS_DEV_VMD] = "VMD", ++ [SYS_DEV_SATA_VMD] = "SATA VMD" + }; + + static int no_platform = -1; +@@ -2598,6 +2599,8 @@ static void print_found_intel_controllers(struct sys_dev *elem) + + if (elem->type == SYS_DEV_VMD) + fprintf(stderr, "VMD domain"); ++ else if (elem->type == SYS_DEV_SATA_VMD) ++ fprintf(stderr, "SATA VMD domain"); + else + fprintf(stderr, "RAID controller"); + +@@ -2768,8 +2771,9 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle + if (!find_imsm_capability(hba)) { + char buf[PATH_MAX]; + pr_err("imsm capabilities not found for controller: %s (type %s)\n", +- hba->type == SYS_DEV_VMD ? vmd_domain_to_controller(hba, buf) : hba->path, +- get_sys_dev_type(hba->type)); ++ hba->type == SYS_DEV_VMD || hba->type == SYS_DEV_SATA_VMD ? ++ vmd_domain_to_controller(hba, buf) : ++ hba->path, get_sys_dev_type(hba->type)); + continue; + } + result = 0; +@@ -2822,11 +2826,12 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle + + printf(" I/O Controller : %s (%s)\n", + hba->path, get_sys_dev_type(hba->type)); +- if (hba->type == SYS_DEV_SATA) { ++ if (hba->type == SYS_DEV_SATA || hba->type == SYS_DEV_SATA_VMD) { + host_base = ahci_get_port_count(hba->path, &port_count); + if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) { + if (verbose > 0) +- pr_err("failed to enumerate ports on SATA controller at %s.\n", hba->pci_id); ++ pr_err("failed to enumerate ports on %s controller at %s.\n", ++ get_sys_dev_type(hba->type), hba->pci_id); + result |= 2; + } + } +@@ -2856,7 +2861,8 @@ static int export_detail_platform_imsm(int verbose, char *controller_path) + if (!find_imsm_capability(hba) && verbose > 0) { + char buf[PATH_MAX]; + pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n", +- hba->type == SYS_DEV_VMD ? vmd_domain_to_controller(hba, buf) : hba->path); ++ hba->type == SYS_DEV_VMD || hba->type == SYS_DEV_SATA_VMD ? ++ vmd_domain_to_controller(hba, buf) : hba->path); + } + else + result = 0; +@@ -2865,7 +2871,7 @@ static int export_detail_platform_imsm(int verbose, char *controller_path) + const struct orom_entry *entry; + + for (entry = orom_entries; entry; entry = entry->next) { +- if (entry->type == SYS_DEV_VMD) { ++ if (entry->type == SYS_DEV_VMD || entry->type == SYS_DEV_SATA_VMD) { + for (hba = list; hba; hba = hba->next) + print_imsm_capability_export(&entry->orom); + continue; +@@ -4782,10 +4788,12 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de + " but the container is assigned to Intel(R) %s %s (", + devname, + get_sys_dev_type(hba_name->type), +- hba_name->type == SYS_DEV_VMD ? "domain" : "RAID controller", ++ hba_name->type == SYS_DEV_VMD || hba_name->type == SYS_DEV_SATA_VMD ? ++ "domain" : "RAID controller", + hba_name->pci_id ? : "Err!", + get_sys_dev_type(super->hba->type), +- hba->type == SYS_DEV_VMD ? "domain" : "RAID controller"); ++ hba->type == SYS_DEV_VMD || hba_name->type == SYS_DEV_SATA_VMD ? ++ "domain" : "RAID controller"); + + while (hba) { + fprintf(stderr, "%s", hba->pci_id ? : "Err!"); +@@ -11274,7 +11282,7 @@ static const char *imsm_get_disk_controller_domain(const char *path) + hba = find_disk_attached_hba(-1, path); + if (hba && hba->type == SYS_DEV_SAS) + drv = "isci"; +- else if (hba && hba->type == SYS_DEV_SATA) ++ else if (hba && (hba->type == SYS_DEV_SATA || hba->type == SYS_DEV_SATA_VMD)) + drv = "ahci"; + else if (hba && hba->type == SYS_DEV_VMD) + drv = "vmd"; +-- +2.38.1 + diff --git a/SOURCES/0126-imsm-Fix-possible-segfault-in-check_no_platform.patch b/SOURCES/0126-imsm-Fix-possible-segfault-in-check_no_platform.patch new file mode 100644 index 0000000..1719f33 --- /dev/null +++ b/SOURCES/0126-imsm-Fix-possible-segfault-in-check_no_platform.patch @@ -0,0 +1,33 @@ +From cf1577bf54afe76b77ecaa62df25901739ca8ae9 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Wed, 5 Jul 2023 16:34:56 +0200 +Subject: [PATCH 126/165] imsm: Fix possible segfault in check_no_platform() + +conf_line() may return NULL, which is not handled and might cause +segfault. + +Signed-off-by: Mateusz Grzonka +Signed-off-by: Jes Sorensen +--- + super-intel.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/super-intel.c b/super-intel.c +index ae0f4a8c..4ef33d31 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -650,6 +650,11 @@ static int check_no_platform(void) + char *l = conf_line(fp); + char *w = l; + ++ if (l == NULL) { ++ fclose(fp); ++ return 0; ++ } ++ + do { + if (strcmp(w, search) == 0) + no_platform = 1; +-- +2.40.1 + diff --git a/SOURCES/0127-imsm-move-sum_extents-calculations-to-merge_extents.patch b/SOURCES/0127-imsm-move-sum_extents-calculations-to-merge_extents.patch new file mode 100644 index 0000000..c5bc8fc --- /dev/null +++ b/SOURCES/0127-imsm-move-sum_extents-calculations-to-merge_extents.patch @@ -0,0 +1,105 @@ +From 9bc426fa1f236b8cad518431574a54fc60718739 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Mon, 29 May 2023 15:52:33 +0200 +Subject: [PATCH 127/165] imsm: move sum_extents calculations to + merge_extents() + +This logic is only used by merge_extents() code, there is no need to pass +it as parameter. Move it up. Add proper description. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-intel.c | 37 +++++++++++++++++++------------------ + 1 file changed, 19 insertions(+), 18 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index 4ef33d31..26b20313 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -6882,21 +6882,31 @@ static unsigned long long find_size(struct extent *e, int *idx, int num_extents) + return end - base_start; + } + +-static unsigned long long merge_extents(struct intel_super *super, int sum_extents) ++/** merge_extents() - analyze extents and get max common free size. ++ * @super: Intel metadata, not NULL. ++ * ++ * Build a composite disk with all known extents and generate a new maxsize ++ * given the "all disks in an array must share a common start offset" ++ * constraint. ++ * ++ * Return: Max free space or 0 on failure. ++ */ ++static unsigned long long merge_extents(struct intel_super *super) + { +- /* build a composite disk with all known extents and generate a new +- * 'maxsize' given the "all disks in an array must share a common start +- * offset" constraint +- */ +- struct extent *e = xcalloc(sum_extents, sizeof(*e)); ++ struct extent *e; + struct dl *dl; + int i, j; +- int start_extent; ++ int start_extent, sum_extents = 0; + unsigned long long pos; + unsigned long long start = 0; + unsigned long long maxsize; + unsigned long reserve; + ++ for (dl = super->disks; dl; dl = dl->next) ++ if (dl->e) ++ sum_extents += dl->extent_cnt; ++ e = xcalloc(sum_extents, sizeof(struct extent)); ++ + /* coalesce and sort all extents. also, check to see if we need to + * reserve space between member arrays + */ +@@ -7555,13 +7565,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, + return 0; + } + +- /* count total number of extents for merge */ +- i = 0; +- for (dl = super->disks; dl; dl = dl->next) +- if (dl->e) +- i += dl->extent_cnt; +- +- maxsize = merge_extents(super, i); ++ maxsize = merge_extents(super); + + if (mpb->num_raid_devs > 0 && size && size != maxsize) + pr_err("attempting to create a second volume with size less then remaining space.\n"); +@@ -7615,7 +7619,6 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, + struct imsm_super *mpb = super->anchor; + struct dl *dl; + int i; +- int extent_cnt; + struct extent *e; + unsigned long long maxsize; + unsigned long long minsize; +@@ -7624,7 +7627,6 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, + + /* find the largest common start free region of the possible disks */ + used = 0; +- extent_cnt = 0; + cnt = 0; + for (dl = super->disks; dl; dl = dl->next) { + dl->raiddisk = -1; +@@ -7645,11 +7647,10 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, + ; + dl->e = e; + dl->extent_cnt = i; +- extent_cnt += i; + cnt++; + } + +- maxsize = merge_extents(super, extent_cnt); ++ maxsize = merge_extents(super); + minsize = size; + if (size == 0) + /* chunk is in K */ +-- +2.40.1 + diff --git a/SOURCES/0128-imsm-imsm_get_free_size-refactor.patch b/SOURCES/0128-imsm-imsm_get_free_size-refactor.patch new file mode 100644 index 0000000..ed43855 --- /dev/null +++ b/SOURCES/0128-imsm-imsm_get_free_size-refactor.patch @@ -0,0 +1,72 @@ +From 5f027b9357c011ca0421400e258a777d97f18d17 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Mon, 29 May 2023 15:52:34 +0200 +Subject: [PATCH 128/165] imsm: imsm_get_free_size() refactor. + +Move minsize calculations up. Add error message if free size is too small. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-intel.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index 26b20313..16a30ba7 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -7600,7 +7600,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, + * @super: &intel_super pointer, not NULL. + * @raiddisks: number of raid disks. + * @size: requested size, could be 0 (means max size). +- * @chunk: requested chunk. ++ * @chunk: requested chunk size in KiB. + * @freesize: pointer for returned size value. + * + * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR. +@@ -7620,14 +7620,15 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, + struct dl *dl; + int i; + struct extent *e; ++ int cnt = 0; ++ int used = 0; + unsigned long long maxsize; +- unsigned long long minsize; +- int cnt; +- int used; ++ unsigned long long minsize = size; ++ ++ if (minsize == 0) ++ minsize = chunk * 2; + + /* find the largest common start free region of the possible disks */ +- used = 0; +- cnt = 0; + for (dl = super->disks; dl; dl = dl->next) { + dl->raiddisk = -1; + +@@ -7651,14 +7652,14 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, + } + + maxsize = merge_extents(super); +- minsize = size; +- if (size == 0) +- /* chunk is in K */ +- minsize = chunk * 2; ++ if (maxsize < minsize) { ++ pr_err("imsm: Free space is %llu but must be equal or larger than %llu.\n", ++ maxsize, minsize); ++ return IMSM_STATUS_ERROR; ++ } + +- if (cnt < raiddisks || (super->orom && used && used != raiddisks) || +- maxsize < minsize || maxsize == 0) { +- pr_err("not enough devices with space to create array.\n"); ++ if (cnt < raiddisks || (super->orom && used && used != raiddisks)) { ++ pr_err("imsm: Not enough devices with space to create array.\n"); + return IMSM_STATUS_ERROR; + } + +-- +2.40.1 + diff --git a/SOURCES/0129-imsm-introduce-round_member_size_to_mb.patch b/SOURCES/0129-imsm-introduce-round_member_size_to_mb.patch new file mode 100644 index 0000000..50d1d36 --- /dev/null +++ b/SOURCES/0129-imsm-introduce-round_member_size_to_mb.patch @@ -0,0 +1,68 @@ +From 78c8028b331c8e281554d43fde4d46e9cb4a227e Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Mon, 29 May 2023 15:52:35 +0200 +Subject: [PATCH 129/165] imsm: introduce round_member_size_to_mb() + +Extract rounding logic to separate function. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-intel.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index 16a30ba7..36171107 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -1644,17 +1644,29 @@ static int is_journal(struct imsm_disk *disk) + return (disk->status & JOURNAL_DISK) == JOURNAL_DISK; + } + +-/* round array size down to closest MB and ensure it splits evenly +- * between members ++/** ++ * round_member_size_to_mb()- Round given size to closest MiB. ++ * @size: size to round in sectors. + */ +-static unsigned long long round_size_to_mb(unsigned long long size, unsigned int +- disk_count) ++static inline unsigned long long round_member_size_to_mb(unsigned long long size) + { +- size /= disk_count; +- size = (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT; +- size *= disk_count; ++ return (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT; ++} + +- return size; ++/** ++ * round_size_to_mb()- Round given size. ++ * @array_size: size to round in sectors. ++ * @disk_count: count of data members. ++ * ++ * Get size per each data member and round it to closest MiB to ensure that data ++ * splits evenly between members. ++ * ++ * Return: Array size, rounded down. ++ */ ++static inline unsigned long long round_size_to_mb(unsigned long long array_size, ++ unsigned int disk_count) ++{ ++ return round_member_size_to_mb(array_size / disk_count) * disk_count; + } + + static int able_to_resync(int raid_level, int missing_disks) +@@ -11810,8 +11822,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, + } else { + /* round size due to metadata compatibility + */ +- geo->size = (geo->size >> SECT_PER_MB_SHIFT) +- << SECT_PER_MB_SHIFT; ++ geo->size = round_member_size_to_mb(geo->size); + dprintf("Prepare update for size change to %llu\n", + geo->size ); + if (current_size >= geo->size) { +-- +2.40.1 + diff --git a/SOURCES/0130-imsm-move-expand-verification-code-into-new-function.patch b/SOURCES/0130-imsm-move-expand-verification-code-into-new-function.patch new file mode 100644 index 0000000..6e5359e --- /dev/null +++ b/SOURCES/0130-imsm-move-expand-verification-code-into-new-function.patch @@ -0,0 +1,238 @@ +From cbaa7904a175628a294ed54b4de6c52afa4f830d Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Mon, 29 May 2023 15:52:36 +0200 +Subject: [PATCH 130/165] imsm: move expand verification code into new function + +The code here is too complex. Move it to separate function and +simplify it. Add more error messages. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-intel.c | 187 +++++++++++++++++++++++++++----------------------- + 1 file changed, 101 insertions(+), 86 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index 36171107..5bd70356 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -11643,6 +11643,102 @@ static void imsm_update_metadata_locally(struct supertype *st, + } + } + ++/** ++ * imsm_analyze_expand() - check expand properties and calculate new size. ++ * @st: imsm supertype. ++ * @geo: new geometry params. ++ * @array: array info. ++ * @direction: reshape direction. ++ * ++ * Obtain free space after the &array and verify if expand to requested size is ++ * possible. If geo->size is set to %MAX_SIZE, assume that max free size is ++ * requested. ++ * ++ * Return: ++ * On success %IMSM_STATUS_OK is returned, geo->size and geo->raid_disks are ++ * updated. ++ * On error, %IMSM_STATUS_ERROR is returned. ++ */ ++static imsm_status_t imsm_analyze_expand(struct supertype *st, ++ struct geo_params *geo, ++ struct mdinfo *array, ++ int direction) ++{ ++ struct intel_super *super = st->sb; ++ struct imsm_dev *dev = get_imsm_dev(super, super->current_vol); ++ struct imsm_map *map = get_imsm_map(dev, MAP_0); ++ int data_disks = imsm_num_data_members(map); ++ ++ unsigned long long current_size; ++ unsigned long long free_size; ++ unsigned long long new_size; ++ unsigned long long max_size; ++ ++ const int chunk_kib = geo->chunksize / 1024; ++ imsm_status_t rv; ++ ++ if (direction == ROLLBACK_METADATA_CHANGES) { ++ /** ++ * Accept size for rollback only. ++ */ ++ new_size = geo->size * 2; ++ goto success; ++ } ++ ++ if (super->current_vol + 1 != super->anchor->num_raid_devs) { ++ pr_err("imsm: The last volume in container can be expanded only (%i/%s).\n", ++ super->current_vol, st->devnm); ++ return IMSM_STATUS_ERROR; ++ } ++ ++ if (data_disks == 0) { ++ pr_err("imsm: Cannot retrieve data disks.\n"); ++ return IMSM_STATUS_ERROR; ++ } ++ current_size = array->custom_array_size / data_disks; ++ ++ rv = imsm_get_free_size(super, dev->vol.map->num_members, 0, chunk_kib, &free_size); ++ if (rv != IMSM_STATUS_OK) { ++ pr_err("imsm: Cannot find free space for expand.\n"); ++ return IMSM_STATUS_ERROR; ++ } ++ max_size = round_member_size_to_mb(free_size + current_size); ++ ++ if (geo->size == MAX_SIZE) ++ new_size = max_size; ++ else ++ new_size = round_member_size_to_mb(geo->size * 2); ++ ++ if (new_size == 0) { ++ pr_err("imsm: Rounded requested size is 0.\n"); ++ return IMSM_STATUS_ERROR; ++ } ++ ++ if (new_size > max_size) { ++ pr_err("imsm: Rounded requested size (%llu) is larger than free space available (%llu).\n", ++ new_size, max_size); ++ return IMSM_STATUS_ERROR; ++ } ++ ++ if (new_size == current_size) { ++ pr_err("imsm: Rounded requested size (%llu) is same as current size (%llu).\n", ++ new_size, current_size); ++ return IMSM_STATUS_ERROR; ++ } ++ ++ if (new_size < current_size) { ++ pr_err("imsm: Size reduction is not supported, rounded requested size (%llu) is smaller than current (%llu).\n", ++ new_size, current_size); ++ return IMSM_STATUS_ERROR; ++ } ++ ++success: ++ dprintf("imsm: New size per member is %llu.\n", new_size); ++ geo->size = data_disks * new_size; ++ geo->raid_disks = dev->vol.map->num_members; ++ return IMSM_STATUS_OK; ++} ++ + /*************************************************************************** + * Function: imsm_analyze_change + * Description: Function analyze change for single volume +@@ -11663,13 +11759,6 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, + int devNumChange = 0; + /* imsm compatible layout value for array geometry verification */ + int imsm_layout = -1; +- int data_disks; +- struct imsm_dev *dev; +- struct imsm_map *map; +- struct intel_super *super; +- unsigned long long current_size; +- unsigned long long free_size; +- unsigned long long max_size; + imsm_status_t rv; + + getinfo_super_imsm_volume(st, &info, NULL); +@@ -11752,94 +11841,20 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, + geo->chunksize = info.array.chunk_size; + } + +- chunk = geo->chunksize / 1024; +- +- super = st->sb; +- dev = get_imsm_dev(super, super->current_vol); +- map = get_imsm_map(dev, MAP_0); +- data_disks = imsm_num_data_members(map); +- /* compute current size per disk member +- */ +- current_size = info.custom_array_size / data_disks; +- +- if (geo->size > 0 && geo->size != MAX_SIZE) { +- /* align component size +- */ +- geo->size = imsm_component_size_alignment_check( +- get_imsm_raid_level(dev->vol.map), +- chunk * 1024, super->sector_size, +- geo->size * 2); +- if (geo->size == 0) { +- pr_err("Error. Size expansion is supported only (current size is %llu, requested size /rounded/ is 0).\n", +- current_size); +- goto analyse_change_exit; +- } +- } +- +- if (current_size != geo->size && geo->size > 0) { ++ if (geo->size > 0) { + if (change != -1) { + pr_err("Error. Size change should be the only one at a time.\n"); + change = -1; + goto analyse_change_exit; + } +- if ((super->current_vol + 1) != super->anchor->num_raid_devs) { +- pr_err("Error. The last volume in container can be expanded only (%i/%s).\n", +- super->current_vol, st->devnm); +- goto analyse_change_exit; +- } +- /* check the maximum available size +- */ +- rv = imsm_get_free_size(super, dev->vol.map->num_members, +- 0, chunk, &free_size); + ++ rv = imsm_analyze_expand(st, geo, &info, direction); + if (rv != IMSM_STATUS_OK) +- /* Cannot find maximum available space +- */ +- max_size = 0; +- else { +- max_size = free_size + current_size; +- /* align component size +- */ +- max_size = imsm_component_size_alignment_check( +- get_imsm_raid_level(dev->vol.map), +- chunk * 1024, super->sector_size, +- max_size); +- } +- if (geo->size == MAX_SIZE) { +- /* requested size change to the maximum available size +- */ +- if (max_size == 0) { +- pr_err("Error. Cannot find maximum available space.\n"); +- change = -1; +- goto analyse_change_exit; +- } else +- geo->size = max_size; +- } +- +- if (direction == ROLLBACK_METADATA_CHANGES) { +- /* accept size for rollback only +- */ +- } else { +- /* round size due to metadata compatibility +- */ +- geo->size = round_member_size_to_mb(geo->size); +- dprintf("Prepare update for size change to %llu\n", +- geo->size ); +- if (current_size >= geo->size) { +- pr_err("Error. Size expansion is supported only (current size is %llu, requested size /rounded/ is %llu).\n", +- current_size, geo->size); +- goto analyse_change_exit; +- } +- if (max_size && geo->size > max_size) { +- pr_err("Error. Requested size is larger than maximum available size (maximum available size is %llu, requested size /rounded/ is %llu).\n", +- max_size, geo->size); +- goto analyse_change_exit; +- } +- } +- geo->size *= data_disks; +- geo->raid_disks = dev->vol.map->num_members; ++ goto analyse_change_exit; + change = CH_ARRAY_SIZE; + } ++ ++ chunk = geo->chunksize / 1024; + if (!validate_geometry_imsm(st, + geo->level, + imsm_layout, +-- +2.40.1 + diff --git a/SOURCES/0131-imsm-return-free-space-after-volume-for-expand.patch b/SOURCES/0131-imsm-return-free-space-after-volume-for-expand.patch new file mode 100644 index 0000000..10faec5 --- /dev/null +++ b/SOURCES/0131-imsm-return-free-space-after-volume-for-expand.patch @@ -0,0 +1,214 @@ +From aa19fdd45b2ba474f6a51a6d4b8f3c44ef19dafd Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Mon, 29 May 2023 15:52:37 +0200 +Subject: [PATCH 131/165] imsm: return free space after volume for expand + +merge_extends() routine searches for the biggest free space. For expand, +it works only in standard cases where the last volume is expanded and +the free space is determined after the last volume. +Add volume index to extent struct and use that do determine size after +super->current_vol during expand. + +Limitation to last volume is no longer needed. It unblocks scenarios +where kill-subarray is used to remove first volume and later it is +recreated (now it is the second volume, even if it is placed before +existing one). + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-intel.c | 71 +++++++++++++++++++++++++++------------------------ + 1 file changed, 37 insertions(+), 34 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index 5bd70356..e249d925 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -499,8 +499,15 @@ struct intel_disk { + struct intel_disk *next; + }; + ++/** ++ * struct extent - reserved space details. ++ * @start: start offset. ++ * @size: size of reservation, set to 0 for metadata reservation. ++ * @vol: index of the volume, meaningful if &size is set. ++ */ + struct extent { + unsigned long long start, size; ++ int vol; + }; + + /* definitions of reshape process types */ +@@ -1539,9 +1546,10 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl, + int get_minimal_reservation) + { + /* find a list of used extents on the given physical device */ +- struct extent *rv, *e; +- int i; + int memberships = count_memberships(dl, super); ++ struct extent *rv = xcalloc(memberships + 1, sizeof(struct extent)); ++ struct extent *e = rv; ++ int i; + __u32 reservation; + + /* trim the reserved area for spares, so they can join any array +@@ -1553,9 +1561,6 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl, + else + reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS; + +- rv = xcalloc(sizeof(struct extent), (memberships + 1)); +- e = rv; +- + for (i = 0; i < super->anchor->num_raid_devs; i++) { + struct imsm_dev *dev = get_imsm_dev(super, i); + struct imsm_map *map = get_imsm_map(dev, MAP_0); +@@ -1563,6 +1568,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl, + if (get_imsm_disk_slot(map, dl->index) >= 0) { + e->start = pba_of_lba0(map); + e->size = per_dev_array_size(map); ++ e->vol = i; + e++; + } + } +@@ -6894,24 +6900,26 @@ static unsigned long long find_size(struct extent *e, int *idx, int num_extents) + return end - base_start; + } + +-/** merge_extents() - analyze extents and get max common free size. ++/** merge_extents() - analyze extents and get free size. + * @super: Intel metadata, not NULL. ++ * @expanding: if set, we are expanding &super->current_vol. + * +- * Build a composite disk with all known extents and generate a new maxsize +- * given the "all disks in an array must share a common start offset" +- * constraint. ++ * Build a composite disk with all known extents and generate a size given the ++ * "all disks in an array must share a common start offset" constraint. ++ * If a volume is expanded, then return free space after the volume. + * +- * Return: Max free space or 0 on failure. ++ * Return: Free space or 0 on failure. + */ +-static unsigned long long merge_extents(struct intel_super *super) ++static unsigned long long merge_extents(struct intel_super *super, const bool expanding) + { + struct extent *e; + struct dl *dl; +- int i, j; +- int start_extent, sum_extents = 0; +- unsigned long long pos; ++ int i, j, pos_vol_idx = -1; ++ int extent_idx = 0; ++ int sum_extents = 0; ++ unsigned long long pos = 0; + unsigned long long start = 0; +- unsigned long long maxsize; ++ unsigned long long maxsize = 0; + unsigned long reserve; + + for (dl = super->disks; dl; dl = dl->next) +@@ -6936,26 +6944,26 @@ static unsigned long long merge_extents(struct intel_super *super) + j = 0; + while (i < sum_extents) { + e[j].start = e[i].start; ++ e[j].vol = e[i].vol; + e[j].size = find_size(e, &i, sum_extents); + j++; + if (e[j-1].size == 0) + break; + } + +- pos = 0; +- maxsize = 0; +- start_extent = 0; + i = 0; + do { +- unsigned long long esize; ++ unsigned long long esize = e[i].start - pos; + +- esize = e[i].start - pos; +- if (esize >= maxsize) { ++ if (expanding ? pos_vol_idx == super->current_vol : esize >= maxsize) { + maxsize = esize; + start = pos; +- start_extent = i; ++ extent_idx = i; + } ++ + pos = e[i].start + e[i].size; ++ pos_vol_idx = e[i].vol; ++ + i++; + } while (e[i-1].size); + free(e); +@@ -6966,7 +6974,7 @@ static unsigned long long merge_extents(struct intel_super *super) + /* FIXME assumes volume at offset 0 is the first volume in a + * container + */ +- if (start_extent > 0) ++ if (extent_idx > 0) + reserve = IMSM_RESERVED_SECTORS; /* gap between raid regions */ + else + reserve = 0; +@@ -7577,7 +7585,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, + return 0; + } + +- maxsize = merge_extents(super); ++ maxsize = merge_extents(super, false); + + if (mpb->num_raid_devs > 0 && size && size != maxsize) + pr_err("attempting to create a second volume with size less then remaining space.\n"); +@@ -7626,7 +7634,8 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, + const int raiddisks, + unsigned long long size, + const int chunk, +- unsigned long long *freesize) ++ unsigned long long *freesize, ++ bool expanding) + { + struct imsm_super *mpb = super->anchor; + struct dl *dl; +@@ -7663,7 +7672,7 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super, + cnt++; + } + +- maxsize = merge_extents(super); ++ maxsize = merge_extents(super, expanding); + if (maxsize < minsize) { + pr_err("imsm: Free space is %llu but must be equal or larger than %llu.\n", + maxsize, minsize); +@@ -7721,7 +7730,7 @@ static imsm_status_t autolayout_imsm(struct intel_super *super, + int vol_cnt = super->anchor->num_raid_devs; + imsm_status_t rv; + +- rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize); ++ rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize, false); + if (rv != IMSM_STATUS_OK) + return IMSM_STATUS_ERROR; + +@@ -11685,19 +11694,13 @@ static imsm_status_t imsm_analyze_expand(struct supertype *st, + goto success; + } + +- if (super->current_vol + 1 != super->anchor->num_raid_devs) { +- pr_err("imsm: The last volume in container can be expanded only (%i/%s).\n", +- super->current_vol, st->devnm); +- return IMSM_STATUS_ERROR; +- } +- + if (data_disks == 0) { + pr_err("imsm: Cannot retrieve data disks.\n"); + return IMSM_STATUS_ERROR; + } + current_size = array->custom_array_size / data_disks; + +- rv = imsm_get_free_size(super, dev->vol.map->num_members, 0, chunk_kib, &free_size); ++ rv = imsm_get_free_size(super, dev->vol.map->num_members, 0, chunk_kib, &free_size, true); + if (rv != IMSM_STATUS_OK) { + pr_err("imsm: Cannot find free space for expand.\n"); + return IMSM_STATUS_ERROR; +-- +2.40.1 + diff --git a/SOURCES/0132-imsm-fix-free-space-calculations.patch b/SOURCES/0132-imsm-fix-free-space-calculations.patch new file mode 100644 index 0000000..fe3025f --- /dev/null +++ b/SOURCES/0132-imsm-fix-free-space-calculations.patch @@ -0,0 +1,113 @@ +From 1dea84ae38288fbefa04d9fda2b3f36c21a9e1bd Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Mon, 29 May 2023 15:52:38 +0200 +Subject: [PATCH 132/165] imsm: fix free space calculations + +Between two volumes or between last volume and metadata at least +IMSM_RESERVED_SECTORS gap must exist. Currently the gap can be doubled +because metadata reservation contains IMSM_RESERVED_SECTORS too. + +Divide reserve variable into pre_reservation and post_reservation to be +more flexible and decide separately if each reservation is needed. + +Pre_reservation is needed only when a volume is created and it is not a +real first volume in a container (we can check that by extent_idx). +This type of reservation is not needed for expand. + +Post_reservation is not needed only if real last volume is created or +expanded because reservation is done with the metadata. + +The volume index in metadata cannot be trusted, because the real volume +order can be reversed. It is safer to use extent table, it is sorted by +start position. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-intel.c | 50 ++++++++++++++++++++++++++++++-------------------- + 1 file changed, 30 insertions(+), 20 deletions(-) + +diff --git a/super-intel.c b/super-intel.c +index e249d925..824c1356 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -6919,8 +6919,11 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex + int sum_extents = 0; + unsigned long long pos = 0; + unsigned long long start = 0; +- unsigned long long maxsize = 0; +- unsigned long reserve; ++ unsigned long long free_size = 0; ++ ++ unsigned long pre_reservation = 0; ++ unsigned long post_reservation = IMSM_RESERVED_SECTORS; ++ unsigned long reservation_size; + + for (dl = super->disks; dl; dl = dl->next) + if (dl->e) +@@ -6955,8 +6958,8 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex + do { + unsigned long long esize = e[i].start - pos; + +- if (expanding ? pos_vol_idx == super->current_vol : esize >= maxsize) { +- maxsize = esize; ++ if (expanding ? pos_vol_idx == super->current_vol : esize >= free_size) { ++ free_size = esize; + start = pos; + extent_idx = i; + } +@@ -6966,28 +6969,35 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex + + i++; + } while (e[i-1].size); +- free(e); + +- if (maxsize == 0) ++ if (free_size == 0) { ++ dprintf("imsm: Cannot find free size.\n"); ++ free(e); + return 0; ++ } + +- /* FIXME assumes volume at offset 0 is the first volume in a +- * container +- */ +- if (extent_idx > 0) +- reserve = IMSM_RESERVED_SECTORS; /* gap between raid regions */ +- else +- reserve = 0; ++ if (!expanding && extent_idx != 0) ++ /* ++ * Not a real first volume in a container is created, pre_reservation is needed. ++ */ ++ pre_reservation = IMSM_RESERVED_SECTORS; + +- if (maxsize < reserve) +- return 0; ++ if (e[extent_idx].size == 0) ++ /* ++ * extent_idx points to the metadata, post_reservation is allready done. ++ */ ++ post_reservation = 0; ++ free(e); + +- super->create_offset = ~((unsigned long long) 0); +- if (start + reserve > super->create_offset) +- return 0; /* start overflows create_offset */ +- super->create_offset = start + reserve; ++ reservation_size = pre_reservation + post_reservation; ++ ++ if (free_size < reservation_size) { ++ dprintf("imsm: Reservation size is greater than free space.\n"); ++ return 0; ++ } + +- return maxsize - reserve; ++ super->create_offset = start + pre_reservation; ++ return free_size - reservation_size; + } + + static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks) +-- +2.40.1 + diff --git a/SOURCES/0133-Add-secure-gethostname-wrapper.patch b/SOURCES/0133-Add-secure-gethostname-wrapper.patch new file mode 100644 index 0000000..19f6c36 --- /dev/null +++ b/SOURCES/0133-Add-secure-gethostname-wrapper.patch @@ -0,0 +1,124 @@ +From 21e622f214a38c048c5689158bc6314a91a46e40 Mon Sep 17 00:00:00 2001 +From: Blazej Kucman +Date: Fri, 16 Jun 2023 21:45:55 +0200 +Subject: [PATCH 133/165] Add secure gethostname() wrapper + +gethostname() func does not ensure null-terminated string +if hostname is longer than buffer length. +For security, a function s_gethostname() has been added +to ensure that "\0" is added to the end of the buffer. +Previously this had to be handled in each place +of the gethostname() call. + +Signed-off-by: Blazej Kucman +Signed-off-by: Jes Sorensen +--- + Monitor.c | 3 +-- + lib.c | 19 +++++++++++++++++++ + mapfile.c | 3 +-- + mdadm.c | 3 +-- + mdadm.h | 1 + + super-ddf.c | 3 +-- + 6 files changed, 24 insertions(+), 8 deletions(-) + +diff --git a/Monitor.c b/Monitor.c +index 66175968..e74a0558 100644 +--- a/Monitor.c ++++ b/Monitor.c +@@ -222,11 +222,10 @@ int Monitor(struct mddev_dev *devlist, + info.dosyslog = dosyslog; + info.test = c->test; + +- if (gethostname(info.hostname, sizeof(info.hostname)) != 0) { ++ if (s_gethostname(info.hostname, sizeof(info.hostname)) != 0) { + pr_err("Cannot get hostname.\n"); + return 1; + } +- info.hostname[sizeof(info.hostname) - 1] = '\0'; + + if (share){ + if (check_one_sharer(c->scan) == 2) +diff --git a/lib.c b/lib.c +index fe5c8d2c..8a4b48e0 100644 +--- a/lib.c ++++ b/lib.c +@@ -585,3 +585,22 @@ int parse_num(int *dest, const char *num) + *dest = temp; + return 0; + } ++ ++/** ++ * s_gethostname() - secure get hostname. Assure null-terminated string. ++ * ++ * @buf: buffer for hostname. ++ * @buf_len: buffer length. ++ * ++ * Return: gethostname() result. ++ */ ++int s_gethostname(char *buf, int buf_len) ++{ ++ assert(buf); ++ ++ int ret = gethostname(buf, buf_len); ++ ++ buf[buf_len - 1] = 0; ++ ++ return ret; ++} +diff --git a/mapfile.c b/mapfile.c +index 34fea179..f1f3ee2c 100644 +--- a/mapfile.c ++++ b/mapfile.c +@@ -363,8 +363,7 @@ void RebuildMap(void) + char *homehost = conf_get_homehost(&require_homehost); + + if (homehost == NULL || strcmp(homehost, "")==0) { +- if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { +- sys_hostname[sizeof(sys_hostname)-1] = 0; ++ if (s_gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { + homehost = sys_hostname; + } + } +diff --git a/mdadm.c b/mdadm.c +index 076b45e0..e32598cb 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -1340,8 +1340,7 @@ int main(int argc, char *argv[]) + if (c.homehost == NULL && c.require_homehost) + c.homehost = conf_get_homehost(&c.require_homehost); + if (c.homehost == NULL || strcasecmp(c.homehost, "") == 0) { +- if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { +- sys_hostname[sizeof(sys_hostname)-1] = 0; ++ if (s_gethostname(sys_hostname, sizeof(sys_hostname)) == 0) { + c.homehost = sys_hostname; + } + } +diff --git a/mdadm.h b/mdadm.h +index 83f2cf7f..f0ceeb78 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1805,6 +1805,7 @@ extern void set_dlm_hooks(void); + extern void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt); + extern bool is_directory(const char *path); + extern bool is_file(const char *path); ++extern int s_gethostname(char *buf, int buf_len); + + #define _ROUND_UP(val, base) (((val) + (base) - 1) & ~(base - 1)) + #define ROUND_UP(val, base) _ROUND_UP(val, (typeof(val))(base)) +diff --git a/super-ddf.c b/super-ddf.c +index 7213284e..c5242654 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -2364,8 +2364,7 @@ static int init_super_ddf(struct supertype *st, + * Remaining 16 are serial number.... maybe a hostname would do? + */ + memcpy(ddf->controller.guid, T10, sizeof(T10)); +- gethostname(hostname, sizeof(hostname)); +- hostname[sizeof(hostname) - 1] = 0; ++ s_gethostname(hostname, sizeof(hostname)); + hostlen = strlen(hostname); + memcpy(ddf->controller.guid + 24 - hostlen, hostname, hostlen); + for (i = strlen(T10) ; i+hostlen < 24; i++) +-- +2.40.1 + diff --git a/SOURCES/0134-mdadm-Stop-mdcheck_continue-timer-when-mdcheck_start.patch b/SOURCES/0134-mdadm-Stop-mdcheck_continue-timer-when-mdcheck_start.patch new file mode 100644 index 0000000..abe9ef6 --- /dev/null +++ b/SOURCES/0134-mdadm-Stop-mdcheck_continue-timer-when-mdcheck_start.patch @@ -0,0 +1,41 @@ +From 1ab341e5ce0cb01a1533a2c36e5b69eabf12bf95 Mon Sep 17 00:00:00 2001 +From: Xiao Ni +Date: Fri, 25 Aug 2023 20:55:41 +0800 +Subject: [PATCH 134/165] mdadm: Stop mdcheck_continue timer when mdcheck_start + service can finish check + +mdcheck_continue is triggered by mdcheck_start timer. It's used to +continue check action if the raid is too big and mdcheck_start +service can't finish check action. If mdcheck start can finish check +action, it doesn't need to mdcheck continue service anymore. So stop +it when mdcheck start service can finish check action. + +Signed-off-by: Xiao Ni +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + misc/mdcheck | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/misc/mdcheck b/misc/mdcheck +index 700c3e25..f87999d3 100644 +--- a/misc/mdcheck ++++ b/misc/mdcheck +@@ -140,7 +140,13 @@ do + echo $a > $fl + any=yes + done +- if [ -z "$any" ]; then exit 0; fi ++ # mdcheck_continue.timer is started by mdcheck_start.timer. ++ # When the check action can be finished in mdcheck_start.service, ++ # it doesn't need mdcheck_continue anymore. ++ if [ -z "$any" ]; then ++ systemctl stop mdcheck_continue.timer ++ exit 0; ++ fi + sleep 120 + done + +-- +2.40.1 + diff --git a/SOURCES/0135-Fix-memory-leak-in-file-Assemble.patch b/SOURCES/0135-Fix-memory-leak-in-file-Assemble.patch new file mode 100644 index 0000000..d7399c9 --- /dev/null +++ b/SOURCES/0135-Fix-memory-leak-in-file-Assemble.patch @@ -0,0 +1,90 @@ +From e9fb93af0f769d147a13e86ab4e5d0aeb935e9fc Mon Sep 17 00:00:00 2001 +From: Guanqin Miao +Date: Mon, 24 Apr 2023 16:06:34 +0800 +Subject: [PATCH 135/165] Fix memory leak in file Assemble + +When we test mdadm with asan, we found some memory leaks in Assemble.c +We fix these memory leaks based on code logic. + +v2: Set st = NULL before jumping to loop + +Signed-off-by: Guanqin Miao +Signed-off-by: Li Xiao Keng +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Assemble.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/Assemble.c b/Assemble.c +index 49804941..61e8cd17 100644 +--- a/Assemble.c ++++ b/Assemble.c +@@ -341,8 +341,10 @@ static int select_devices(struct mddev_dev *devlist, + st->ss->free_super(st); + dev_policy_free(pol); + domain_free(domains); +- if (tst) ++ if (tst) { + tst->ss->free_super(tst); ++ free(tst); ++ } + return -1; + } + +@@ -417,6 +419,7 @@ static int select_devices(struct mddev_dev *devlist, + st->ss->free_super(st); + dev_policy_free(pol); + domain_free(domains); ++ free(st); + return -1; + } + if (c->verbose > 0) +@@ -425,6 +428,8 @@ static int select_devices(struct mddev_dev *devlist, + + /* make sure we finished the loop */ + tmpdev = NULL; ++ free(st); ++ st = NULL; + goto loop; + } else { + content = *contentp; +@@ -533,6 +538,7 @@ static int select_devices(struct mddev_dev *devlist, + st->ss->free_super(st); + dev_policy_free(pol); + domain_free(domains); ++ free(tst); + return -1; + } + tmpdev->used = 1; +@@ -546,8 +552,10 @@ static int select_devices(struct mddev_dev *devlist, + } + dev_policy_free(pol); + pol = NULL; +- if (tst) ++ if (tst) { + tst->ss->free_super(tst); ++ free(tst); ++ } + } + + /* Check if we found some imsm spares but no members */ +@@ -839,6 +847,7 @@ static int load_devices(struct devs *devices, char *devmap, + close(mdfd); + free(devices); + free(devmap); ++ free(best); + *stp = st; + return -1; + } +@@ -1950,6 +1959,7 @@ out: + } else if (mdfd >= 0) + close(mdfd); + ++ free(best); + /* '2' means 'OK, but not started yet' */ + if (rv == -1) { + free(devices); +-- +2.40.1 + diff --git a/SOURCES/0136-Fix-memory-leak-in-file-Kill.patch b/SOURCES/0136-Fix-memory-leak-in-file-Kill.patch new file mode 100644 index 0000000..d4b1a83 --- /dev/null +++ b/SOURCES/0136-Fix-memory-leak-in-file-Kill.patch @@ -0,0 +1,54 @@ +From 8fd0c565b09ba449418d7d604ceba66313246152 Mon Sep 17 00:00:00 2001 +From: Guanqin Miao +Date: Mon, 24 Apr 2023 16:06:35 +0800 +Subject: [PATCH 136/165] Fix memory leak in file Kill + +When we test mdadm with asan, we found some memory leaks in Kill.c +We fix these memory leaks based on code logic. + +Signed-off-by: Guanqin Miao +Signed-off-by: Li Xiao Keng +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Kill.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/Kill.c b/Kill.c +index bfd0efdc..43c9abed 100644 +--- a/Kill.c ++++ b/Kill.c +@@ -41,6 +41,7 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl) + * 4 - failed to find a superblock. + */ + ++ bool free_super = false; + int fd, rv = 0; + + if (force) +@@ -52,8 +53,10 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl) + dev); + return 2; + } +- if (st == NULL) ++ if (st == NULL) { + st = guess_super(fd); ++ free_super = true; ++ } + if (st == NULL || st->ss->init_super == NULL) { + if (verbose >= 0) + pr_err("Unrecognised md component device - %s\n", dev); +@@ -77,6 +80,10 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl) + rv = 0; + } + } ++ if (free_super && st) { ++ st->ss->free_super(st); ++ free(st); ++ } + close(fd); + return rv; + } +-- +2.40.1 + diff --git a/SOURCES/0137-Fix-memory-leak-in-file-Manage.patch b/SOURCES/0137-Fix-memory-leak-in-file-Manage.patch new file mode 100644 index 0000000..214c0e2 --- /dev/null +++ b/SOURCES/0137-Fix-memory-leak-in-file-Manage.patch @@ -0,0 +1,74 @@ +From f6feb3fbb50f48c193e9e4d775a20aa20f7b47b3 Mon Sep 17 00:00:00 2001 +From: Guanqin Miao +Date: Mon, 24 Apr 2023 16:06:36 +0800 +Subject: [PATCH 137/165] Fix memory leak in file Manage + +When we test mdadm with asan, we found some memory leaks in Manage.c +We fix these memory leaks based on code logic. + +v2: Fix free() of uninitialized 'tst' in abort path. + +Signed-off-by: Guanqin Miao +Signed-off-by: Li Xiao Keng +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Manage.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/Manage.c b/Manage.c +index f54de7c6..f997b163 100644 +--- a/Manage.c ++++ b/Manage.c +@@ -222,6 +222,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry) + if (verbose >= 0) + pr_err("Cannot get exclusive access to %s:Perhaps a running process, mounted filesystem or active volume group?\n", + devname); ++ sysfs_free(mdi); + return 1; + } + /* If this is an mdmon managed array, just write 'inactive' +@@ -801,8 +802,14 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + rdev, update, devname, + verbose, array); + dev_st->ss->free_super(dev_st); +- if (rv) ++ if (rv) { ++ free(dev_st); + return rv; ++ } ++ } ++ if (dev_st) { ++ dev_st->ss->free_super(dev_st); ++ free(dev_st); + } + } + if (dv->disposition == 'M') { +@@ -1362,7 +1369,7 @@ int Manage_subdevs(char *devname, int fd, + unsigned long long array_size; + struct mddev_dev *dv; + int tfd = -1; +- struct supertype *tst; ++ struct supertype *tst = NULL; + char *subarray = NULL; + int sysfd = -1; + int count = 0; /* number of actions taken */ +@@ -1699,6 +1706,7 @@ int Manage_subdevs(char *devname, int fd, + break; + } + } ++ free(tst); + if (frozen > 0) + sysfs_set_str(&info, NULL, "sync_action","idle"); + if (test && count == 0) +@@ -1706,6 +1714,7 @@ int Manage_subdevs(char *devname, int fd, + return 0; + + abort: ++ free(tst); + if (frozen > 0) + sysfs_set_str(&info, NULL, "sync_action","idle"); + return !test && busy ? 2 : 1; +-- +2.40.1 + diff --git a/SOURCES/0138-Fix-memory-leak-in-file-mdadm.patch b/SOURCES/0138-Fix-memory-leak-in-file-mdadm.patch new file mode 100644 index 0000000..2cb9f7f --- /dev/null +++ b/SOURCES/0138-Fix-memory-leak-in-file-mdadm.patch @@ -0,0 +1,34 @@ +From e62a561ee8b7157a2390eab215dcef6240bd7b03 Mon Sep 17 00:00:00 2001 +From: Guanqin Miao +Date: Mon, 24 Apr 2023 16:06:37 +0800 +Subject: [PATCH 138/165] Fix memory leak in file mdadm + +When we test mdadm with asan, we found some memory leaks in mdadm.c +We fix these memory leaks based on code logic. + +Signed-off-by: Guanqin Miao +Signed-off-by: Li Xiao Keng +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + mdadm.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/mdadm.c b/mdadm.c +index e32598cb..22d1c53b 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -1708,6 +1708,10 @@ int main(int argc, char *argv[]) + autodetect(); + break; + } ++ if (ss) { ++ ss->ss->free_super(ss); ++ free(ss); ++ } + if (locked) + cluster_release_dlmlock(); + close_fd(&mdfd); +-- +2.40.1 + diff --git a/SOURCES/0139-Fix-unsafe-string-functions.patch b/SOURCES/0139-Fix-unsafe-string-functions.patch new file mode 100644 index 0000000..955b1bb --- /dev/null +++ b/SOURCES/0139-Fix-unsafe-string-functions.patch @@ -0,0 +1,116 @@ +From dd5ab40204b1d78ec3bdbcfd5a38a8ffb72bdb50 Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Thu, 11 May 2023 04:55:12 +0200 +Subject: [PATCH 139/165] Fix unsafe string functions + +Add string length limitations where necessary to +avoid buffer overflows. + +Signed-off-by: Kinga Tanska +Signed-off-by: Jes Sorensen +--- + mdmon.c | 6 +++--- + mdopen.c | 4 ++-- + platform-intel.c | 2 +- + super-intel.c | 6 +++--- + 4 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/mdmon.c b/mdmon.c +index cef5bbc8..a2038fe6 100644 +--- a/mdmon.c ++++ b/mdmon.c +@@ -240,7 +240,7 @@ static int make_control_sock(char *devname) + return -1; + + addr.sun_family = PF_LOCAL; +- strcpy(addr.sun_path, path); ++ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path); + umask(077); /* ensure no world write access */ + if (bind(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + close(sfd); +@@ -389,7 +389,7 @@ int main(int argc, char *argv[]) + + if (all) { + struct mdstat_ent *mdstat, *e; +- int container_len = strlen(container_name); ++ int container_len = strnlen(container_name, MD_NAME_MAX); + + /* launch an mdmon instance for each container found */ + mdstat = mdstat_read(0, 0); +@@ -472,7 +472,7 @@ static int mdmon(char *devnm, int must_fork, int takeover) + pfd[0] = pfd[1] = -1; + + container = xcalloc(1, sizeof(*container)); +- strcpy(container->devnm, devnm); ++ snprintf(container->devnm, MD_NAME_MAX, "%s", devnm); + container->arrays = NULL; + container->sock = -1; + +diff --git a/mdopen.c b/mdopen.c +index d3022a54..3daa71f9 100644 +--- a/mdopen.c ++++ b/mdopen.c +@@ -193,14 +193,14 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy, + + if (dev) { + if (strncmp(dev, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) { +- strcpy(cname, dev + DEV_MD_DIR_LEN); ++ snprintf(cname, MD_NAME_MAX, "%s", dev + DEV_MD_DIR_LEN); + } else if (strncmp(dev, "/dev/", 5) == 0) { + char *e = dev + strlen(dev); + while (e > dev && isdigit(e[-1])) + e--; + if (e[0]) + num = strtoul(e, NULL, 10); +- strcpy(cname, dev+5); ++ snprintf(cname, MD_NAME_MAX, "%s", dev + 5); + cname[e-(dev+5)] = 0; + /* name *must* be mdXX or md_dXX in this context */ + if (num < 0 || +diff --git a/platform-intel.c b/platform-intel.c +index 914164c0..eb6e1b7e 100644 +--- a/platform-intel.c ++++ b/platform-intel.c +@@ -214,7 +214,7 @@ struct sys_dev *device_by_id_and_path(__u16 device_id, const char *path) + + static int devpath_to_ll(const char *dev_path, const char *entry, unsigned long long *val) + { +- char path[strlen(dev_path) + strlen(entry) + 2]; ++ char path[strnlen(dev_path, PATH_MAX) + strnlen(entry, PATH_MAX) + 2]; + int fd; + int n; + +diff --git a/super-intel.c b/super-intel.c +index 824c1356..ce813172 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -7043,7 +7043,7 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist, + int fd = -1; + while (dev && !is_fd_valid(fd)) { + char *path = xmalloc(strlen(dev->name) + strlen("/dev/") + 1); +- num = sprintf(path, "%s%s", "/dev/", dev->name); ++ num = snprintf(path, PATH_MAX, "%s%s", "/dev/", dev->name); + if (num > 0) + fd = open(path, O_RDONLY, 0); + if (num <= 0 || !is_fd_valid(fd)) { +@@ -7935,7 +7935,7 @@ static int kill_subarray_imsm(struct supertype *st, char *subarray_id) + + if (i < current_vol) + continue; +- sprintf(subarray, "%u", i); ++ snprintf(subarray, sizeof(subarray), "%u", i); + if (is_subarray_active(subarray, st->devnm)) { + pr_err("deleting subarray-%d would change the UUID of active subarray-%d, aborting\n", + current_vol, i); +@@ -11308,7 +11308,7 @@ static const char *imsm_get_disk_controller_domain(const char *path) + char *drv=NULL; + struct stat st; + +- strcpy(disk_path, disk_by_path); ++ strncpy(disk_path, disk_by_path, PATH_MAX); + strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1); + if (stat(disk_path, &st) == 0) { + struct sys_dev* hba; +-- +2.40.1 + diff --git a/SOURCES/0140-platform-intel-limit-guid-length.patch b/SOURCES/0140-platform-intel-limit-guid-length.patch new file mode 100644 index 0000000..8ed03fa --- /dev/null +++ b/SOURCES/0140-platform-intel-limit-guid-length.patch @@ -0,0 +1,55 @@ +From 5ccd457b29809bee442749b5f66ac27ebba4a72d Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Thu, 11 May 2023 04:55:13 +0200 +Subject: [PATCH 140/165] platform-intel: limit guid length + +Moving GUID_STR_MAX to header to use it as +a length limitation for snprintf function. + +Signed-off-by: Kinga Tanska +Signed-off-by: Jes Sorensen +--- + platform-intel.c | 3 --- + platform-intel.h | 5 ++++- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/platform-intel.c b/platform-intel.c +index eb6e1b7e..ef90c3fd 100644 +--- a/platform-intel.c ++++ b/platform-intel.c +@@ -510,9 +510,6 @@ static const struct imsm_orom *find_imsm_hba_orom(struct sys_dev *hba) + return get_orom_by_device_id(hba->dev_id); + } + +-#define GUID_STR_MAX 37 /* according to GUID format: +- * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */ +- + #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + ((struct efi_guid) \ + {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ +diff --git a/platform-intel.h b/platform-intel.h +index 2c0f4e39..ba97fb04 100644 +--- a/platform-intel.h ++++ b/platform-intel.h +@@ -19,6 +19,9 @@ + #include + #include + ++/* according to GUID format: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */ ++#define GUID_STR_MAX 37 ++ + /* The IMSM Capability (IMSM AHCI and ISCU OROM/EFI variable) Version Table definition */ + struct imsm_orom { + __u8 signature[4]; +@@ -229,7 +232,7 @@ extern struct orom_entry *orom_entries; + + static inline char *guid_str(char *buf, struct efi_guid guid) + { +- sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", ++ snprintf(buf, GUID_STR_MAX, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid.b[3], guid.b[2], guid.b[1], guid.b[0], + guid.b[5], guid.b[4], guid.b[7], guid.b[6], + guid.b[8], guid.b[9], guid.b[10], guid.b[11], +-- +2.40.1 + diff --git a/SOURCES/0141-imsm-Add-reading-vmd-register-for-finding-imsm-capab.patch b/SOURCES/0141-imsm-Add-reading-vmd-register-for-finding-imsm-capab.patch new file mode 100644 index 0000000..be4cc37 --- /dev/null +++ b/SOURCES/0141-imsm-Add-reading-vmd-register-for-finding-imsm-capab.patch @@ -0,0 +1,220 @@ +From 8d1114be8c0a307d251c24078833b029efabc448 Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Wed, 5 Jul 2023 16:23:17 +0200 +Subject: [PATCH 141/165] imsm: Add reading vmd register for finding imsm + capability + +Currently mdadm does not find imsm capability when running inside VM. +This patch adds the possibility to read from vmd register and check for +capability, effectively allowing to use mdadm with imsm inside virtual machines. + +Additionally refactor find_imsm_capability() to make assignments in new +lines. + +Signed-off-by: Mateusz Grzonka +Signed-off-by: Jes Sorensen +--- + platform-intel.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++- + platform-intel.h | 11 ++++- + super-intel.c | 11 +++-- + 3 files changed, 130 insertions(+), 6 deletions(-) + +diff --git a/platform-intel.c b/platform-intel.c +index ef90c3fd..ac282bc5 100644 +--- a/platform-intel.c ++++ b/platform-intel.c +@@ -700,6 +700,106 @@ const struct imsm_orom *find_imsm_nvme(struct sys_dev *hba) + return &nvme_orom->orom; + } + ++#define VMD_REGISTER_OFFSET 0x3FC ++#define VMD_REGISTER_SKU_SHIFT 1 ++#define VMD_REGISTER_SKU_MASK (0x00000007) ++#define VMD_REGISTER_SKU_PREMIUM 2 ++#define MD_REGISTER_VER_MAJOR_SHIFT 4 ++#define MD_REGISTER_VER_MAJOR_MASK (0x0000000F) ++#define MD_REGISTER_VER_MINOR_SHIFT 8 ++#define MD_REGISTER_VER_MINOR_MASK (0x0000000F) ++ ++/* ++ * read_vmd_register() - Reads VMD register and writes contents to buff ptr ++ * @buff: buffer for vmd register data, should be the size of uint32_t ++ * ++ * Return: 0 on success, 1 on error ++ */ ++int read_vmd_register(uint32_t *buff, struct sys_dev *hba) ++{ ++ int fd; ++ char vmd_pci_config_path[PATH_MAX]; ++ ++ if (!vmd_domain_to_controller(hba, vmd_pci_config_path)) ++ return 1; ++ ++ strncat(vmd_pci_config_path, "/config", PATH_MAX - strnlen(vmd_pci_config_path, PATH_MAX)); ++ ++ fd = open(vmd_pci_config_path, O_RDONLY); ++ if (fd < 0) ++ return 1; ++ ++ if (pread(fd, buff, sizeof(uint32_t), VMD_REGISTER_OFFSET) != sizeof(uint32_t)) { ++ close(fd); ++ return 1; ++ } ++ close(fd); ++ return 0; ++} ++ ++/* ++ * add_vmd_orom() - Adds VMD orom cap to orom list, writes orom_entry ptr into vmd_orom ++ * @vmd_orom: pointer to orom entry pointer ++ * ++ * Return: 0 on success, 1 on error ++ */ ++int add_vmd_orom(struct orom_entry **vmd_orom, struct sys_dev *hba) ++{ ++ uint8_t sku; ++ uint32_t vmd_register_data; ++ struct imsm_orom vmd_orom_cap = { ++ .signature = IMSM_VMD_OROM_COMPAT_SIGNATURE, ++ .sss = IMSM_OROM_SSS_4kB | IMSM_OROM_SSS_8kB | ++ IMSM_OROM_SSS_16kB | IMSM_OROM_SSS_32kB | ++ IMSM_OROM_SSS_64kB | IMSM_OROM_SSS_128kB, ++ .dpa = IMSM_OROM_DISKS_PER_ARRAY_NVME, ++ .tds = IMSM_OROM_TOTAL_DISKS_VMD, ++ .vpa = IMSM_OROM_VOLUMES_PER_ARRAY, ++ .vphba = IMSM_OROM_VOLUMES_PER_HBA_VMD, ++ .attr = IMSM_OROM_ATTR_2TB | IMSM_OROM_ATTR_2TB_DISK, ++ .driver_features = IMSM_OROM_CAPABILITIES_EnterpriseSystem | ++ IMSM_OROM_CAPABILITIES_TPV ++ }; ++ ++ if (read_vmd_register(&vmd_register_data, hba) != 0) ++ return 1; ++ ++ sku = (uint8_t)((vmd_register_data >> VMD_REGISTER_SKU_SHIFT) & ++ VMD_REGISTER_SKU_MASK); ++ ++ if (sku == VMD_REGISTER_SKU_PREMIUM) ++ vmd_orom_cap.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 | ++ IMSM_OROM_RLC_RAID10 | IMSM_OROM_RLC_RAID5; ++ else ++ vmd_orom_cap.rlc = IMSM_OROM_RLC_RAID_CNG; ++ ++ vmd_orom_cap.major_ver = (uint8_t) ++ ((vmd_register_data >> MD_REGISTER_VER_MAJOR_SHIFT) & ++ MD_REGISTER_VER_MAJOR_MASK); ++ vmd_orom_cap.minor_ver = (uint8_t) ++ ((vmd_register_data >> MD_REGISTER_VER_MINOR_SHIFT) & ++ MD_REGISTER_VER_MINOR_MASK); ++ ++ *vmd_orom = add_orom(&vmd_orom_cap); ++ ++ return 0; ++} ++ ++const struct imsm_orom *find_imsm_vmd(struct sys_dev *hba) ++{ ++ static struct orom_entry *vmd_orom; ++ ++ if (hba->type != SYS_DEV_VMD) ++ return NULL; ++ ++ if (!vmd_orom && add_vmd_orom(&vmd_orom, hba) != 0) ++ return NULL; ++ ++ add_orom_device_id(vmd_orom, hba->dev_id); ++ vmd_orom->type = SYS_DEV_VMD; ++ return &vmd_orom->orom; ++} ++ + const struct imsm_orom *find_imsm_capability(struct sys_dev *hba) + { + const struct imsm_orom *cap = get_orom_by_device_id(hba->dev_id); +@@ -709,9 +809,19 @@ const struct imsm_orom *find_imsm_capability(struct sys_dev *hba) + + if (hba->type == SYS_DEV_NVME) + return find_imsm_nvme(hba); +- if ((cap = find_imsm_efi(hba)) != NULL) ++ ++ cap = find_imsm_efi(hba); ++ if (cap) + return cap; +- if ((cap = find_imsm_hba_orom(hba)) != NULL) ++ ++ if (hba->type == SYS_DEV_VMD) { ++ cap = find_imsm_vmd(hba); ++ if (cap) ++ return cap; ++ } ++ ++ cap = find_imsm_hba_orom(hba); ++ if (cap) + return cap; + + return NULL; +diff --git a/platform-intel.h b/platform-intel.h +index ba97fb04..ce29d3da 100644 +--- a/platform-intel.h ++++ b/platform-intel.h +@@ -27,6 +27,7 @@ struct imsm_orom { + __u8 signature[4]; + #define IMSM_OROM_SIGNATURE "$VER" + #define IMSM_NVME_OROM_COMPAT_SIGNATURE "$NVM" ++ #define IMSM_VMD_OROM_COMPAT_SIGNATURE "$VMD" + __u8 table_ver_major; /* Currently 2 (can change with future revs) */ + __u8 table_ver_minor; /* Currently 2 (can change with future revs) */ + __u16 major_ver; /* Example: 8 as in 8.6.0.1020 */ +@@ -68,11 +69,13 @@ struct imsm_orom { + __u16 tds; /* Total Disks Supported */ + #define IMSM_OROM_TOTAL_DISKS 6 + #define IMSM_OROM_TOTAL_DISKS_NVME 12 ++ #define IMSM_OROM_TOTAL_DISKS_VMD 48 + __u8 vpa; /* # Volumes Per Array supported */ + #define IMSM_OROM_VOLUMES_PER_ARRAY 2 + __u8 vphba; /* # Volumes Per Host Bus Adapter supported */ + #define IMSM_OROM_VOLUMES_PER_HBA 4 + #define IMSM_OROM_VOLUMES_PER_HBA_NVME 4 ++ #define IMSM_OROM_VOLUMES_PER_HBA_VMD 24 + /* Attributes supported. This should map to the + * attributes in the MPB. Also, lower 16 bits + * should match/duplicate RLC bits above. +@@ -185,7 +188,13 @@ static inline int imsm_orom_is_enterprise(const struct imsm_orom *orom) + static inline int imsm_orom_is_nvme(const struct imsm_orom *orom) + { + return memcmp(orom->signature, IMSM_NVME_OROM_COMPAT_SIGNATURE, +- sizeof(orom->signature)) == 0; ++ sizeof(orom->signature)) == 0; ++} ++ ++static inline int imsm_orom_is_vmd_without_efi(const struct imsm_orom *orom) ++{ ++ return memcmp(orom->signature, IMSM_VMD_OROM_COMPAT_SIGNATURE, ++ sizeof(orom->signature)) == 0; + } + + static inline int imsm_orom_has_tpv_support(const struct imsm_orom *orom) +diff --git a/super-intel.c b/super-intel.c +index ce813172..77b0066f 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -2672,9 +2672,14 @@ static void print_imsm_capability(const struct imsm_orom *orom) + else + printf("Rapid Storage Technology%s\n", + imsm_orom_is_enterprise(orom) ? " enterprise" : ""); +- if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) +- printf(" Version : %d.%d.%d.%d\n", orom->major_ver, +- orom->minor_ver, orom->hotfix_ver, orom->build); ++ if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) { ++ if (imsm_orom_is_vmd_without_efi(orom)) ++ printf(" Version : %d.%d\n", orom->major_ver, ++ orom->minor_ver); ++ else ++ printf(" Version : %d.%d.%d.%d\n", orom->major_ver, ++ orom->minor_ver, orom->hotfix_ver, orom->build); ++ } + printf(" RAID Levels :%s%s%s%s%s\n", + imsm_orom_has_raid0(orom) ? " raid0" : "", + imsm_orom_has_raid1(orom) ? " raid1" : "", +-- +2.40.1 + diff --git a/SOURCES/0142-Add-compiler-defenses-flags.patch b/SOURCES/0142-Add-compiler-defenses-flags.patch new file mode 100644 index 0000000..6102288 --- /dev/null +++ b/SOURCES/0142-Add-compiler-defenses-flags.patch @@ -0,0 +1,109 @@ +From 55a1150c7438afcb7756fccd49713ede20a58e4a Mon Sep 17 00:00:00 2001 +From: Mateusz Grzonka +Date: Mon, 17 Jul 2023 15:19:10 +0200 +Subject: [PATCH 142/165] Add compiler defenses flags + +It is essential to avoid buffer overflows and similar bugs as much as +possible. + +According to Intel rules we are obligated to verify certain +compiler flags, so it will be much easier if they are added to the +Makefile. + +Add gcc flags for prevention of buffer overflows, format string vulnerabilities, +stack protection to prevent stack overwrites and aslr enablement through -fPIE. +Also make the flags configurable. + +The changes were verified on gcc versions 7.5, 8.3, 9.2, 10 and 12.2. + +Signed-off-by: Mateusz Grzonka +Signed-off-by: Jes Sorensen +--- + Makefile | 41 +++++++++++++++++++++++++++++------------ + 1 file changed, 29 insertions(+), 12 deletions(-) + +diff --git a/Makefile b/Makefile +index 5eac1a4e..b3aa36f6 100644 +--- a/Makefile ++++ b/Makefile +@@ -30,7 +30,7 @@ + + # define "CXFLAGS" to give extra flags to CC. + # e.g. make CXFLAGS=-O to optimise +-CXFLAGS ?=-O2 ++CXFLAGS ?=-O2 -D_FORTIFY_SOURCE=2 + TCC = tcc + UCLIBC_GCC = $(shell for nm in i386-uclibc-linux-gcc i386-uclibc-gcc; do which $$nm > /dev/null && { echo $$nm ; exit; } ; done; echo false No uclibc found ) + #DIET_GCC = diet gcc +@@ -50,14 +50,30 @@ ifeq ($(origin CC),default) + CC := $(CROSS_COMPILE)gcc + endif + CXFLAGS ?= -ggdb +-CWFLAGS = -Wall -Werror -Wstrict-prototypes -Wextra -Wno-unused-parameter ++CWFLAGS ?= -Wall -Werror -Wstrict-prototypes -Wextra -Wno-unused-parameter -Wformat -Wformat-security -Werror=format-security -fstack-protector-strong -fPIE -Warray-bounds + ifdef WARN_UNUSED +-CWFLAGS += -Wp,-D_FORTIFY_SOURCE=2 -O3 ++CWFLAGS += -Wp -O3 + endif + +-FALLTHROUGH := $(shell gcc -v --help 2>&1 | grep "implicit-fallthrough" | wc -l) +-ifneq "$(FALLTHROUGH)" "0" +-CWFLAGS += -Wimplicit-fallthrough=0 ++ifeq ($(origin FALLTHROUGH), undefined) ++ FALLTHROUGH := $(shell gcc -Q --help=warnings 2>&1 | grep "implicit-fallthrough" | wc -l) ++ ifneq "$(FALLTHROUGH)" "0" ++ CWFLAGS += -Wimplicit-fallthrough=0 ++ endif ++endif ++ ++ifeq ($(origin FORMATOVERFLOW), undefined) ++ FORMATOVERFLOW := $(shell gcc -Q --help=warnings 2>&1 | grep "format-overflow" | wc -l) ++ ifneq "$(FORMATOVERFLOW)" "0" ++ CWFLAGS += -Wformat-overflow ++ endif ++endif ++ ++ifeq ($(origin STRINGOPOVERFLOW), undefined) ++ STRINGOPOVERFLOW := $(shell gcc -Q --help=warnings 2>&1 | grep "stringop-overflow" | wc -l) ++ ifneq "$(STRINGOPOVERFLOW)" "0" ++ CWFLAGS += -Wstringop-overflow ++ endif + endif + + ifdef DEBIAN +@@ -116,10 +132,12 @@ CFLAGS += -DUSE_PTHREADS + MON_LDFLAGS += -pthread + endif + ++LDFLAGS = -Wl,-z,now,-z,noexecstack ++ + # If you want a static binary, you might uncomment these +-# LDFLAGS = -static ++# LDFLAGS += -static + # STRIP = -s +-LDLIBS = -ldl ++LDLIBS = -ldl -pie + + # To explicitly disable libudev, set -DNO_LIBUDEV in CXFLAGS + ifeq (, $(findstring -DNO_LIBUDEV, $(CXFLAGS))) +@@ -209,14 +227,13 @@ mdadm.Os : $(SRCS) $(INCL) + $(CC) -o mdadm.Os $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -Os $(SRCS) $(LDLIBS) + + mdadm.O2 : $(SRCS) $(INCL) mdmon.O2 +- $(CC) -o mdadm.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -O2 -D_FORTIFY_SOURCE=2 $(SRCS) $(LDLIBS) ++ $(CC) -o mdadm.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -O2 $(SRCS) $(LDLIBS) + + mdmon.O2 : $(MON_SRCS) $(INCL) mdmon.h +- $(CC) -o mdmon.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -DHAVE_STDINT_H -O2 -D_FORTIFY_SOURCE=2 $(MON_SRCS) $(LDLIBS) ++ $(CC) -o mdmon.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -DHAVE_STDINT_H -O2 $(MON_SRCS) $(LDLIBS) + +-# use '-z now' to guarantee no dynamic linker interactions with the monitor thread + mdmon : $(MON_OBJS) | check_rundir +- $(CC) $(CFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -Wl,-z,now -o mdmon $(MON_OBJS) $(LDLIBS) ++ $(CC) $(CFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -o mdmon $(MON_OBJS) $(LDLIBS) + msg.o: msg.c msg.h + + test_stripe : restripe.c xmalloc.o mdadm.h +-- +2.40.1 + diff --git a/SOURCES/0143-Assemble-fix-redundant-memory-free.patch b/SOURCES/0143-Assemble-fix-redundant-memory-free.patch new file mode 100644 index 0000000..4583718 --- /dev/null +++ b/SOURCES/0143-Assemble-fix-redundant-memory-free.patch @@ -0,0 +1,34 @@ +From 024d652e16dd9e3bd1ecdfce4d6f7a8cb498ba42 Mon Sep 17 00:00:00 2001 +From: Kinga Tanska +Date: Tue, 12 Sep 2023 04:27:01 +0200 +Subject: [PATCH 143/165] Assemble: fix redundant memory free + +Commit e9fb93af0f76 ("Fix memory leak in file Assemble") +fixes few memory leaks in Assemble, but it introduces +problem with assembling RAID volume. It was caused by +clearing metadata too fast, not only on fail in +select_devices() function. +This commit removes redundant memory free. + +Signed-off-by: Kinga Tanska +Signed-off-by: Jes Sorensen +--- + Assemble.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Assemble.c b/Assemble.c +index 61e8cd17..5be58e40 100644 +--- a/Assemble.c ++++ b/Assemble.c +@@ -428,8 +428,6 @@ static int select_devices(struct mddev_dev *devlist, + + /* make sure we finished the loop */ + tmpdev = NULL; +- free(st); +- st = NULL; + goto loop; + } else { + content = *contentp; +-- +2.40.1 + diff --git a/SOURCES/0144-tests-add-a-new-test-for-rdev-lifetime.patch b/SOURCES/0144-tests-add-a-new-test-for-rdev-lifetime.patch new file mode 100644 index 0000000..dbbd3c5 --- /dev/null +++ b/SOURCES/0144-tests-add-a-new-test-for-rdev-lifetime.patch @@ -0,0 +1,92 @@ +From 7fe21767d3ab65a686518d2e36d18a07f535972e Mon Sep 17 00:00:00 2001 +From: Yu Kuai +Date: Mon, 29 May 2023 21:28:19 +0800 +Subject: [PATCH 144/165] tests: add a new test for rdev lifetime + +This test add and remove a underlying disk to raid concurretly, verify +that the following problem is fixed: + +run mdadm test 23rdev-lifetime at Fri Apr 28 03:25:30 UTC 2023 +md: could not open device unknown-block(1,0). +sysfs: cannot create duplicate filename '/devices/virtual/block/md0/md/dev-ram0' +CPU: 26 PID: 10521 Comm: test Not tainted 6.3.0-rc2-00134-g7b3a8828043c #115 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.1-2.fc37 04/014 +Call Trace: + + dump_stack_lvl+0xe7/0x180 + dump_stack+0x18/0x30 + sysfs_warn_dup+0xa2/0xd0 + sysfs_create_dir_ns+0x119/0x140 + kobject_add_internal+0x143/0x4d0 + kobject_add_varg+0x35/0x70 + kobject_add+0x64/0xd0 + bind_rdev_to_array+0x254/0x840 [md_mod] + new_dev_store+0x14d/0x350 [md_mod] + md_attr_store+0xc1/0x1a0 [md_mod] + sysfs_kf_write+0x51/0x70 + kernfs_fop_write_iter+0x188/0x270 + vfs_write+0x27e/0x460 + ksys_write+0x85/0x180 + __x64_sys_write+0x21/0x30 + do_syscall_64+0x6c/0xe0 + entry_SYSCALL_64_after_hwframe+0x63/0xcd +RIP: 0033:0x7f26bacf5387 +Code: 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 84 +RSP: 002b:00007ffe98d79e68 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f26bacf5387 +RDX: 0000000000000004 RSI: 000055bd10282bf0 RDI: 0000000000000001 +RBP: 000055bd10282bf0 R08: 000000000000000a R09: 00007f26bad8b4e0 +R10: 00007f26bad8b3e0 R11: 0000000000000246 R12: 0000000000000004 +R13: 00007f26badc8520 R14: 0000000000000004 R15: 00007f26badc8700 + + +Signed-off-by: Yu Kuai +Signed-off-by: Jes Sorensen +--- + tests/23rdev-lifetime | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + create mode 100644 tests/23rdev-lifetime + +diff --git a/tests/23rdev-lifetime b/tests/23rdev-lifetime +new file mode 100644 +index 00000000..1750b0db +--- /dev/null ++++ b/tests/23rdev-lifetime +@@ -0,0 +1,34 @@ ++devname=${dev0##*/} ++devt=`cat /sys/block/$devname/dev` ++pid="" ++runtime=2 ++ ++clean_up_test() { ++ pill -9 $pid ++ echo clear > /sys/block/md0/md/array_state ++} ++ ++trap 'clean_up_test' EXIT ++ ++add_by_sysfs() { ++ while true; do ++ echo $devt > /sys/block/md0/md/new_dev ++ done ++} ++ ++remove_by_sysfs(){ ++ while true; do ++ echo remove > /sys/block/md0/md/dev-${devname}/state ++ done ++} ++ ++echo md0 > /sys/module/md_mod/parameters/new_array || die "create md0 failed" ++ ++add_by_sysfs & ++pid="$pid $!" ++ ++remove_by_sysfs & ++pid="$pid $!" ++ ++sleep $runtime ++exit 0 +-- +2.40.1 + diff --git a/SOURCES/0145-tests-support-to-skip-checking-dmesg.patch b/SOURCES/0145-tests-support-to-skip-checking-dmesg.patch new file mode 100644 index 0000000..39b38d2 --- /dev/null +++ b/SOURCES/0145-tests-support-to-skip-checking-dmesg.patch @@ -0,0 +1,38 @@ +From 0ef9465f6355db612e53afc32e3084721c3dd7c7 Mon Sep 17 00:00:00 2001 +From: Yu Kuai +Date: Mon, 29 May 2023 21:28:20 +0800 +Subject: [PATCH 145/165] tests: support to skip checking dmesg + +Prepare to add a regression test for raid10 that require error injection +to trigger error path, and kernel will complain about io error, checking +dmesg for error log will make it impossible to pass this test. + +Signed-off-by: Yu Kuai +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + test | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/test b/test +index 61d9ee83..b244453b 100755 +--- a/test ++++ b/test +@@ -107,8 +107,12 @@ do_test() { + echo -ne "$_script... " + if ( set -ex ; . $_script ) &> $targetdir/log + then +- dmesg | grep -iq "error\|call trace\|segfault" && +- die "dmesg prints errors when testing $_basename!" ++ if [ -f "${_script}.inject_error" ]; then ++ echo "dmesg checking is skipped because test inject error" ++ else ++ dmesg | grep -iq "error\|call trace\|segfault" && ++ die "dmesg prints errors when testing $_basename!" ++ fi + echo "succeeded" + _fail=0 + else +-- +2.40.1 + diff --git a/SOURCES/0146-tests-add-a-regression-test-for-raid10-deadlock.patch b/SOURCES/0146-tests-add-a-regression-test-for-raid10-deadlock.patch new file mode 100644 index 0000000..04e4304 --- /dev/null +++ b/SOURCES/0146-tests-add-a-regression-test-for-raid10-deadlock.patch @@ -0,0 +1,122 @@ +From 3973f65293ce69ddd7c19be9a7a796abfe80e370 Mon Sep 17 00:00:00 2001 +From: Yu Kuai +Date: Mon, 29 May 2023 21:28:21 +0800 +Subject: [PATCH 146/165] tests: add a regression test for raid10 deadlock + +The deadlock is described in [1], it's fixed first by [2], however, +it turns out this commit will trigger other problems[3], hence this +commit will be reverted and the deadlock is supposed to be fixed by [1]. + +[1] https://lore.kernel.org/linux-raid/20230322064122.2384589-5-yukuai1@huaweicloud.com/ +[2] https://lore.kernel.org/linux-raid/20220621031129.24778-1-guoqing.jiang@linux.dev/ +[3] https://lore.kernel.org/linux-raid/20230322064122.2384589-2-yukuai1@huaweicloud.com/ + +Signed-off-by: Yu Kuai +Signed-off-by: Jes Sorensen +--- + tests/24raid10deadlock | 88 +++++++++++++++++++++++++++++ + tests/24raid10deadlock.inject_error | 0 + 2 files changed, 88 insertions(+) + create mode 100644 tests/24raid10deadlock + create mode 100644 tests/24raid10deadlock.inject_error + +diff --git a/tests/24raid10deadlock b/tests/24raid10deadlock +new file mode 100644 +index 00000000..ee330aa9 +--- /dev/null ++++ b/tests/24raid10deadlock +@@ -0,0 +1,88 @@ ++devs="$dev0 $dev1 $dev2 $dev3" ++runtime=120 ++pid="" ++action_pid="" ++ ++set_up_injection() ++{ ++ echo -1 > /sys/kernel/debug/fail_make_request/times ++ echo 1 > /sys/kernel/debug/fail_make_request/probability ++ echo 0 > /sys/kernel/debug/fail_make_request/verbose ++ echo 1 > /sys/block/${1##*/}/make-it-fail ++} ++ ++clean_up_injection() ++{ ++ echo 0 > /sys/block/${1##*/}/make-it-fail ++ echo 0 > /sys/kernel/debug/fail_make_request/times ++ echo 0 > /sys/kernel/debug/fail_make_request/probability ++ echo 2 > /sys/kernel/debug/fail_make_request/verbose ++} ++ ++test_rdev() ++{ ++ while true; do ++ mdadm -f $md0 $1 &> /dev/null ++ mdadm -r $md0 $1 &> /dev/null ++ mdadm --zero-superblock $1 &> /dev/null ++ mdadm -a $md0 $1 &> /dev/null ++ sleep $2 ++ done ++} ++ ++test_write_action() ++{ ++ while true; do ++ echo frozen > /sys/block/md0/md/sync_action ++ echo idle > /sys/block/md0/md/sync_action ++ sleep 0.1 ++ done ++} ++ ++set_up_test() ++{ ++ fio -h &> /dev/null || die "fio not found" ++ ++ # create a simple raid10 ++ mdadm -Cv -R -n 4 -l10 $md0 $devs || die "create raid10 failed" ++} ++ ++clean_up_test() ++{ ++ clean_up_injection $dev0 ++ pkill -9 fio ++ kill -9 $pid ++ kill -9 $action_pid ++ ++ sleep 1 ++ ++ if ps $action_pid | tail -1 | awk '{print $3}' | grep D; then ++ die "thread that is writing sysfs is stuck in D state, deadlock is triggered" ++ fi ++ mdadm -S $md0 ++} ++ ++cat /sys/kernel/debug/fail_make_request/times || die "fault injection is not enabled" ++ ++trap 'clean_up_test' EXIT ++ ++set_up_test || die "set up test failed" ++ ++# backgroup io pressure ++fio -filename=$md0 -rw=randwrite -direct=1 -name=test -bs=4k -numjobs=16 -iodepth=16 & ++ ++# trigger add/remove device by io failure ++set_up_injection $dev0 ++test_rdev $dev0 2 & ++pid="$pid $!" ++ ++# add/remove device directly ++test_rdev $dev3 10 & ++pid="$pid $!" ++ ++test_write_action & ++action_pid="$!" ++ ++sleep $runtime ++ ++exit 0 +diff --git a/tests/24raid10deadlock.inject_error b/tests/24raid10deadlock.inject_error +new file mode 100644 +index 00000000..e69de29b +-- +2.40.1 + diff --git a/SOURCES/0147-tests-add-a-regression-test-for-raid456-deadlock.patch b/SOURCES/0147-tests-add-a-regression-test-for-raid456-deadlock.patch new file mode 100644 index 0000000..78c5836 --- /dev/null +++ b/SOURCES/0147-tests-add-a-regression-test-for-raid456-deadlock.patch @@ -0,0 +1,87 @@ +From 9d0fb58f3b1314678564b4ac7bfb19942acc8926 Mon Sep 17 00:00:00 2001 +From: Yu Kuai +Date: Mon, 29 May 2023 21:28:22 +0800 +Subject: [PATCH 147/165] tests: add a regression test for raid456 deadlock + +The deadlock is described in [1], as the last patch described, it's +fixed first by [2], however this fix will be reverted and the deadlock +is supposed to be fixed by [3]. + +[1] https://lore.kernel.org/linux-raid/5ed54ffc-ce82-bf66-4eff-390cb23bc1ac@molgen.mpg.de/T/#t +[2] https://lore.kernel.org/linux-raid/20220621031129.24778-1-guoqing.jiang@linux.dev/ +[3] https://lore.kernel.org/linux-raid/20230322064122.2384589-5-yukuai1@huaweicloud.com/ + +Signed-off-by: Yu Kuai +Signed-off-by: Jes Sorensen +--- + tests/24raid456deadlock | 58 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 58 insertions(+) + create mode 100644 tests/24raid456deadlock + +diff --git a/tests/24raid456deadlock b/tests/24raid456deadlock +new file mode 100644 +index 00000000..80e6e97e +--- /dev/null ++++ b/tests/24raid456deadlock +@@ -0,0 +1,58 @@ ++devs="$dev0 $dev1 $dev2 $dev3 $dev4 $dev5" ++runtime=120 ++pid="" ++old=`cat /proc/sys/vm/dirty_background_ratio` ++ ++test_write_action() ++{ ++ while true; do ++ echo check > /sys/block/md0/md/sync_action &> /dev/null ++ sleep 0.1 ++ echo idle > /sys/block/md0/md/sync_action &> /dev/null ++ done ++} ++ ++test_write_back() ++{ ++ fio -filename=$md0 -bs=4k -rw=write -numjobs=1 -name=test \ ++ -time_based -runtime=$runtime &> /dev/null ++} ++ ++set_up_test() ++{ ++ fio -h &> /dev/null || die "fio not found" ++ ++ # create a simple raid6 ++ mdadm -Cv -R -n 6 -l6 $md0 $devs --assume-clean || die "create raid6 failed" ++ ++ # trigger dirty pages write back ++ echo 0 > /proc/sys/vm/dirty_background_ratio ++} ++ ++clean_up_test() ++{ ++ echo $old > /proc/sys/vm/dirty_background_ratio ++ ++ pkill -9 fio ++ kill -9 $pid ++ ++ sleep 1 ++ ++ if ps $pid | tail -1 | awk '{print $3}' | grep D; then ++ die "thread that is writing sysfs is stuck in D state, deadlock is triggered" ++ fi ++ mdadm -S $md0 ++} ++ ++trap 'clean_up_test' EXIT ++ ++set_up_test || die "set up test failed" ++ ++test_write_back & ++ ++test_write_action & ++pid="$!" ++ ++sleep $runtime ++ ++exit 0 +-- +2.40.1 + diff --git a/SOURCES/0148-tests-add-a-regression-test-that-raid456-can-t-assem.patch b/SOURCES/0148-tests-add-a-regression-test-that-raid456-can-t-assem.patch new file mode 100644 index 0000000..a10b3b2 --- /dev/null +++ b/SOURCES/0148-tests-add-a-regression-test-that-raid456-can-t-assem.patch @@ -0,0 +1,59 @@ +From 4db8a3d452daaf2def41ca45c36e36c5781627ac Mon Sep 17 00:00:00 2001 +From: Yu Kuai +Date: Mon, 29 May 2023 21:28:23 +0800 +Subject: [PATCH 148/165] tests: add a regression test that raid456 can't + assemble + +If recovery is interrupted and reshape is started, then this array can't +assemble anymore. The problem is supposed to be fixed by [1]. + +[1] https://lore.kernel.org/linux-raid/20230529031045.1760883-1-yukuai1@huaweicloud.com/ + +Signed-off-by: Yu Kuai +Signed-off-by: Jes Sorensen +--- + tests/25raid456-reshape-while-recovery | 32 ++++++++++++++++++++++++++ + 1 file changed, 32 insertions(+) + create mode 100644 tests/25raid456-reshape-while-recovery + +diff --git a/tests/25raid456-reshape-while-recovery b/tests/25raid456-reshape-while-recovery +new file mode 100644 +index 00000000..b9f871f2 +--- /dev/null ++++ b/tests/25raid456-reshape-while-recovery +@@ -0,0 +1,32 @@ ++devs="$dev0 $dev1 $dev2" ++ ++set_up_test() ++{ ++ mdadm -Cv -R -n 3 -l5 $md0 $devs --assume-clean --size=50M || die "create array failed" ++ mdadm -a $md0 $dev3 $dev4 || die "failed to bind new disk to array" ++ echo 1000 > /sys/block/md0/md/sync_speed_max ++} ++ ++clean_up_test() ++{ ++ mdadm -S $md0 ++} ++ ++trap 'clean_up_test' EXIT ++ ++set_up_test || die "set up test failed" ++ ++# set up replacement ++echo want_replacement > /sys/block/md0/md/rd0/state ++sleep 1 ++ ++# trigger reshape ++echo frozen > /sys/block/md0/md/sync_action ++mdadm --grow -l 6 $md0 ++sleep 1 ++ ++# reassemeble array ++mdadm -S $md0 || die "can't stop array" ++mdadm --assemble $md0 $devs $dev3 $dev4 || die "can't assemble array" ++ ++exit 0 +-- +2.40.1 + diff --git a/SOURCES/0149-tests-add-a-regression-test-that-raid456-can-t-assem.patch b/SOURCES/0149-tests-add-a-regression-test-that-raid456-can-t-assem.patch new file mode 100644 index 0000000..3d52868 --- /dev/null +++ b/SOURCES/0149-tests-add-a-regression-test-that-raid456-can-t-assem.patch @@ -0,0 +1,58 @@ +From 8d45abd0c317d3f4971b779b4f8d1e33b5490dac Mon Sep 17 00:00:00 2001 +From: Yu Kuai +Date: Mon, 29 May 2023 21:28:24 +0800 +Subject: [PATCH 149/165] tests: add a regression test that raid456 can't + assemble again + +This is a regression test for commit 0aecb06e2249 ("md/raid5: don't allow +replacement while reshape is in progress"). + +Signed-off-by: Yu Kuai +Signed-off-by: Jes Sorensen +--- + tests/25raid456-recovery-while-reshape | 33 ++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + create mode 100644 tests/25raid456-recovery-while-reshape + +diff --git a/tests/25raid456-recovery-while-reshape b/tests/25raid456-recovery-while-reshape +new file mode 100644 +index 00000000..3f6251bf +--- /dev/null ++++ b/tests/25raid456-recovery-while-reshape +@@ -0,0 +1,33 @@ ++devs="$dev0 $dev1 $dev2" ++ ++set_up_test() ++{ ++ mdadm -Cv -R -n 3 -l5 $md0 $devs --assume-clean --size=50M || die "create array failed" ++ mdadm -a $md0 $dev3 $dev4 || die "failed to bind new disk to array" ++ echo 1000 > /sys/block/md0/md/sync_speed_max ++} ++ ++clean_up_test() ++{ ++ mdadm -S $md0 ++} ++ ++trap 'clean_up_test' EXIT ++ ++set_up_test || die "set up test failed" ++ ++# trigger reshape ++mdadm --grow -l 6 $md0 ++sleep 1 ++ ++# set up replacement ++echo frozen > /sys/block/md0/md/sync_action ++echo want_replacement > /sys/block/md0/md/rd0/state ++echo reshape > /sys/block/md0/md/sync_action ++sleep 1 ++ ++# reassemeble array ++mdadm -S $md0 || die "can't stop array" ++mdadm --assemble $md0 $devs $dev3 $dev4 || die "can't assemble array" ++ ++exit 0 +-- +2.40.1 + diff --git a/SOURCES/0150-tests-add-a-regression-test-that-reshape-can-corrupt.patch b/SOURCES/0150-tests-add-a-regression-test-that-reshape-can-corrupt.patch new file mode 100644 index 0000000..20f0272 --- /dev/null +++ b/SOURCES/0150-tests-add-a-regression-test-that-reshape-can-corrupt.patch @@ -0,0 +1,60 @@ +From 481433482942c2ee2990965af394eff059990901 Mon Sep 17 00:00:00 2001 +From: Yu Kuai +Date: Mon, 29 May 2023 21:28:25 +0800 +Subject: [PATCH 150/165] tests: add a regression test that reshape can corrupt + data + +This is a regression test for commit 1544e95c6dd8 ("md: fix data +corruption for raid456 when reshape restart while grow up"). + +Signed-off-by: Yu Kuai +Signed-off-by: Jes Sorensen +--- + tests/25raid456-reshape-corrupt-data | 35 ++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + create mode 100644 tests/25raid456-reshape-corrupt-data + +diff --git a/tests/25raid456-reshape-corrupt-data b/tests/25raid456-reshape-corrupt-data +new file mode 100644 +index 00000000..fdb875fb +--- /dev/null ++++ b/tests/25raid456-reshape-corrupt-data +@@ -0,0 +1,35 @@ ++devs="$dev0 $dev1 $dev2" ++ ++set_up_test() ++{ ++ mdadm -Cv -R -n 3 -l5 $md0 $devs --size=50M || die "create array failed" ++ mdadm -a $md0 $dev3 || die "failed to bind new disk to array" ++ mkfs.xfs -f $md0 || die "mkfs failed" ++ xfs_ncheck $md0 || die "check fs failed" ++} ++ ++clean_up_test() ++{ ++ mdadm -S $md0 ++} ++ ++trap 'clean_up_test' EXIT ++ ++set_up_test || die "set up test failed" ++ ++# trigger reshape ++echo 1000 > /sys/block/md0/md/sync_speed_max ++mdadm --grow -l 6 $md0 ++sleep 1 ++ ++# stop and start reshape ++echo frozen > /sys/block/md0/md/sync_action ++echo system > /sys/block/md0/md/sync_speed_max ++echo reshape > /sys/block/md0/md/sync_action ++ ++mdadm -W $md0 ++ ++# check if data is corrupted ++xfs_ncheck $md0 || die "data is corrupted after reshape" ++ ++exit 0 +-- +2.40.1 + diff --git a/SOURCES/0151-tests-add-a-regression-test-for-raid456-deadlock-aga.patch b/SOURCES/0151-tests-add-a-regression-test-for-raid456-deadlock-aga.patch new file mode 100644 index 0000000..ab916c5 --- /dev/null +++ b/SOURCES/0151-tests-add-a-regression-test-for-raid456-deadlock-aga.patch @@ -0,0 +1,59 @@ +From c6c7bce5a3064ac9d2956ae42ecab27f2e33dc2b Mon Sep 17 00:00:00 2001 +From: Yu Kuai +Date: Mon, 29 May 2023 21:28:26 +0800 +Subject: [PATCH 151/165] tests: add a regression test for raid456 deadlock + again + +This is a regression test for commit ("md/raid5: fix a deadlock in the +case that reshape is interrupted"). + +Signed-off-by: Yu Kuai +Signed-off-by: Jes Sorensen +--- + tests/25raid456-reshape-deadlock | 34 ++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + create mode 100644 tests/25raid456-reshape-deadlock + +diff --git a/tests/25raid456-reshape-deadlock b/tests/25raid456-reshape-deadlock +new file mode 100644 +index 00000000..bfa0cc56 +--- /dev/null ++++ b/tests/25raid456-reshape-deadlock +@@ -0,0 +1,34 @@ ++devs="$dev0 $dev1 $dev2" ++ ++set_up_test() ++{ ++ mdadm -Cv -R -n 3 -l5 $md0 $devs --size=50M || die "create array failed" ++ mdadm -a $md0 $dev3 || die "failed to bind new disk to array" ++ echo 1000 > /sys/block/md0/md/sync_speed_max ++} ++ ++clean_up_test() ++{ ++ echo idle > /sys/block/md0/md/sync_action ++ mdadm -S $md0 ++} ++ ++trap 'clean_up_test' EXIT ++ ++set_up_test || die "set up test failed" ++ ++# trigger reshape ++mdadm --grow -l 6 $md0 ++sleep 1 ++ ++# stop reshape ++echo frozen > /sys/block/md0/md/sync_action ++ ++# read accross reshape ++dd if=$md0 of=/dev/NULL bs=1m count=100 iflag=direct &> /dev/null & ++sleep 2 ++ ++# suspend array ++echo 1 > /sys/block/md0/md/suspend_lo ++ ++exit 0 +-- +2.40.1 + diff --git a/SOURCES/0152-tests-create-names_template.patch b/SOURCES/0152-tests-create-names_template.patch new file mode 100644 index 0000000..a3db688 --- /dev/null +++ b/SOURCES/0152-tests-create-names_template.patch @@ -0,0 +1,193 @@ +From d5fee8654e41dc4067dfdc3312542f1f43ebe884 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 1 Jun 2023 09:27:45 +0200 +Subject: [PATCH 152/165] tests: create names_template + +Create templates directory and names_template. Move code from +00createnames. This code will be reused for 00confnames in next patch. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + tests/00createnames | 86 +++++++--------------------------- + tests/templates/names_template | 53 +++++++++++++++++++++ + 2 files changed, 70 insertions(+), 69 deletions(-) + create mode 100644 tests/templates/names_template + +diff --git a/tests/00createnames b/tests/00createnames +index 64b81b92..064eeef2 100644 +--- a/tests/00createnames ++++ b/tests/00createnames +@@ -1,93 +1,41 @@ + set -x -e ++. tests/templates/names_template + + # 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" ++names_create "/dev/md/name" ++names_verify "/dev/md127" "name" "name" + mdadm -S "/dev/md127" + +-_create "name" +-_verify "/dev/md127" "name" "name" ++names_create "name" ++names_verify "/dev/md127" "name" "name" + mdadm -S "/dev/md127" + + # Use 'mdX' as name. +-_create "/dev/md/md0" +-_verify "/dev/md127" "md0" "md0" ++names_create "/dev/md/md0" ++names_verify "/dev/md127" "md0" "md0" + mdadm -S "/dev/md127" + +-_create "md0" +-_verify "/dev/md127" "md0" "md0" ++names_create "md0" ++names_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" ++names_create "/dev/md/devnode" "name" ++names_verify "/dev/md127" "devnode" "name" + mdadm -S "/dev/md127" + +-_create "devnode" "name" +-_verify "/dev/md127" "devnode" "name" ++names_create "devnode" "name" ++names_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" ++names_create "/dev/md0" ++names_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" ++names_create "/dev/md0" "name" ++names_verify "/dev/md0" "empty" "name" + mdadm -S "/dev/md0" +diff --git a/tests/templates/names_template b/tests/templates/names_template +new file mode 100644 +index 00000000..9f09be9e +--- /dev/null ++++ b/tests/templates/names_template +@@ -0,0 +1,53 @@ ++# NAME is optional. Testing with native 1.2 superblock. ++function names_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" --metadata=1.2 -l0 -n 1 $dev0 --force ++ fi ++ ++ if [[ "$?" != "0" ]]; then ++ echo "Cannot create device." ++ exit 1 ++ fi ++} ++ ++# Three properties to check: ++# - devnode name ++# - link in /dev/md/ (MD_DEVNAME property from --detail --export) ++# - name in metadata (MD_NAME property from --detail --export)- that works only with 1.2 sb. ++function names_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" ++ fi ++ ++ if [[ "$RES" != "$EXPECTED" ]]; then ++ echo "$RES doesn't match $EXPECTED." ++ exit 1 ++ fi ++ ++ local RES="$(mdadm -D --export $DEVNODE_NAME | 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 ++} +-- +2.40.1 + diff --git a/SOURCES/0153-tests-create-00confnames.patch b/SOURCES/0153-tests-create-00confnames.patch new file mode 100644 index 0000000..1534d93 --- /dev/null +++ b/SOURCES/0153-tests-create-00confnames.patch @@ -0,0 +1,164 @@ +From 569a23425939e4bfc7b4d7f871d8510bb968f892 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 1 Jun 2023 09:27:46 +0200 +Subject: [PATCH 153/165] tests: create 00confnames + +The test is an attempt to document current implementation of devnode +and name handling for config entries. It is focused on incremental- +default way of array assembling on boot. +The expectations are aligned to current implementation for native +metadata because it is the most complicated scenario- both variables +can be set. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + tests/00confnames | 107 +++++++++++++++++++++++++++++++++ + tests/templates/names_template | 20 ++++++ + 2 files changed, 127 insertions(+) + create mode 100644 tests/00confnames + +diff --git a/tests/00confnames b/tests/00confnames +new file mode 100644 +index 00000000..25a7127b +--- /dev/null ++++ b/tests/00confnames +@@ -0,0 +1,107 @@ ++set -x -e ++. tests/templates/names_template ++ ++# Test how and from config are handled during Incremental assemblation. ++# 1-6 only tests (no in config). ++# 6-10 and combinations are tested. ++# 11-13 corner cases. ++ ++names_create "/dev/md/name" ++local _UUID="$(mdadm -D --export /dev/md127 | grep MD_UUID | cut -d'=' -f2)" ++[[ "$_UUID" == "" ]] && echo "Cannot obtain UUID for $DEVNODE_NAME" && exit 1 ++ ++ ++# 1. definition consistent with metadata name. ++names_make_conf $_UUID "/dev/md/name" "empty" $config ++mdadm -S "/dev/md127" ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 2. Same as 1, but use short name form of . ++names_make_conf $_UUID "name" "empty" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 3. Same as 1, but use different than metadata provides. ++names_make_conf $_UUID "/dev/md/other" "empty" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "other" "name" ++mdadm -S "/dev/md127" ++ ++# 4. Same as 3, but use short name form of . ++names_make_conf $_UUID "other" "empty" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "other" "name" ++mdadm -S "/dev/md127" ++ ++# 5. Force particular node creation by setting to /dev/mdX. Link is not created in this ++# case. ++names_make_conf $_UUID "/dev/md4" "empty" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md4" "empty" "name" ++mdadm -S "/dev/md4" ++ ++# 6. set to /dev/mdX, same as in metadata. ++# Metadata name and default node used - controversial. Current behavior documented. ++names_make_conf $_UUID "/dev/md22" "name" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 7. set to /dev/mdX, different than in metadata. ++# Metadata name and default node used - controversial. Current behavior documented. ++names_make_conf $_UUID "/dev/md8" "other" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 8. Both and different than in metadata. ++# Metadata name and default node used - controversial. Current behavior documented. ++names_make_conf $_UUID "devnode" "other_name" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 9. set to metadata name, different than in metadata. ++# Metadata name and default node used - controversial. Current behavior documented. ++names_make_conf $_UUID "name" "other_name" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 10. Bad set, no . ++# Metadata name and default node used - expected. ++names_make_conf $_UUID "/im/bad/devname" "empty" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 11. with some special symbols and locales, no . ++# It needs to wait a while for timeout because udev cannot create a link - known issue. ++names_make_conf $_UUID "tźż-\.,<>st+-" "empty" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "tźż-\.,<>st+-" "name" ++mdadm -S "/dev/md127" ++ ++# 12. No and set. ++# Metadata name and default node used - expected. ++names_make_conf $_UUID "empty" "empty" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 13. No , set to /dev/mdX. ++# Entry should be ignored, it is not ignored but result is good anyway. ++names_make_conf $_UUID "empty" "/dev/md12" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" ++ ++# 13. No , with special symbols and locales. ++# Entry should be ignored, it is not ignored but result is good anyway. ++names_make_conf $_UUID "empty" "./\śćń#&" $config ++mdadm -I $dev0 --config=$config ++names_verify "/dev/md127" "name" "name" ++mdadm -S "/dev/md127" +diff --git a/tests/templates/names_template b/tests/templates/names_template +index 9f09be9e..8d2b5c81 100644 +--- a/tests/templates/names_template ++++ b/tests/templates/names_template +@@ -51,3 +51,23 @@ function names_verify() { + exit 1 + fi + } ++ ++# Generate ARRAYLINE for tested array. ++names_make_conf() { ++ local UUID="$1" ++ local WANTED_DEVNAME="$2" ++ local WANTED_NAME="$3" ++ local CONF="$4" ++ ++ local LINE="ARRAY metadata=1.2 UUID=$UUID" ++ ++ if [[ "$WANTED_DEVNAME" != "empty" ]]; then ++ LINE="$LINE $WANTED_DEVNAME" ++ fi ++ ++ if [[ "$WANTED_NAME" != "empty" ]]; then ++ LINE="$LINE name=$WANTED_NAME" ++ fi ++ ++ echo $LINE > $CONF ++} +-- +2.40.1 + diff --git a/SOURCES/0154-mdadm-set-ident.devname-if-applicable.patch b/SOURCES/0154-mdadm-set-ident.devname-if-applicable.patch new file mode 100644 index 0000000..14ca30e --- /dev/null +++ b/SOURCES/0154-mdadm-set-ident.devname-if-applicable.patch @@ -0,0 +1,399 @@ +From 330c07f8e4d26f4f2d068e11f09c9df8a3380087 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 1 Jun 2023 09:27:47 +0200 +Subject: [PATCH 154/165] mdadm: set ident.devname if applicable + +This patch tries to propagate the usage of struct mddev_ident for cmdline +where it is applicable. To avoid regression, this value is derived +from devlist->devname for applicable modes only. +As a result, the whole structure is passed to some functions. It produces +some changes for Build, Create and Assemble. +No functional changes intended. + +The goal of the change is to unify devname validation which is done in +next patches. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Build.c | 21 +++++++++------------ + Create.c | 35 ++++++++++++++++------------------ + mdadm.c | 57 +++++++++++++++++++++++++------------------------------- + mdadm.h | 13 +++++-------- + 4 files changed, 55 insertions(+), 71 deletions(-) + +diff --git a/Build.c b/Build.c +index 8d6f6f58..657ab315 100644 +--- a/Build.c ++++ b/Build.c +@@ -24,8 +24,8 @@ + + #include "mdadm.h" + +-int Build(char *mddev, struct mddev_dev *devlist, +- struct shape *s, struct context *c) ++int Build(struct mddev_ident *ident, struct mddev_dev *devlist, struct shape *s, ++ struct context *c) + { + /* Build a linear or raid0 arrays without superblocks + * We cannot really do any checks, we just do it. +@@ -75,13 +75,12 @@ int Build(char *mddev, struct mddev_dev *devlist, + + /* We need to create the device. It can have no name. */ + map_lock(&map); +- mdfd = create_mddev(mddev, NULL, c->autof, LOCAL, ++ mdfd = create_mddev(ident->devname, NULL, c->autof, LOCAL, + chosen_name, 0); + if (mdfd < 0) { + map_unlock(&map); + return 1; + } +- mddev = chosen_name; + + map_update(&map, fd2devnm(mdfd), "none", uuid, chosen_name); + map_unlock(&map); +@@ -93,7 +92,7 @@ int Build(char *mddev, struct mddev_dev *devlist, + array.nr_disks = s->raiddisks; + array.raid_disks = s->raiddisks; + array.md_minor = 0; +- if (fstat_is_blkdev(mdfd, mddev, &rdev)) ++ if (fstat_is_blkdev(mdfd, chosen_name, &rdev)) + array.md_minor = minor(rdev); + array.not_persistent = 1; + array.state = 0; /* not clean, but no errors */ +@@ -108,8 +107,7 @@ int Build(char *mddev, struct mddev_dev *devlist, + array.chunk_size = s->chunk*1024; + array.layout = s->layout; + if (md_set_array_info(mdfd, &array)) { +- pr_err("md_set_array_info() failed for %s: %s\n", +- mddev, strerror(errno)); ++ pr_err("md_set_array_info() failed for %s: %s\n", chosen_name, strerror(errno)); + goto abort; + } + +@@ -178,8 +176,8 @@ int Build(char *mddev, struct mddev_dev *devlist, + } + if (bitmap_fd >= 0) { + if (ioctl(mdfd, SET_BITMAP_FILE, bitmap_fd) < 0) { +- pr_err("Cannot set bitmap file for %s: %s\n", +- mddev, strerror(errno)); ++ pr_err("Cannot set bitmap file for %s: %s\n", chosen_name, ++ strerror(errno)); + goto abort; + } + } +@@ -193,9 +191,8 @@ int Build(char *mddev, struct mddev_dev *devlist, + } + + if (c->verbose >= 0) +- pr_err("array %s built and started.\n", +- mddev); +- wait_for(mddev, mdfd); ++ pr_err("array %s built and started.\n", chosen_name); ++ wait_for(chosen_name, mdfd); + close(mdfd); + return 0; + +diff --git a/Create.c b/Create.c +index ea6a4745..a280c7bc 100644 +--- a/Create.c ++++ b/Create.c +@@ -471,11 +471,8 @@ out: + return ret; + } + +-int Create(struct supertype *st, char *mddev, +- char *name, int *uuid, +- int subdevs, struct mddev_dev *devlist, +- struct shape *s, +- struct context *c) ++int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, ++ struct mddev_dev *devlist, struct shape *s, struct context *c) + { + /* + * Create a new raid array. +@@ -497,6 +494,8 @@ int Create(struct supertype *st, char *mddev, + unsigned long long minsize = 0, maxsize = 0; + char *mindisc = NULL; + char *maxdisc = NULL; ++ char *name = ident->name; ++ int *uuid = ident->uuid_set == 1 ? ident->uuid : NULL; + int dnum; + struct mddev_dev *dv; + dev_t rdev; +@@ -1015,7 +1014,7 @@ int Create(struct supertype *st, char *mddev, + + /* We need to create the device */ + map_lock(&map); +- mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name, 1); ++ mdfd = create_mddev(ident->devname, ident->name, c->autof, LOCAL, chosen_name, 1); + if (mdfd < 0) { + map_unlock(&map); + return 1; +@@ -1032,7 +1031,6 @@ int Create(struct supertype *st, char *mddev, + udev_unblock(); + return 1; + } +- mddev = chosen_name; + + memset(&inf, 0, sizeof(inf)); + md_get_array_info(mdfd, &inf); +@@ -1050,7 +1048,7 @@ int Create(struct supertype *st, char *mddev, + * with, but it chooses to trust me instead. Sigh + */ + info.array.md_minor = 0; +- if (fstat_is_blkdev(mdfd, mddev, &rdev)) ++ if (fstat_is_blkdev(mdfd, chosen_name, &rdev)) + info.array.md_minor = minor(rdev); + info.array.not_persistent = 0; + +@@ -1102,8 +1100,8 @@ int Create(struct supertype *st, char *mddev, + info.array.layout = s->layout; + info.array.chunk_size = s->chunk*1024; + +- if (name == NULL || *name == 0) { +- /* base name on mddev */ ++ if (*name == 0) { ++ /* base name on devname */ + /* /dev/md0 -> 0 + * /dev/md_d0 -> d0 + * /dev/md_foo -> foo +@@ -1113,15 +1111,16 @@ int Create(struct supertype *st, char *mddev, + * /dev/mdhome -> home + */ + /* FIXME compare this with rules in create_mddev */ +- name = strrchr(mddev, '/'); ++ name = strrchr(chosen_name, '/'); ++ + if (name) { + name++; + if (strncmp(name, "md_", 3) == 0 && +- strlen(name) > 3 && (name-mddev) == 5 /* /dev/ */) ++ strlen(name) > 3 && (name - chosen_name) == 5 /* /dev/ */) + name += 3; + else if (strncmp(name, "md", 2) == 0 && + strlen(name) > 2 && isdigit(name[2]) && +- (name-mddev) == 5 /* /dev/ */) ++ (name - chosen_name) == 5 /* /dev/ */) + name += 2; + } + } +@@ -1215,8 +1214,7 @@ int Create(struct supertype *st, char *mddev, + } + rv = set_array_info(mdfd, st, &info); + if (rv) { +- pr_err("failed to set array info for %s: %s\n", +- mddev, strerror(errno)); ++ pr_err("failed to set array info for %s: %s\n", chosen_name, strerror(errno)); + goto abort_locked; + } + +@@ -1237,8 +1235,7 @@ int Create(struct supertype *st, char *mddev, + goto abort_locked; + } + if (ioctl(mdfd, SET_BITMAP_FILE, bitmap_fd) < 0) { +- pr_err("Cannot set bitmap file for %s: %s\n", +- mddev, strerror(errno)); ++ pr_err("Cannot set bitmap file for %s: %s\n", chosen_name, strerror(errno)); + goto abort_locked; + } + } +@@ -1254,7 +1251,7 @@ int Create(struct supertype *st, char *mddev, + * create links */ + sysfs_uevent(&info, "change"); + if (c->verbose >= 0) +- pr_err("container %s prepared.\n", mddev); ++ pr_err("container %s prepared.\n", chosen_name); + wait_for(chosen_name, mdfd); + } else if (c->runstop == 1 || subdevs >= s->raiddisks) { + if (st->ss->external) { +@@ -1312,7 +1309,7 @@ int Create(struct supertype *st, char *mddev, + ioctl(mdfd, RESTART_ARRAY_RW, NULL); + } + if (c->verbose >= 0) +- pr_info("array %s started.\n", mddev); ++ pr_info("array %s started.\n", chosen_name); + if (st->ss->external && st->container_devnm[0]) { + if (need_mdmon) + start_mdmon(st->container_devnm); +diff --git a/mdadm.c b/mdadm.c +index 22d1c53b..0a56ed26 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -1290,37 +1290,39 @@ int main(int argc, char *argv[]) + pr_err("an md device must be given in this mode\n"); + exit(2); + } ++ ident.devname = devlist->devname; ++ + if ((int)ident.super_minor == -2 && c.autof) { + pr_err("--super-minor=dev is incompatible with --auto\n"); + exit(2); + } + if (mode == MANAGE || mode == GROW) { +- mdfd = open_mddev(devlist->devname, 1); ++ mdfd = open_mddev(ident.devname, 1); + if (mdfd < 0) + exit(1); + + ret = fstat(mdfd, &stb); + if (ret) { +- pr_err("fstat failed on %s.\n", devlist->devname); ++ pr_err("fstat failed on %s.\n", ident.devname); + exit(1); + } + } else { +- char *bname = basename(devlist->devname); ++ char *bname = basename(ident.devname); + + if (strlen(bname) > MD_NAME_MAX) { +- pr_err("Name %s is too long.\n", devlist->devname); ++ pr_err("Name %s is too long.\n", ident.devname); + exit(1); + } + +- ret = stat(devlist->devname, &stb); ++ ret = stat(ident.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); ++ ident.devname); + exit(1); + } + + if (!ret && !stat_is_md_dev(&stb)) { +- pr_err("device %s exists but is not an md array.\n", devlist->devname); ++ pr_err("device %s exists but is not an md array.\n", ident.devname); + exit(1); + } + } +@@ -1408,17 +1410,17 @@ int main(int argc, char *argv[]) + case MANAGE: + /* readonly, add/remove, readwrite, runstop */ + if (c.readonly > 0) +- rv = Manage_ro(devlist->devname, mdfd, c.readonly); ++ rv = Manage_ro(ident.devname, mdfd, c.readonly); + if (!rv && devs_found > 1) +- rv = Manage_subdevs(devlist->devname, mdfd, ++ rv = Manage_subdevs(ident.devname, mdfd, + devlist->next, c.verbose, + c.test, c.update, c.force); + if (!rv && c.readonly < 0) +- rv = Manage_ro(devlist->devname, mdfd, c.readonly); ++ rv = Manage_ro(ident.devname, mdfd, c.readonly); + if (!rv && c.runstop > 0) +- rv = Manage_run(devlist->devname, mdfd, &c); ++ rv = Manage_run(ident.devname, mdfd, &c); + if (!rv && c.runstop < 0) +- rv = Manage_stop(devlist->devname, mdfd, c.verbose, 0); ++ rv = Manage_stop(ident.devname, mdfd, c.verbose, 0); + break; + case ASSEMBLE: + if (!c.scan && c.runstop == -1) { +@@ -1428,22 +1430,19 @@ int main(int argc, char *argv[]) + ident.super_minor == UnSet && ident.name[0] == 0 && + !c.scan) { + /* Only a device has been given, so get details from config file */ +- struct mddev_ident *array_ident = conf_get_ident(devlist->devname); ++ struct mddev_ident *array_ident = conf_get_ident(ident.devname); + if (array_ident == NULL) { +- pr_err("%s not identified in config file.\n", +- devlist->devname); ++ pr_err("%s not identified in config file.\n", ident.devname); + rv |= 1; + if (mdfd >= 0) + close(mdfd); + } else { + if (array_ident->autof == 0) + array_ident->autof = c.autof; +- rv |= Assemble(ss, devlist->devname, array_ident, +- NULL, &c); ++ rv |= Assemble(ss, ident.devname, array_ident, NULL, &c); + } + } else if (!c.scan) +- rv = Assemble(ss, devlist->devname, &ident, +- devlist->next, &c); ++ rv = Assemble(ss, ident.devname, &ident, devlist->next, &c); + else if (devs_found > 0) { + if (c.update && devs_found > 1) { + pr_err("can only update a single array at a time\n"); +@@ -1501,7 +1500,7 @@ int main(int argc, char *argv[]) + break; + } + } +- rv = Build(devlist->devname, devlist->next, &s, &c); ++ rv = Build(&ident, devlist->next, &s, &c); + break; + case CREATE: + if (c.delay == 0) +@@ -1538,9 +1537,7 @@ int main(int argc, char *argv[]) + break; + } + +- rv = Create(ss, devlist->devname, +- ident.name, ident.uuid_set ? ident.uuid : NULL, +- devs_found - 1, devlist->next, &s, &c); ++ rv = Create(ss, &ident, devs_found - 1, devlist->next, &s, &c); + break; + case MISC: + if (devmode == 'E') { +@@ -1637,8 +1634,7 @@ int main(int argc, char *argv[]) + break; + } + for (dv = devlist->next; dv; dv = dv->next) { +- rv = Grow_Add_device(devlist->devname, mdfd, +- dv->devname); ++ rv = Grow_Add_device(ident.devname, mdfd, dv->devname); + if (rv) + break; + } +@@ -1651,18 +1647,15 @@ int main(int argc, char *argv[]) + } + if (c.delay == 0) + c.delay = DEFAULT_BITMAP_DELAY; +- rv = Grow_addbitmap(devlist->devname, mdfd, &c, &s); ++ rv = Grow_addbitmap(ident.devname, mdfd, &c, &s); + } else if (grow_continue) +- rv = Grow_continue_command(devlist->devname, +- mdfd, c.backup_file, +- c.verbose); ++ rv = Grow_continue_command(ident.devname, mdfd, c.backup_file, c.verbose); + else if (s.size > 0 || s.raiddisks || s.layout_str || + s.chunk != 0 || s.level != UnSet || + s.data_offset != INVALID_SECTORS) { +- rv = Grow_reshape(devlist->devname, mdfd, +- devlist->next, &c, &s); ++ rv = Grow_reshape(ident.devname, mdfd, devlist->next, &c, &s); + } else if (s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN) { +- rv = Grow_consistency_policy(devlist->devname, mdfd, &c, &s); ++ rv = Grow_consistency_policy(ident.devname, mdfd, &c, &s); + } else if (array_size == 0) + pr_err("no changes to --grow\n"); + break; +diff --git a/mdadm.h b/mdadm.h +index f0ceeb78..5678eb11 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1531,14 +1531,11 @@ extern int Assemble(struct supertype *st, char *mddev, + struct mddev_dev *devlist, + struct context *c); + +-extern int Build(char *mddev, struct mddev_dev *devlist, +- struct shape *s, struct context *c); +- +-extern int Create(struct supertype *st, char *mddev, +- char *name, int *uuid, +- int subdevs, struct mddev_dev *devlist, +- struct shape *s, +- struct context *c); ++extern int Build(struct mddev_ident *ident, struct mddev_dev *devlist, struct shape *s, ++ struct context *c); ++ ++extern int Create(struct supertype *st, struct mddev_ident *ident, int subdevs, ++ struct mddev_dev *devlist, struct shape *s, 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.40.1 + diff --git a/SOURCES/0155-mdadm-refactor-ident-name-handling.patch b/SOURCES/0155-mdadm-refactor-ident-name-handling.patch new file mode 100644 index 0000000..423b876 --- /dev/null +++ b/SOURCES/0155-mdadm-refactor-ident-name-handling.patch @@ -0,0 +1,253 @@ +From 67417d9222c505103357191bb0e0ae300892e8a9 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 1 Jun 2023 09:27:48 +0200 +Subject: [PATCH 155/165] mdadm: refactor ident->name handling + +Create dedicated setter for name in mddev_ident and propagate it. +Following changes are made: +- move duplicated code from config.c and mdadm.c into new function. +- Add error enum in mdadm.h. +- Use MD_NAME_MAX instead of hardcoded value in mddev_ident. +- Use secure functions. +- Add more detailed verification of the name. +- make error messages reusable for cmdline and config: + - for cmdline, these are errors so use pr_err(). + - for config, these are just warnings, so use pr_info(). + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + config.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++------ + lib.c | 18 +++++++++++++ + mdadm.c | 12 +++------ + mdadm.h | 20 ++++++++++----- + 4 files changed, 104 insertions(+), 23 deletions(-) + +diff --git a/config.c b/config.c +index 450880e3..a9a0b4f7 100644 +--- a/config.c ++++ b/config.c +@@ -131,6 +131,34 @@ bool is_devname_ignore(char *devname) + return false; + } + ++/** ++ * ident_log() - generate and write message to the user. ++ * @param_name: name of the property. ++ * @value: value of the property. ++ * @reason: meaningful description. ++ * @cmdline: context dependent actions, see below. ++ * ++ * The function is made to provide similar error handling for both config and cmdline. The behavior ++ * is configurable via @cmdline. Message has following format: ++ * "Value "@value" cannot be set for @param_name. Reason: @reason." ++ * ++ * If cmdline is on: ++ * - message is written to stderr. ++ * otherwise: ++ * - message is written to stdout. ++ * - "Value ignored" is added at the end of the message. ++ */ ++static void ident_log(const char *param_name, const char *value, const char *reason, ++ const bool cmdline) ++{ ++ if (cmdline == true) ++ pr_err("Value \"%s\" cannot be set as %s. Reason: %s.\n", value, param_name, ++ reason); ++ else ++ pr_info("Value \"%s\" cannot be set as %s. Reason: %s. Value ignored.\n", value, ++ param_name, reason); ++} ++ + /** + * ident_init() - Set defaults. + * @ident: ident pointer, not NULL. +@@ -159,6 +187,46 @@ inline void ident_init(struct mddev_ident *ident) + ident->uuid_set = 0; + } + ++/** ++ * _ident_set_name()- set name in &mddev_ident. ++ * @ident: pointer to &mddev_ident. ++ * @name: name to be set. ++ * @cmdline: context dependent actions. ++ * ++ * If criteria passed, set name in @ident. ++ * ++ * Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR. ++ */ ++static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *name, ++ const bool cmdline) ++{ ++ assert(name); ++ assert(ident); ++ ++ const char *prop_name = "name"; ++ ++ if (ident->name[0]) { ++ ident_log(prop_name, name, "Already defined", cmdline); ++ return MDADM_STATUS_ERROR; ++ } ++ ++ if (is_string_lq(name, MD_NAME_MAX + 1) == false) { ++ ident_log(prop_name, name, "Too long or empty", cmdline); ++ return MDADM_STATUS_ERROR; ++ } ++ ++ snprintf(ident->name, MD_NAME_MAX + 1, "%s", name); ++ return MDADM_STATUS_SUCCESS; ++} ++ ++/** ++ * ident_set_name()- exported, for cmdline. ++ */ ++mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name) ++{ ++ return _ident_set_name(ident, name, true); ++} ++ + struct conf_dev { + struct conf_dev *next; + char *name; +@@ -444,14 +512,7 @@ void arrayline(char *line) + mis.super_minor = minor; + } + } else if (strncasecmp(w, "name=", 5) == 0) { +- if (mis.name[0]) +- pr_err("only specify name once, %s ignored.\n", +- w); +- else if (strlen(w + 5) > 32) +- pr_err("name too long, ignoring %s\n", w); +- else +- strcpy(mis.name, w + 5); +- ++ _ident_set_name(&mis, w + 5, false); + } else if (strncasecmp(w, "bitmap=", 7) == 0) { + if (mis.bitmap_file) + pr_err("only specify bitmap file once. %s ignored\n", +diff --git a/lib.c b/lib.c +index 8a4b48e0..03198e2d 100644 +--- a/lib.c ++++ b/lib.c +@@ -27,6 +27,24 @@ + #include + #include + ++/** ++ * is_string_lq() - Check if string length with NULL byte is lower or equal to requested. ++ * @str: string to check. ++ * @max_len: max length. ++ * ++ * @str length must be bigger than 0 and be lower or equal @max_len, including termination byte. ++ */ ++bool is_string_lq(const char * const str, size_t max_len) ++{ ++ assert(str); ++ ++ size_t _len = strnlen(str, max_len); ++ ++ if (_len > 0 && _len < max_len) ++ return true; ++ return false; ++} ++ + bool is_dev_alive(char *path) + { + if (!path) +diff --git a/mdadm.c b/mdadm.c +index 0a56ed26..8bc9304e 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -690,20 +690,14 @@ int main(int argc, char *argv[]) + case O(CREATE,'N'): + case O(ASSEMBLE,'N'): + case O(MISC,'N'): +- if (ident.name[0]) { +- pr_err("name cannot be set twice. Second value %s.\n", optarg); +- exit(2); +- } + if (mode == MISC && !c.subarray) { + pr_err("-N/--name only valid with --update-subarray in misc mode\n"); + exit(2); + } +- if (strlen(optarg) > 32) { +- pr_err("name '%s' is too long, 32 chars max.\n", +- optarg); ++ ++ if (ident_set_name(&ident, optarg) != MDADM_STATUS_SUCCESS) + exit(2); +- } +- strcpy(ident.name, optarg); ++ + continue; + + case O(ASSEMBLE,'m'): /* super-minor for array */ +diff --git a/mdadm.h b/mdadm.h +index 5678eb11..bbf386d6 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -294,6 +294,11 @@ static inline void __put_unaligned32(__u32 val, void *p) + #define KIB_TO_BYTES(x) ((x) << 10) + #define SEC_TO_BYTES(x) ((x) << 9) + ++/** ++ * This is true for native and DDF, IMSM allows 16. ++ */ ++#define MD_NAME_MAX 32 ++ + extern const char Name[]; + + struct md_bb_entry { +@@ -425,6 +430,12 @@ struct spare_criteria { + unsigned int sector_size; + }; + ++typedef enum mdadm_status { ++ MDADM_STATUS_SUCCESS = 0, ++ MDADM_STATUS_ERROR, ++ MDADM_STATUS_UNDEF, ++} mdadm_status_t; ++ + enum mode { + ASSEMBLE=1, + BUILD, +@@ -593,7 +604,7 @@ struct mddev_ident { + + int uuid_set; + int uuid[4]; +- char name[33]; ++ char name[MD_NAME_MAX + 1]; + + int super_minor; + +@@ -1609,6 +1620,7 @@ extern int check_partitions(int fd, char *dname, + extern int fstat_is_blkdev(int fd, char *devname, dev_t *rdev); + extern int stat_is_blkdev(char *devname, dev_t *rdev); + ++extern bool is_string_lq(const char * const str, size_t max_len); + extern bool is_dev_alive(char *path); + extern int get_mdp_major(void); + extern int get_maj_min(char *dev, int *major, int *minor); +@@ -1626,6 +1638,7 @@ extern void manage_fork_fds(int close_all); + extern int continue_via_systemd(char *devnm, char *service_name, char *prefix); + + extern void ident_init(struct mddev_ident *ident); ++extern mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name); + + extern int parse_auto(char *str, char *msg, int config); + extern struct mddev_ident *conf_get_ident(char *dev); +@@ -2002,11 +2015,6 @@ enum r0layout { + /* And another special number needed for --data_offset=variable */ + #define VARIABLE_OFFSET 3 + +-/** +- * This is true for native and DDF, IMSM allows 16. +- */ +-#define MD_NAME_MAX 32 +- + /** + * is_container() - check if @level is &LEVEL_CONTAINER + * @level: level value +-- +2.40.1 + diff --git a/SOURCES/0156-mdadm-define-ident_set_devname.patch b/SOURCES/0156-mdadm-define-ident_set_devname.patch new file mode 100644 index 0000000..8c7441b --- /dev/null +++ b/SOURCES/0156-mdadm-define-ident_set_devname.patch @@ -0,0 +1,249 @@ +From ae5f13a971bc309e0e25087421119b86daf2e510 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 1 Jun 2023 09:27:49 +0200 +Subject: [PATCH 156/165] mdadm: define ident_set_devname() + +Use dedicated set method for ident->devname. Now, devname validation +is done early for modes where device is created (Build, Create and +Assemble). The rules, used for devname validation are derived from +config file. + +It could cause regression with execeptional cases where existing device +has name which doesn't match criteria for Manage and Grow modes. It is +low risk and those modes are not omitted from early devname validation. +Use can used main numbered devnode to avoid this problem. +Messages exposed to user are changed so it might cause a regression +in negative scenarios. Error codes are not changed. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + config.c | 102 +++++++++++++++++++++++++-------- + mdadm.c | 10 +--- + mdadm.h | 3 +- + tests/00createnames | 3 + + tests/templates/names_template | 7 +++ + 5 files changed, 92 insertions(+), 33 deletions(-) + +diff --git a/config.c b/config.c +index a9a0b4f7..a0424845 100644 +--- a/config.c ++++ b/config.c +@@ -122,7 +122,7 @@ int match_keyword(char *word) + /** + * is_devname_ignore() - check if &devname is a special "" keyword. + */ +-bool is_devname_ignore(char *devname) ++bool is_devname_ignore(const char *devname) + { + static const char keyword[] = ""; + +@@ -187,6 +187,74 @@ inline void ident_init(struct mddev_ident *ident) + ident->uuid_set = 0; + } + ++/** ++ * _ident_set_devname()- verify devname and set it in &mddev_ident. ++ * @ident: pointer to &mddev_ident. ++ * @devname: devname to be set. ++ * @cmdline: context dependent actions. If set, ignore keyword is not allowed. ++ * ++ * @devname can have following forms: ++ * '' keyword (if allowed) ++ * /dev/md{number} ++ * /dev/md_d{number} (legacy) ++ * /dev/md_{name} ++ * /dev/md/{name} ++ * {name} - anything that doesn't start from '/' or '<'. ++ * ++ * {name} must follow name's criteria. ++ * If criteria passed, duplicate memory and set devname in @ident. ++ * ++ * Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR. ++ */ ++mdadm_status_t _ident_set_devname(struct mddev_ident *ident, const char *devname, ++ const bool cmdline) ++{ ++ assert(ident); ++ assert(devname); ++ ++ static const char named_dev_pref[] = DEV_NUM_PREF "_"; ++ static const int named_dev_pref_size = sizeof(named_dev_pref) - 1; ++ const char *prop_name = "devname"; ++ const char *name; ++ ++ if (ident->devname) { ++ ident_log(prop_name, devname, "Already defined", cmdline); ++ return MDADM_STATUS_ERROR; ++ } ++ ++ if (is_devname_ignore(devname) == true) { ++ if (!cmdline) ++ goto pass; ++ ++ ident_log(prop_name, devname, "Special keyword is invalid in this context", ++ cmdline); ++ return MDADM_STATUS_ERROR; ++ } ++ ++ if (is_devname_md_numbered(devname) == true || is_devname_md_d_numbered(devname) == true) ++ goto pass; ++ ++ if (strncmp(devname, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) ++ name = devname + DEV_MD_DIR_LEN; ++ else if (strncmp(devname, named_dev_pref, named_dev_pref_size) == 0) ++ name = devname + named_dev_pref_size; ++ else ++ name = devname; ++ ++ if (*name == '/' || *name == '<') { ++ ident_log(prop_name, devname, "Cannot be started from \'/\' or \'<\'", cmdline); ++ return MDADM_STATUS_ERROR; ++ } ++ ++ if (is_string_lq(name, MD_NAME_MAX + 1) == false) { ++ ident_log(prop_name, devname, "Invalid length", cmdline); ++ return MDADM_STATUS_ERROR; ++ } ++pass: ++ ident->devname = xstrdup(devname); ++ return MDADM_STATUS_SUCCESS; ++} ++ + /** + * _ident_set_name()- set name in &mddev_ident. + * @ident: pointer to &mddev_ident. +@@ -219,6 +287,14 @@ static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *nam + return MDADM_STATUS_SUCCESS; + } + ++/** ++ * ident_set_devname()- exported, for cmdline. ++ */ ++mdadm_status_t ident_set_devname(struct mddev_ident *ident, const char *name) ++{ ++ return _ident_set_devname(ident, name, true); ++} ++ + /** + * ident_set_name()- exported, for cmdline. + */ +@@ -464,29 +540,7 @@ void arrayline(char *line) + + for (w = dl_next(line); w != line; w = dl_next(w)) { + if (w[0] == '/' || strchr(w, '=') == NULL) { +- /* This names the device, or is ''. +- * The rules match those in create_mddev. +- * 'w' must be: +- * /dev/md/{anything} +- * /dev/mdNN +- * /dev/md_dNN +- * +- * or anything that doesn't start '/' or '<' +- */ +- if (is_devname_ignore(w) == true || +- strncmp(w, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 || +- (w[0] != '/' && w[0] != '<') || +- is_devname_md_numbered(w) == true || +- is_devname_md_d_numbered(w) == true) { +- /* This is acceptable */; +- if (mis.devname) +- pr_err("only give one device per ARRAY line: %s and %s\n", +- mis.devname, w); +- else +- mis.devname = w; +- }else { +- pr_err("%s is an invalid name for an md device - ignored.\n", w); +- } ++ _ident_set_devname(&mis, w, false); + } else if (strncasecmp(w, "uuid=", 5) == 0) { + if (mis.uuid_set) + pr_err("only specify uuid once, %s ignored.\n", +diff --git a/mdadm.c b/mdadm.c +index 8bc9304e..62f981df 100644 +--- a/mdadm.c ++++ b/mdadm.c +@@ -1284,7 +1284,8 @@ int main(int argc, char *argv[]) + pr_err("an md device must be given in this mode\n"); + exit(2); + } +- ident.devname = devlist->devname; ++ if (ident_set_devname(&ident, devlist->devname) != MDADM_STATUS_SUCCESS) ++ exit(1); + + if ((int)ident.super_minor == -2 && c.autof) { + pr_err("--super-minor=dev is incompatible with --auto\n"); +@@ -1301,13 +1302,6 @@ int main(int argc, char *argv[]) + exit(1); + } + } else { +- char *bname = basename(ident.devname); +- +- if (strlen(bname) > MD_NAME_MAX) { +- pr_err("Name %s is too long.\n", ident.devname); +- exit(1); +- } +- + ret = stat(ident.devname, &stb); + if (ident.super_minor == -2 && ret != 0) { + pr_err("--super-minor=dev given, and listed device %s doesn't exist.\n", +diff --git a/mdadm.h b/mdadm.h +index bbf386d6..49422e24 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1638,6 +1638,7 @@ extern void manage_fork_fds(int close_all); + extern int continue_via_systemd(char *devnm, char *service_name, char *prefix); + + extern void ident_init(struct mddev_ident *ident); ++extern mdadm_status_t ident_set_devname(struct mddev_ident *ident, const char *devname); + extern mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name); + + extern int parse_auto(char *str, char *msg, int config); +@@ -1660,7 +1661,7 @@ extern void print_escape(char *str); + extern int use_udev(void); + extern unsigned long GCD(unsigned long a, unsigned long b); + extern int conf_name_is_free(char *name); +-extern bool is_devname_ignore(char *devname); ++extern bool is_devname_ignore(const char *devname); + extern bool is_devname_md_numbered(const char *devname); + extern bool is_devname_md_d_numbered(const char *devname); + extern int conf_verify_devnames(struct mddev_ident *array_list); +diff --git a/tests/00createnames b/tests/00createnames +index 064eeef2..a95e7d2b 100644 +--- a/tests/00createnames ++++ b/tests/00createnames +@@ -39,3 +39,6 @@ mdadm -S "/dev/md0" + names_create "/dev/md0" "name" + names_verify "/dev/md0" "empty" "name" + mdadm -S "/dev/md0" ++ ++# Devnode is a special ignore keyword. Should be rejected. ++names_create "" "name", "true" +diff --git a/tests/templates/names_template b/tests/templates/names_template +index 8d2b5c81..6181bfaa 100644 +--- a/tests/templates/names_template ++++ b/tests/templates/names_template +@@ -2,6 +2,7 @@ + function names_create() { + local DEVNAME=$1 + local NAME=$2 ++ local NEG_TEST=$3 + + if [[ -z "$NAME" ]]; then + mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force +@@ -9,6 +10,12 @@ function names_create() { + mdadm -CR "$DEVNAME" --name="$NAME" --metadata=1.2 -l0 -n 1 $dev0 --force + fi + ++ if [[ "$NEG_TEST" == "true" ]]; then ++ [[ "$?" == "0" ]] && return 0 ++ echo "Negative verification failed" ++ exit 1 ++ fi ++ + if [[ "$?" != "0" ]]; then + echo "Cannot create device." + exit 1 +-- +2.40.1 + diff --git a/SOURCES/0157-mdadm-Follow-POSIX-Portable-Character-Set.patch b/SOURCES/0157-mdadm-Follow-POSIX-Portable-Character-Set.patch new file mode 100644 index 0000000..50d2bbb --- /dev/null +++ b/SOURCES/0157-mdadm-Follow-POSIX-Portable-Character-Set.patch @@ -0,0 +1,471 @@ +From e2eb503bd797908f515b58428b274f1ba6a05349 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Thu, 1 Jun 2023 09:27:50 +0200 +Subject: [PATCH 157/165] mdadm: Follow POSIX Portable Character Set + +When the user creates a device with a name that contains whitespace, +mdadm timeouts and throws an error. This issue is caused by udev, which +truncates /dev/md link until the first whitespace. + +This patch introduces prohibition of characters other than A-Za-z0-9.-_ +in the device name. Also, it prohibits using leading "-" in device name, +so name won't be confused with cli parameter. +Set of allowed characters is taken from POSIX 3.280 Portable Character +Set. Also, device name length now is limited to NAME_MAX. + +In some places, there are other requirements for string length (e.g. size +up to MD_NAME_MAX for device name). This routine is made to follow POSIX +and other, more strict limitations should be checked separately. +We are aware of the risk of regression in exceptional cases (as +escape_devname function is removed) that should be fixed by updating +the array name. + +The POSIX validation is added for: +- 'name' parameter in every mode. +- first devlist entry, for Build, Create, Assemble, Manage, Grow. +- config entries, both devname and "name=". + +Additionally, some manual cleanups are made. + +Signed-off-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Detail.c | 17 ++++-------- + config.c | 13 ++++++--- + lib.c | 58 ++++++++++++++++++++++++++++----------- + mdadm.8.in | 70 ++++++++++++++++++++--------------------------- + mdadm.conf.5.in | 4 --- + mdadm.h | 2 +- + super-intel.c | 47 ++++++++++++++++--------------- + tests/00confnames | 4 +-- + 8 files changed, 113 insertions(+), 102 deletions(-) + +diff --git a/Detail.c b/Detail.c +index 206d88e3..57ac336f 100644 +--- a/Detail.c ++++ b/Detail.c +@@ -254,11 +254,9 @@ int Detail(char *dev, struct context *c) + fname_from_uuid(st, info, nbuf, ':'); + printf("MD_UUID=%s\n", nbuf + 5); + mp = map_by_uuid(&map, info->uuid); +- if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) { +- printf("MD_DEVNAME="); +- print_escape(mp->path + DEV_MD_DIR_LEN); +- putchar('\n'); +- } ++ ++ if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) ++ printf("MD_DEVNAME=%s\n", mp->path + DEV_MD_DIR_LEN); + + if (st->ss->export_detail_super) + st->ss->export_detail_super(st); +@@ -271,12 +269,9 @@ int Detail(char *dev, struct context *c) + __fname_from_uuid(mp->uuid, 0, nbuf, ':'); + printf("MD_UUID=%s\n", nbuf+5); + } +- if (mp && mp->path && +- strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) { +- printf("MD_DEVNAME="); +- print_escape(mp->path + DEV_MD_DIR_LEN); +- putchar('\n'); +- } ++ if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) ++ printf("MD_DEVNAME=%s\n", mp->path + DEV_MD_DIR_LEN); ++ + map_free(map); + } + if (!c->no_devices && sra) { +diff --git a/config.c b/config.c +index a0424845..5f12a1f8 100644 +--- a/config.c ++++ b/config.c +@@ -199,9 +199,9 @@ inline void ident_init(struct mddev_ident *ident) + * /dev/md_d{number} (legacy) + * /dev/md_{name} + * /dev/md/{name} +- * {name} - anything that doesn't start from '/' or '<'. ++ * {name} + * +- * {name} must follow name's criteria. ++ * {name} must follow name's criteria and be POSIX compatible. + * If criteria passed, duplicate memory and set devname in @ident. + * + * Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR. +@@ -241,8 +241,8 @@ mdadm_status_t _ident_set_devname(struct mddev_ident *ident, const char *devname + else + name = devname; + +- if (*name == '/' || *name == '<') { +- ident_log(prop_name, devname, "Cannot be started from \'/\' or \'<\'", cmdline); ++ if (is_name_posix_compatible(name) == false) { ++ ident_log(prop_name, name, "Not POSIX compatible", cmdline); + return MDADM_STATUS_ERROR; + } + +@@ -283,6 +283,11 @@ static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *nam + return MDADM_STATUS_ERROR; + } + ++ if (is_name_posix_compatible(name) == false) { ++ ident_log(prop_name, name, "Not POSIX compatible", cmdline); ++ return MDADM_STATUS_ERROR; ++ } ++ + snprintf(ident->name, MD_NAME_MAX + 1, "%s", name); + return MDADM_STATUS_SUCCESS; + } +diff --git a/lib.c b/lib.c +index 03198e2d..7ab59988 100644 +--- a/lib.c ++++ b/lib.c +@@ -483,24 +483,50 @@ void print_quoted(char *str) + putchar(q); + } + +-void print_escape(char *str) ++/** ++ * is_alphanum() - Check if sign is letter or digit. ++ * @c: char to analyze. ++ * ++ * Similar to isalnum() but additional locales are excluded. ++ * ++ * Return: %true on success, %false otherwise. ++ */ ++bool is_alphanum(const char c) + { +- /* print str, but change space and tab to '_' +- * as is suitable for device names +- */ +- for (; *str; str++) { +- switch (*str) { +- case ' ': +- case '\t': +- putchar('_'); +- break; +- case '/': +- putchar('-'); +- break; +- default: +- putchar(*str); +- } ++ if (isupper(c) || islower(c) || isdigit(c) != 0) ++ return true; ++ return false; ++} ++ ++/** ++ * is_name_posix_compatible() - Check if name is POSIX compatible. ++ * @name: name to check. ++ * ++ * POSIX portable file name character set contains ASCII letters, ++ * digits, '_', '.', and '-'. Also forbid leading '-'. ++ * The length of the name cannot exceed NAME_MAX - 1 (ensure NULL ending). ++ * ++ * Return: %true on success, %false otherwise. ++ */ ++bool is_name_posix_compatible(const char * const name) ++{ ++ assert(name); ++ ++ char allowed_symbols[] = "-_."; ++ const char *n = name; ++ ++ if (!is_string_lq(name, NAME_MAX)) ++ return false; ++ ++ if (*n == '-') ++ return false; ++ ++ while (*n != '\0') { ++ if (!is_alphanum(*n) && !strchr(allowed_symbols, *n)) ++ return false; ++ n++; + } ++ return true; + } + + int check_env(char *name) +diff --git a/mdadm.8.in b/mdadm.8.in +index b7159509..3142436f 100644 +--- a/mdadm.8.in ++++ b/mdadm.8.in +@@ -364,7 +364,7 @@ Use the Intel(R) Matrix Storage Manager metadata format. This creates a + which is managed in a similar manner to DDF, and is supported by an + option-rom on some platforms: + .IP +-.B https://www.intel.com/content/www/us/en/support/products/122484/memory-and-storage/ssd-software/intel-virtual-raid-on-cpu-intel-vroc.html ++.B https://www.intel.com/content/www/us/en/support/products/122484 + .PP + .RE + +@@ -932,17 +932,14 @@ option will be ignored. + .BR \-N ", " \-\-name= + Set a + .B name +-for the array. This is currently only effective when creating an +-array with a version-1 superblock, or an array in a DDF container. +-The name is a simple textual string that can be used to identify array +-components when assembling. If name is needed but not specified, it +-is taken from the basename of the device that is being created. +-e.g. when creating +-.I /dev/md/home +-the +-.B name +-will default to +-.IR home . ++for the array. It must be ++.BR "POSIX PORTABLE NAME" ++compatible and cannot be longer than 32 chars. This is effective when creating an array ++with a v1 metadata, or an external array. ++ ++If name is needed but not specified, it is taken from the basename of the device ++that is being created. See ++.BR "DEVICE NAMES" + + .TP + .BR \-R ", " \-\-run +@@ -1132,8 +1129,10 @@ is much safer. + + .TP + .BR \-N ", " \-\-name= +-Specify the name of the array to assemble. This must be the name +-that was specified when creating the array. It must either match ++Specify the name of the array to assemble. It must be ++.BR "POSIX PORTABLE NAME" ++compatible and cannot be longer than 32 chars. This must be the name ++that was specified when creating the array. It must either match + the name stored in the superblock exactly, or it must match + with the current + .I homehost +@@ -2179,14 +2178,17 @@ Usage: + .I md-device + .BI \-\-chunk= X + .BI \-\-level= Y +-.br + .BI \-\-raid\-devices= Z + .I devices + + .PP +-This usage will initialise a new md array, associate some devices with ++This usage will initialize a new md array, associate some devices with + it, and activate the array. + ++.I md-device ++is a new device. This could be standard name or chosen name. For details see: ++.BR "DEVICE NAMES" ++ + The named device will normally not exist when + .I "mdadm \-\-create" + is run, but will be created by +@@ -2227,24 +2229,6 @@ array. This feature can be overridden with the + .B \-\-force + option. + +-When creating an array with version-1 metadata a name for the array is +-required. +-If this is not given with the +-.B \-\-name +-option, +-.I mdadm +-will choose a name based on the last component of the name of the +-device being created. So if +-.B /dev/md3 +-is being created, then the name +-.B 3 +-will be chosen. +-If +-.B /dev/md/home +-is being created, then the name +-.B home +-will be used. +- + When creating a partition based array, using + .I mdadm + with version-1.x metadata, the partition type should be set to +@@ -2429,12 +2413,10 @@ and + + The + .B name +-option updates the subarray name in the metadata, it may not affect the +-device node name or the device node symlink until the subarray is +-re\-assembled. If updating +-.B name +-would change the UUID of an active subarray this operation is blocked, +-and the command will end in an error. ++option updates the subarray name in the metadata. It must be ++.BR "POSIX PORTABLE NAME" ++compatible and cannot be longer than 32 chars. If successes, new value will be respected after ++next assembly. + + The + .B ppl +@@ -3395,6 +3377,10 @@ When + .B \-\-incremental + mode is used, this file gets a list of arrays currently being created. + ++.SH POSIX PORTABLE NAME ++A valid name can only consist of characters "A-Za-z0-9.-_". ++The name cannot start with a leading "-" and cannot exceed 255 chars. ++ + .SH DEVICE NAMES + + .I mdadm +@@ -3416,6 +3402,10 @@ can be given, or just the suffix of the second sort of name, such as + .I home + can be given. + ++In every style, raw name must be compatible with ++.BR "POSIX PORTABLE NAME" ++and has to be no longer than 32 chars. ++ + When + .I mdadm + chooses device names during auto-assembly or incremental assembly, it +diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in +index bc2295c2..94e23dd0 100644 +--- a/mdadm.conf.5.in ++++ b/mdadm.conf.5.in +@@ -717,10 +717,6 @@ ARRAY /dev/md/home UUID=9187a482:5dde19d9:eea3cc4a:d646ab8b + .br + auto=part + .br +-# The name of this array contains a space. +-.br +-ARRAY /dev/md9 name='Data Storage' +-.sp + POLICY domain=domain1 metadata=imsm path=pci-0000:00:1f.2-scsi-* + .br + action=spare +diff --git a/mdadm.h b/mdadm.h +index 49422e24..9effb941 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -1617,6 +1617,7 @@ extern int check_raid(int fd, char *name); + extern int check_partitions(int fd, char *dname, + unsigned long long freesize, + unsigned long long size); ++extern bool is_name_posix_compatible(const char *path); + extern int fstat_is_blkdev(int fd, char *devname, dev_t *rdev); + extern int stat_is_blkdev(char *devname, dev_t *rdev); + +@@ -1657,7 +1658,6 @@ extern int conf_get_monitor_delay(void); + extern char *conf_line(FILE *file); + extern char *conf_word(FILE *file, int allow_key); + extern void print_quoted(char *str); +-extern void print_escape(char *str); + extern int use_udev(void); + extern unsigned long GCD(unsigned long a, unsigned long b); + extern int conf_name_is_free(char *name); +diff --git a/super-intel.c b/super-intel.c +index 77b0066f..05d3b056 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -5561,40 +5561,37 @@ static void imsm_update_version_info(struct intel_super *super) + } + } + +-static int check_name(struct intel_super *super, char *name, int quiet) ++/** ++ * imsm_check_name() - check imsm naming criteria. ++ * @super: &intel_super pointer, not NULL. ++ * @name: name to check. ++ * @verbose: verbose level. ++ * ++ * Name must be no longer than &MAX_RAID_SERIAL_LEN and must be unique across volumes. ++ * ++ * Returns: &true if @name matches, &false otherwise. ++ */ ++static bool imsm_is_name_allowed(struct intel_super *super, const char * const name, ++ const int verbose) + { + struct imsm_super *mpb = super->anchor; +- char *reason = NULL; +- char *start = name; +- size_t len = strlen(name); + int i; + +- if (len > 0) { +- while (isspace(start[len - 1])) +- start[--len] = 0; +- while (*start && isspace(*start)) +- ++start, --len; +- memmove(name, start, len + 1); ++ if (is_string_lq(name, MAX_RAID_SERIAL_LEN + 1) == false) { ++ pr_vrb("imsm: Name \"%s\" is too long\n", name); ++ return false; + } + +- if (len > MAX_RAID_SERIAL_LEN) +- reason = "must be 16 characters or less"; +- else if (len == 0) +- reason = "must be a non-empty string"; +- + for (i = 0; i < mpb->num_raid_devs; i++) { + struct imsm_dev *dev = get_imsm_dev(super, i); + + if (strncmp((char *) dev->volume, name, MAX_RAID_SERIAL_LEN) == 0) { +- reason = "already exists"; +- break; ++ pr_vrb("imsm: Name \"%s\" already exists\n", name); ++ return false; + } + } + +- if (reason && !quiet) +- pr_err("imsm volume name %s\n", reason); +- +- return !reason; ++ return true; + } + + static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, +@@ -5689,8 +5686,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, + } + } + +- if (!check_name(super, name, 0)) ++ if (imsm_is_name_allowed(super, name, 1) == false) + return 0; ++ + dv = xmalloc(sizeof(*dv)); + dev = xcalloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1)); + /* +@@ -8018,7 +8016,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray, + char *ep; + int vol; + +- if (!check_name(super, name, 0)) ++ if (imsm_is_name_allowed(super, name, 1) == false) + return 2; + + vol = strtoul(subarray, &ep, 10); +@@ -10345,7 +10343,8 @@ 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 || !check_name(super, name, 1)) { ++ ++ if (a || !dev || imsm_is_name_allowed(super, name, 0) == false) { + dprintf("failed to rename subarray-%d\n", target); + break; + } +diff --git a/tests/00confnames b/tests/00confnames +index 25a7127b..10823f01 100644 +--- a/tests/00confnames ++++ b/tests/00confnames +@@ -79,10 +79,10 @@ names_verify "/dev/md127" "name" "name" + mdadm -S "/dev/md127" + + # 11. with some special symbols and locales, no . +-# It needs to wait a while for timeout because udev cannot create a link - known issue. ++# should be ignored. + names_make_conf $_UUID "tźż-\.,<>st+-" "empty" $config + mdadm -I $dev0 --config=$config +-names_verify "/dev/md127" "tźż-\.,<>st+-" "name" ++names_verify "/dev/md127" "name" "name" + mdadm -S "/dev/md127" + + # 12. No and set. +-- +2.40.1 + diff --git a/SOURCES/0158-Incremental-remove-obsoleted-calls-to-udisks.patch b/SOURCES/0158-Incremental-remove-obsoleted-calls-to-udisks.patch new file mode 100644 index 0000000..68e1e6d --- /dev/null +++ b/SOURCES/0158-Incremental-remove-obsoleted-calls-to-udisks.patch @@ -0,0 +1,128 @@ +From ba489abd688bf70c83e70700aaaec5f5e90889c5 Mon Sep 17 00:00:00 2001 +From: Coly Li +Date: Mon, 14 Aug 2023 00:46:13 +0800 +Subject: [PATCH 158/165] Incremental: remove obsoleted calls to udisks + +Utility udisks is removed from udev upstream, calling this obsoleted +command in run_udisks() doesn't make any sense now. + +This patch removes the calls chain of udisks, which includes routines +run_udisk(), force_remove(), and 2 locations where force_remove() are +called. Considering force_remove() is removed with udisks util, it is +fair to remove Manage_stop() inside force_remove() as well. + +In the two modifications where calling force_remove() are removed, +the failure from Manage_subdevs() can be safely ignored, because, +1) udisks doesn't exist, no need to check the return value to umount + the file system by udisks and remove the component disk again. +2) After the 'I' inremental remove, there is another 'r' hot remove + following up. The first incremental remove is a best-try effort. + +Therefore in this patch, where force_remove() is removed, the return +value of calling Manage_subdevs() is not checked too. + +Signed-off-by: Coly Li +Reviewed-by: Mariusz Tkaczyk +Cc: Jes Sorensen +Signed-off-by: Jes Sorensen +--- + Incremental.c | 64 +++++++++++---------------------------------------- + 1 file changed, 13 insertions(+), 51 deletions(-) + +diff --git a/Incremental.c b/Incremental.c +index f13ce027..05b33c45 100644 +--- a/Incremental.c ++++ b/Incremental.c +@@ -1628,54 +1628,18 @@ release: + return rv; + } + +-static void run_udisks(char *arg1, char *arg2) +-{ +- int pid = fork(); +- int status; +- if (pid == 0) { +- manage_fork_fds(1); +- execl("/usr/bin/udisks", "udisks", arg1, arg2, NULL); +- execl("/bin/udisks", "udisks", arg1, arg2, NULL); +- exit(1); +- } +- while (pid > 0 && wait(&status) != pid) +- ; +-} +- +-static int force_remove(char *devnm, int fd, struct mdinfo *mdi, int verbose) +-{ +- int rv; +- int devid = devnm2devid(devnm); +- +- run_udisks("--unmount", map_dev(major(devid), minor(devid), 0)); +- rv = Manage_stop(devnm, fd, verbose, 1); +- if (rv) { +- /* At least we can try to trigger a 'remove' */ +- sysfs_uevent(mdi, "remove"); +- if (verbose) +- pr_err("Fail to stop %s too.\n", devnm); +- } +- return rv; +-} +- + static void remove_from_member_array(struct mdstat_ent *memb, + struct mddev_dev *devlist, int verbose) + { +- int rv; +- struct mdinfo mmdi; + int subfd = open_dev(memb->devnm); + + if (subfd >= 0) { +- rv = Manage_subdevs(memb->devnm, subfd, devlist, verbose, +- 0, UOPT_UNDEFINED, 0); +- if (rv & 2) { +- if (sysfs_init(&mmdi, -1, memb->devnm)) +- pr_err("unable to initialize sysfs for: %s\n", +- memb->devnm); +- else +- force_remove(memb->devnm, subfd, &mmdi, +- verbose); +- } ++ /* ++ * Ignore the return value because it's necessary ++ * to handle failure condition here. ++ */ ++ Manage_subdevs(memb->devnm, subfd, devlist, verbose, ++ 0, UOPT_UNDEFINED, 0); + close(subfd); + } + } +@@ -1758,21 +1722,19 @@ int IncrementalRemove(char *devname, char *id_path, int verbose) + } + free_mdstat(mdstat); + } else { +- rv |= Manage_subdevs(ent->devnm, mdfd, &devlist, +- verbose, 0, UOPT_UNDEFINED, 0); +- if (rv & 2) { +- /* Failed due to EBUSY, try to stop the array. +- * Give udisks a chance to unmount it first. ++ /* ++ * This 'I' incremental remove is a try-best effort, ++ * the failure condition can be safely ignored ++ * because of the following up 'r' remove. + */ +- rv = force_remove(ent->devnm, mdfd, &mdi, verbose); +- goto end; +- } ++ Manage_subdevs(ent->devnm, mdfd, &devlist, ++ verbose, 0, UOPT_UNDEFINED, 0); + } + + devlist.disposition = 'r'; + rv = Manage_subdevs(ent->devnm, mdfd, &devlist, + verbose, 0, UOPT_UNDEFINED, 0); +-end: ++ + close(mdfd); + free_mdstat(ent); + return rv; +-- +2.40.1 + diff --git a/SOURCES/0159-mdadm-tests-Fix-regular-expression-failure.patch b/SOURCES/0159-mdadm-tests-Fix-regular-expression-failure.patch new file mode 100644 index 0000000..1493294 --- /dev/null +++ b/SOURCES/0159-mdadm-tests-Fix-regular-expression-failure.patch @@ -0,0 +1,31 @@ +From 28fc84168646910a9271ebe1a12b1571e14f5900 Mon Sep 17 00:00:00 2001 +From: Xiao Ni +Date: Thu, 7 Sep 2023 16:57:44 +0800 +Subject: [PATCH 159/165] mdadm/tests: Fix regular expression failure + +The test fails because of the regular expression. + +Signed-off-by: Xiao Ni +Signed-off-by: Jes Sorensen +--- + tests/06name | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/06name b/tests/06name +index 4d5e824d..86eaab69 100644 +--- a/tests/06name ++++ b/tests/06name +@@ -3,8 +3,8 @@ set -x + # create an array with a name + + mdadm -CR $md0 -l0 -n2 --metadata=1 --name="Fred" $dev0 $dev1 +-mdadm -E $dev0 | grep 'Name : [^:]*:Fred ' > /dev/null || exit 1 +-mdadm -D $md0 | grep 'Name : [^:]*:Fred ' > /dev/null || exit 1 ++mdadm -E $dev0 | grep 'Name : Fred' > /dev/null || exit 1 ++mdadm -D $md0 | grep 'Name : Fred' > /dev/null || exit 1 + mdadm -S $md0 + + mdadm -A $md0 --name="Fred" $devlist +-- +2.40.1 + diff --git a/SOURCES/0160-Fix-race-of-mdadm-add-and-mdadm-incremental.patch b/SOURCES/0160-Fix-race-of-mdadm-add-and-mdadm-incremental.patch new file mode 100644 index 0000000..311f30a --- /dev/null +++ b/SOURCES/0160-Fix-race-of-mdadm-add-and-mdadm-incremental.patch @@ -0,0 +1,141 @@ +From ed2c2cb3d440f3bd2692f1896446c4bcc703f05c Mon Sep 17 00:00:00 2001 +From: Li Xiao Keng +Date: Thu, 7 Sep 2023 19:37:44 +0800 +Subject: [PATCH 160/165] Fix race of "mdadm --add" and "mdadm --incremental" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There is a raid1 with sda and sdb. And we add sdc to this raid, +it may return -EBUSY. + +The main process of --add: +1. dev_open(sdc) in Manage_add +2. store_super1(st, di->fd) in write_init_super1 +3. fsync(fd) in store_super1 +4. close(di->fd) in write_init_super1 +5. ioctl(ADD_NEW_DISK) + +Step 2 and 3 will add sdc to metadata of raid1. There will be +udev(change of sdc) event after step4. Then "/usr/sbin/mdadm +--incremental --export $devnode --offroot $env{DEVLINKS}" +will be run, and the sdc will be added to the raid1. Then +step 5 will return -EBUSY because it checks if device isn't +claimed in md_import_device()->lock_rdev()->blkdev_get_by_dev() +->blkdev_get(). + +It will be confusing for users because sdc is added first time. +The "incremental" will get map_lock before add sdc to raid1. +So we add map_lock before write_init_super in "mdadm --add" +to fix the race of "add" and "incremental". + +Signed-off-by: Li Xiao Keng +Signed-off-by: Guanqin Miao +Reviewed-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + Manage.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/Manage.c b/Manage.c +index f997b163..075dd720 100644 +--- a/Manage.c ++++ b/Manage.c +@@ -704,6 +704,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + struct supertype *dev_st; + int j; + mdu_disk_info_t disc; ++ struct map_ent *map = NULL; + + if (!get_dev_size(tfd, dv->devname, &ldsize)) { + if (dv->disposition == 'M') +@@ -907,6 +908,9 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + disc.raid_disk = 0; + } + ++ if (map_lock(&map)) ++ pr_err("failed to get exclusive lock on mapfile when add disk\n"); ++ + if (array->not_persistent==0) { + int dfd; + if (dv->disposition == 'j') +@@ -918,9 +922,9 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT); + if (tst->ss->add_to_super(tst, &disc, dfd, + dv->devname, INVALID_SECTORS)) +- return -1; ++ goto unlock; + if (tst->ss->write_init_super(tst)) +- return -1; ++ goto unlock; + } else if (dv->disposition == 'A') { + /* this had better be raid1. + * As we are "--re-add"ing we must find a spare slot +@@ -978,14 +982,14 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + pr_err("add failed for %s: could not get exclusive access to container\n", + dv->devname); + tst->ss->free_super(tst); +- return -1; ++ goto unlock; + } + + /* Check if metadata handler is able to accept the drive */ + if (!tst->ss->validate_geometry(tst, LEVEL_CONTAINER, 0, 1, NULL, + 0, 0, dv->devname, NULL, 0, 1)) { + close(container_fd); +- return -1; ++ goto unlock; + } + + Kill(dv->devname, NULL, 0, -1, 0); +@@ -994,7 +998,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + dv->devname, INVALID_SECTORS)) { + close(dfd); + close(container_fd); +- return -1; ++ goto unlock; + } + if (!mdmon_running(tst->container_devnm)) + tst->ss->sync_metadata(tst); +@@ -1005,7 +1009,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + dv->devname); + close(container_fd); + tst->ss->free_super(tst); +- return -1; ++ goto unlock; + } + sra->array.level = LEVEL_CONTAINER; + /* Need to set data_offset and component_size */ +@@ -1020,7 +1024,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + pr_err("add new device to external metadata failed for %s\n", dv->devname); + close(container_fd); + sysfs_free(sra); +- return -1; ++ goto unlock; + } + ping_monitor(devnm); + sysfs_free(sra); +@@ -1034,7 +1038,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + else + pr_err("add new device failed for %s as %d: %s\n", + dv->devname, j, strerror(errno)); +- return -1; ++ goto unlock; + } + if (dv->disposition == 'j') { + pr_err("Journal added successfully, making %s read-write\n", devname); +@@ -1045,7 +1049,11 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv, + } + if (verbose >= 0) + pr_err("added %s\n", dv->devname); ++ map_unlock(&map); + return 1; ++unlock: ++ map_unlock(&map); ++ return -1; + } + + int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv, +-- +2.40.1 + diff --git a/SOURCES/0161-mdadm-tests-Don-t-run-mknod-before-losetup.patch b/SOURCES/0161-mdadm-tests-Don-t-run-mknod-before-losetup.patch new file mode 100644 index 0000000..7d00a5b --- /dev/null +++ b/SOURCES/0161-mdadm-tests-Don-t-run-mknod-before-losetup.patch @@ -0,0 +1,32 @@ +From c32b4754014c1eec8cc0c025fad2e9b621486164 Mon Sep 17 00:00:00 2001 +From: Xiao Ni +Date: Fri, 8 Sep 2023 16:44:35 +0800 +Subject: [PATCH 161/165] mdadm/tests: Don't run mknod before losetup + +Sometimes it can fail: +losetup: /var/tmp/mdtest0: failed to set up loop device: No such device or address +/dev/loop0 and /var/tmp/mdtest0 are already created before losetup. + +Because losetup can create device node by itself. So remove mknod. + +Signed-off-by: Xiao Ni +Signed-off-by: Jes Sorensen +--- + tests/func.sh | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tests/func.sh b/tests/func.sh +index 9710a53b..5053b012 100644 +--- a/tests/func.sh ++++ b/tests/func.sh +@@ -170,7 +170,6 @@ do_setup() { + dd if=/dev/zero of=$targetdir/mdtest$d count=$sz bs=1K > /dev/null 2>&1 + # make sure udev doesn't touch + mdadm --zero $targetdir/mdtest$d 2> /dev/null +- [ -b /dev/loop$d ] || mknod /dev/loop$d b 7 $d + if [ $d -eq 7 ] + then + losetup /dev/loop$d $targetdir/mdtest6 # for multipath use +-- +2.40.1 + diff --git a/SOURCES/0162-mdadm-ddf-Abort-when-raid-disk-is-smaller-in-getinfo.patch b/SOURCES/0162-mdadm-ddf-Abort-when-raid-disk-is-smaller-in-getinfo.patch new file mode 100644 index 0000000..9c9ad6b --- /dev/null +++ b/SOURCES/0162-mdadm-ddf-Abort-when-raid-disk-is-smaller-in-getinfo.patch @@ -0,0 +1,45 @@ +From 246b4b40558f6f7f84882e9c34659f1b582944e2 Mon Sep 17 00:00:00 2001 +From: Xiao Ni +Date: Wed, 11 Oct 2023 21:03:32 +0800 +Subject: [PATCH 162/165] mdadm/ddf: Abort when raid disk is smaller in + getinfo_super_ddf +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The metadata is corrupted when the raid_disk<0. So abort directly. +This also can avoid a building error: +super-ddf.c:1988:58: error: array subscript -1 is below array bounds of ‘struct phys_disk_entry[0]’ + +Suggested-by: Mariusz Tkaczyk +Ackedy-by: Xiao Ni +Acked-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super-ddf.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/super-ddf.c b/super-ddf.c +index c5242654..7571e3b7 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -1984,12 +1984,14 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m + info->disk.number = be32_to_cpu(ddf->dlist->disk.refnum); + info->disk.raid_disk = find_phys(ddf, ddf->dlist->disk.refnum); + ++ if (info->disk.raid_disk < 0) ++ return; ++ + info->data_offset = be64_to_cpu(ddf->phys-> + entries[info->disk.raid_disk]. + config_size); + info->component_size = ddf->dlist->size - info->data_offset; +- if (info->disk.raid_disk >= 0) +- pde = ddf->phys->entries + info->disk.raid_disk; ++ pde = ddf->phys->entries + info->disk.raid_disk; + if (pde && + !(be16_to_cpu(pde->state) & DDF_Failed) && + !(be16_to_cpu(pde->state) & DDF_Missing)) +-- +2.40.1 + diff --git a/SOURCES/0163-mdadm-super1-Add-MD_FEATURE_RAID0_LAYOUT-if-kernel-5.patch b/SOURCES/0163-mdadm-super1-Add-MD_FEATURE_RAID0_LAYOUT-if-kernel-5.patch new file mode 100644 index 0000000..f31d4c6 --- /dev/null +++ b/SOURCES/0163-mdadm-super1-Add-MD_FEATURE_RAID0_LAYOUT-if-kernel-5.patch @@ -0,0 +1,75 @@ +From 6af520a5b4d91cd0fd32ab6361ff4519505c7f47 Mon Sep 17 00:00:00 2001 +From: Xiao Ni +Date: Tue, 17 Oct 2023 20:35:46 +0800 +Subject: [PATCH 163/165] mdadm/super1: Add MD_FEATURE_RAID0_LAYOUT if + kernel>=5.4 + +After and include kernel v5.4, it adds one feature bit MD_FEATURE_RAID0_LAYOUT. +It must need to specify a layout for raid0 with more than one zone. But for +raid0 with one zone, in fact it also has a defalut layout. + +Now for raid0 with one zone, *unknown* layout can be seen when running mdadm -D +command. It's the reason that mdadm doesn't set MD_FEATURE_RAID0_LAYOUT for +raid0 with one zone. Then in kernel space, super_1_validate sets mddev->layout +to -1 because of no MD_FEATURE_RAID0_LAYOUT. In fact, in raid0 io path, it +uses the default layout. Set raid0_need_layout to true if kernel_version<=v5.4. + +Fixes: 329dfc28debb ('Create: add support for RAID0 layouts.') +Signed-off-by: Xiao Ni +Reviewed-by: Mariusz Tkaczyk +Signed-off-by: Jes Sorensen +--- + super1.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/super1.c b/super1.c +index 856b0208..1da71b98 100644 +--- a/super1.c ++++ b/super1.c +@@ -1967,6 +1967,14 @@ fail_to_write: + return 1; + } + ++static bool has_raid0_layout(struct mdp_superblock_1 *sb) ++{ ++ if (sb->level == 0 && sb->layout != 0) ++ return true; ++ else ++ return false; ++} ++ + static int write_init_super1(struct supertype *st) + { + struct mdp_superblock_1 *sb = st->sb; +@@ -1978,12 +1986,17 @@ static int write_init_super1(struct supertype *st) + unsigned long long sb_offset; + unsigned long long data_offset; + long bm_offset; +- int raid0_need_layout = 0; ++ bool raid0_need_layout = false; ++ ++ /* Since linux kernel v5.4, raid0 always has a layout */ ++ if (has_raid0_layout(sb) && get_linux_version() >= 5004000) ++ raid0_need_layout = true; + + for (di = st->info; di; di = di->next) { + if (di->disk.state & (1 << MD_DISK_JOURNAL)) + sb->feature_map |= __cpu_to_le32(MD_FEATURE_JOURNAL); +- if (sb->level == 0 && sb->layout != 0) { ++ if (has_raid0_layout(sb) && !raid0_need_layout) { ++ + struct devinfo *di2 = st->info; + unsigned long long s1, s2; + s1 = di->dev_size; +@@ -1995,7 +2008,7 @@ static int write_init_super1(struct supertype *st) + s2 -= di2->data_offset; + s2 /= __le32_to_cpu(sb->chunksize); + if (s1 != s2) +- raid0_need_layout = 1; ++ raid0_need_layout = true; + } + } + +-- +2.40.1 + diff --git a/SOURCES/0164-mdadm-remove-container_enough-logic.patch b/SOURCES/0164-mdadm-remove-container_enough-logic.patch new file mode 100644 index 0000000..2077aab --- /dev/null +++ b/SOURCES/0164-mdadm-remove-container_enough-logic.patch @@ -0,0 +1,139 @@ +From 4dde420fc3e24077ab926f79674eaae1b71de10b Mon Sep 17 00:00:00 2001 +From: Pawel Piatkowski +Date: Thu, 19 Oct 2023 16:35:24 +0200 +Subject: [PATCH 164/165] mdadm: remove container_enough logic + +Arrays without enough disk count will be assembled but not +started. +Now RAIDs will be assembled always (even if they are failed). +RAID devices in all states will be assembled and exposed +to mdstat. +This change affects only IMSM (for ddf it wasn't used, +container_enough was set to true always). +Removed this logic from incremental_container as well with +runstop checking because runstop condition is being verified +in assemble_container_content function. + +Signed-off-by: Pawel Piatkowski +Signed-off-by: Jes Sorensen +--- + Incremental.c | 11 ----------- + mdadm.h | 3 --- + super-ddf.c | 1 - + super-intel.c | 32 +------------------------------- + 4 files changed, 1 insertion(+), 46 deletions(-) + +diff --git a/Incremental.c b/Incremental.c +index 05b33c45..3551c65b 100644 +--- a/Incremental.c ++++ b/Incremental.c +@@ -1467,17 +1467,6 @@ static int Incremental_container(struct supertype *st, char *devname, + + st->ss->getinfo_super(st, &info, NULL); + +- if ((c->runstop > 0 && info.container_enough >= 0) || +- info.container_enough > 0) +- /* pass */; +- else { +- if (c->export) { +- printf("MD_STARTED=no\n"); +- } else if (c->verbose) +- pr_err("not enough devices to start the container\n"); +- return 0; +- } +- + match = conf_match(st, &info, devname, c->verbose, &rv); + if (match == NULL && rv == 2) + return rv; +diff --git a/mdadm.h b/mdadm.h +index 9effb941..b48e6f86 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -377,9 +377,6 @@ struct mdinfo { + int container_member; /* for assembling external-metatdata arrays + * This is to be used internally by metadata + * handler only */ +- int container_enough; /* flag external handlers can set to +- * indicate that subarrays have not enough (-1), +- * enough to start (0), or all expected disks (1) */ + char sys_name[32]; + struct mdinfo *devs; + struct mdinfo *next; +diff --git a/super-ddf.c b/super-ddf.c +index 7571e3b7..a87e3169 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -1975,7 +1975,6 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m + info->array.ctime = DECADE + __be32_to_cpu(*cptr); + + info->array.chunk_size = 0; +- info->container_enough = 1; + + info->disk.major = 0; + info->disk.minor = 0; +diff --git a/super-intel.c b/super-intel.c +index 05d3b056..6bdd5c4c 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -3806,7 +3806,6 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char * + struct intel_super *super = st->sb; + struct imsm_disk *disk; + int map_disks = info->array.raid_disks; +- int max_enough = -1; + int i; + struct imsm_super *mpb; + +@@ -3848,12 +3847,9 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char * + + for (i = 0; i < mpb->num_raid_devs; i++) { + struct imsm_dev *dev = get_imsm_dev(super, i); +- int failed, enough, j, missing = 0; ++ int j = 0; + struct imsm_map *map; +- __u8 state; + +- failed = imsm_count_failed(super, dev, MAP_0); +- state = imsm_check_degraded(super, dev, failed, MAP_0); + map = get_imsm_map(dev, MAP_0); + + /* any newly missing disks? +@@ -3868,36 +3864,10 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char * + + if (!(ord & IMSM_ORD_REBUILD) && + get_imsm_missing(super, idx)) { +- missing = 1; + break; + } + } +- +- if (state == IMSM_T_STATE_FAILED) +- enough = -1; +- else if (state == IMSM_T_STATE_DEGRADED && +- (state != map->map_state || missing)) +- enough = 0; +- else /* we're normal, or already degraded */ +- enough = 1; +- if (is_gen_migration(dev) && missing) { +- /* during general migration we need all disks +- * that process is running on. +- * No new missing disk is allowed. +- */ +- max_enough = -1; +- enough = -1; +- /* no more checks necessary +- */ +- break; +- } +- /* in the missing/failed disk case check to see +- * if at least one array is runnable +- */ +- max_enough = max(max_enough, enough); + } +- dprintf("enough: %d\n", max_enough); +- info->container_enough = max_enough; + + if (super->disks) { + __u32 reserved = imsm_reserved_sectors(super, super->disks); +-- +2.40.1 + diff --git a/SOURCES/0165-Fix-assembling-RAID-volume-by-using-incremental.patch b/SOURCES/0165-Fix-assembling-RAID-volume-by-using-incremental.patch new file mode 100644 index 0000000..0db1767 --- /dev/null +++ b/SOURCES/0165-Fix-assembling-RAID-volume-by-using-incremental.patch @@ -0,0 +1,49 @@ +From d8d09c1633b2f06f88633ab960aa02b41a6bdfb6 Mon Sep 17 00:00:00 2001 +From: Pawel Piatkowski +Date: Thu, 19 Oct 2023 16:35:25 +0200 +Subject: [PATCH 165/165] Fix assembling RAID volume by using incremental + +After change "mdadm: remove container_enough logic" +IMSM volumes are started immediately. If volume is during +reshape, then it will be blocked by block_subarray() during +first mdadm -I . Assemble_container_content() for +next disk will see the change because metadata version from +sysfs and metadata doesn't match and will execute +sysfs_set_array again. Then it fails to set same +component_size, it is prohibited by kernel. + +If array is frozen then first sign from metadata version +is different ("/" vs "-"), so exclude it from comparison. +All we want is to double check that base properties are set +and we don't need to call sysfs_set_array again. + +Signed-off-by: Pawel Piatkowski +Signed-off-by: Jes Sorensen +--- + Assemble.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/Assemble.c b/Assemble.c +index 5be58e40..0557a007 100644 +--- a/Assemble.c ++++ b/Assemble.c +@@ -1990,12 +1990,10 @@ int assemble_container_content(struct supertype *st, int mdfd, + return 1; + } + +- if (strcmp(sra->text_version, content->text_version) != 0) { +- if (content->array.major_version == -1 && +- content->array.minor_version == -2 && +- c->readonly && +- content->text_version[0] == '/') +- content->text_version[0] = '-'; ++ /* Fill sysfs properties only if they are not set. Determine it by checking text_version ++ * and ignoring special character on the first place. ++ */ ++ if (strcmp(sra->text_version + 1, content->text_version + 1) != 0) { + if (sysfs_set_array(content, 9003) != 0) { + sysfs_free(sra); + return 1; +-- +2.40.1 + diff --git a/SOURCES/0166-Revert-mdadm-remove-container_enough-logic.patch b/SOURCES/0166-Revert-mdadm-remove-container_enough-logic.patch new file mode 100644 index 0000000..943fd9d --- /dev/null +++ b/SOURCES/0166-Revert-mdadm-remove-container_enough-logic.patch @@ -0,0 +1,151 @@ +From 476b00bdeeb6c004b3a758bd842b0fa9e4164508 Mon Sep 17 00:00:00 2001 +From: Mariusz Tkaczyk +Date: Mon, 5 Feb 2024 15:50:29 +0100 +Subject: [PATCH 1/1] Revert "mdadm: remove container_enough logic" + +Mentioned patch changes way of IMSM member arrays assembling, they are +updated by every new drive incremental processes. Previously, member +arrays were created and filled once, by last drive incremental process. + +We determined regressions with various impact. Unfortunately, initial +testing didn't show them. + +Regressions are connected to drive appearance order and may not be +reproducible on every configuration, there are at least two know +issues for now: + +- sysfs attributes are filled using old metadata if there is + outdated drive and it is enumerated first. + +- rebuild may be aborted and started from beginning after reboot, + if drive under rebuild is enumerated as the last one. + +This reverts commit 4dde420fc3e24077ab926f79674eaae1b71de10b. It fixes +checkpatch issues and reworks logic to remove empty "if" branch in +Incremental. + +Signed-off-by: Mariusz Tkaczyk +--- + Incremental.c | 9 +++++++++ + mdadm.h | 7 +++++++ + super-ddf.c | 1 + + super-intel.c | 32 +++++++++++++++++++++++++++++++- + 4 files changed, 48 insertions(+), 1 deletion(-) + +diff --git a/Incremental.c b/Incremental.c +index 6cbc164a27b9..30c07c037028 100644 +--- a/Incremental.c ++++ b/Incremental.c +@@ -1467,6 +1467,15 @@ static int Incremental_container(struct supertype *st, char *devname, + + st->ss->getinfo_super(st, &info, NULL); + ++ if (info.container_enough < 0 || (info.container_enough == 0 && c->runstop < 1)) { ++ if (c->export) ++ printf("MD_STARTED=no\n"); ++ else if (c->verbose) ++ pr_err("Not enough devices to start the container.\n"); ++ ++ return 0; ++ } ++ + match = conf_match(st, &info, devname, c->verbose, &rv); + if (match == NULL && rv == 2) + return rv; +diff --git a/mdadm.h b/mdadm.h +index 709b6104c401..1f28b3e754be 100644 +--- a/mdadm.h ++++ b/mdadm.h +@@ -377,6 +377,13 @@ struct mdinfo { + int container_member; /* for assembling external-metatdata arrays + * This is to be used internally by metadata + * handler only */ ++ /** ++ * flag external handlers can set to indicate that subarrays have: ++ * - not enough disks to start (-1), ++ * - enough disks to start (0), ++ * - all expected disks (1). ++ */ ++ int container_enough; + char sys_name[32]; + struct mdinfo *devs; + struct mdinfo *next; +diff --git a/super-ddf.c b/super-ddf.c +index a87e3169d325..7571e3b740c6 100644 +--- a/super-ddf.c ++++ b/super-ddf.c +@@ -1975,6 +1975,7 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m + info->array.ctime = DECADE + __be32_to_cpu(*cptr); + + info->array.chunk_size = 0; ++ info->container_enough = 1; + + info->disk.major = 0; + info->disk.minor = 0; +diff --git a/super-intel.c b/super-intel.c +index 6a664a2e58d3..dbea235dd4bd 100644 +--- a/super-intel.c ++++ b/super-intel.c +@@ -3778,6 +3778,7 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char * + struct intel_super *super = st->sb; + struct imsm_disk *disk; + int map_disks = info->array.raid_disks; ++ int max_enough = -1; + int i; + struct imsm_super *mpb; + +@@ -3819,9 +3820,12 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char * + + for (i = 0; i < mpb->num_raid_devs; i++) { + struct imsm_dev *dev = get_imsm_dev(super, i); +- int j = 0; ++ int failed, enough, j, missing = 0; + struct imsm_map *map; ++ __u8 state; + ++ failed = imsm_count_failed(super, dev, MAP_0); ++ state = imsm_check_degraded(super, dev, failed, MAP_0); + map = get_imsm_map(dev, MAP_0); + + /* any newly missing disks? +@@ -3836,11 +3840,37 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char * + + if (!(ord & IMSM_ORD_REBUILD) && + get_imsm_missing(super, idx)) { ++ missing = 1; + break; + } + } ++ ++ if (state == IMSM_T_STATE_FAILED) ++ enough = -1; ++ else if (state == IMSM_T_STATE_DEGRADED && ++ (state != map->map_state || missing)) ++ enough = 0; ++ else /* we're normal, or already degraded */ ++ enough = 1; ++ if (is_gen_migration(dev) && missing) { ++ /* during general migration we need all disks ++ * that process is running on. ++ * No new missing disk is allowed. ++ */ ++ max_enough = -1; ++ enough = -1; ++ /* no more checks necessary ++ */ ++ break; ++ } ++ /* in the missing/failed disk case check to see ++ * if at least one array is runnable ++ */ ++ max_enough = max(max_enough, enough); + } + ++ info->container_enough = max_enough; ++ + if (super->disks) { + __u32 reserved = imsm_reserved_sectors(super, super->disks); + +-- +2.32.0 (Apple Git-132) + diff --git a/SOURCES/disable-Werror.patch b/SOURCES/disable-Werror.patch deleted file mode 100644 index 2d52c67..0000000 --- a/SOURCES/disable-Werror.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- mdadm/Makefile.orig 2021-07-28 21:39:23.887433859 +0800 -+++ mdadm/Makefile 2021-07-28 21:39:37.989432841 +0800 -@@ -50,7 +50,7 @@ - CC := $(CROSS_COMPILE)gcc - endif - CXFLAGS ?= -ggdb --CWFLAGS = -Wall -Werror -Wstrict-prototypes -Wextra -Wno-unused-parameter -+CWFLAGS = -Wall -Wstrict-prototypes -Wextra -Wno-unused-parameter - ifdef WARN_UNUSED - CWFLAGS += -Wp,-D_FORTIFY_SOURCE=2 -O3 - endif diff --git a/SOURCES/md-auto-readd.rule b/SOURCES/md-auto-readd.rule new file mode 100644 index 0000000..5ce29fb --- /dev/null +++ b/SOURCES/md-auto-readd.rule @@ -0,0 +1,27 @@ +# +# Enable/Disable - default is Disabled +# to disable this rule, GOTO="md_end" should be the first active command. +# to enable this rule, Comment out GOTO="md_end". +GOTO="md_end" + +# Required: MD arrays must have a bitmap for transient devices to +# be added back in the array. +# mdadm -CR /dev/md0 -l1 -n2 /dev/sd[ab] –bitmap=internal + +# Don't process any events if anaconda is running as anaconda brings up +# raid devices manually +ENV{ANACONDA}=="?*", GOTO="md_end" + +# Also don't process disks that are slated to be a multipath device +ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="md_end" + +# We process add events on block devices (since they are ready as soon as +# they are added to the system) + +ACTION!="add", GOTO="md_end" +ENV{ID_FS_TYPE}!="linux_raid_member", GOTO="md_end" +SUBSYSTEM=="block", RUN{program}+="/usr/sbin/md-auto-readd.sh $devnode" + +# +# Land here to exit cleanly +LABEL="md_end" diff --git a/SOURCES/md-auto-readd.sh b/SOURCES/md-auto-readd.sh new file mode 100644 index 0000000..f15c482 --- /dev/null +++ b/SOURCES/md-auto-readd.sh @@ -0,0 +1,17 @@ +#!/usr/bin/bash +MDADM=/sbin/mdadm +DEVNAME=$1 + +export $(${MDADM} --examine --export ${DEVNAME}) +if [ -z "${MD_UUID}" ]; then + exit 1 +fi + +UUID_LINK=$(readlink /dev/disk/by-id/md-uuid-${MD_UUID}) +MD_DEVNAME=${UUID_LINK##*/} +export $(${MDADM} --detail --export /dev/${MD_DEVNAME}) +if [ -z "${MD_METADATA}" ] ; then + exit 1 +fi + +${MDADM} --manage /dev/${MD_DEVNAME} --re-add ${DEVNAME} --verbose diff --git a/SOURCES/mdcheck b/SOURCES/mdcheck new file mode 100644 index 0000000..700c3e2 --- /dev/null +++ b/SOURCES/mdcheck @@ -0,0 +1,166 @@ +#!/bin/bash + +# Copyright (C) 2014-2017 Neil Brown +# +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Author: Neil Brown +# Email: + +# This script should be run periodically to automatically +# perform a 'check' on any md arrays. +# +# It supports a 'time budget' such that any incomplete 'check' +# will be checkpointed when that time has expired. +# A subsequent invocation can allow the 'check' to continue. +# +# Options are: +# --continue Don't start new checks, only continue old ones. +# --duration This is passed to "date --date=$duration" to find out +# when to finish +# +# To support '--continue', arrays are identified by UUID and the 'sync_completed' +# value is stored in /var/lib/mdcheck/$UUID + +# convert a /dev/md name into /sys/.../md equivalent +sysname() { + set `ls -lLd $1` + maj=${5%,} + min=$6 + readlink -f /sys/dev/block/$maj:$min +} + +args=$(getopt -o hcd: -l help,continue,duration: -n mdcheck -- "$@") +rv=$? +if [ $rv -ne 0 ]; then exit $rv; fi + +eval set -- $args + +cont= +endtime= +while [ " $1" != " --" ] +do + case $1 in + --help ) + echo >&2 'Usage: mdcheck [--continue] [--duration time-offset]' + echo >&2 ' time-offset must be understood by "date --date"' + exit 0 + ;; + --continue ) cont=yes ;; + --duration ) shift; dur=$1 + endtime=$(date --date "$dur" "+%s") + ;; + esac + shift +done +shift + +# We need a temp file occasionally... +tmp=/var/lib/mdcheck/.md-check-$$ +trap 'rm -f "$tmp"' 0 2 3 15 + + +# firstly, clean out really old state files +mkdir -p /var/lib/mdcheck +find /var/lib/mdcheck -name "MD_UUID*" -type f -mtime +180 -exec rm {} \; + +# Now look at each md device. +cnt=0 +for dev in /dev/md?* +do + [ -e "$dev" ] || continue + sys=`sysname $dev` + if [ ! -f "$sys/md/sync_action" ] + then # cannot check this array + continue + fi + if [ "`cat $sys/md/sync_action`" != 'idle' ] + then # This array is busy + continue + fi + + mdadm --detail --export "$dev" | grep '^MD_UUID=' > $tmp || continue + source $tmp + fl="/var/lib/mdcheck/MD_UUID_$MD_UUID" + if [ -z "$cont" ] + then + start=0 + logger -p daemon.info mdcheck start checking $dev + elif [ -z "$MD_UUID" -o ! -f "$fl" ] + then + # Nothing to continue here + continue + else + start=`cat "$fl"` + logger -p daemon.info mdcheck continue checking $dev from $start + fi + + cnt=$[cnt+1] + eval MD_${cnt}_fl=\$fl + eval MD_${cnt}_sys=\$sys + eval MD_${cnt}_dev=\$dev + echo $start > $fl + echo $start > $sys/md/sync_min + echo check > $sys/md/sync_action +done + +if [ -z "$endtime" ] +then + exit 0 +fi + +while [ `date +%s` -lt $endtime ] +do + any= + for i in `eval echo {1..$cnt}` + do + eval fl=\$MD_${i}_fl + eval sys=\$MD_${i}_sys + eval dev=\$MD_${i}_dev + + if [ -z "$fl" ]; then continue; fi + + if [ "`cat $sys/md/sync_action`" != 'check' ] + then + logger -p daemon.info mdcheck finished checking $dev + eval MD_${i}_fl= + rm -f $fl + continue; + fi + read a rest < $sys/md/sync_completed + echo $a > $fl + any=yes + done + if [ -z "$any" ]; then exit 0; fi + sleep 120 +done + +# We've waited, and there are still checks running. +# Time to stop them. +for i in `eval echo {1..$cnt}` +do + eval fl=\$MD_${i}_fl + eval sys=\$MD_${i}_sys + eval dev=\$MD_${i}_dev + + if [ -z "$fl" ]; then continue; fi + + if [ "`cat $sys/md/sync_action`" != 'check' ] + then + eval MD_${i}_fl= + rm -f $fl + continue; + fi + echo idle > $sys/md/sync_action + cat $sys/md/sync_min > $fl + logger -p daemon.info pause checking $dev at `cat $fl` +done diff --git a/SPECS/mdadm.spec b/SPECS/mdadm.spec index 3693f7b..fb8e164 100644 --- a/SPECS/mdadm.spec +++ b/SPECS/mdadm.spec @@ -1,7 +1,7 @@ Name: mdadm Version: 4.2 # extraversion is used to define rhel internal version -%define extraversion 8 +%define extraversion 12 Release: %{extraversion}%{?dist} Summary: The mdadm program controls Linux md devices (software RAID arrays) URL: http://www.kernel.org/pub/linux/utils/raid/mdadm/ @@ -15,6 +15,9 @@ Source4: mdadm.conf Source5: mdadm_event.conf Source6: raid-check.timer Source7: raid-check.service +Source8: mdcheck +Source9: md-auto-readd.rule +Source10: md-auto-readd.sh Patch000: 0001-Unify-error-message.patch Patch001: 0002-mdadm-Fix-double-free.patch @@ -27,85 +30,166 @@ Patch007: 0008-mdadm-Update-config-man-regarding-default-files-and-.patch Patch008: 0009-mdadm-Update-config-manual.patch Patch009: 0010-Create-Build-use-default_layout.patch Patch010: 0011-mdadm-add-map_num_s.patch -# patch0012 is deleted because of needing KillMode=none -Patch011: 0013-mdmon-Stop-parsing-duplicate-options.patch -Patch012: 0014-Grow-block-n-on-external-volumes.patch -Patch013: 0015-Incremental-Fix-possible-memory-and-resource-leaks.patch -Patch014: 0016-Mdmonitor-Fix-segfault.patch -Patch015: 0017-Mdmonitor-Improve-logging-method.patch -Patch016: 0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch -Patch017: 0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch -Patch018: 0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch -Patch019: 0021-util-replace-ioctl-use-with-function.patch -Patch020: 0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch -Patch021: 0023-imsm-introduce-get_disk_slot_in_dev.patch -Patch022: 0024-imsm-use-same-slot-across-container.patch -Patch023: 0025-imsm-block-changing-slots-during-creation.patch -Patch024: 0026-mdadm-block-update-ppl-for-non-raid456-levels.patch -Patch025: 0027-mdadm-Fix-array-size-mismatch-after-grow.patch -Patch026: 0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch -Patch027: 0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch -Patch028: 0030-Monitor-use-snprintf-to-fill-device-name.patch -Patch029: 0031-Makefile-Don-t-build-static-build-with-everything-an.patch -Patch030: 0032-DDF-Cleanup-validate_geometry_ddf_container.patch -Patch031: 0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch -Patch032: 0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch -Patch033: 0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch -Patch034: 0036-mdadm-Fix-mdadm-r-remove-option-regression.patch -Patch035: 0037-mdadm-Fix-optional-write-behind-parameter.patch -Patch036: 0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch -Patch037: 0039-tests-fix-raid0-tests-for-0.90-metadata.patch -Patch038: 0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch -Patch039: 0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch -Patch040: 0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch -Patch041: 0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch -Patch042: 0044-tests-Add-broken-files-for-all-broken-tests.patch -Patch043: 0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch -Patch044: 0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch -Patch045: 0047-tests-add-test-for-names.patch -Patch046: 0048-mdadm-remove-symlink-option.patch -Patch047: 0049-mdadm-move-data_offset-to-struct-shape.patch -Patch048: 0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch -Patch049: 0051-Grow-Split-Grow_reshape-into-helper-function.patch -Patch050: 0052-Assemble-check-if-device-is-container-before-schedul.patch -Patch051: 0053-super1-report-truncated-device.patch -Patch052: 0054-mdadm-Correct-typos-punctuation-and-grammar-in-man.patch -Patch053: 0055-Manage-Block-unsafe-member-failing.patch -Patch054: 0056-Monitor-Fix-statelist-memory-leaks.patch -Patch055: 0057-mdadm-added-support-for-Intel-Alderlake-RST-on-VMD-p.patch -Patch056: 0058-mdadm-Add-Documentation-entries-to-systemd-services.patch -Patch057: 0059-ReadMe-fix-command-line-help.patch -Patch058: 0060-mdadm-replace-container-level-checking-with-inline.patch -Patch059: 0061-Mdmonitor-Omit-non-md-devices.patch -Patch060: 0062-Mdmonitor-Split-alert-into-separate-functions.patch -Patch061: 0063-Monitor-block-if-monitor-modes-are-combined.patch -Patch062: 0064-Update-mdadm-Monitor-manual.patch -Patch063: 0065-Grow-fix-possible-memory-leak.patch -Patch064: 0066-mdadm-create-ident_init.patch -Patch065: 0067-mdadm-Add-option-validation-for-update-subarray.patch -Patch066: 0068-Fix-update-subarray-on-active-volume.patch -Patch067: 0069-Add-code-specific-update-options-to-enum.patch -Patch068: 0070-super-ddf-Remove-update_super_ddf.patch -Patch069: 0071-super0-refactor-the-code-for-enum.patch -Patch070: 0072-super1-refactor-the-code-for-enum.patch -Patch071: 0073-super-intel-refactor-the-code-for-enum.patch -Patch072: 0074-Change-update-to-enum-in-update_super-and-update_sub.patch -Patch073: 0075-Manage-Incremental-code-refactor-string-to-enum.patch -Patch074: 0076-Change-char-to-enum-in-context-update-refactor-code.patch -Patch075: 0077-mdmon-fix-segfault.patch -Patch076: 0078-util-remove-obsolete-code-from-get_md_name.patch -Patch077: 0079-mdadm-udev-Don-t-handle-change-event-on-raw-devices.patch -Patch078: 0080-Manage-do-not-check-array-state-when-drive-is-remove.patch -Patch079: 0081-incremental-manage-do-not-verify-if-remove-is-safe.patch -Patch080: 0082-super-intel-make-freesize-not-required-for-chunk-siz.patch -Patch081: 0083-manage-move-comment-with-function-description.patch +Patch011: 0012-mdadm-systemd-remove-KillMode-none-from-service-file.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 +Patch052: 0053-super1-report-truncated-device.patch +Patch053: 0054-mdadm-Correct-typos-punctuation-and-grammar-in-man.patch +Patch054: 0055-Manage-Block-unsafe-member-failing.patch +Patch055: 0056-Monitor-Fix-statelist-memory-leaks.patch +Patch056: 0057-mdadm-added-support-for-Intel-Alderlake-RST-on-VMD-p.patch +Patch057: 0058-mdadm-Add-Documentation-entries-to-systemd-services.patch +Patch058: 0059-ReadMe-fix-command-line-help.patch +Patch059: 0060-mdadm-replace-container-level-checking-with-inline.patch +Patch060: 0061-Mdmonitor-Omit-non-md-devices.patch +Patch061: 0062-Mdmonitor-Split-alert-into-separate-functions.patch +Patch062: 0063-Monitor-block-if-monitor-modes-are-combined.patch +Patch063: 0064-Update-mdadm-Monitor-manual.patch +Patch064: 0065-Grow-fix-possible-memory-leak.patch +Patch065: 0066-mdadm-create-ident_init.patch +Patch066: 0067-mdadm-Add-option-validation-for-update-subarray.patch +Patch067: 0068-Fix-update-subarray-on-active-volume.patch +Patch068: 0069-Add-code-specific-update-options-to-enum.patch +Patch069: 0070-super-ddf-Remove-update_super_ddf.patch +Patch070: 0071-super0-refactor-the-code-for-enum.patch +Patch071: 0072-super1-refactor-the-code-for-enum.patch +Patch072: 0073-super-intel-refactor-the-code-for-enum.patch +Patch073: 0074-Change-update-to-enum-in-update_super-and-update_sub.patch +Patch074: 0075-Manage-Incremental-code-refactor-string-to-enum.patch +Patch075: 0076-Change-char-to-enum-in-context-update-refactor-code.patch +Patch076: 0077-mdmon-fix-segfault.patch +Patch077: 0078-util-remove-obsolete-code-from-get_md_name.patch +Patch078: 0079-mdadm-udev-Don-t-handle-change-event-on-raw-devices.patch +Patch079: 0080-Manage-do-not-check-array-state-when-drive-is-remove.patch +Patch080: 0081-incremental-manage-do-not-verify-if-remove-is-safe.patch +Patch081: 0082-super-intel-make-freesize-not-required-for-chunk-siz.patch +Patch082: 0083-manage-move-comment-with-function-description.patch +Patch083: 0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch +Patch084: 0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch +Patch085: 0086-Fix-NULL-dereference-in-super_by_fd.patch +Patch086: 0087-Mdmonitor-Make-alert_info-global.patch +Patch087: 0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch +Patch088: 0089-Mdmonitor-Add-helper-functions.patch +Patch089: 0090-Add-helpers-to-determine-whether-directories-or-file.patch +Patch090: 0091-Mdmonitor-Refactor-write_autorebuild_pid.patch +Patch091: 0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch +Patch092: 0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch +Patch093: 0094-util.c-fix-memleak-in-parse_layout_faulty.patch +Patch094: 0095-Detail.c-fix-memleak-in-Detail.patch +Patch095: 0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch +Patch096: 0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch +Patch097: 0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch +Patch098: 0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch +Patch099: 0100-Create-remove-safe_mode_delay-local-variable.patch +Patch100: 0101-Create-Factor-out-add_disks-helpers.patch +Patch101: 0102-mdadm-Introduce-pr_info.patch +Patch102: 0103-mdadm-Add-write-zeros-option-for-Create.patch +Patch103: 0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch +Patch104: 0105-manpage-Add-write-zeroes-option-to-manpage.patch +Patch105: 0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch +Patch106: 0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch +Patch107: 0108-mdmon-don-t-test-both-all-and-container_name.patch +Patch108: 0109-mdmon-change-systemd-unit-file-to-use-foreground.patch +Patch109: 0110-mdmon-Remove-need-for-KillMode-none.patch +Patch110: 0111-mdmon-Improve-switchroot-interactions.patch +Patch111: 0112-mdopen-always-try-create_named_array.patch +Patch112: 0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch +Patch113: 0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch +Patch114: 0115-Create-Fix-checking-for-container-in-update_metadata.patch +Patch115: 0116-Fix-null-pointer-for-incremental-in-mdadm.patch +Patch116: 0117-super1-fix-truncation-check-for-journal-device.patch +Patch117: 0118-Fix-some-cases-eyesore-formatting.patch +Patch118: 0119-Bump-minimum-kernel-version-to-2.6.32.patch +Patch119: 0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch +Patch120: 0121-mdadm-define-DEV_MD_DIR.patch +Patch121: 0122-mdadm-define-DEV_NUM_PREF.patch +Patch122: 0123-mdadm-define-is_devname_ignore.patch +Patch123: 0124-mdadm-numbered-names-verification.patch +Patch124: 0125-enable-RAID-for-SATA-under-VMD.patch +Patch125: 0126-imsm-Fix-possible-segfault-in-check_no_platform.patch +Patch126: 0127-imsm-move-sum_extents-calculations-to-merge_extents.patch +Patch127: 0128-imsm-imsm_get_free_size-refactor.patch +Patch128: 0129-imsm-introduce-round_member_size_to_mb.patch +Patch129: 0130-imsm-move-expand-verification-code-into-new-function.patch +Patch130: 0131-imsm-return-free-space-after-volume-for-expand.patch +Patch131: 0132-imsm-fix-free-space-calculations.patch +Patch132: 0133-Add-secure-gethostname-wrapper.patch +Patch133: 0134-mdadm-Stop-mdcheck_continue-timer-when-mdcheck_start.patch +Patch134: 0135-Fix-memory-leak-in-file-Assemble.patch +Patch135: 0136-Fix-memory-leak-in-file-Kill.patch +Patch136: 0137-Fix-memory-leak-in-file-Manage.patch +Patch137: 0138-Fix-memory-leak-in-file-mdadm.patch +Patch138: 0139-Fix-unsafe-string-functions.patch +Patch139: 0140-platform-intel-limit-guid-length.patch +Patch140: 0141-imsm-Add-reading-vmd-register-for-finding-imsm-capab.patch +Patch141: 0142-Add-compiler-defenses-flags.patch +Patch142: 0143-Assemble-fix-redundant-memory-free.patch +Patch143: 0144-tests-add-a-new-test-for-rdev-lifetime.patch +Patch144: 0145-tests-support-to-skip-checking-dmesg.patch +Patch145: 0146-tests-add-a-regression-test-for-raid10-deadlock.patch +Patch146: 0147-tests-add-a-regression-test-for-raid456-deadlock.patch +Patch147: 0148-tests-add-a-regression-test-that-raid456-can-t-assem.patch +Patch148: 0149-tests-add-a-regression-test-that-raid456-can-t-assem.patch +Patch149: 0150-tests-add-a-regression-test-that-reshape-can-corrupt.patch +Patch150: 0151-tests-add-a-regression-test-for-raid456-deadlock-aga.patch +Patch151: 0152-tests-create-names_template.patch +Patch152: 0153-tests-create-00confnames.patch +Patch153: 0154-mdadm-set-ident.devname-if-applicable.patch +Patch154: 0155-mdadm-refactor-ident-name-handling.patch +Patch155: 0156-mdadm-define-ident_set_devname.patch +Patch156: 0157-mdadm-Follow-POSIX-Portable-Character-Set.patch +Patch157: 0158-Incremental-remove-obsoleted-calls-to-udisks.patch +Patch158: 0159-mdadm-tests-Fix-regular-expression-failure.patch +Patch159: 0160-Fix-race-of-mdadm-add-and-mdadm-incremental.patch +Patch160: 0161-mdadm-tests-Don-t-run-mknod-before-losetup.patch +Patch161: 0162-mdadm-ddf-Abort-when-raid-disk-is-smaller-in-getinfo.patch +Patch162: 0163-mdadm-super1-Add-MD_FEATURE_RAID0_LAYOUT-if-kernel-5.patch +Patch163: 0164-mdadm-remove-container_enough-logic.patch +Patch164: 0165-Fix-assembling-RAID-volume-by-using-incremental.patch +Patch165: 0166-Revert-mdadm-remove-container_enough-logic.patch # Fedora customization patches Patch200: mdadm-udev.patch Patch201: mdadm-2.5.2-static.patch -# Build without -Werror. -Patch202: disable-Werror.patch BuildRequires: make BuildRequires: systemd-rpm-macros binutils-devel gcc systemd-devel @@ -133,6 +217,10 @@ make DESTDIR=%{buildroot} MANDIR=%{_mandir} BINDIR=%{_sbindir} SYSTEMD_DIR=%{_un install -Dp -m 755 %{SOURCE1} %{buildroot}%{_sbindir}/raid-check install -Dp -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/sysconfig/raid-check mkdir -p -m 710 %{buildroot}/run/mdadm +mkdir -p -m 700 %{buildroot}/usr/share/mdadm +install -Dp -m 755 %{SOURCE8} %{buildroot}/usr/share/mdadm/mdcheck +install -Dp -m 644 %{SOURCE9} %{buildroot}%{_udevrulesdir}/66-md-auto-readd.rules +install -Dp -m 755 %{SOURCE10} %{buildroot}%{_sbindir}/md-auto-readd.sh # systemd mkdir -p %{buildroot}%{_unitdir} @@ -172,8 +260,25 @@ install -m644 %{SOURCE5} %{buildroot}/etc/libreport/events.d %dir /run/%{name}/ %config(noreplace) %{_tmpfilesdir}/%{name}.conf /etc/libreport/events.d/* +/usr/share/mdadm/mdcheck %changelog +* Wed Mar 20 2024 Xiao Ni 4.2-12 +- To fix errata/osci problems +- Resolves RHEL-26272 + +* Fri Mar 15 2024 Xiao Ni 4.2-11 +- revert "mdadm: remove container_enough logic" +- Resolves RHEL-26272 + +* Fri Nov 3 2023 Xiao Ni - 4.2-10 +- Update to latest upstream +- Resolves RHEL-15386 + +* Tue May 16 2023 Xiao Ni - 4.2-9 +- Update to latest upstream and fix mdcheck service bug +- Resolves rhbz#2159923, rhbz#2150865, rhbz#2124071, rhbz#2203859 + * Fri Jan 6 2023 Xiao Ni - 4.2-8 - Update to latest upstream - Resolves rhbz#2127101, rhbz#2139789, rhbz#2149292, rhbz#2151209, rhbz#2148945