diff --git a/0012-mdadm-systemd-remove-KillMode-none-from-service-file.patch b/0012-mdadm-systemd-remove-KillMode-none-from-service-file.patch new file mode 100644 index 0000000..ae67325 --- /dev/null +++ b/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/120] 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/0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch b/0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch new file mode 100644 index 0000000..d824449 --- /dev/null +++ b/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/120] 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/0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch b/0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch new file mode 100644 index 0000000..0bc1069 --- /dev/null +++ b/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/120] 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/0086-Fix-NULL-dereference-in-super_by_fd.patch b/0086-Fix-NULL-dereference-in-super_by_fd.patch new file mode 100644 index 0000000..95cb79a --- /dev/null +++ b/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/120] 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/0087-Mdmonitor-Make-alert_info-global.patch b/0087-Mdmonitor-Make-alert_info-global.patch new file mode 100644 index 0000000..c8da02b --- /dev/null +++ b/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/120] 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/0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch b/0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch new file mode 100644 index 0000000..c5f2b97 --- /dev/null +++ b/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/120] 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/0089-Mdmonitor-Add-helper-functions.patch b/0089-Mdmonitor-Add-helper-functions.patch new file mode 100644 index 0000000..b8fc968 --- /dev/null +++ b/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/120] 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/0090-Add-helpers-to-determine-whether-directories-or-file.patch b/0090-Add-helpers-to-determine-whether-directories-or-file.patch new file mode 100644 index 0000000..7d7ecdd --- /dev/null +++ b/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/120] 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/0091-Mdmonitor-Refactor-write_autorebuild_pid.patch b/0091-Mdmonitor-Refactor-write_autorebuild_pid.patch new file mode 100644 index 0000000..0985905 --- /dev/null +++ b/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/120] 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/0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch b/0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch new file mode 100644 index 0000000..a7de95e --- /dev/null +++ b/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/120] 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/0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch b/0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch new file mode 100644 index 0000000..b040ba7 --- /dev/null +++ b/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/120] 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/0094-util.c-fix-memleak-in-parse_layout_faulty.patch b/0094-util.c-fix-memleak-in-parse_layout_faulty.patch new file mode 100644 index 0000000..b5d0d09 --- /dev/null +++ b/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/120] 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/0095-Detail.c-fix-memleak-in-Detail.patch b/0095-Detail.c-fix-memleak-in-Detail.patch new file mode 100644 index 0000000..0e9b700 --- /dev/null +++ b/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/120] 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/0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch b/0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch new file mode 100644 index 0000000..bf71aa0 --- /dev/null +++ b/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/120] 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/0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch b/0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch new file mode 100644 index 0000000..fd60fe2 --- /dev/null +++ b/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/120] 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/0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch b/0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch new file mode 100644 index 0000000..d781036 --- /dev/null +++ b/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/120] 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/0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch b/0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch new file mode 100644 index 0000000..4fb641f --- /dev/null +++ b/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/120] 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/0100-Create-remove-safe_mode_delay-local-variable.patch b/0100-Create-remove-safe_mode_delay-local-variable.patch new file mode 100644 index 0000000..4b826a8 --- /dev/null +++ b/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/120] 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/0101-Create-Factor-out-add_disks-helpers.patch b/0101-Create-Factor-out-add_disks-helpers.patch new file mode 100644 index 0000000..c4bfcc5 --- /dev/null +++ b/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/120] 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/0102-mdadm-Introduce-pr_info.patch b/0102-mdadm-Introduce-pr_info.patch new file mode 100644 index 0000000..196624f --- /dev/null +++ b/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/120] 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/0103-mdadm-Add-write-zeros-option-for-Create.patch b/0103-mdadm-Add-write-zeros-option-for-Create.patch new file mode 100644 index 0000000..1e06a73 --- /dev/null +++ b/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/120] 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/0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch b/0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch new file mode 100644 index 0000000..6c32b5c --- /dev/null +++ b/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/120] 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/0105-manpage-Add-write-zeroes-option-to-manpage.patch b/0105-manpage-Add-write-zeroes-option-to-manpage.patch new file mode 100644 index 0000000..489faca --- /dev/null +++ b/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/120] 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/0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch b/0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch new file mode 100644 index 0000000..acb55ed --- /dev/null +++ b/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/120] 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/0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch b/0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch new file mode 100644 index 0000000..f7b06c5 --- /dev/null +++ b/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/120] 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/0108-mdmon-don-t-test-both-all-and-container_name.patch b/0108-mdmon-don-t-test-both-all-and-container_name.patch new file mode 100644 index 0000000..479e5a5 --- /dev/null +++ b/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/120] 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/0109-mdmon-change-systemd-unit-file-to-use-foreground.patch b/0109-mdmon-change-systemd-unit-file-to-use-foreground.patch new file mode 100644 index 0000000..49240d5 --- /dev/null +++ b/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/120] 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/0110-mdmon-Remove-need-for-KillMode-none.patch b/0110-mdmon-Remove-need-for-KillMode-none.patch new file mode 100644 index 0000000..5e6cc63 --- /dev/null +++ b/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/120] 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/0111-mdmon-Improve-switchroot-interactions.patch b/0111-mdmon-Improve-switchroot-interactions.patch new file mode 100644 index 0000000..65654a0 --- /dev/null +++ b/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/120] 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/0112-mdopen-always-try-create_named_array.patch b/0112-mdopen-always-try-create_named_array.patch new file mode 100644 index 0000000..bfd899c --- /dev/null +++ b/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/120] 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/0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch b/0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch new file mode 100644 index 0000000..d4e6a4f --- /dev/null +++ b/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/120] 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/0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch b/0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch new file mode 100644 index 0000000..39b1809 --- /dev/null +++ b/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/120] 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/0115-Create-Fix-checking-for-container-in-update_metadata.patch b/0115-Create-Fix-checking-for-container-in-update_metadata.patch new file mode 100644 index 0000000..0868469 --- /dev/null +++ b/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/120] 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/0116-Fix-null-pointer-for-incremental-in-mdadm.patch b/0116-Fix-null-pointer-for-incremental-in-mdadm.patch new file mode 100644 index 0000000..53bc051 --- /dev/null +++ b/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/120] 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/0117-super1-fix-truncation-check-for-journal-device.patch b/0117-super1-fix-truncation-check-for-journal-device.patch new file mode 100644 index 0000000..bf985c8 --- /dev/null +++ b/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/120] 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/0118-Fix-some-cases-eyesore-formatting.patch b/0118-Fix-some-cases-eyesore-formatting.patch new file mode 100644 index 0000000..4da8078 --- /dev/null +++ b/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/120] 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/0119-Bump-minimum-kernel-version-to-2.6.32.patch b/0119-Bump-minimum-kernel-version-to-2.6.32.patch new file mode 100644 index 0000000..7fcbf6c --- /dev/null +++ b/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/120] 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/0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch b/0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch new file mode 100644 index 0000000..cb73179 --- /dev/null +++ b/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/120] 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/mdadm.spec b/mdadm.spec index e03694c..53d4357 100644 --- a/mdadm.spec +++ b/mdadm.spec @@ -1,6 +1,6 @@ Name: mdadm Version: 4.2 -Release: 4%{?dist} +Release: 5%{?dist} Summary: The mdadm program controls Linux md devices (software RAID arrays) URL: http://www.kernel.org/pub/linux/utils/raid/mdadm/ License: GPLv2+ @@ -13,6 +13,7 @@ Source4: mdadm.conf Source5: mdadm_event.conf Source6: raid-check.timer Source7: raid-check.service +Source8: mdcheck Patch000: 0001-Unify-error-message.patch Patch001: 0002-mdadm-Fix-double-free.patch @@ -25,84 +26,121 @@ 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 # Fedora customization patches -Patch97: mdadm-udev.patch -Patch98: mdadm-2.5.2-static.patch +Patch197: mdadm-udev.patch +Patch198: mdadm-2.5.2-static.patch # Build without -Werror. -Patch99: disable-Werror.patch +Patch199: disable-Werror.patch BuildRequires: make BuildRequires: systemd-rpm-macros binutils-devel gcc systemd-devel @@ -129,6 +167,8 @@ 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 # systemd mkdir -p %{buildroot}%{_unitdir} @@ -168,8 +208,13 @@ 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 Apr 12 2023 Xiao Ni - 4.2-5 +- Update to latest upstream for rawhide(f39) and fix mdcheck service bug +- Resolves bz#2175540 + * Mon Jan 30 2023 Xiao Ni - 4.2-4 - Update to latest upstream for f38 - Resolves bz#2163711 diff --git a/mdcheck b/mdcheck new file mode 100644 index 0000000..700c3e2 --- /dev/null +++ b/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