<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>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.
+ <para>When run in the initial RAM disk (initrd) this generator can automatically search for the root file
+ system. Specifically:
+
+ <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>
<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
<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>
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>
<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>
<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>
}
}
-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;
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++) {
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;
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;
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,
}
}
+ if (is_gpt)
+ find_gpt_root(event, pr, backing_fname);
+
return 0;
}