From: Lennart Poettering Date: Mon, 10 Feb 2025 11:56:08 +0000 (+0100) Subject: fstab-generator: support creating bind mounts via root= kernel cmdline switches X-Git-Tag: v258-rc1~1280^2~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4bee5684db5f252e7480d66fd81625e91951498;p=thirdparty%2Fsystemd.git fstab-generator: support creating bind mounts via root= kernel cmdline switches This is useful for bind mounting a freshly downloaded and unpacked tar disk images to /sysroot to mount into. Specifically, with a kernel command line like this one: rd.systemd.pull=verify=no,machine,tar:root:http://_gateway:8081/image.tar root=bind:/run/machines/root ip=any The first parameter downloads the root image, the second one then binds it to /sysroot so that we can boot into it. --- diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml index 42c6d27bfc5..f04334b9851 100644 --- a/man/systemd-fstab-generator.xml +++ b/man/systemd-fstab-generator.xml @@ -99,6 +99,10 @@ separate, immutable /usr/ file system. Also see systemd.volatile= below. + Use bind:… to bind mount another directory as operating system root + filesystems (added in v258). Expects an absolute path name referencing an existing directory within the initrd's file + hierarchy to boot into. + diff --git a/man/systemd-import-generator.xml b/man/systemd-import-generator.xml index cea015e6f8a..dfadf5db5fc 100644 --- a/man/systemd-import-generator.xml +++ b/man/systemd-import-generator.xml @@ -242,6 +242,16 @@ http://example.com/image.efi this would result in a root disk being downloaded from http://example.com/image.raw.xz. + + + Boot into disk image (tar), with URL derived from UEFI HTTP network booting + + systemd.pull=tar,machine,verify=no,bootorigin:root:image.tar.xz root=bind:/run/machines/root + + This is similar to the previous example, but instead of a raw (i.e. block device based) disk + image the system boots into a tarball that is downloaded from the originating UEFI network + server. + diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 4dfe9fea897..475981f36d0 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -494,7 +494,8 @@ static int add_mount( const char *opts, int passno, MountPointFlags flags, - const char *target_unit) { + const char *target_unit, + const char *extra_after) { _cleanup_free_ char *name = NULL, *automount_name = NULL, *filtered = NULL, *where_escaped = NULL, *opts_root_filtered = NULL; @@ -596,6 +597,9 @@ static int add_mount( if (target_unit && !FLAGS_SET(flags, MOUNT_NOFAIL)) fprintf(f, "Before=%s\n", target_unit); + if (extra_after) + fprintf(f, "After=%s\n", extra_after); + if (passno != 0) { r = generator_write_fsck_deps(f, dest, what, where, fstype); if (r < 0) @@ -814,15 +818,16 @@ static bool sysfs_check(void) { static int add_sysusr_sysroot_usr_bind_mount(const char *source) { return add_mount(source, - arg_dest, - "/sysusr/usr", - "/sysroot/usr", - NULL, - NULL, - "bind", - 0, - 0, - SPECIAL_INITRD_FS_TARGET); + arg_dest, + "/sysusr/usr", + "/sysroot/usr", + /* original_where= */ NULL, + /* fstype= */ NULL, + "bind", + /* passno= */ 0, + /* flags= */ 0, + SPECIAL_INITRD_FS_TARGET, + /* extra_after= */ NULL); } static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap) { @@ -1000,7 +1005,8 @@ static int parse_fstab_one( options, passno, flags, - target_unit); + target_unit, + /* extra_after= */ NULL); if (r <= 0) return r; @@ -1105,8 +1111,8 @@ static int sysroot_is_nfsroot(void) { static int add_sysroot_mount(void) { _cleanup_free_ char *what = NULL; - const char *opts, *fstype; - bool default_rw, makefs; + const char *extra_opts = NULL, *fstype = NULL; + bool default_rw = true, makefs = false; MountPointFlags flags; int r; @@ -1149,7 +1155,20 @@ static int add_sysroot_mount(void) { return 0; } - if (streq(arg_root_what, "tmpfs")) { + const char *bind = startswith(arg_root_what, "bind:"); + if (bind) { + if (!path_is_valid(bind) || !path_is_absolute(bind)) { + log_debug("Invalid root=bind: source path, ignoring: %s", bind); + return 0; + } + + what = strdup(bind); + if (!what) + return log_oom(); + + extra_opts = "bind"; + + } else if (streq(arg_root_what, "tmpfs")) { /* If root=tmpfs is specified, then take this as shortcut for a writable tmpfs mount as root */ what = strdup("rootfs"); /* just a pretty name, to show up in /proc/self/mountinfo */ @@ -1157,8 +1176,6 @@ static int add_sysroot_mount(void) { return log_oom(); fstype = arg_root_fstype ?: "tmpfs"; /* tmpfs, unless overridden */ - - default_rw = true; /* writable, unless overridden */; } else { what = fstab_node_to_udev_node(arg_root_what); @@ -1166,40 +1183,44 @@ static int add_sysroot_mount(void) { return log_oom(); fstype = arg_root_fstype; /* if not specified explicitly, don't default to anything here */ - default_rw = false; /* read-only, unless overridden */ } - if (!arg_root_options) - opts = arg_root_rw > 0 || (arg_root_rw < 0 && default_rw) ? "rw" : "ro"; - else if (arg_root_rw >= 0 || - !fstab_test_option(arg_root_options, "ro\0" "rw\0")) - opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro"); - else - opts = arg_root_options; + _cleanup_free_ char *combined_options = NULL; + if (strdup_to(&combined_options, arg_root_options) < 0) + return log_oom(); + + if (arg_root_rw >= 0 || !fstab_test_option(combined_options, "ro\0" "rw\0")) + if (!strextend_with_separator(&combined_options, ",", arg_root_rw > 0 || (arg_root_rw < 0 && default_rw) ? "rw" : "ro")) + return log_oom(); + + if (extra_opts) + if (!strextend_with_separator(&combined_options, ",", extra_opts)) + return log_oom(); - log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what, strna(arg_root_fstype), strempty(opts)); + log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what, strna(arg_root_fstype), strempty(combined_options)); - makefs = fstab_test_option(opts, "x-systemd.makefs\0"); + makefs = fstab_test_option(combined_options, "x-systemd.makefs\0"); flags = makefs * MOUNT_MAKEFS; return add_mount("/proc/cmdline", arg_dest, what, "/sysroot", - NULL, + /* original_where= */ NULL, fstype, - opts, - is_device_path(what) ? 1 : 0, /* passno */ - flags, /* makefs off, pcrfs off, quota off, noauto off, nofail off, automount off */ - SPECIAL_INITRD_ROOT_FS_TARGET); + combined_options, + /* passno= */ is_device_path(what) ? 1 : 0, + flags, + SPECIAL_INITRD_ROOT_FS_TARGET, + "imports.target"); } static int add_sysroot_usr_mount(void) { _cleanup_free_ char *what = NULL; - const char *opts; - bool makefs; + const char *extra_opts = NULL; MountPointFlags flags; + bool makefs; int r; /* Returns 0 if we didn't do anything, > 0 if we either generated a unit for the /usr/ mount, or we @@ -1250,16 +1271,35 @@ static int add_sysroot_usr_mount(void) { return 1; /* As above, report that NFS code will create the unit */ } - what = fstab_node_to_udev_node(arg_usr_what); - if (!what) + const char *bind = startswith(arg_usr_what, "bind:"); + if (bind) { + if (!path_is_valid(bind) || !path_is_absolute(bind)) { + log_debug("Invalid mount.usr=bind: source path, ignoring: %s", bind); + return 0; + } + + what = strdup(bind); + if (!what) + return log_oom(); + + extra_opts = "bind"; + } else { + what = fstab_node_to_udev_node(arg_usr_what); + if (!what) + return log_oom(); + } + + _cleanup_free_ char *combined_options = NULL; + if (strdup_to(&combined_options, arg_usr_options) < 0) return log_oom(); - if (!arg_usr_options) - opts = arg_root_rw > 0 ? "rw" : "ro"; - else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0")) - opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro"); - else - opts = arg_usr_options; + if (!fstab_test_option(combined_options, "ro\0" "rw\0")) + if (!strextend_with_separator(&combined_options, ",", arg_root_rw > 0 ? "rw" : "ro")) + return log_oom(); + + if (extra_opts) + if (!strextend_with_separator(&combined_options, ",", extra_opts)) + return log_oom(); /* 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 @@ -1268,21 +1308,22 @@ static int add_sysroot_usr_mount(void) { * 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)); + log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what, strna(arg_usr_fstype), strempty(combined_options)); - makefs = fstab_test_option(opts, "x-systemd.makefs\0"); + makefs = fstab_test_option(combined_options, "x-systemd.makefs\0"); flags = makefs * MOUNT_MAKEFS; r = add_mount("/proc/cmdline", arg_dest, what, "/sysusr/usr", - NULL, + /* original_where= */ NULL, arg_usr_fstype, - opts, - is_device_path(what) ? 1 : 0, /* passno */ + combined_options, + /* passno= */ is_device_path(what) ? 1 : 0, flags, - SPECIAL_INITRD_USR_FS_TARGET); + SPECIAL_INITRD_USR_FS_TARGET, + "imports.target"); if (r < 0) return r; @@ -1336,12 +1377,13 @@ static int add_volatile_var(void) { arg_dest_late, "tmpfs", "/var", - NULL, + /* original_where= */ NULL, "tmpfs", "mode=0755" TMPFS_LIMITS_VAR, - 0, - 0, - SPECIAL_LOCAL_FS_TARGET); + /* passno= */ 0, + /* flags= */ 0, + SPECIAL_LOCAL_FS_TARGET, + /* extra_after= */ NULL); } static int add_mounts_from_cmdline(void) { diff --git a/test/test-fstab-generator/test-12-dev-sdx.expected/sysroot.mount b/test/test-fstab-generator/test-12-dev-sdx.expected/sysroot.mount index 8f8ef486173..92eed56423a 100644 --- a/test/test-fstab-generator/test-12-dev-sdx.expected/sysroot.mount +++ b/test/test-fstab-generator/test-12-dev-sdx.expected/sysroot.mount @@ -4,6 +4,7 @@ Documentation=man:fstab(5) man:systemd-fstab-generator(8) SourcePath=/proc/cmdline Before=initrd-root-fs.target +After=imports.target Requires=systemd-fsck-root.service After=systemd-fsck-root.service After=blockdev@dev-sdx1.target diff --git a/test/test-fstab-generator/test-13-label.expected/sysroot.mount b/test/test-fstab-generator/test-13-label.expected/sysroot.mount index 98698d5968a..8b0f6cce257 100644 --- a/test/test-fstab-generator/test-13-label.expected/sysroot.mount +++ b/test/test-fstab-generator/test-13-label.expected/sysroot.mount @@ -4,6 +4,7 @@ Documentation=man:fstab(5) man:systemd-fstab-generator(8) SourcePath=/proc/cmdline Before=initrd-root-fs.target +After=imports.target Requires=systemd-fsck-root.service After=systemd-fsck-root.service After=blockdev@dev-disk-by\x2dlabel-Root.target diff --git a/test/test-fstab-generator/test-14-uuid.expected/sysroot.mount b/test/test-fstab-generator/test-14-uuid.expected/sysroot.mount index 999acb0b23e..096da67f1e4 100644 --- a/test/test-fstab-generator/test-14-uuid.expected/sysroot.mount +++ b/test/test-fstab-generator/test-14-uuid.expected/sysroot.mount @@ -4,6 +4,7 @@ Documentation=man:fstab(5) man:systemd-fstab-generator(8) SourcePath=/proc/cmdline Before=initrd-root-fs.target +After=imports.target Requires=systemd-fsck-root.service After=systemd-fsck-root.service After=blockdev@dev-disk-by\x2duuid-3f5ad593\x2d4546\x2d4a94\x2da374\x2dbcfb68aa11f7.target diff --git a/test/test-fstab-generator/test-15-partuuid.expected/sysroot.mount b/test/test-fstab-generator/test-15-partuuid.expected/sysroot.mount index d10fb6ef761..6d948b91c29 100644 --- a/test/test-fstab-generator/test-15-partuuid.expected/sysroot.mount +++ b/test/test-fstab-generator/test-15-partuuid.expected/sysroot.mount @@ -4,6 +4,7 @@ Documentation=man:fstab(5) man:systemd-fstab-generator(8) SourcePath=/proc/cmdline Before=initrd-root-fs.target +After=imports.target Requires=systemd-fsck-root.service After=systemd-fsck-root.service After=blockdev@dev-disk-by\x2dpartuuid-3f5ad593\x2d4546\x2d4a94\x2da374\x2dbcfb68aa11f7.target diff --git a/test/test-fstab-generator/test-16-tmpfs.expected/sysroot.mount b/test/test-fstab-generator/test-16-tmpfs.expected/sysroot.mount index 6bd9a07f2c4..99728fd0ca3 100644 --- a/test/test-fstab-generator/test-16-tmpfs.expected/sysroot.mount +++ b/test/test-fstab-generator/test-16-tmpfs.expected/sysroot.mount @@ -4,6 +4,7 @@ Documentation=man:fstab(5) man:systemd-fstab-generator(8) SourcePath=/proc/cmdline Before=initrd-root-fs.target +After=imports.target [Mount] What=rootfs