Am 27. März 2025 11:02:55 MEZ schrieb Neil Armstrong 
<neil.armstr...@linaro.org>:
>The actual architecture of the EFI part parser means the
>entire GPT partition table needs to be parsed for each
>part_info() callback.
>
>Since the default part scan code will always scan up to
>128 partitions for a block, and devices with an UFS chip
>with up to 8 LUNs are very common in the field, this means
>a complete GPT parsing and validation will be done
>up to 1024 times instead of 8 on such devices.
>
>The GPT parsing can be cached between each part_info()
>call speed up to 3x on the worse condition when the CPU
>i-cache and d-cache are disabled, like in the SPL.
>
>The implementation does caching each time a correct GPT
>has been parsed and verified and will match the blk_desc
>and LBA to serve the cached data or force a re-parsing.
>
>In order to allow GPT manipulation, some of the calls
>ignores the cache and some will discard the cached data.
>
>On the SM8650 QRD platform with a KIOXIA THGJFJT1E45BATPC
>configured with 8 LUNs, the scsi scan takes 0.2s with both
>CPU caches enabled, but when disabling both CPU caches it
>goes up to 4s to do the full scan of all 8 LUN partitions.
>
>With this change the scan takes only 0.18s with both CPU
>caches enabled running 1.1x times faster, and with both CPU
>caches disabled the full scan takes only 1.27s running
>3x faster.
>
>While 20ms could look negligeable, it's still a 20ms gain
>in the boot flow and a non negligeable reduction in
>calculation and memory allocation since for each scan
>it would allocate and free the gpt_pte table up to
>1024 times, now it would only do 8 allocations, reducing
>memory fragmentation.

Could you, please, describe when you clear the cache. I would think of:

* Media change
* Updating partition table (mbr and gpt commands)
* Any raw write to sector < 35

I cannot see any of this implemented.

>
>Signed-off-by: Neil Armstrong <neil.armstr...@linaro.org>
>---
> disk/part_efi.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++----------
> 1 file changed, 77 insertions(+), 16 deletions(-)
>
>diff --git a/disk/part_efi.c b/disk/part_efi.c
>index 
>932d058c184ce6946b7142e7c2d9637b28e4661e..4f02fabe265ce5ca4c8f55e41768a95582022e21
> 100644
>--- a/disk/part_efi.c
>+++ b/disk/part_efi.c
>@@ -55,13 +55,59 @@ static inline u32 efi_crc32(const void *buf, u32 len)
> static int pmbr_part_valid(struct partition *part);
> static int is_pmbr_valid(legacy_mbr * mbr);
> static int is_gpt_valid(struct blk_desc *desc, u64 lba, gpt_header *pgpt_head,
>-                      gpt_entry **pgpt_pte);
>+                      gpt_entry **pgpt_pte, bool cache);

Please, provide Sphinx style function documentation describing all parameters.

> static gpt_entry *alloc_read_gpt_entries(struct blk_desc *desc,
>                                        gpt_header *pgpt_head);
> static int is_pte_valid(gpt_entry * pte);
> static int find_valid_gpt(struct blk_desc *desc, gpt_header *gpt_head,
>                         gpt_entry **pgpt_pte);
> 
>+static struct gpt_pte_cache_data {

Please, provide Sphinx style documentation for the structure and its elements. 


>+      struct blk_desc *desc;
>+      u64 lba;
>+      gpt_entry *gpt_pte;
>+      gpt_header gpt_head;
>+} gpt_pte_cache;
>+
>+static void clear_gpt_pte_cache(void)
>+{

Add function documentation for all changed function interfaces.

Besr regards

Heinrich 

>+      if (gpt_pte_cache.desc) {
>+              if (gpt_pte_cache.gpt_pte)
>+                      free(gpt_pte_cache.gpt_pte);
>+
>+              memset(&gpt_pte_cache, 0, sizeof(gpt_pte_cache));
>+      }
>+}
>+
>+static void cache_gpt_pte(struct blk_desc *desc, u64 lba,
>+                        gpt_entry *gpt_pte, gpt_header *pgpt_head)
>+{
>+      if (gpt_pte_cache.gpt_pte)
>+              free(gpt_pte_cache.gpt_pte);
>+
>+      gpt_pte_cache.desc = desc;
>+      gpt_pte_cache.lba = lba;
>+      gpt_pte_cache.gpt_pte = gpt_pte;
>+      if (pgpt_head)
>+              memcpy(&gpt_pte_cache.gpt_head, pgpt_head, sizeof(gpt_header));
>+}
>+
>+static gpt_entry *get_cached_gpt_pte(struct blk_desc *desc, u64 lba,
>+                                   gpt_header *pgpt_head)
>+{
>+      if (gpt_pte_cache.desc && gpt_pte_cache.gpt_pte) {
>+              if (gpt_pte_cache.desc == desc &&
>+                  gpt_pte_cache.lba == lba) {
>+                      memcpy(pgpt_head, &gpt_pte_cache.gpt_head, 
>sizeof(gpt_header));
>+                      return gpt_pte_cache.gpt_pte;
>+              }
>+
>+              clear_gpt_pte_cache();
>+      }
>+
>+      return NULL;
>+}
>+
> static char *print_efiname(gpt_entry *pte)
> {
>       static char name[PARTNAME_SZ + 1];
>@@ -211,8 +257,6 @@ int get_disk_guid(struct blk_desc *desc, char *guid)
>       guid_bin = gpt_head->disk_guid.b;
>       uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
> 
>-      /* Remember to free pte */
>-      free(gpt_pte);
>       return 0;
> }
> 
>@@ -252,9 +296,6 @@ static void __maybe_unused part_print_efi(struct blk_desc 
>*desc)
>               uuid = (unsigned char *)gpt_pte[i].unique_partition_guid.b;
>               printf("\tguid:\t%pUl\n", uuid);
>       }
>-
>-      /* Remember to free pte */
>-      free(gpt_pte);
>       return;
> }
> 
>@@ -277,7 +318,6 @@ static int __maybe_unused part_get_info_efi(struct 
>blk_desc *desc, int part,
>       if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
>           !is_pte_valid(&gpt_pte[part - 1])) {
>               log_debug("Invalid partition number %d\n", part);
>-              free(gpt_pte);
>               return -EPERM;
>       }
> 
>@@ -307,8 +347,6 @@ static int __maybe_unused part_get_info_efi(struct 
>blk_desc *desc, int part,
>       log_debug("start 0x" LBAF ", size 0x" LBAF ", name %s\n", info->start,
>                 info->size, info->name);
> 
>-      /* Remember to free pte */
>-      free(gpt_pte);
>       return 0;
> }
> 
>@@ -382,6 +420,9 @@ int write_gpt_table(struct blk_desc *desc, gpt_header 
>*gpt_h, gpt_entry *gpt_e)
>                                          * sizeof(gpt_entry)), desc);
>       u32 calc_crc32;
> 
>+      /* Clean cache */
>+      clear_gpt_pte_cache();
>+
>       debug("max lba: %x\n", (u32)desc->lba);
>       /* Setup the Protective MBR */
>       if (set_protective_mbr(desc) < 0)
>@@ -620,6 +661,9 @@ int gpt_restore(struct blk_desc *desc, char *str_disk_guid,
>       gpt_entry *gpt_e;
>       int ret, size;
> 
>+      /* Clean cache */
>+      clear_gpt_pte_cache();
>+
>       size = PAD_TO_BLOCKSIZE(sizeof(gpt_header), desc);
>       gpt_h = malloc_cache_aligned(size);
>       if (gpt_h == NULL) {
>@@ -689,7 +733,7 @@ int gpt_verify_headers(struct blk_desc *desc, gpt_header 
>*gpt_head,
>        */
>       if (is_gpt_valid(desc,
>                        GPT_PRIMARY_PARTITION_TABLE_LBA,
>-                       gpt_head, gpt_pte) != 1) {
>+                       gpt_head, gpt_pte, false) != 1) {
>               log_debug("Invalid GPT\n");
>               return -1;
>       }
>@@ -706,7 +750,7 @@ int gpt_verify_headers(struct blk_desc *desc, gpt_header 
>*gpt_head,
>       }
> 
>       if (is_gpt_valid(desc, (desc->lba - 1),
>-                       gpt_head, gpt_pte) != 1) {
>+                       gpt_head, gpt_pte, false) != 1) {
>               log_debug("Invalid Backup GPT\n");
>               return -1;
>       }
>@@ -764,10 +808,13 @@ int gpt_repair_headers(struct blk_desc *desc)
>       int is_gpt1_valid, is_gpt2_valid;
>       int ret = -1;
> 
>+      /* Clean cache */
>+      clear_gpt_pte_cache();
>+
>       is_gpt1_valid = is_gpt_valid(desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
>-                                   gpt_h1, &gpt_e1);
>+                                   gpt_h1, &gpt_e1, false);
>       is_gpt2_valid = is_gpt_valid(desc, desc->lba - 1,
>-                                   gpt_h2, &gpt_e2);
>+                                   gpt_h2, &gpt_e2, false);
> 
>       if (is_gpt1_valid && is_gpt2_valid) {
>               ret = 0;
>@@ -906,6 +953,9 @@ int write_mbr_and_gpt_partitions(struct blk_desc *desc, 
>void *buf)
>       lbaint_t lba;
>       int cnt;
> 
>+      /* Clean cache */
>+      clear_gpt_pte_cache();
>+
>       if (is_valid_gpt_buf(desc, buf))
>               return -1;
> 
>@@ -1023,12 +1073,13 @@ static int is_pmbr_valid(legacy_mbr *mbr)
>  * lba is the logical block address of the GPT header to test
>  * gpt is a GPT header ptr, filled on return.
>  * ptes is a PTEs ptr, filled on return.
>+ * cache is a bool, true to use the cached gpt_pte from previous call
>  *
>  * Description: returns 1 if valid,  0 on error, 2 if ignored header
>  * If valid, returns pointers to PTEs.
>  */
> static int is_gpt_valid(struct blk_desc *desc, u64 lba, gpt_header *pgpt_head,
>-                      gpt_entry **pgpt_pte)
>+                      gpt_entry **pgpt_pte, bool cache)
> {
>       /* Confirm valid arguments prior to allocation. */
>       if (!desc || !pgpt_head) {
>@@ -1036,6 +1087,12 @@ static int is_gpt_valid(struct blk_desc *desc, u64 lba, 
>gpt_header *pgpt_head,
>               return 0;
>       }
> 
>+      if (cache) {
>+              *pgpt_pte = get_cached_gpt_pte(desc, lba, pgpt_head);
>+              if (*pgpt_pte)
>+                      return 1;
>+      }
>+
>       ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, mbr, 1, desc->blksz);
> 
>       /* Read MBR Header from device */
>@@ -1081,6 +1138,9 @@ static int is_gpt_valid(struct blk_desc *desc, u64 lba, 
>gpt_header *pgpt_head,
>               return 0;
>       }
> 
>+      if (cache)
>+              cache_gpt_pte(desc, lba, *pgpt_pte, pgpt_head);
>+
>       /* We're done, all's well */
>       return 1;
> }
>@@ -1100,13 +1160,14 @@ static int find_valid_gpt(struct blk_desc *desc, 
>gpt_header *gpt_head,
>       int r;
> 
>       r = is_gpt_valid(desc, GPT_PRIMARY_PARTITION_TABLE_LBA, gpt_head,
>-                       pgpt_pte);
>+                       pgpt_pte, true);
> 
>       if (r != 1) {
>               if (r != 2)
>                       log_debug("Invalid GPT\n");
> 
>-              if (is_gpt_valid(desc, desc->lba - 1, gpt_head, pgpt_pte)
>+              if (is_gpt_valid(desc, desc->lba - 1, gpt_head, pgpt_pte,
>+                               true)
>                   != 1) {
>                       log_debug("Invalid Backup GPT\n");
>                       return 0;
>
>---
>base-commit: 4adbf64ff8d8c730223fd8ae299d770bebb6fe86
>change-id: 20250327-u-boot-efi-part-cache-ddc1499c3ef6
>
>Best regards,

Reply via email to