mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/7] init: discoverable root partitions
@ 2026-11-02 21:29 Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 1/7] block: store GPT partition type UUID Vincent Mailhol
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Vincent Mailhol @ 2026-11-02 21:29 UTC (permalink / raw)
  To: Jens Axboe, Davidlohr Bueso, Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-kernel, linux-block, linux-efi, linux-fsdevel, Dave Hansen,
	James Bottomley, Helge Deller, Matthew Wilcox, Vincent Mailhol,
	Jonathan Corbet, Shuah Khan, Randy Dunlap, linux-doc

DPS [1] defines GPT partition type UUIDs for OS partitions and
attributes that control whether such partitions should be
automatically discovered. The specification states that:

  The OS can discover and mount the necessary file systems with a
  non-existent or incomplete /etc/fstab file and without the root=
  kernel command line option.

DPS is already implemented in systemd-gpt-auto-generator [2], which,
when embedded in an initrd, indeed allows automatic detection of the
root filesystem through its partition type UUID.

This series adds root discovery directly into the kernel so that people
who are not using an initrd can still benefit from it.

The scope is deliberately limited to block devices that the kernel can
already mount through the root= parameter. Other DPS features, such as
setting up LUKS-encrypted partitions, mounting partitions other than
root or container setup, remain userspace responsibilities, with no
future plan to implement them in the kernel. The intended usage is
thus a hybrid approach in which the kernel DPS only mounts the root
partition and leaves the remaining setup to userspace (either with DPS
or with a classic fstab), just as it does today when root= specifies
the root device.

The benefit is being able to boot a kernel with no accompanying
bootloader configuration: no root= parameter and no initramfs. The root
partition is identified from the existing on-disk metadata instead.

This is useful for booting a kernel manually, for example from the edk2
file browser, or recovering from a lost or corrupted bootloader
configuration without having to supply the correct root= argument or
load an initrd from the bootloader shell. Finally, it allows systems
that otherwise need no initrd to discover their root partition through
DPS without introducing an early userspace environment solely for that
lookup.

The implementation follows these rules:

  - GPT partition type UUIDs are used for automatic discovery policy
    only. No root=PARTTYPEUUID=xxx cmdline option or similar syntax is
    added.

  - An initramfs providing an early userspace init, a root= command-line
    option, or a root device supplied by the boot loader takes
    precedence. Existing working boot configurations therefore retain
    their current behaviour. Automatic discovery triggers only when
    booting without any of these, where the kernel would otherwise panic
    because no root device was specified.

  - As required by DPS, discovery is restricted to the disk containing
    the active EFI System Partition, identified through the
    LoaderDevicePartUUID EFI variable. This avoids inadvertently
    selecting a root partition on another disk, assuming partition UUIDs
    are unique. This is not a security feature: an attacker could
    duplicate the ESP's PARTUUID on another disk, just as with
    root=PARTUUID=xxx today.

  - If several eligible partitions have the selected type, the first
    match in block-device enumeration order is used.

  - The native architecture's root partition type takes precedence.
    Where the kernel supports compatible 32-bit userspace, its root
    partition type is accepted as a fallback.

  - Partitions carrying the DPS no-auto attribute are excluded.

  - The DPS read-only attribute is intentionally not enforced. The
    kernel already mounts the root filesystem read-only by default and
    if the command line requests rw, it takes precedence over the DPS
    attribute. User space remains responsible for deciding whether a
    discovered root should later be remounted read-write based on DPS
    metadata and local policy.

Patch 1 retains GPT partition type UUIDs in partition metadata for early
block lookup.

Patch 2 defines the architecture-specific DPS root partition type UUIDs
and the derived DPS_ROOT_AUTO_DISCOVERY symbol in Kconfig.

Patch 3 factors out lookup_root_device() so initial root lookup and
rootwait retries share the same lookup policy.

Patch 4 implements DPS root discovery through early_lookup_dps_root()
and integrates it into the root mount path.

Patch 5 excludes partitions marked no-auto.

Patch 6 adds the compatible 32-bit root partition type UUID as a
fallback when no partition with the native type UUID can be found.

Finally, patch 7 documents automatic root discovery.

Tested with the Linux EFI stub [3] and with GRUB [4], which both expose
the LoaderDevicePartUUID EFI variable.

[1] The Discoverable Partitions Specification (DPS)
Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/

[2] systemd-gpt-auto-generator
Link: https://www.freedesktop.org/software/systemd/man/latest/systemd-gpt-auto-generator.html

[3] commit 0f7d63d9a725 ("efi/libstub: add initial Boot Loader Interface
    support")
Link: https://git.kernel.org/torvalds/c/0f7d63d9a725

[4] GRUB -- §16.20 bli
Link: https://www.gnu.org/software/grub/manual/grub/html_node/bli_005fmodule.html

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Changes in v3:

  - Rebase on v7.4-rc1.

  - Clarify in the cover letter that ESP UUID matching is not a security
    feature.

  - Move the DPS Kconfig symbols from init/Kconfig to block/Kconfig,
    alongside the root discovery implementation.

  - Restrict the LoongArch root partition type UUID to 64-bit kernels,
    since DPS does not define a root partition type UUID for LoongArch32.

  - Reject LoaderDevicePartUUID if it contains trailing characters.

  - Document when automatic discovery stops waiting.

Link to v2: https://patch.msgid.link/20261025-discoverable-root_partitions-v2-0-fb77d0821fab@kernel.org

Changes in v2:

  - Remove all architectures which do not have CONFIG_EFI.

  - Replace the per-architecture UUID headers with Kconfig definitions.

  - Move most of the DPS lookup logic to block/early-lookup.c.

  - Bail out if ROOT_DEV already exists.

  - Hold the disk's open_mutex during lookup so partition scanning
    finishes before reporting -ENODEV. This is a prerequisite for the
    next two changes.

  - Do an early abort when early_lookup_dps_root() returns -ENODEV.

  - Add the secondary partition type UUID as a fallback.

  - Small tweaks in log messages.

  - Documentation is updated accordingly.

Link to v1: https://lore.kernel.org/r/20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org

---
Vincent Mailhol (7):
      block: store GPT partition type UUID
      block: add DPS root partition type UUID definitions
      init: factor out root device lookup into lookup_root_device()
      block: discover root by DPS partition type UUID
      block: skip partitions with DPS no-auto GPT attribute
      block: add secondary DPS root partition type UUID
      docs: document discoverable root partitions

 Documentation/admin-guide/discoverable-root.rst |  46 +++++++++
 Documentation/admin-guide/index.rst             |   1 +
 Documentation/admin-guide/kernel-parameters.txt |   5 +
 block/Kconfig                                   |  21 ++++
 block/early-lookup.c                            | 121 +++++++++++++++++++++++-
 block/partitions/efi.c                          |   2 +
 include/linux/blkdev.h                          |  15 +++
 init/do_mounts.c                                |  44 +++++++--
 8 files changed, 242 insertions(+), 13 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20260611-discoverable-root_partitions-bdacbada570d

Best regards,
--  
Vincent Mailhol <mailhol@kernel.org>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 1/7] block: store GPT partition type UUID
  2026-11-02 21:29 [PATCH v3 0/7] init: discoverable root partitions Vincent Mailhol
@ 2026-11-02 21:29 ` Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 2/7] block: add DPS root partition type UUID definitions Vincent Mailhol
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Vincent Mailhol @ 2026-11-02 21:29 UTC (permalink / raw)
  To: Jens Axboe, Davidlohr Bueso, Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-kernel, linux-block, linux-efi, linux-fsdevel, Dave Hansen,
	James Bottomley, Helge Deller, Matthew Wilcox, Vincent Mailhol

DPS [1] identifies OS partitions by GPT partition type UUID.

Keep that UUID in struct partition_meta_info and populate it while
scanning GPT partition tables so early root discovery can use it.

[1] The Discoverable Partitions Specification (DPS)
Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
 block/partitions/efi.c | 1 +
 include/linux/blkdev.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/block/partitions/efi.c b/block/partitions/efi.c
index 9865d59093fa..4a3835ed9561 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -742,6 +742,7 @@ int efi_partition(struct parsed_partitions *state)
 
 		info = &state->parts[i + 1].info;
 		efi_guid_to_str(&ptes[i].unique_partition_guid, info->uuid);
+		efi_guid_to_str(&ptes[i].partition_type_guid, info->type_uuid);
 
 		/* Naively convert UTF16-LE to 7 bits. */
 		label_max = min(ARRAY_SIZE(info->volname) - 1,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 0c2010230632..0e0f5d68425d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -67,6 +67,7 @@ extern const struct class block_class;
 
 struct partition_meta_info {
 	char uuid[PARTITION_META_INFO_UUIDLTH];
+	char type_uuid[PARTITION_META_INFO_UUIDLTH];
 	u8 volname[PARTITION_META_INFO_VOLNAMELTH];
 };
 

-- 
2.56.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 2/7] block: add DPS root partition type UUID definitions
  2026-11-02 21:29 [PATCH v3 0/7] init: discoverable root partitions Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 1/7] block: store GPT partition type UUID Vincent Mailhol
@ 2026-11-02 21:29 ` Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 3/7] init: factor out root device lookup into lookup_root_device() Vincent Mailhol
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Vincent Mailhol @ 2026-11-02 21:29 UTC (permalink / raw)
  To: Jens Axboe, Davidlohr Bueso, Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-kernel, linux-block, linux-efi, linux-fsdevel, Dave Hansen,
	James Bottomley, Helge Deller, Matthew Wilcox, Vincent Mailhol

DPS [1] assigns a native root partition type UUID to each supported
architecture. Add a hidden DPS_ROOT_PARTITION_TYPE_UUID string symbol
and populate it from the architecture selected in Kconfig. Only
architectures with EFI support in the kernel are added.

Gate the symbol on EFI and EFI_PARTITION because discovery needs block
devices, EFI runtime services and GPT partition parsing.

Derive the hidden DPS_ROOT_AUTO_DISCOVERY boolean from whether
DPS_ROOT_PARTITION_TYPE_UUID is nonempty.

[1] The Discoverable Partitions Specification (DPS)
Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
 block/Kconfig | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/block/Kconfig b/block/Kconfig
index 70e4a66d941f..3b5d3ad42dde 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -211,6 +211,20 @@ config BLK_INLINE_ENCRYPTION_FALLBACK
 
 source "block/partitions/Kconfig"
 
+config DPS_ROOT_PARTITION_TYPE_UUID
+	depends on EFI && EFI_PARTITION
+	string
+	default "69dad710-2ce4-4e3c-b16c-21a1d49abed3" if ARM
+	default "b921b045-1df0-41c3-af44-4c6f280d3fae" if ARM64
+	default "77055800-792c-4f94-b39a-98c91b762bb6" if LOONGARCH && 64BIT
+	default "72ec70a6-cf74-40e6-bd49-4bda08e8f224" if RISCV && 64BIT
+	default "60d5a7fe-8e7d-435c-b714-3dd8162144e1" if RISCV
+	default "4f68bce3-e8cd-4db1-96e7-fbcaf984b709" if X86_64
+	default "44479540-f297-41b2-9af7-d131d5f0458a" if X86
+
+config DPS_ROOT_AUTO_DISCOVERY
+	def_bool DPS_ROOT_PARTITION_TYPE_UUID != ""
+
 config BLK_PM
 	def_bool PM
 

-- 
2.56.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 3/7] init: factor out root device lookup into lookup_root_device()
  2026-11-02 21:29 [PATCH v3 0/7] init: discoverable root partitions Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 1/7] block: store GPT partition type UUID Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 2/7] block: add DPS root partition type UUID definitions Vincent Mailhol
@ 2026-11-02 21:29 ` Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 4/7] block: discover root by DPS partition type UUID Vincent Mailhol
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Vincent Mailhol @ 2026-11-02 21:29 UTC (permalink / raw)
  To: Jens Axboe, Davidlohr Bueso, Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-kernel, linux-block, linux-efi, linux-fsdevel, Dave Hansen,
	James Bottomley, Helge Deller, Matthew Wilcox, Vincent Mailhol

DPS root detection will also need to work if root_wait is set, meaning
that wait_for_root() needs to handle the DPS logic.

Move the early_lookup_bdev() calls and the rootwait error handling into
the new lookup_root_device() so later changes can extend the lookup
policy without duplicating the rootwait retry logic.

While at it, reword the error message to add the "VFS: " prefix.

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
 init/do_mounts.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/init/do_mounts.c b/init/do_mounts.c
index b088021b1546..b0dccad20971 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -402,6 +402,18 @@ void __init mount_root(char *root_device_name)
 	}
 }
 
+static int __init lookup_root_device(const char *root_device_name, dev_t *dev)
+{
+	int err;
+
+	err = early_lookup_bdev(root_device_name, dev);
+	if (err == -EINVAL && root_wait) {
+		pr_err("VFS: root= is invalid; disabling rootwait.\n");
+		root_wait = 0;
+	}
+	return err;
+}
+
 /* wait for any asynchronous scanning to complete */
 static void __init wait_for_root(char *root_device_name)
 {
@@ -415,7 +427,7 @@ static void __init wait_for_root(char *root_device_name)
 	end = ktime_add_ms(ktime_get_raw(), root_wait);
 
 	while (!driver_probe_done() ||
-	       early_lookup_bdev(root_device_name, &ROOT_DEV) < 0) {
+	       lookup_root_device(root_device_name, &ROOT_DEV) < 0) {
 		msleep(5);
 		if (root_wait > 0 && ktime_after(ktime_get_raw(), end))
 			break;
@@ -440,14 +452,9 @@ static dev_t __init parse_root_device(char *root_device_name)
 	if (strcmp(root_device_name, "/dev/ram") == 0)
 		return Root_RAM0;
 
-	error = early_lookup_bdev(root_device_name, &dev);
-	if (error) {
-		if (error == -EINVAL && root_wait) {
-			pr_err("Disabling rootwait; root= is invalid.\n");
-			root_wait = 0;
-		}
+	error = lookup_root_device(root_device_name, &dev);
+	if (error)
 		return 0;
-	}
 	return dev;
 }
 

-- 
2.56.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 4/7] block: discover root by DPS partition type UUID
  2026-11-02 21:29 [PATCH v3 0/7] init: discoverable root partitions Vincent Mailhol
                   ` (2 preceding siblings ...)
  2026-11-02 21:29 ` [PATCH v3 3/7] init: factor out root device lookup into lookup_root_device() Vincent Mailhol
@ 2026-11-02 21:29 ` Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 5/7] block: skip partitions with DPS no-auto GPT attribute Vincent Mailhol
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Vincent Mailhol @ 2026-11-02 21:29 UTC (permalink / raw)
  To: Jens Axboe, Davidlohr Bueso, Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-kernel, linux-block, linux-efi, linux-fsdevel, Dave Hansen,
	James Bottomley, Helge Deller, Matthew Wilcox, Vincent Mailhol

When root= and ROOT_DEV are not set, discover the root block device
using the architecture's DPS root partition type UUID. Preserve explicit
root selection and an existing ROOT_DEV supplied by the boot protocol.

DPS [1] restricts discovery to the disk containing the active EFI System
Partition. Read LoaderDevicePartUUID from the Boot Loader Interface to
identify that disk and cache the UUID for subsequent lookup attempts.

Add early_lookup_bdev_by_type_uuid() to select the first matching
partition. The EFI System Partition may become visible before the root
partition has been registered. Hold the disk's open_mutex during lookup
so partition scanning finishes before returning -ENODEV.

Add early_lookup_dps_root() and have lookup_root_device() call it when
root= is absent. early_lookup_bdev() is kept unchanged so other callers
cannot trigger root discovery inadvertently. Return -EINVAL if the EFI
variable cannot be read or does not contain a valid UUID, so
lookup_root_device() disables rootwait. Return -EAGAIN if the EFI
partition is not available yet so rootwait can retry. Return -ENODEV if
its disk has no matching root partition. In that case, have
lookup_root_device() disable rootwait, clear the device number and
return zero to stop retries. This is safe because partition registration
failures do not schedule a rescan, nor does rootwait.

[1] The Discoverable Partitions Specification (DPS)
Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
 block/early-lookup.c   | 117 +++++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/blkdev.h |  10 +++++
 init/do_mounts.c       |  25 +++++++++--
 3 files changed, 145 insertions(+), 7 deletions(-)

diff --git a/block/early-lookup.c b/block/early-lookup.c
index 3fb57f7d2b12..e3da4bfb41e7 100644
--- a/block/early-lookup.c
+++ b/block/early-lookup.c
@@ -5,10 +5,14 @@
  */
 #include <linux/blkdev.h>
 #include <linux/ctype.h>
+#include <linux/efi.h>
+#include <linux/ucs2_string.h>
+#include <linux/uuid.h>
 
 struct uuidcmp {
 	const char *uuid;
 	int len;
+	struct gendisk *disk;
 };
 
 /**
@@ -45,13 +49,11 @@ static int __init match_dev_by_uuid(struct device *dev, const void *data)
  */
 static int __init devt_from_partuuid(const char *uuid_str, dev_t *devt)
 {
-	struct uuidcmp cmp;
+	struct uuidcmp cmp = { .uuid = uuid_str };
 	struct device *dev = NULL;
 	int offset = 0;
 	char *slash;
 
-	cmp.uuid = uuid_str;
-
 	slash = strchr(uuid_str, '/');
 	/* Check for optional partition number offset attributes. */
 	if (slash) {
@@ -252,6 +254,115 @@ int __init early_lookup_bdev(const char *name, dev_t *devt)
 	return devt_from_devnum(name, devt);
 }
 
+#ifdef CONFIG_DPS_ROOT_AUTO_DISCOVERY
+static int __init match_dev_by_type_uuid(struct device *dev, const void *data)
+{
+	struct block_device *bdev = dev_to_bdev(dev);
+	const struct uuidcmp *cmp = data;
+
+	return bdev->bd_disk == cmp->disk && bdev->bd_meta_info &&
+		!strcasecmp(cmp->uuid, bdev->bd_meta_info->type_uuid);
+}
+
+/*
+ * Search the ESP's disk for an eligible partition of the requested type.
+ * Return -EAGAIN until the ESP is available, or -ENODEV if no match exists.
+ */
+static int __init early_lookup_bdev_by_type_uuid(const char *type_uuid,
+						 const char *esp_partuuid,
+						 dev_t *devt)
+{
+	struct uuidcmp esp_cmp = {
+		.uuid = esp_partuuid,
+		.len = UUID_STRING_LEN,
+	};
+	struct uuidcmp type_cmp = {
+		.uuid = type_uuid,
+	};
+	struct device *esp_dev;
+	struct device *type_dev;
+
+	esp_dev = class_find_device(&block_class, NULL, &esp_cmp,
+				    &match_dev_by_uuid);
+	if (!esp_dev)
+		return -EAGAIN;
+
+	type_cmp.disk = dev_to_disk(esp_dev);
+	scoped_guard(mutex, &type_cmp.disk->open_mutex)
+		type_dev = class_find_device(&block_class, NULL, &type_cmp,
+					     &match_dev_by_type_uuid);
+	put_device(esp_dev);
+	if (!type_dev)
+		return -ENODEV;
+
+	*devt = type_dev->devt;
+	pr_info("VFS: Discovered root partition /dev/%pg with GPT type UUID %s\n",
+		dev_to_bdev(type_dev), type_uuid);
+	put_device(type_dev);
+	return 0;
+}
+
+static int __init efi_get_esp_partuuid(char *partuuid, size_t size)
+{
+	static efi_guid_t loader_guid __initdata = LINUX_EFI_LOADER_ENTRY_GUID;
+	efi_char16_t partuuid_ucs2[UUID_STRING_LEN + 1] = {};
+	unsigned long partuuid_ucs2_size = sizeof(partuuid_ucs2);
+	efi_status_t status;
+
+	if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+		return -EOPNOTSUPP;
+
+	status = efi.get_variable(L"LoaderDevicePartUUID", &loader_guid, NULL,
+				  &partuuid_ucs2_size, partuuid_ucs2);
+	if (status != EFI_SUCCESS)
+		return efi_status_to_err(status);
+
+	if (partuuid_ucs2_size != sizeof(partuuid_ucs2) ||
+	    partuuid_ucs2[UUID_STRING_LEN] ||
+	    ucs2_as_utf8((u8 *)partuuid, partuuid_ucs2, size) != UUID_STRING_LEN ||
+	    !uuid_is_valid(partuuid))
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * early_lookup_dps_root - discover the root device by DPS partition type UUID
+ * @dev: receives the discovered device number
+ *
+ * Return: 0 on success, -EINVAL if the ESP partition UUID cannot be read or
+ * is invalid, -EAGAIN if the EFI partition is not yet available, or -ENODEV
+ * if no matching root exists.
+ * With DPS disabled, return 0 and set @dev to zero.
+ */
+int __init early_lookup_dps_root(dev_t *dev)
+{
+	static const char root_type_uuids[][UUID_STRING_LEN + 1] __initconst = {
+		CONFIG_DPS_ROOT_PARTITION_TYPE_UUID,
+	};
+	static char esp_partuuid[UUID_STRING_LEN + 1] __initdata;
+	int err;
+
+	if (!esp_partuuid[0]) {
+		err = efi_get_esp_partuuid(esp_partuuid, sizeof(esp_partuuid));
+		if (err) {
+			pr_err("VFS: Unable to get EFI partition UUID: %pe, skipping root partition discovery\n",
+				ERR_PTR(err));
+			return -EINVAL;
+		}
+	}
+
+	for (int i = 0; i < ARRAY_SIZE(root_type_uuids); i++) {
+		err = early_lookup_bdev_by_type_uuid(root_type_uuids[i],
+						     esp_partuuid, dev);
+		if (err != -ENODEV)
+			return err;
+	}
+
+	return -ENODEV;
+}
+#endif /* CONFIG_DPS_ROOT_AUTO_DISCOVERY */
+
 static char __init *bdevt_str(dev_t devt, char *buf)
 {
 	if (MAJOR(devt) <= 0xff && MINOR(devt) <= 0xff) {
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 0e0f5d68425d..5cfef05b552e 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1748,6 +1748,16 @@ static inline int early_lookup_bdev(const char *pathname, dev_t *dev)
 }
 #endif /* CONFIG_BLOCK */
 
+#ifdef CONFIG_DPS_ROOT_AUTO_DISCOVERY
+int __init early_lookup_dps_root(dev_t *dev);
+#else
+static inline int early_lookup_dps_root(dev_t *dev)
+{
+	*dev = 0;
+	return 0;
+}
+#endif /* CONFIG_DPS_ROOT_AUTO_DISCOVERY */
+
 int bdev_freeze(struct block_device *bdev);
 int bdev_thaw(struct block_device *bdev);
 int bdev_deny_freeze(struct block_device *bdev);
diff --git a/init/do_mounts.c b/init/do_mounts.c
index b0dccad20971..c1106e3cab3d 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -406,10 +406,24 @@ static int __init lookup_root_device(const char *root_device_name, dev_t *dev)
 {
 	int err;
 
-	err = early_lookup_bdev(root_device_name, dev);
+	if (root_device_name[0]) {
+		err = early_lookup_bdev(root_device_name, dev);
+		if (err == -EINVAL && root_wait) {
+			pr_err("VFS: root= is invalid; disabling rootwait.\n");
+			root_wait = 0;
+		}
+		return err;
+	}
+
+	err = early_lookup_dps_root(dev);
 	if (err == -EINVAL && root_wait) {
-		pr_err("VFS: root= is invalid; disabling rootwait.\n");
+		pr_err("VFS: Root discovery is unavailable; disabling rootwait.\n");
 		root_wait = 0;
+	} else if (err == -ENODEV) {
+		pr_err("VFS: No discoverable root partition found; aborting.\n");
+		root_wait = 0;
+		*dev = 0;
+		return 0;
 	}
 	return err;
 }
@@ -422,7 +436,10 @@ static void __init wait_for_root(char *root_device_name)
 	if (ROOT_DEV != 0)
 		return;
 
-	pr_info("Waiting for root device %s...\n", root_device_name);
+	if (root_device_name[0])
+		pr_info("Waiting for root device %s...\n", root_device_name);
+	else if (IS_ENABLED(CONFIG_DPS_ROOT_AUTO_DISCOVERY))
+		pr_info("Waiting for discoverable root partition...\n");
 
 	end = ktime_add_ms(ktime_get_raw(), root_wait);
 
@@ -480,7 +497,7 @@ void __init prepare_namespace(void)
 
 	md_run_setup();
 
-	if (saved_root_name[0])
+	if (saved_root_name[0] || !ROOT_DEV)
 		ROOT_DEV = parse_root_device(saved_root_name);
 
 	initrd_load();

-- 
2.56.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 5/7] block: skip partitions with DPS no-auto GPT attribute
  2026-11-02 21:29 [PATCH v3 0/7] init: discoverable root partitions Vincent Mailhol
                   ` (3 preceding siblings ...)
  2026-11-02 21:29 ` [PATCH v3 4/7] block: discover root by DPS partition type UUID Vincent Mailhol
@ 2026-11-02 21:29 ` Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 6/7] block: add secondary DPS root partition type UUID Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 7/7] docs: document discoverable root partitions Vincent Mailhol
  6 siblings, 0 replies; 8+ messages in thread
From: Vincent Mailhol @ 2026-11-02 21:29 UTC (permalink / raw)
  To: Jens Axboe, Davidlohr Bueso, Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-kernel, linux-block, linux-efi, linux-fsdevel, Dave Hansen,
	James Bottomley, Helge Deller, Matthew Wilcox, Vincent Mailhol

DPS [1] defines GPT attribute bit 63 as no-auto. Partitions with this
bit set must not be used by automatic discovery.

Store the GPT attributes in partition_meta_info and check
GPT_ATTR_NO_AUTO_DISCOVERY when matching a root partition by type UUID.

[1] The Discoverable Partitions Specification (DPS)
Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
 block/early-lookup.c   | 1 +
 block/partitions/efi.c | 1 +
 include/linux/blkdev.h | 4 ++++
 3 files changed, 6 insertions(+)

diff --git a/block/early-lookup.c b/block/early-lookup.c
index e3da4bfb41e7..c59d14889fee 100644
--- a/block/early-lookup.c
+++ b/block/early-lookup.c
@@ -261,6 +261,7 @@ static int __init match_dev_by_type_uuid(struct device *dev, const void *data)
 	const struct uuidcmp *cmp = data;
 
 	return bdev->bd_disk == cmp->disk && bdev->bd_meta_info &&
+		!(bdev->bd_meta_info->gpt_attr & GPT_ATTR_NO_AUTO_DISCOVERY) &&
 		!strcasecmp(cmp->uuid, bdev->bd_meta_info->type_uuid);
 }
 
diff --git a/block/partitions/efi.c b/block/partitions/efi.c
index 4a3835ed9561..ed5e2f21ad85 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -741,6 +741,7 @@ int efi_partition(struct parsed_partitions *state)
 			state->parts[i + 1].flags = ADDPART_FLAG_RAID;
 
 		info = &state->parts[i + 1].info;
+		info->gpt_attr = le64_to_cpu(ptes[i].attributes);
 		efi_guid_to_str(&ptes[i].unique_partition_guid, info->uuid);
 		efi_guid_to_str(&ptes[i].partition_type_guid, info->type_uuid);
 
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 5cfef05b552e..fd6d809189e8 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -5,6 +5,7 @@
 #ifndef _LINUX_BLKDEV_H
 #define _LINUX_BLKDEV_H
 
+#include <linux/bits.h>
 #include <linux/types.h>
 #include <linux/blk_types.h>
 #include <linux/blk_plug.h>
@@ -65,10 +66,13 @@ extern const struct class block_class;
  */
 #define PARTITION_META_INFO_UUIDLTH	(UUID_STRING_LEN + 1)
 
+#define GPT_ATTR_NO_AUTO_DISCOVERY	BIT_U64(63)
+
 struct partition_meta_info {
 	char uuid[PARTITION_META_INFO_UUIDLTH];
 	char type_uuid[PARTITION_META_INFO_UUIDLTH];
 	u8 volname[PARTITION_META_INFO_VOLNAMELTH];
+	u64 gpt_attr;
 };
 
 /**

-- 
2.56.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 6/7] block: add secondary DPS root partition type UUID
  2026-11-02 21:29 [PATCH v3 0/7] init: discoverable root partitions Vincent Mailhol
                   ` (4 preceding siblings ...)
  2026-11-02 21:29 ` [PATCH v3 5/7] block: skip partitions with DPS no-auto GPT attribute Vincent Mailhol
@ 2026-11-02 21:29 ` Vincent Mailhol
  2026-11-02 21:29 ` [PATCH v3 7/7] docs: document discoverable root partitions Vincent Mailhol
  6 siblings, 0 replies; 8+ messages in thread
From: Vincent Mailhol @ 2026-11-02 21:29 UTC (permalink / raw)
  To: Jens Axboe, Davidlohr Bueso, Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-kernel, linux-block, linux-efi, linux-fsdevel, Dave Hansen,
	James Bottomley, Helge Deller, Matthew Wilcox, Vincent Mailhol

Some 64-bit architectures can run 32-bit user space. For those
configurations, also allow DPS root discovery to use the compatible
32-bit root partition type UUID as a fallback.

Add a secondary root partition type UUID Kconfig symbol and include it
in the DPS root lookup when it is defined.

Try the secondary UUID only when the native lookup returns -ENODEV.

The fallback reflects compatibility support built into the kernel. If
32-bit execution is disabled, for example with ia32_emulation=0, the
selected root's 32-bit init will fail to execute. Do not check
ia32_enabled(): rejecting the fallback would instead leave no
discoverable root partition, resulting in a kernel panic either way.

Suggested-by: Dave Hansen <dave.hansen@intel.com>
Link: https://lore.kernel.org/r/03be57ae-0e41-4b8a-adc5-bdd85ccce951@intel.com
Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
 block/Kconfig        | 7 +++++++
 block/early-lookup.c | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/block/Kconfig b/block/Kconfig
index 3b5d3ad42dde..f3a0730ffcde 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -222,6 +222,13 @@ config DPS_ROOT_PARTITION_TYPE_UUID
 	default "4f68bce3-e8cd-4db1-96e7-fbcaf984b709" if X86_64
 	default "44479540-f297-41b2-9af7-d131d5f0458a" if X86
 
+config DPS_ROOT_PARTITION_TYPE_UUID_SECONDARY
+	depends on DPS_ROOT_PARTITION_TYPE_UUID != "" && COMPAT
+	string
+	default "69dad710-2ce4-4e3c-b16c-21a1d49abed3" if ARM64
+	default "60d5a7fe-8e7d-435c-b714-3dd8162144e1" if RISCV
+	default "44479540-f297-41b2-9af7-d131d5f0458a" if X86_64 && IA32_EMULATION
+
 config DPS_ROOT_AUTO_DISCOVERY
 	def_bool DPS_ROOT_PARTITION_TYPE_UUID != ""
 
diff --git a/block/early-lookup.c b/block/early-lookup.c
index c59d14889fee..2e7dace5efa3 100644
--- a/block/early-lookup.c
+++ b/block/early-lookup.c
@@ -340,6 +340,9 @@ int __init early_lookup_dps_root(dev_t *dev)
 {
 	static const char root_type_uuids[][UUID_STRING_LEN + 1] __initconst = {
 		CONFIG_DPS_ROOT_PARTITION_TYPE_UUID,
+#ifdef CONFIG_DPS_ROOT_PARTITION_TYPE_UUID_SECONDARY
+		CONFIG_DPS_ROOT_PARTITION_TYPE_UUID_SECONDARY,
+#endif
 	};
 	static char esp_partuuid[UUID_STRING_LEN + 1] __initdata;
 	int err;

-- 
2.56.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 7/7] docs: document discoverable root partitions
  2026-11-02 21:29 [PATCH v3 0/7] init: discoverable root partitions Vincent Mailhol
                   ` (5 preceding siblings ...)
  2026-11-02 21:29 ` [PATCH v3 6/7] block: add secondary DPS root partition type UUID Vincent Mailhol
@ 2026-11-02 21:29 ` Vincent Mailhol
  6 siblings, 0 replies; 8+ messages in thread
From: Vincent Mailhol @ 2026-11-02 21:29 UTC (permalink / raw)
  To: Jens Axboe, Davidlohr Bueso, Alexander Viro, Christian Brauner, Jan Kara
  Cc: linux-kernel, linux-block, linux-efi, linux-fsdevel, Dave Hansen,
	James Bottomley, Helge Deller, Matthew Wilcox, Vincent Mailhol,
	Jonathan Corbet, Shuah Khan, Randy Dunlap, linux-doc

Document the automatic root block device discovery feature.

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: linux-doc@vger.kernel.org
---
 Documentation/admin-guide/discoverable-root.rst | 46 +++++++++++++++++++++++++
 Documentation/admin-guide/index.rst             |  1 +
 Documentation/admin-guide/kernel-parameters.txt |  5 +++
 3 files changed, 52 insertions(+)

diff --git a/Documentation/admin-guide/discoverable-root.rst b/Documentation/admin-guide/discoverable-root.rst
new file mode 100644
index 000000000000..29c93b3526a6
--- /dev/null
+++ b/Documentation/admin-guide/discoverable-root.rst
@@ -0,0 +1,46 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _discoverable_root:
+
+Discoverable root partitions
+============================
+
+On EFI systems, the kernel can discover the root block device from GPT partition
+type UUID metadata on the disk containing the active EFI System Partition.
+
+This follows the `Discoverable Partitions Specification`_ which defines a list
+of architecture-specific root partition type UUIDs.
+
+An initramfs providing an early userspace ``init``, a ``root=`` kernel
+command-line option, or a root device supplied through the boot protocol takes
+precedence over this automatic root partition discovery.
+
+Automatic discovery uses the Boot Loader Interface ``LoaderDevicePartUUID`` EFI
+variable to identify the partition whose disk is searched. This variable is
+provided by the boot loader or, when the kernel is booted directly by EFI
+firmware, by the Linux EFI stub.
+
+The kernel first searches for the native root partition type UUID. On
+architectures that can run compatible 32-bit user space, the matching 32-bit
+root partition type UUID may be used as a fallback if no partition with the
+native type UUID is found. If multiple partitions on that disk match the
+selected type UUID, the kernel selects the first match in block device
+enumeration order, but this may change. Systems should not expose multiple
+eligible root partitions.
+
+Partitions marked with the DPS ``no-auto`` GPT attribute are skipped. This
+allows a partition with an otherwise discoverable type UUID to opt out from
+automatic discovery.
+
+With ``rootwait`` or ``rootwait=<seconds>``, discovery retries while the EFI
+System Partition is unavailable, subject to any specified timeout. Once its disk
+has been scanned, discovery either selects an eligible root partition or stops
+if none was found. Waiting is also disabled if ``LoaderDevicePartUUID`` is not
+available or is malformed.
+
+The DPS read-only attribute is not enforced by kernel root discovery. The
+root filesystem is mounted read-only by default unless ``rw`` is specified,
+and user space remains responsible for later remount policy.
+
+.. _Discoverable Partitions Specification:
+   https://uapi-group.org/specifications/specs/discoverable_partitions_specification/
diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst
index cd28dfe91b06..0d9c2796ae09 100644
--- a/Documentation/admin-guide/index.rst
+++ b/Documentation/admin-guide/index.rst
@@ -50,6 +50,7 @@ Booting the kernel
 
    bootconfig
    kernel-parameters
+   discoverable-root
    efi-stub
    initrd
 
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 0b3c140babd9..2e7b89a05944 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6746,6 +6746,11 @@ Kernel parameters
 			ramdisk, "nfs" and "cifs" for root on a network file
 			system, or "mtd" and "ubi" for mounting from raw flash.
 
+			If this option is omitted, the kernel may try to
+			discover the root block device from the GPT partition
+			type UUID metadata when additional requirements are met.
+			See Documentation/admin-guide/discoverable-root.rst.
+
 	rootdelay=	[KNL] Delay (in seconds) to pause before attempting to
 			mount the root filesystem
 

-- 
2.56.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-11-02 21:29 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-02 21:29 [PATCH v3 0/7] init: discoverable root partitions Vincent Mailhol
2026-11-02 21:29 ` [PATCH v3 1/7] block: store GPT partition type UUID Vincent Mailhol
2026-11-02 21:29 ` [PATCH v3 2/7] block: add DPS root partition type UUID definitions Vincent Mailhol
2026-11-02 21:29 ` [PATCH v3 3/7] init: factor out root device lookup into lookup_root_device() Vincent Mailhol
2026-11-02 21:29 ` [PATCH v3 4/7] block: discover root by DPS partition type UUID Vincent Mailhol
2026-11-02 21:29 ` [PATCH v3 5/7] block: skip partitions with DPS no-auto GPT attribute Vincent Mailhol
2026-11-02 21:29 ` [PATCH v3 6/7] block: add secondary DPS root partition type UUID Vincent Mailhol
2026-11-02 21:29 ` [PATCH v3 7/7] docs: document discoverable root partitions Vincent Mailhol

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®