mirror of
https://github.com/systemd/systemd.git
synced 2025-03-14 04:58:28 +03:00
udev-builtin-blkid: use loopback block device 'ref' field fo determining gpt-auto whole block device
So far the gpt-auto logic only looked for the partition table of devices that the ESP/XBOOTLDR partition used to boot was on. This works great for local boots, but is more problematic if we boot a UKI via UEFI HTTP boot, because there is no ESP in play in that case. Let's introduce an alternative to communicate the intended default root disk to cover for this situation: any loopback block device whose backing file field (i.e. the userspace controlled freeform field we use for /dev/disk/by-loop-ref/ naming) is set to "rootdisk" will be consider for gpt-auto will be consider for gpt-auto. With this in place we should have nice automatic behaviour: 1. If we are booted locally we'll get the ESP/XBOOTLDR data, and derive the root disk from that. 2. If we are booted via UEFI HTTP boot we expect that the caller makes the loopback device appear with the right loop-ref identifier, and then will use that.
This commit is contained in:
parent
3d49850096
commit
f8825c1364
@ -50,19 +50,49 @@
|
||||
<para>If the units this generator creates are overridden, for example by units in directories with higher
|
||||
precedence, drop-ins and additional dependencies created by this generator might still be used.</para>
|
||||
|
||||
<para>This generator will only look for the root partition on the same physical disk where the EFI System
|
||||
Partition (ESP) is located. Note that support from the boot loader is required: the EFI variable
|
||||
<varname>LoaderDevicePartUUID</varname> of the <constant>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</constant>
|
||||
vendor UUID is used to determine from which partition, and hence the disk, from which the system was
|
||||
booted. If the boot loader does not set this variable, this generator will not be able to detect the root
|
||||
partition. See the <ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>
|
||||
for details.</para>
|
||||
<para>When run in the initial RAM disk (initrd) this generator can automatically search for the root file
|
||||
system. Specifically:
|
||||
|
||||
<para>Similarly, this generator will only look for the other partitions on the same physical disk as the
|
||||
root partition. In this case, boot loader support is not required. These partitions will not be searched
|
||||
for on systems where the root file system is distributed on multiple disks, for example via btrfs RAID.
|
||||
<itemizedlist>
|
||||
<listitem><para>It will look for the root partition on the same physical disk where the EFI System
|
||||
Partition (ESP) is located. Note that support from the boot loader is required for this to work: the
|
||||
EFI variable <varname>LoaderDevicePartUUID</varname> of the
|
||||
<constant>4a67b082-0a4c-41cf-b6c7-440b29bb8c4f</constant> vendor UUID is used to determine from which
|
||||
partition (and hence disk) the system was booted. If the boot loader does not set this variable, this
|
||||
generator will not be able to detect the root partition. See the <ulink
|
||||
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink> for
|
||||
details.</para></listitem>
|
||||
|
||||
<listitem><para>Alternatively, it will look for the root file system on a loopback block device whose
|
||||
<literal>.lo_name</literal> field is set to one of the literal strings <literal>rootdisk</literal> or
|
||||
<literal>rootdisk.raw</literal>. This field can be set via <command>losetup</command>'s
|
||||
<option>--loop-ref=</option> string. For images downloaded via
|
||||
<citerefentry><refentrytitle>systemd-import-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
make sure to set the <literal>blockdev</literal> option and set the local name string to
|
||||
<literal>rootdisk</literal> to achieve this effect. Note that discovery of the root file system on
|
||||
loopback block devices like this is only done if <literal>root=gpt-auto</literal> is specified
|
||||
explicitly on the kernel command line, unlike the discovery based on the boot loader reported ESP which
|
||||
is also enabled if no <literal>root=</literal> parameter is specified at all. (The latter relies on
|
||||
<command>systemd-udevd.service</command>'s <filename>/dev/gpt-auto-root</filename> block device symlink
|
||||
generation).</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>When run on the host system (i.e. after successfully transitioning out of the initrd into the root
|
||||
filesystem) this generator will look for all other partitions on the same physical disk as the root
|
||||
partition. For this discovery, boot loader support is not required. Moreover, it is not required that the
|
||||
root partition was automatically discovered by the initrd (as described above) for the discovery of the
|
||||
non-root file partitions to take place. Or in other words: automatic discovery of the root file system
|
||||
and of the non-root file systems are independent operations, that do not rely on each other, and are done
|
||||
during two distinct phases of the boot process (one in the initrd, the other after). These partitions will
|
||||
not be searched for on systems where the root file system is distributed on multiple disks, for example
|
||||
via btrfs RAID.</para>
|
||||
|
||||
<para>The root partition can be configured explicitly by symlinking
|
||||
<filename>/run/systemd/volatile-root</filename> to <filename>/dev/block/$major:$minor</filename>. This is
|
||||
especially useful if the root mount has been replaced by some form of volatile file system
|
||||
(overlayfs).</para>
|
||||
|
||||
<para><filename>systemd-gpt-auto-generator</filename> is useful for centralizing file system
|
||||
configuration in the partition table and making configuration in <filename>/etc/fstab</filename> or on
|
||||
the kernel command line unnecessary.</para>
|
||||
@ -225,11 +255,6 @@
|
||||
<citerefentry><refentrytitle>bootup</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
|
||||
</para>
|
||||
|
||||
<para>The root partition can be specified by symlinking <filename>/run/systemd/volatile-root</filename>
|
||||
to <filename>/dev/block/$major:$minor</filename>. This is especially useful if the root mount has been
|
||||
replaced by some form of volatile file system (overlayfs).
|
||||
</para>
|
||||
|
||||
<para>Mount and automount units for the EFI System Partition (ESP) and Extended Boot Loader Partition
|
||||
(XBOOTLDR) are generated on EFI systems. If the disk contains an XBOOTLDR partition, as defined in the
|
||||
<ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader
|
||||
@ -297,10 +322,14 @@
|
||||
<term><varname>rootflags=</varname></term>
|
||||
|
||||
<listitem><para>When <varname>root=</varname> is used with the special value
|
||||
<literal>gpt-auto</literal> (or if the parameter is not used at all), automatic discovery of the root
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
|
@ -125,6 +125,17 @@
|
||||
device (via <filename>systemd-loop@.service</filename>) after completion. This permits booting
|
||||
from downloaded disk images. This is only supported for <literal>raw</literal> disk images.</para>
|
||||
|
||||
<para>Note when this option is used with the purpose of mounting a disk image conforming to the
|
||||
<ulink url="https://uapi-group.org/specifications/specs/discoverable_disk_image/">Discoverable
|
||||
Disk Image Specification</ulink> as root file system, and the automatic GPT partition discovery
|
||||
logic as implemented by
|
||||
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
shall process it, it's essential to specify <literal>rootdisk</literal> as the local name for the
|
||||
import. Moreover, <literal>root=gpt-auto</literal> must be specified on the kernel command line
|
||||
explicitly. Also, prefix the <literal>systemd.pull=</literal> commmand line option with
|
||||
<literal>rd.</literal> to ensure it is executed in the initial RAM disk (initrd) already, also
|
||||
see below.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@ -235,12 +246,14 @@
|
||||
<example>
|
||||
<title>Boot into disk image (raw), with URL derived from UEFI HTTP network booting</title>
|
||||
|
||||
<programlisting>rd.systemd.pull=raw,machine,verify=no,blockdev,bootorigin:rootdisk:image.raw.xz root=/dev/disk/by-loop-ref/rootdisk.raw-part2</programlisting>
|
||||
<programlisting>rd.systemd.pull=raw,machine,verify=no,blockdev,bootorigin:rootdisk:image.raw.xz root=gpt-auto</programlisting>
|
||||
|
||||
<para>This is similar to the previous example, but this time the source URL is automatically derived
|
||||
from the UEFI HTTP network boot URL. For example, if an UKI is booted from an URL
|
||||
<literal>http://example.com/image.efi</literal> this would result in a root disk being downloaded from
|
||||
<literal>http://example.com/image.raw.xz</literal>.</para>
|
||||
<literal>http://example.com/image.raw.xz</literal>. Moreover this uses the
|
||||
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
logic to mount the root file system from the disk image.</para>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
@ -263,6 +276,7 @@
|
||||
<member><citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-loop@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
@ -125,12 +125,13 @@ static void print_property(UdevEvent *event, const char *name, const char *value
|
||||
}
|
||||
}
|
||||
|
||||
static int find_gpt_root(UdevEvent *event, blkid_probe pr) {
|
||||
static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_backing_fname) {
|
||||
|
||||
#if defined(SD_GPT_ROOT_NATIVE) && ENABLE_EFI
|
||||
|
||||
sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
|
||||
sd_id128_t esp_or_xbootldr = SD_ID128_NULL;
|
||||
_cleanup_free_ char *root_label = NULL;
|
||||
bool found_esp_or_xbootldr = false;
|
||||
bool found_esp_or_xbootldr = false, need_esp_or_xbootldr;
|
||||
sd_id128_t root_id = SD_ID128_NULL;
|
||||
int r;
|
||||
|
||||
@ -138,13 +139,42 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr) {
|
||||
assert(pr);
|
||||
|
||||
/* Iterate through the partitions on this disk, and see if the UEFI ESP or XBOOTLDR partition we
|
||||
* booted from is on it. If so, find the first root disk, and add a property indicating its partition
|
||||
* UUID. */
|
||||
* booted from is on it. If so, find the newest root partition, and add a property indicating its
|
||||
* partition UUID. We also do this if we are dealing with a loopback block device whose "backing
|
||||
* filename" field is set to the string "root". In the latter case we do not search for ESP or
|
||||
* XBOOTLDR. */
|
||||
|
||||
if (!device_is_devtype(dev, "disk")) {
|
||||
log_device_debug(dev, "Skipping GPT root logic on partition block device.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = efi_loader_get_device_part_uuid(&esp_or_xbootldr);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT && !ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return log_debug_errno(r, "Unable to determine loader partition UUID: %m");
|
||||
|
||||
log_device_debug(dev, "No loader partition UUID EFI variable set, not using partition data for search for default root block device.");
|
||||
|
||||
/* NB: if an ESP/xbootldr field is set, we always use that. We do this in order to guarantee
|
||||
* systematic behaviour. */
|
||||
if (!STRPTR_IN_SET(loop_backing_fname, "rootdisk", "rootdisk.raw")) {
|
||||
log_device_debug(dev, "Device is not a loopback block device with reference string 'root', not considering block device as default root block device.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* OK, we have now sufficiently identified this device as the right root "whole" device,
|
||||
* hence no need to bother with searching for ESP/XBOOTLDR */
|
||||
need_esp_or_xbootldr = false;
|
||||
} else
|
||||
/* We now know the the ESP/xbootldr UUID, but we cannot be sure yet it's on this block
|
||||
* device, hence look for it among partitions now */
|
||||
need_esp_or_xbootldr = true;
|
||||
|
||||
errno = 0;
|
||||
blkid_partlist pl = blkid_probe_get_partitions(pr);
|
||||
if (!pl)
|
||||
return errno_or_else(ENOMEM);
|
||||
return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to probe partitions: %m");
|
||||
|
||||
int nvals = blkid_partlist_numof_partitions(pl);
|
||||
for (int i = 0; i < nvals; i++) {
|
||||
@ -158,27 +188,21 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr) {
|
||||
|
||||
r = blkid_partition_get_uuid_id128(pp, &id);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to get partition UUID, ignoring: %m");
|
||||
log_device_debug_errno(dev, r, "Failed to get partition UUID, ignoring: %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
r = blkid_partition_get_type_id128(pp, &type);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to get partition type UUID, ignoring: %m");
|
||||
log_device_debug_errno(dev, r, "Failed to get partition type UUID, ignoring: %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
label = blkid_partition_get_name(pp); /* returns NULL if empty */
|
||||
|
||||
if (sd_id128_in_set(type, SD_GPT_ESP, SD_GPT_XBOOTLDR)) {
|
||||
sd_id128_t esp_or_xbootldr;
|
||||
if (need_esp_or_xbootldr && sd_id128_in_set(type, SD_GPT_ESP, SD_GPT_XBOOTLDR)) {
|
||||
|
||||
/* We found an ESP or XBOOTLDR, let's see if it matches the ESP/XBOOTLDR we booted from. */
|
||||
|
||||
r = efi_loader_get_device_part_uuid(&esp_or_xbootldr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_id128_equal(id, esp_or_xbootldr))
|
||||
found_esp_or_xbootldr = true;
|
||||
|
||||
@ -195,17 +219,20 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr) {
|
||||
if (sd_id128_is_null(root_id) || strverscmp_improved(label, root_label) > 0) {
|
||||
root_id = id;
|
||||
|
||||
r = free_and_strdup(&root_label, label);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (free_and_strdup(&root_label, label) < 0)
|
||||
return log_oom_debug();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We found the ESP/XBOOTLDR on this disk, and also found a root partition, nice! Let's export its
|
||||
* UUID */
|
||||
if (found_esp_or_xbootldr && !sd_id128_is_null(root_id))
|
||||
udev_builtin_add_property(event, "ID_PART_GPT_AUTO_ROOT_UUID", SD_ID128_TO_UUID_STRING(root_id));
|
||||
if (!need_esp_or_xbootldr || found_esp_or_xbootldr) {
|
||||
/* We found the ESP/XBOOTLDR on this disk (or we didn't need it) */
|
||||
udev_builtin_add_property(event, "ID_PART_GPT_AUTO_ROOT_DISK", "1");
|
||||
|
||||
/* We found a root partition, nice! Let's export its UUID. */
|
||||
if (!sd_id128_is_null(root_id))
|
||||
udev_builtin_add_property(event, "ID_PART_GPT_AUTO_ROOT_UUID", SD_ID128_TO_UUID_STRING(root_id));
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@ -437,9 +464,6 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
|
||||
udev_builtin_add_property(event, "ID_PART_GPT_AUTO_ROOT", "1");
|
||||
}
|
||||
|
||||
if (is_gpt)
|
||||
find_gpt_root(event, pr);
|
||||
|
||||
r = read_loopback_backing_inode(
|
||||
dev,
|
||||
fd,
|
||||
@ -466,6 +490,9 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_gpt)
|
||||
find_gpt_root(event, pr, backing_fname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user