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

Quentin Schulz quentin.schulz at cherry.de
Wed Feb 25 17:27:45 CET 2026


Hi Padmarao,

On 2/22/26 8:07 AM, Padmarao Begari 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.
> 
> 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>

Can you check the size impact of adding those three include files if we 
aren't enabling CMD_PART_DUPCHECK? I'm wondering if we shouldn't guard 
those includes with the Kconfig symbol as well?

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

This is 4+KiB (MAX_SEARCH_PARTITIONS is 128 and uuid length is 37 chars 
(1+B each)) **per block device**, can't help wonder if we cannot do 
better than this. It feels wrong but I couldn't come up with something 
much better than this (we could have two blk_foreach_probe loops and 
simply print duplicates when they are encountered instead of storing 
them in an array; you can start the nested blk_foreach_probe starting 
from the current device since we'll have checked any blkdev before the 
blkdev in the main loop). More CPU intensive, less memory usage I guess. 
Possibly easier to read?

We have alist also, maybe that's something that could be useful here.

> +	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"

Avoid using a newline when CMD_PART_DUPCHECK is not enabled by doing 
(not tested):

#if CONFIG_IS_ENABLED(CMD_PART_DUPCHECK)
     "\n"
     "part dupcheck\n"

Otherwise, I agree with Köry about supporting PARTLABEL too, FWIW we use 
PARTLABEL for our rootfs images and we've hit the issue of having the 
"same" rootfs flashed on both eMMC and SD card and not reliably booting 
the same image every time.

This is also definitely missing appropriate documentation in 
doc/usage/cmd/part.rst.

Cheers,
Quentin


More information about the U-Boot mailing list