gpt-auto-generator: if root=gpt-auto-force is specified ignore factory reset state

This commit is contained in:
Lennart Poettering
2025-02-21 17:23:22 +01:00
parent c7da91ff66
commit 1c0b8270f4
3 changed files with 66 additions and 23 deletions

View File

@@ -322,16 +322,20 @@
<term><varname>rootflags=</varname></term>
<listitem><para>When <varname>root=</varname> is used with the special value
<literal>gpt-auto</literal>, full automatic discovery of the root
partition based on the GPT partition type is enabled. Any other value disables this
logic.</para>
<literal>gpt-auto</literal>, full automatic discovery of the root partition based on the GPT
partition type is enabled. Use of the root partition is delayed until factory reset mode is left, in
case it is enabled during the current boot. See <ulink url="https://systemd.io/FACTORY_RESET">Factory
Reset</ulink> for more information on that. If <literal>gpt-auto-force</literal> is specified
automatic discovery of the root partition is enabled, ignoring any factory reset mode. Any other
value disables this logic.</para>
<para>If <varname>root=</varname> is not specified at all on the kernel command line automatic
discovery of the root partition via the boot loader reported ESP is also enabled, however in this
case discovery based on the loopback block device <literal>.lo_name</literal> field is not enabled.</para>
discovery of the root partition via the ESP reported by the boot loader is also enabled (taking
factory reset state into account), however in this case discovery based on the loopback block device
<literal>.lo_name</literal> field is not enabled.</para>
<para>The <varname>rootfstype=</varname> and <varname>rootflags=</varname> are used to select the
file system type and options when the root file system is automatically discovered.</para>
<para>The <varname>rootfstype=</varname> and <varname>rootflags=</varname> options are used to select
the file system type and options when the root file system is automatically discovered.</para>
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
</varlistentry>

View File

@@ -1119,7 +1119,7 @@ static bool validate_root_or_usr_mount_source(const char *what, const char *swit
return false;
}
if (streq(what, "gpt-auto")) {
if (STR_IN_SET(what, "gpt-auto", "gpt-auto-force")) {
/* This is handled by gpt-auto-generator */
log_debug("Skipping %s directory handling, as gpt-auto was requested.", switch_name);
return false;

View File

@@ -17,6 +17,7 @@
#include "dissect-image.h"
#include "dropin.h"
#include "efi-loader.h"
#include "factory-reset.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
@@ -37,9 +38,16 @@
#include "unit-name.h"
#include "virt.h"
typedef enum GptAutoRoot {
GPT_AUTO_ROOT_UNSPECIFIED, /* no root= specified */
GPT_AUTO_ROOT_OFF, /* root= set to something else */
GPT_AUTO_ROOT_ON, /* root= set explicitly to "gpt-auto" */
GPT_AUTO_ROOT_FORCE, /* root= set explicitly to "gpt-auto-force" → ignores factory reset mode */
} GptAutoRoot;
static const char *arg_dest = NULL;
static bool arg_enabled = true;
static int arg_root_enabled = -1; /* tristate */
static GptAutoRoot arg_auto_root = GPT_AUTO_ROOT_UNSPECIFIED;
static bool arg_swap_enabled = true;
static char *arg_root_fstype = NULL;
static char *arg_root_options = NULL;
@@ -47,7 +55,6 @@ static int arg_root_rw = -1;
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);
@@ -661,7 +668,19 @@ static int add_root_cryptsetup(void) {
/* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
* sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
return add_cryptsetup("root", "/dev/gpt-auto-root-luks", arg_root_options, /* rw= */ true, /* require= */ false, /* measure= */ true, NULL);
const char *bdev = "/dev/gpt-auto-root-luks";
if (arg_auto_root == GPT_AUTO_ROOT_FORCE) {
/* Similar logic as in add_root_mount(), see below */
FactoryResetMode f = factory_reset_mode();
if (f < 0)
log_warning_errno(f, "Failed to determine whether we are in factory reset mode, assuming not: %m");
if (IN_SET(f, FACTORY_RESET_ON, FACTORY_RESET_COMPLETE))
bdev = "/dev/gpt-auto-root-luks-ignore-factory-reset";
}
return add_cryptsetup("root", bdev, arg_root_options, /* rw= */ true, /* require= */ false, /* measure= */ true, NULL);
#else
return 0;
#endif
@@ -674,11 +693,11 @@ static int add_root_mount(void) {
int r;
/* Explicitly disabled? Then exit immediately */
if (arg_root_enabled == 0)
if (arg_auto_root == GPT_AUTO_ROOT_OFF)
return 0;
/* Neither explicitly enabled nor disabled? Then decide based on the EFI partition variables to be set */
if (arg_root_enabled < 0) {
if (arg_auto_root == GPT_AUTO_ROOT_UNSPECIFIED) {
if (!is_efi_boot()) {
log_debug("Not an EFI boot, not creating root mount.");
return 0;
@@ -695,10 +714,27 @@ static int add_root_mount(void) {
}
/* OK, we shall look for a root device, so let's wait for a root device to show up. A udev rule will
* create the link for us under the right name. */
* create the link for us under the right name.
*
* There are two distinct names: the /dev/gpt-auto-root-ignore-factory-reset symlink is created for
* the root partition if factory reset mode is enabled or complete, and the /dev/gpt-auto-root
* symlink is only created if factory reset mode is off or already complete (thus taking factory
* reset state into account). In scenarios where the root disk is partially reformatted during
* factory reset the latter is the link to use, otherwise the former (so that we don't accidentally
* mount a root partition too early that is about to be wiped and replaced by another one). */
const char *bdev = "/dev/gpt-auto-root";
if (arg_auto_root == GPT_AUTO_ROOT_FORCE) {
FactoryResetMode f = factory_reset_mode();
if (f < 0)
log_warning_errno(f, "Failed to determine whether we are in factory reset mode, assuming not: %m");
if (IN_SET(f, FACTORY_RESET_ON, FACTORY_RESET_COMPLETE))
bdev = "/dev/gpt-auto-root-ignore-factory-reset";
}
if (in_initrd()) {
r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
r = generator_write_initrd_root_device_deps(arg_dest, bdev);
if (r < 0)
return 0;
@@ -727,7 +763,7 @@ static int add_root_mount(void) {
return add_mount(
"root",
"/dev/gpt-auto-root",
bdev,
in_initrd() ? "/sysroot" : "/",
arg_root_fstype,
/* rw= */ arg_root_rw > 0,
@@ -909,15 +945,18 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
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") */
/* Disable root disk logic if there's a root= value specified (unless it happens to be
* "gpt-auto" or "gpt-auto-force") */
if (streq(value, "gpt-auto")) {
arg_root_enabled = true;
log_debug("Enabling root partition auto-detection, root= is explicitly set to 'gpt_auto'.");
arg_auto_root = GPT_AUTO_ROOT_ON;
log_debug("Enabling root partition auto-detection (respecting factory reset mode), root= is explicitly set to 'gpt-auto'.");
} else if (streq(value, "gpt-auto-force")) {
arg_auto_root = GPT_AUTO_ROOT_FORCE;
log_debug("Enabling root partition auto-detection (ignoring factory reset mode), root= is explicitly set to 'gpt-auto-force'.");
} else {
arg_root_enabled = false;
log_debug("Disabling root partition auto-detection, root= is neither unset, nor set to 'gpt-auto'.");
arg_auto_root = GPT_AUTO_ROOT_OFF;
log_debug("Disabling root partition auto-detection, root= is neither unset, nor set to 'gpt-auto' or 'gpt-auto-force'.");
}
} else if (streq(key, "roothash")) {
@@ -927,7 +966,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
/* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
arg_root_enabled = false;
arg_auto_root = GPT_AUTO_ROOT_OFF;
log_debug("Disabling root partition auto-detection, roothash= is set.");
} else if (streq(key, "rootfstype")) {