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.target systemd-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.target systemd-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