summaryrefslogtreecommitdiff
path: root/common/bloblist.c
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2021-07-05 16:32:53 -0600
committerSimon Glass <sjg@chromium.org>2021-07-21 10:27:34 -0600
commit1fe59375498fb84cd9ab72cf1f7f89437cd24cf4 (patch)
tree89be56988d867198dec854907c36e764010ce6be /common/bloblist.c
parent56dae9ef3c56a7de6ed4af5efb82e661329d4738 (diff)
bloblist: Support resizing a blob
Sometimes a blob needs to expand, e.g. because it needs to hold more log data. Add support for this. Note that the bloblist must have sufficient spare space for this to work. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'common/bloblist.c')
-rw-r--r--common/bloblist.c71
1 files changed, 69 insertions, 2 deletions
diff --git a/common/bloblist.c b/common/bloblist.c
index eab63e9ca5..bb49ecab92 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -57,13 +57,22 @@ static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
}
-static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
- struct bloblist_rec *rec)
+static ulong bloblist_blob_end_ofs(struct bloblist_hdr *hdr,
+ struct bloblist_rec *rec)
{
ulong offset;
offset = (void *)rec - (void *)hdr;
offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN);
+
+ return offset;
+}
+
+static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
+ struct bloblist_rec *rec)
+{
+ ulong offset = bloblist_blob_end_ofs(hdr, rec);
+
if (offset >= hdr->alloced)
return NULL;
return (struct bloblist_rec *)((void *)hdr + offset);
@@ -215,6 +224,64 @@ int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp)
return 0;
}
+static int bloblist_resize_rec(struct bloblist_hdr *hdr,
+ struct bloblist_rec *rec,
+ int new_size)
+{
+ int expand_by; /* Number of bytes to expand by (-ve to contract) */
+ int new_alloced; /* New value for @hdr->alloced */
+ ulong next_ofs; /* Offset of the record after @rec */
+
+ expand_by = ALIGN(new_size - rec->size, BLOBLIST_ALIGN);
+ new_alloced = ALIGN(hdr->alloced + expand_by, BLOBLIST_ALIGN);
+ if (new_size < 0) {
+ log(LOGC_BLOBLIST, LOGL_DEBUG,
+ "Attempt to shrink blob size below 0 (%x)\n", new_size);
+ return log_msg_ret("size", -EINVAL);
+ }
+ if (new_alloced > hdr->size) {
+ log(LOGC_BLOBLIST, LOGL_ERR,
+ "Failed to allocate %x bytes size=%x, need size=%x\n",
+ new_size, hdr->size, new_alloced);
+ return log_msg_ret("alloc", -ENOSPC);
+ }
+
+ /* Move the following blobs up or down, if this is not the last */
+ next_ofs = bloblist_blob_end_ofs(hdr, rec);
+ if (next_ofs != hdr->alloced) {
+ memmove((void *)hdr + next_ofs + expand_by,
+ (void *)hdr + next_ofs, new_alloced - next_ofs);
+ }
+ hdr->alloced = new_alloced;
+
+ /* Zero the new part of the blob */
+ if (expand_by > 0) {
+ memset((void *)rec + rec->hdr_size + rec->size, '\0',
+ new_size - rec->size);
+ }
+
+ /* Update the size of this blob */
+ rec->size = new_size;
+
+ return 0;
+}
+
+int bloblist_resize(uint tag, int new_size)
+{
+ struct bloblist_hdr *hdr = gd->bloblist;
+ struct bloblist_rec *rec;
+ int ret;
+
+ rec = bloblist_findrec(tag);
+ if (!rec)
+ return log_msg_ret("find", -ENOENT);
+ ret = bloblist_resize_rec(hdr, rec, new_size);
+ if (ret)
+ return log_msg_ret("resize", ret);
+
+ return 0;
+}
+
static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr)
{
struct bloblist_rec *rec;