]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
mdmon: Improve switchroot interactions.
authorNeilBrown <neilb@suse.de>
Mon, 13 Mar 2023 03:42:58 +0000 (14:42 +1100)
committerJes Sorensen <jes@trained-monkey.org>
Sun, 19 Mar 2023 16:33:25 +0000 (12:33 -0400)
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 <neilb@suse.de>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
Grow.c
mdadm.h
mdmon.c
systemd/mdmon@.service
udev-md-raid-arrays.rules
util.c

diff --git a/Grow.c b/Grow.c
index bb5fe45c851cf82c3e476d3063b86c3f2b40c48c..06001f2d334a8a6782e43adfa9789d61104599cc 100644 (file)
--- 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 b9127f9a8ef64cd5fd6630c73bf731a2868b5167..1e518276116bbb1295b54bb3b2eab68d2bc04ead 100644 (file)
--- 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 f8fd2f0f44c4f5194c9a6124af5f82aa5935af44..096b4d7650cf717ea39438e36865101aa9c56c72 100644 (file)
--- 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;
        }
index 303ad05c0bc7b889547744c3ecd402be5aa6050c..23a375f6ba48e3804647050a2069318ac353c259 100644 (file)
@@ -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)
index 2967ace1f0403219565b0ad80156a5f87be385cb..4e64b249b2db561f446618cacaaa7e1ac2e494cd 100644 (file)
@@ -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 509fb43ea906f38527b191f27a89a7af752a42b8..d70ca43bc31dc3749dd8481682c1b6d4082d7e23 100644 (file)
--- 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",