[RFC PATCH v2] cmd: part: add dupcheck command to detect duplicate PARTUUIDs
Padmarao Begari
padmarao.begari at amd.com
Sun Feb 22 08:07:39 CET 2026
Add a 'part dupcheck' subcommand that scans all block devices for
duplicate partition UUIDs. This helps detect situations where the
same disk image has been flashed to multiple boot devices (e.g.,
USB stick and UFS), which can lead to unpredictable boot behavior
when using PARTUUID-based root filesystem specifications. It
iterates all block devices using blk_foreach_probe() and checks
partition UUIDs via part_get_info().
When duplicates are found, a warning is printed for each occurrence:
Warning: duplicate PARTUUID 20c5fba5-0171-457f-b9cd-f5129cd07228
first seen on usb_mass_storage.lun0:3
also on ufs_scsi.id0lun0:3
Add Kconfig option `CMD_PART_DUPCHECK` and update the `part` help
text accordingly.
Signed-off-by: John Toomey <john.toomey at amd.com>
Signed-off-by: Padmarao Begari <padmarao.begari at amd.com>
---
Changes in v2:
-Add own kconfig symbol for dupcheck subcommand and guard it.
---
cmd/Kconfig | 7 ++++
cmd/part.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 110 insertions(+), 1 deletion(-)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 322ebe600c5..73d27fe2e28 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1663,6 +1663,13 @@ config CMD_PART
Read and display information about the partition table on
various media.
+config CMD_PART_DUPCHECK
+ bool "part dupcheck"
+ depends on CMD_PART
+ help
+ Enable the 'part dupcheck' sub-command under 'part' to scan the
+ current partition table and report any duplicate partition UUIDs.
+
config CMD_PCI
bool "pci - Access PCI devices"
help
diff --git a/cmd/part.c b/cmd/part.c
index 975a0a08a99..c4df5053936 100644
--- a/cmd/part.c
+++ b/cmd/part.c
@@ -15,9 +15,12 @@
* Pavel Bartusek <pba at sysgo.com>
*/
+#include <blk.h>
#include <config.h>
#include <command.h>
+#include <dm.h>
#include <env.h>
+#include <malloc.h>
#include <part.h>
#include <stdio.h>
#include <vsprintf.h>
@@ -246,6 +249,97 @@ static int do_part_type(int argc, char *const argv[])
}
#endif
+#if CONFIG_IS_ENABLED(CMD_PART_DUPCHECK)
+struct part_seen {
+ char uuid[UUID_STR_LEN + 1];
+ struct udevice *dev;
+ int part;
+};
+
+static int do_part_dupcheck(int argc, char *const argv[])
+{
+ struct part_seen *seen;
+ int count = 0;
+ int duplicates = 0;
+ int max_entries;
+ int dev_count;
+ struct udevice *dev;
+
+ if (argc)
+ return CMD_RET_USAGE;
+
+ dev_count = blk_count_devices(BLKF_BOTH);
+ if (!dev_count) {
+ printf("No block devices found\n");
+ return CMD_RET_SUCCESS;
+ }
+
+ max_entries = dev_count * MAX_SEARCH_PARTITIONS;
+ seen = calloc(max_entries, sizeof(*seen));
+ if (!seen) {
+ printf("Unable to allocate dupcheck table (%d entries)\n",
+ max_entries);
+ return CMD_RET_FAILURE;
+ }
+
+ blk_foreach_probe(BLKF_BOTH, dev) {
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
+
+ for (int part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
+ struct disk_partition info;
+ int first_match = -1;
+
+ if (part_get_info(desc, part, &info))
+ continue;
+ if (!info.uuid[0])
+ continue;
+
+ for (int i = 0; i < count; i++) {
+ if (strcmp(seen[i].uuid, info.uuid))
+ continue;
+ if (first_match == -1) {
+ printf("Warning: duplicate PARTUUID %s\n",
+ info.uuid);
+ printf(" first seen on %s:%d\n",
+ seen[i].dev->name,
+ seen[i].part);
+ printf(" also on %s:%d\n",
+ dev->name, part);
+ duplicates++;
+ first_match = i;
+ } else {
+ printf(" also on %s:%d\n",
+ seen[i].dev->name,
+ seen[i].part);
+ }
+ }
+
+ if (count >= max_entries) {
+ printf("Error: dupcheck capacity %d entries\n",
+ max_entries);
+ printf(" exceeded\n");
+ free(seen);
+ return CMD_RET_FAILURE;
+ }
+
+ strlcpy(seen[count].uuid, info.uuid,
+ sizeof(seen[0].uuid));
+ seen[count].dev = dev;
+ seen[count].part = part;
+ count++;
+ }
+ }
+
+ if (duplicates)
+ printf("Found %d duplicate(s) among %d partitions checked\n",
+ duplicates, count);
+
+ free(seen);
+
+ return duplicates ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+#endif
+
static int do_part_types(int argc, char * const argv[])
{
struct part_driver *drv = ll_entry_start(struct part_driver,
@@ -291,6 +385,10 @@ static int do_part(struct cmd_tbl *cmdtp, int flag, int argc,
#ifdef CONFIG_PARTITION_TYPE_GUID
else if (!strcmp(argv[1], "type"))
return do_part_type(argc - 2, argv + 2);
+#endif
+#if CONFIG_IS_ENABLED(CMD_PART_DUPCHECK)
+ else if (!strcmp(argv[1], "dupcheck"))
+ return do_part_dupcheck(argc - 2, argv + 2);
#endif
return CMD_RET_USAGE;
}
@@ -328,5 +426,9 @@ U_BOOT_CMD(
"part set <interface> <dev> type\n"
" - set partition type for a device\n"
"part types\n"
- " - list supported partition table types"
+ " - list supported partition table types\n"
+#if CONFIG_IS_ENABLED(CMD_PART_DUPCHECK)
+ "part dupcheck\n"
+ " - scan all block devices for duplicate partition UUIDs"
+#endif
);
--
2.34.1
More information about the U-Boot
mailing list