]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: do not serialize mounts and automounts for switch-root 19817/head
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 3 Jun 2021 17:40:01 +0000 (19:40 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 8 Jun 2021 14:04:38 +0000 (16:04 +0200)
When e.g. tmp.mount is present in the initrd, and we serialize it, switch root,
and deserialize, the new systemd is confused because it thinks /tmp is mounted.
In general, it doesn't make sense to serialize anything that refers to paths in
the old root file system.

This fixes two errors for me:

1. tmp.mount was not mounted properly before local-fs.target. It would be
mounted as some point (I guess when we re-read /proc/self/mountinfo for some
other reason). In effect systemd-tmpfiles-setup.service would see one fs, and
some other units started later a different one. In particular gdm.service would
fail because the pre-created /tmp/.X11-unix with proper permissions would not
exist at time it was started.

2. # systemd[1]: proc-sys-fs-binfmt_misc.automount: Got hangup/error on autofs pipe from kernel. Likely our automount point has been unmounted by someone or something else?
   # systemd[1]: proc-sys-fs-binfmt_misc.automount: Failed with result 'unmounted'.
   # systemd[1]: Mounting proc-sys-fs-binfmt_misc.mount...
   # systemd[1]: Mounted proc-sys-fs-binfmt_misc.mount.
   # systemd[1]: Starting systemd-binfmt.service...
   # systemd[1]: Finished systemd-binfmt.service.
   # systemd[1]: proc-sys-fs-binfmt_misc.automount: Path /proc/sys/fs/binfmt_misc is already a mount point, refusing start.
   # systemd[1]: Failed to set up automount proc-sys-fs-binfmt_misc.automount.
   # systemd[1]: proc-sys-fs-binfmt_misc.automount: Path /proc/sys/fs/binfmt_misc is already a mount point, refusing start.
   # systemd[1]: Failed to set up automount proc-sys-fs-binfmt_misc.automount.
   # systemd[1]: proc-sys-fs-binfmt_misc.automount: Path /proc/sys/fs/binfmt_misc is already a mount point, refusing start.
   # systemd[1]: Failed to set up automount proc-sys-fs-binfmt_misc.automount.
   # systemd[1]: Stopping systemd-binfmt.service...
   # systemd[1]: systemd-binfmt.service: Deactivated successfully.
   # systemd[1]: Stopped systemd-binfmt.service.

I couldn't understand the error here, but in retrospect the first line is entirely
correct: "someone or something else" was the old systemd unmounting the old root.

src/core/automount.c
src/core/manager.c
src/core/mount.c
src/core/unit-serialize.c
src/core/unit.h

index 8d75346d97c26d1a195152da2f6bcfec56d7a7d4..57d126572340101bf2c51ad490650f31f9cb680e 100644 (file)
@@ -1087,6 +1087,7 @@ const UnitVTable automount_vtable = {
         .can_transient = true,
         .can_fail = true,
         .can_trigger = true,
+        .exclude_from_switch_root_serialization = true,
 
         .init = automount_init,
         .load = automount_load,
index dd6e7693d099181444cc9bd4e93e4965531b8180..addd04067f41a0967a2ae9bbf7c6d94ebeb5506a 100644 (file)
@@ -3321,11 +3321,7 @@ int manager_serialize(
                 if (u->id != t)
                         continue;
 
-                /* Start marker */
-                fputs(u->id, f);
-                fputc('\n', f);
-
-                r = unit_serialize(u, f, fds, !switching_root);
+                r = unit_serialize(u, f, fds, switching_root);
                 if (r < 0)
                         return r;
         }
index c1f36ac4f14e9accb60834c5d2b554c21a90100c..8e39cf3ab3a12395552ba923a2b9a965c8d7e78c 100644 (file)
@@ -2176,6 +2176,7 @@ const UnitVTable mount_vtable = {
 
         .can_transient = true,
         .can_fail = true,
+        .exclude_from_switch_root_serialization = true,
 
         .init = mount_init,
         .load = mount_load,
index 7da0d8a3dbcf453384ff4d0783ebecacd6ac8cb2..4da69769a68a8cfc5fc731af5558432204e51c17 100644 (file)
@@ -89,13 +89,25 @@ static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_M
         [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
 };
 
-int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
+int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool switching_root) {
         int r;
 
         assert(u);
         assert(f);
         assert(fds);
 
+        if (switching_root && UNIT_VTABLE(u)->exclude_from_switch_root_serialization) {
+                /* In the new root, paths for mounts and automounts will be different, so it doesn't make
+                 * much sense to serialize things. API file systems will be moved to the new root, but we
+                 * don't have mount units for those. */
+                log_unit_debug(u, "not serializing before switch-root");
+                return 0;
+        }
+
+        /* Start marker */
+        fputs(u->id, f);
+        fputc('\n', f);
+
         if (unit_can_serialize(u)) {
                 r = UNIT_VTABLE(u)->serialize(u, f, fds);
                 if (r < 0)
@@ -175,7 +187,7 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
                         (void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v);
         }
 
-        if (serialize_jobs) {
+        if (!switching_root) {
                 if (u->job) {
                         fputs("job\n", f);
                         job_serialize(u->job, f);
index dddb41961375919ba788c577744f603b9ca15c7c..8818392731adac1bd7fba4e980aa38b3d9c07181 100644 (file)
@@ -668,6 +668,9 @@ typedef struct UnitVTable {
         /* True if units of this type shall be startable only once and then never again */
         bool once_only;
 
+        /* Do not serialize this unit when preparing for root switch */
+        bool exclude_from_switch_root_serialization;
+
         /* True if queued jobs of this type should be GC'ed if no other job needs them anymore */
         bool gc_jobs;