[RFC PATCH v2] cmd: part: add dupcheck command to detect duplicate PARTUUIDs

Kory Maincent kory.maincent at bootlin.com
Mon Feb 23 11:34:04 CET 2026


On Sun, 22 Feb 2026 12:37:39 +0530
Padmarao Begari <padmarao.begari at amd.com> wrote:

> 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.

It would be nice to also check the partition label, which is also used sometimes
in the boot process.

> 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 you have 3 partitions (A,B,C) with the same uuid you will report the
information twice:
When processing B: "Warning ... first seen on A:x / also on B:x"
When processing C: "Warning ... first seen on A:x / also on C:x / also on B:x"

Also this means the duplicates variable will be incremented to 2 which is
confusing for the print in my last comment:

> +
> +			if (count >= max_entries) {
> +				printf("Error: dupcheck capacity %d
> entries\n",
> +				       max_entries);
> +				printf("       exceeded\n");

Weird print here:
Maybe something like that: "Error: dupcheck capacity exceeded (%d entries)"

> +				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);

So with 3 partitions using the same uuid, it will report
"Found 2 duplicate(s) ..."

Which can be confusing. We should report either "1 UUID duplication" or "3
copies of the same UUID" 

> +
> +	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
>  );



-- 
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


More information about the U-Boot mailing list