]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
gpt-auto-generator: add support for mount.usr=dissect
authorLennart Poettering <lennart@poettering.net>
Mon, 17 Mar 2025 16:01:49 +0000 (17:01 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 3 Apr 2025 09:08:57 +0000 (11:08 +0200)
So far, we did not support auto-discovery the /usr/ partition at boot.
Change that: on explicit request (i.e. mount.usr=dissect) automatically
discover the /usr/ partition based on our usual dissection logic.

src/fstab-generator/fstab-generator.c
src/gpt-auto-generator/gpt-auto-generator.c
src/shared/generator.c
src/shared/generator.h

index ab009e8b212ce39b3514ac545788a72cddafb6f0..5adf48f20c7622c2df9610393f7273864502065a 100644 (file)
@@ -1137,7 +1137,7 @@ static bool validate_root_or_usr_mount_source(const char *what, const char *swit
                 return false;
         }
 
-        if (parse_gpt_auto_root(what) > 0) {
+        if (parse_gpt_auto_root(switch_name, what) > 0) {
                 /* This is handled by gpt-auto-generator */
                 log_debug("Skipping %s directory handling, as gpt-auto was requested.", switch_name);
                 return false;
index 28242850ac113bd4b6e65aa096f227eb91551e7f..c7acbcb2b0c372089198acbf578ebe07d27343f3 100644 (file)
@@ -48,15 +48,20 @@ typedef enum MountPointFlags {
 static const char *arg_dest = NULL;
 static bool arg_enabled = true;
 static GptAutoRoot arg_auto_root = _GPT_AUTO_ROOT_INVALID;
+static GptAutoRoot arg_auto_usr = _GPT_AUTO_ROOT_INVALID;
 static bool arg_swap_enabled = true;
 static char *arg_root_fstype = NULL;
 static char *arg_root_options = NULL;
 static int arg_root_rw = -1;
+static char *arg_usr_fstype = NULL;
+static char *arg_usr_options = NULL;
 static ImagePolicy *arg_image_policy = NULL;
 
 STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_usr_fstype, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_usr_options, freep);
 
 #define LOADER_PARTITION_IDLE_USEC (120 * USEC_PER_SEC)
 
@@ -679,7 +684,13 @@ static int add_root_cryptsetup(void) {
                                 "/dev/gpt-auto-root-luks-ignore-factory-reset";
         }
 
-        return add_cryptsetup("root", bdev, arg_root_options, MOUNT_RW|MOUNT_MEASURE, /* require= */ false, NULL);
+        return add_cryptsetup(
+                        "root",
+                        bdev,
+                        arg_root_options,
+                        MOUNT_RW|MOUNT_MEASURE,
+                        /* require= */ false,
+                        /* ret_device= */ NULL);
 #else
         return 0;
 #endif
@@ -782,6 +793,84 @@ static int add_root_mount(void) {
 #endif
 }
 
+
+static int add_usr_mount(void) {
+#if ENABLE_EFI
+        int r;
+
+        /* /usr/ discovery must be enabled explicitly. */
+        if (arg_auto_usr == GPT_AUTO_ROOT_OFF ||
+            arg_auto_usr < 0)
+                return 0;
+
+        /* We do not support the other gpt-auto modes for /usr/, but the parser should already have checked that. */
+        assert(arg_auto_usr == GPT_AUTO_ROOT_DISSECT);
+
+        if (arg_root_fstype && !arg_usr_fstype) {
+                arg_usr_fstype = strdup(arg_root_fstype);
+                if (!arg_usr_fstype)
+                        return log_oom();
+        }
+
+        if (arg_root_options && !arg_usr_options) {
+                arg_usr_options = strdup(arg_root_options);
+                if (!arg_usr_options)
+                        return log_oom();
+        }
+
+        if (in_initrd()) {
+                r = add_cryptsetup(
+                                "usr",
+                                "/dev/disk/by-designator/usr-luks",
+                                arg_usr_options,
+                                MOUNT_RW|MOUNT_MEASURE,
+                                /* require= */ false,
+                                /* ret_device= */ NULL);
+                if (r < 0)
+                        return r;
+        }
+
+        _cleanup_free_ char *options = NULL;
+        r = partition_pick_mount_options(
+                        PARTITION_USR,
+                        arg_usr_fstype,
+                        /* rw= */ false,
+                        /* discard= */ true,
+                        &options,
+                        /* ret_ms_flags= */ NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to pick /usr/ mount options: %m");
+
+        if (arg_usr_options)
+                if (!strextend_with_separator(&options, ",", arg_usr_options))
+                        return log_oom();
+
+        r = add_mount("usr",
+                      "/dev/disk/by-designator/usr",
+                      in_initrd() ? "/sysusr/usr" : "/usr",
+                      arg_usr_fstype,
+                      (in_initrd() ? MOUNT_VALIDATEFS : 0),
+                      options,
+                      "/usr/ Partition",
+                      in_initrd() ? SPECIAL_INITRD_USR_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
+        if (r < 0)
+                return r;
+
+        log_debug("Synthesizing entry what=/sysusr/usr where=/sysroot/usr opts=bind");
+
+        return add_mount("usr-bind",
+                         "/sysusr/usr",
+                         "/sysroot/usr",
+                         /* fstype= */ NULL,
+                         /* flags= */ 0,
+                         "bind",
+                         "/usr/ Partition (Final)",
+                         in_initrd() ? SPECIAL_INITRD_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
+#else
+        return 0;
+#endif
+}
+
 static int process_loader_partitions(DissectedPartition *esp, DissectedPartition *xbootldr) {
         sd_id128_t loader_uuid;
         int r;
@@ -973,7 +1062,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 /* Disable root disk logic if there's a root= value specified (unless it happens to be
                  * "gpt-auto" or "gpt-auto-force") */
 
-                arg_auto_root = parse_gpt_auto_root(value);
+                arg_auto_root = parse_gpt_auto_root("root=", value);
                 assert(arg_auto_root >= 0);
 
         } else if (streq(key, "roothash")) {
@@ -1001,6 +1090,37 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 if (!strextend_with_separator(&arg_root_options, ",", value))
                         return log_oom();
 
+        } else if (streq(key, "mount.usr")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                /* Disable root disk logic if there's a root= value specified (unless it happens to be
+                 * "gpt-auto" or "gpt-auto-force") */
+
+                arg_auto_usr = parse_gpt_auto_root("mount.usr=", value);
+                assert(arg_auto_usr >= 0);
+
+                if (IN_SET(arg_auto_usr, GPT_AUTO_ROOT_ON, GPT_AUTO_ROOT_FORCE, GPT_AUTO_ROOT_DISSECT_FORCE)) {
+                        log_warning("'gpt-auto', 'gpt-auto-force' and 'dissect-force' are not supported for mount.usr=. Automatically resorting to mount.usr=dissect mode instead.");
+                        arg_auto_usr = GPT_AUTO_ROOT_DISSECT;
+                }
+
+        } else if (streq(key, "mount.usrfstype")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                return free_and_strdup_warn(&arg_usr_fstype, empty_to_null(value));
+
+        } else if (streq(key, "mount.usrflags")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                if (!strextend_with_separator(&arg_usr_options, ",", value))
+                        return log_oom();
+
         } else if (streq(key, "rw") && !value)
                 arg_root_rw = true;
         else if (streq(key, "ro") && !value)
@@ -1045,6 +1165,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
 
         r = 0;
         RET_GATHER(r, add_root_mount());
+        RET_GATHER(r, add_usr_mount());
         RET_GATHER(r, add_mounts());
 
         return r;
index d1c643b9231cd0f02ecbe1959a4128ba513583f0..90568e3ec94d416cf3790591e3fa1b70b747d8e0 100644 (file)
@@ -216,8 +216,8 @@ static int write_fsck_sysroot_service(
 
         /* Writes out special versions of systemd-fsck-root.service and systemd-fsck-usr.service for use in
          * the initrd. The regular statically shipped versions of these unit files use / and /usr for as
-         * paths, which doesn't match what we need for the initrd (where the dirs are /sysroot +
-         * /sysusr/usr), hence we overwrite those versions here. */
+         * paths, which doesn't match what we need for the initrd (where the dirs are /sysroot/ +
+         * /sysusr/usr/), hence we overwrite those versions here. */
 
         escaped = specifier_escape(what);
         if (!escaped)
@@ -281,7 +281,7 @@ int generator_write_fsck_deps(
         assert(where);
 
         /* Let's do an early exit if we are invoked for the root and /usr/ trees in the initrd, to avoid
-         * generating confusing log messages */
+         * generating confusing log messages. */
         if (in_initrd() && PATH_IN_SET(where, "/", "/usr")) {
                 log_debug("Skipping fsck for %s in initrd.", where);
                 return 0;
@@ -1086,7 +1086,8 @@ bool generator_soft_rebooted(void) {
         return (cached = (u > 0));
 }
 
-GptAutoRoot parse_gpt_auto_root(const char *value) {
+GptAutoRoot parse_gpt_auto_root(const char *switch_name, const char *value) {
+        assert(switch_name);
         assert(value);
 
         /* Parses the 'gpt-auto'/'gpt-auto-root'/'dissect'/'dissect-force' parameters to root=
@@ -1095,29 +1096,29 @@ GptAutoRoot parse_gpt_auto_root(const char *value) {
          * the parameter names. And root= being something else is not an error. */
 
         if (streq(value, "gpt-auto")) {
-                log_debug("Enabling root partition auto-detection (respecting factory reset mode), root= is explicitly set to 'gpt-auto'.");
+                log_debug("Enabling partition auto-detection (respecting factory reset mode), %s is explicitly set to 'gpt-auto'.", switch_name);
                 return GPT_AUTO_ROOT_ON;
         }
 
         if (streq(value, "gpt-auto-force")) {
-                log_debug("Enabling root partition auto-detection (ignoring factory reset mode), root= is explicitly set to 'gpt-auto-force'.");
+                log_debug("Enabling partition auto-detection (ignoring factory reset mode), %s is explicitly set to 'gpt-auto-force'.", switch_name);
                 return GPT_AUTO_ROOT_FORCE;
         }
 
         if (streq(value, "dissect")) {
-                log_debug("Enabling root partition auto-detection via full image dissection (respecting factory reset mode), root= is explicitly set to 'dissect'.");
+                log_debug("Enabling partition auto-detection via full image dissection (respecting factory reset mode), %s is explicitly set to 'dissect'.", switch_name);
                 return GPT_AUTO_ROOT_DISSECT;
         }
 
         if (streq(value, "dissect-force")) {
-                log_debug("Enabling root partition auto-detection via full image dissection (ignoring factory reset mode), root= is explicitly set to 'dissect-force'.");
+                log_debug("Enabling partition auto-detection via full image dissection (ignoring factory reset mode), %s is explicitly set to 'dissect-force'.", switch_name);
                 return GPT_AUTO_ROOT_DISSECT_FORCE;
         }
 
         if (streq(value, "off"))
-                log_debug("Disabling root partition auto-detection, root= handling is explicitly turned off.");
+                log_debug("Disabling partition auto-detection, %s handling is explicitly turned off.", switch_name);
         else
-                log_debug("Disabling root partition auto-detection, root= is neither unset, nor set to 'gpt-auto', 'gpt-auto-force', 'dissect' or 'dissect-force'.");
+                log_debug("Disabling partition auto-detection, %s is neither unset, nor set to 'gpt-auto', 'gpt-auto-force', 'dissect' or 'dissect-force'.", switch_name);
 
         return GPT_AUTO_ROOT_OFF;
 }
index 4ded62d011e349c916e9af0cdfa4bc18e2aa292e..68ea9b376ff0d5fb7d59c556a1a4788a9198523c 100644 (file)
@@ -131,4 +131,4 @@ typedef enum GptAutoRoot {
         _GPT_AUTO_ROOT_INVALID = -EINVAL,
 } GptAutoRoot;
 
-GptAutoRoot parse_gpt_auto_root(const char *value);
+GptAutoRoot parse_gpt_auto_root(const char *switch_name, const char *value);