diff --git a/man/systemd.special.xml b/man/systemd.special.xml
index c9f320935d..73fd1dcc94 100644
--- a/man/systemd.special.xml
+++ b/man/systemd.special.xml
@@ -46,6 +46,7 @@
initrd-fs.target,
initrd-root-device.target,
initrd-root-fs.target,
+ initrd-usr-fs.target,
kbrequest.target,
kexec.target,
local-fs-pre.target,
@@ -372,12 +373,13 @@
initrd-fs.targetsystemd-fstab-generator3
- automatically adds dependencies of type
- Before= to
- sysroot-usr.mount and all mount points
- found in /etc/fstab that have
- and not have
- mount options set.
+ automatically adds dependencies of type Before= to
+ sysroot-usr.mount and all mount points found in
+ /etc/fstab that have the mount option set
+ and do not have the mount option set. It is also indirectly ordered after
+ sysroot.mount. Thus, once this target is reached the
+ /sysroot/ hierarchy is fully set up, in preparation for the transition to
+ the host OS.
@@ -396,11 +398,27 @@
initrd-root-fs.targetsystemd-fstab-generator3
- automatically adds dependencies of type
- Before= to the
- sysroot.mount unit, which is generated
- from the kernel command line.
-
+ automatically adds dependencies of type Before= to the
+ sysroot.mount unit, which is generated from the kernel command line's
+ root= setting (or equivalent).
+
+
+
+ initrd-usr-fs.target
+
+ systemd-fstab-generator3
+ automatically adds dependencies of type Before= to the
+ sysusr-usr.mount unit, which is generated from the kernel command line's
+ usr= switch. Services may order themselves after this target unit in order to
+ run once the /sysusr/ hierarchy becomes available, on systems that come up
+ initially without a root file system, but with an initialized /usr/ and need
+ to access that before setting up the root file system to ultimately switch to. On systems where
+ usr= is not used this target is ordered afer
+ sysroot.mount and thus mostly equivalent to
+ initrd-root-fs.target. In effect on any system once this target is reached
+ the file system backing /usr/ is mounted, though possibly at two different
+ locations, either below the /sysusr/ or the /sysroot/
+ hierarchies.
diff --git a/src/basic/special.h b/src/basic/special.h
index b9b7be7a7d..841e8ad132 100644
--- a/src/basic/special.h
+++ b/src/basic/special.h
@@ -37,6 +37,7 @@
#define SPECIAL_INITRD_FS_TARGET "initrd-fs.target"
#define SPECIAL_INITRD_ROOT_DEVICE_TARGET "initrd-root-device.target"
#define SPECIAL_INITRD_ROOT_FS_TARGET "initrd-root-fs.target"
+#define SPECIAL_INITRD_USR_FS_TARGET "initrd-usr-fs.target"
#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */
#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target"
#define SPECIAL_SWAP_TARGET "swap.target"
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 69ba4bfc64..110a9bd1ba 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -433,6 +433,11 @@ static int add_mount(
if (r < 0)
return r;
+ /* Order the mount unit we generate relative to the post unit, so that DefaultDependencies= on the
+ * target unit won't affect us. */
+ if (post && !FLAGS_SET(flags, AUTOMOUNT) && !FLAGS_SET(flags, NOAUTO))
+ fprintf(f, "Before=%s\n", post);
+
if (passno != 0) {
r = generator_write_fsck_deps(f, dest, what, where, fstype);
if (r < 0)
@@ -721,7 +726,7 @@ static int add_sysroot_mount(void) {
else
opts = arg_root_options;
- log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
+ log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what, strna(arg_root_fstype), strempty(opts));
if (is_device_path(what)) {
r = generator_write_initrd_root_device_deps(arg_dest, what);
@@ -744,6 +749,10 @@ static int add_sysroot_mount(void) {
static int add_sysroot_usr_mount(void) {
_cleanup_free_ char *what = NULL;
const char *opts;
+ int r;
+
+ /* Returns 0 if we didn't do anything, > 0 if we either generated a unit for the /usr/ mount, or we
+ * know for sure something else did */
if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
return 0;
@@ -767,8 +776,23 @@ static int add_sysroot_usr_mount(void) {
return log_oom();
}
- if (!arg_usr_what)
+ if (isempty(arg_usr_what)) {
+ log_debug("Could not find a usr= entry on the kernel command line.");
return 0;
+ }
+
+ if (streq(arg_usr_what, "gpt-auto")) {
+ /* This is handled by the gpt-auto generator */
+ log_debug("Skipping /usr/ directory handling, as gpt-auto was requested.");
+ return 1; /* systemd-gpt-auto-generator will generate a unit for this, hence report that a
+ * unit file is being created for the host /usr/ mount. */
+ }
+
+ if (path_equal(arg_usr_what, "/dev/nfs")) {
+ /* This is handled by the initrd (if at all supported, that is) */
+ log_debug("Skipping /usr/ directory handling, as /dev/nfs was requested.");
+ return 1; /* As above, report that NFS code will create the unit */
+ }
what = fstab_node_to_udev_node(arg_usr_what);
if (!what)
@@ -781,17 +805,62 @@ static int add_sysroot_usr_mount(void) {
else
opts = arg_usr_options;
- log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
- return add_mount(arg_dest,
- what,
- "/sysroot/usr",
- NULL,
- arg_usr_fstype,
- opts,
- is_device_path(what) ? 1 : 0, /* passno */
- 0,
- SPECIAL_INITRD_FS_TARGET,
- "/proc/cmdline");
+ /* When mounting /usr from the initrd, we add an extra level of indirection: we first mount the /usr/
+ * partition to /sysusr/usr/, and then afterwards bind mount that to /sysroot/usr/. We do this so
+ * that we can cover for systems that initially only have a /usr/ around and where the root fs needs
+ * to be synthesized, based on configuration included in /usr/, e.g. systemd-repart. Software like
+ * this should order itself after initrd-usr-fs.target and before initrd-fs.target; and it should
+ * look into both /sysusr/ and /sysroot/ for the configuration data to apply. */
+
+ log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what, strna(arg_usr_fstype), strempty(opts));
+
+ r = add_mount(arg_dest,
+ what,
+ "/sysusr/usr",
+ NULL,
+ arg_usr_fstype,
+ opts,
+ is_device_path(what) ? 1 : 0, /* passno */
+ 0,
+ SPECIAL_INITRD_USR_FS_TARGET,
+ "/proc/cmdline");
+ if (r < 0)
+ return r;
+
+ log_debug("Synthesizing entry what=/sysusr/usr where=/sysrootr/usr opts=bind");
+
+ r = add_mount(arg_dest,
+ "/sysusr/usr",
+ "/sysroot/usr",
+ NULL,
+ NULL,
+ "bind",
+ 0,
+ 0,
+ SPECIAL_INITRD_FS_TARGET,
+ "/proc/cmdline");
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int add_sysroot_usr_mount_or_fallback(void) {
+ int r;
+
+ r = add_sysroot_usr_mount();
+ if (r != 0)
+ return r;
+
+ /* OK, so we didn't write anything out for /sysusr/usr/ nor /sysroot/usr/. In this case, let's make
+ * sure that initrd-usr-fs.target is at least ordered after sysroot.mount so that services that order
+ * themselves get the guarantee that /usr/ is definitely mounted somewhere. */
+
+ return generator_add_symlink(
+ arg_dest,
+ SPECIAL_INITRD_USR_FS_TARGET,
+ "requires",
+ "sysroot.mount");
}
static int add_volatile_root(void) {
@@ -953,7 +1022,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
if (in_initrd()) {
r = add_sysroot_mount();
- r2 = add_sysroot_usr_mount();
+ r2 = add_sysroot_usr_mount_or_fallback();
r3 = add_volatile_root();
} else
diff --git a/units/initrd-fs.target b/units/initrd-fs.target
index 8c6bdf35f5..674b7ae74d 100644
--- a/units/initrd-fs.target
+++ b/units/initrd-fs.target
@@ -10,9 +10,9 @@
[Unit]
Description=Initrd File Systems
Documentation=man:systemd.special(7)
+AssertPathExists=/etc/initrd-release
OnFailure=emergency.target
OnFailureJobMode=replace-irreversibly
-AssertPathExists=/etc/initrd-release
After=initrd-parse-etc.service
DefaultDependencies=no
Conflicts=shutdown.target
diff --git a/units/initrd-usr-fs.target b/units/initrd-usr-fs.target
new file mode 100644
index 0000000000..7219655c9c
--- /dev/null
+++ b/units/initrd-usr-fs.target
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Initrd /usr File System
+Documentation=man:systemd.special(7)
+AssertPathExists=/etc/initrd-release
+OnFailure=emergency.target
+OnFailureJobMode=replace-irreversibly
+DefaultDependencies=no
+Conflicts=shutdown.target
diff --git a/units/initrd.target b/units/initrd.target
index 655158a58b..fc8fbff4bd 100644
--- a/units/initrd.target
+++ b/units/initrd.target
@@ -14,6 +14,6 @@ OnFailure=emergency.target
OnFailureJobMode=replace-irreversibly
AssertPathExists=/etc/initrd-release
Requires=basic.target
-Wants=initrd-root-fs.target initrd-root-device.target initrd-fs.target initrd-parse-etc.service
-After=initrd-root-fs.target initrd-root-device.target initrd-fs.target basic.target rescue.service rescue.target
+Wants=initrd-root-fs.target initrd-root-device.target initrd-fs.target initrd-usr-fs.target initrd-parse-etc.service
+After=initrd-root-fs.target initrd-root-device.target initrd-fs.target initrd-usr-fs.target basic.target rescue.service rescue.target
AllowIsolate=yes
diff --git a/units/meson.build b/units/meson.build
index 15463760c6..fe8e95ff91 100644
--- a/units/meson.build
+++ b/units/meson.build
@@ -38,6 +38,7 @@ units = [
['initrd-switch-root.service', 'ENABLE_INITRD'],
['initrd-switch-root.target', 'ENABLE_INITRD'],
['initrd-udevadm-cleanup-db.service', 'ENABLE_INITRD'],
+ ['initrd-usr-fs.target', 'ENABLE_INITRD'],
['initrd.target', 'ENABLE_INITRD'],
['kexec.target', ''],
['ldconfig.service', 'ENABLE_LDCONFIG',
diff --git a/units/systemd-repart.service.in b/units/systemd-repart.service.in
index a5565834eb..60dc7783b3 100644
--- a/units/systemd-repart.service.in
+++ b/units/systemd-repart.service.in
@@ -12,7 +12,7 @@ Description=Repartition Root Disk
Documentation=man:systemd-repart.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
-After=sysroot.mount
+After=initrd-usr-fs.target
Before=initrd-root-fs.target shutdown.target
ConditionVirtualization=!container
ConditionDirectoryNotEmpty=|/usr/lib/repart.d
diff --git a/units/systemd-volatile-root.service.in b/units/systemd-volatile-root.service.in
index 5ecc702b6d..468d85f968 100644
--- a/units/systemd-volatile-root.service.in
+++ b/units/systemd-volatile-root.service.in
@@ -12,7 +12,7 @@ Description=Enforce Volatile Root File Systems
Documentation=man:systemd-volatile-root.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
-After=sysroot.mount systemd-repart.service
+After=sysroot.mount sysroot-usr.mount systemd-repart.service
Before=initrd-root-fs.target shutdown.target
AssertPathExists=/etc/initrd-release