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 <[email protected]>
Signed-off-by: Padmarao Begari <[email protected]>
---
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 <[email protected]>
  */
 
+#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

Reply via email to