From: Simon Glass <sjg@chromium.org> Add a function to remove a blob of a particular type. Signed-off-by: Simon Glass <sjg@chromium.org> Co-developed-by: Claude <noreply@anthropic.com> --- common/bloblist.c | 32 +++++++++++++++++++++ include/bloblist.h | 12 ++++++++ test/common/bloblist.c | 64 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/common/bloblist.c b/common/bloblist.c index d1d7ddb956a..e5fa67b0f71 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -356,6 +356,38 @@ int bloblist_resize(uint tag, int new_size) return 0; } +int bloblist_remove(uint tag) +{ + struct bloblist_hdr *hdr = gd->bloblist; + struct bloblist_rec *rec; + ulong rec_start; /* offset where record starts */ + ulong next_ofs; /* offset of the record after @rec */ + ulong removed_size; /* total size to remove, including alignment */ + + rec = bloblist_findrec(tag); + if (!rec) + return log_msg_ret("find", -ENOENT); + + /* Calculate where this record starts and where the next one begins */ + rec_start = (void *)rec - (void *)hdr; + next_ofs = bloblist_blob_end_ofs(hdr, rec); + + /* Calculate total size to remove (record + alignment) */ + removed_size = next_ofs - rec_start; + + /* Move all following blobs backward to fill the gap */ + if (next_ofs < hdr->used_size) { + memmove((void *)hdr + rec_start, + (void *)hdr + next_ofs, + hdr->used_size - next_ofs); + } + + /* Update the used size */ + hdr->used_size -= removed_size; + + return 0; +} + static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr) { u8 chksum; diff --git a/include/bloblist.h b/include/bloblist.h index e55d71110c3..ff88f4c8d5e 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -350,6 +350,18 @@ int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp); */ int bloblist_resize(uint tag, int new_size); +/** + * bloblist_remove() - remove a blob from the bloblist + * + * This removes the blob with the given tag from the bloblist. Any blobs after + * this one are relocated backward to fill the gap. The space is reclaimed and + * used_size is reduced accordingly. + * + * @tag: Tag to remove (enum bloblist_tag_t) + * Return: 0 if OK, -ENOENT if the tag is not found + */ +int bloblist_remove(uint tag); + /** * bloblist_new() - Create a new, empty bloblist of a given size * diff --git a/test/common/bloblist.c b/test/common/bloblist.c index 797bde27025..ad87b104d9c 100644 --- a/test/common/bloblist.c +++ b/test/common/bloblist.c @@ -605,3 +605,67 @@ static int bloblist_test_blob_maxsize(struct unit_test_state *uts) return 0; } BLOBLIST_TEST(bloblist_test_blob_maxsize, UFT_BLOBLIST); + +/* Test removing a blob */ +static int bloblist_test_remove(struct unit_test_state *uts) +{ + const uint small_size = 0x20; + struct bloblist_hdr *hdr; + void *blob1, *blob2, *blob3; + ulong used_before, used_after; + + clear_bloblist(); + ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0, 0)); + hdr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE); + + /* Create three blobs */ + blob1 = bloblist_add(TEST_TAG, small_size, 0); + ut_assertnonnull(blob1); + strcpy(blob1, test1_str); + + blob2 = bloblist_add(TEST_TAG2, small_size, 0); + ut_assertnonnull(blob2); + strcpy(blob2, test2_str); + + blob3 = bloblist_add(TEST_TAG_MISSING, small_size, 0); + ut_assertnonnull(blob3); + + used_before = hdr->used_size; + + /* Remove the middle blob */ + ut_assertok(bloblist_remove(TEST_TAG2)); + + /* Check that the blob is gone */ + ut_assertnull(bloblist_find(TEST_TAG2, 0)); + + /* Check that the first blob is still there and intact */ + ut_asserteq_ptr(blob1, bloblist_find(TEST_TAG, small_size)); + ut_asserteq_str(test1_str, blob1); + + /* Check that the third blob is still there */ + ut_assertnonnull(bloblist_find(TEST_TAG_MISSING, small_size)); + + /* Check that used_size was reduced */ + used_after = hdr->used_size; + ut_assert(used_after < used_before); + + /* Try to remove a non-existent blob */ + ut_asserteq(-ENOENT, bloblist_remove(TEST_TAG2)); + + /* Remove the first blob */ + ut_assertok(bloblist_remove(TEST_TAG)); + ut_assertnull(bloblist_find(TEST_TAG, 0)); + + /* The third blob should still be accessible */ + ut_assertnonnull(bloblist_find(TEST_TAG_MISSING, small_size)); + + /* Remove the last blob */ + ut_assertok(bloblist_remove(TEST_TAG_MISSING)); + ut_assertnull(bloblist_find(TEST_TAG_MISSING, 0)); + + /* Check that we're back to just the header */ + ut_asserteq(sizeof(struct bloblist_hdr), hdr->used_size); + + return 0; +} +BLOBLIST_TEST(bloblist_test_remove, UFT_BLOBLIST); -- 2.43.0