From 1fe59375498fb84cd9ab72cf1f7f89437cd24cf4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:53 -0600 Subject: 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 --- common/bloblist.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) (limited to 'common/bloblist.c') diff --git a/common/bloblist.c b/common/bloblist.c index eab63e9ca51..bb49ecab92e 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; -- cgit v1.2.3 From 1f618d528e234d2b7b0047750284dd531f5d718f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:55 -0600 Subject: bloblist: Correct condition in bloblist_addrec() It is possible to add a blob that ends at the end of the bloblist, but at present this is not supported. Fix it and add a regression test for this case. Signed-off-by: Simon Glass --- common/bloblist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common/bloblist.c') diff --git a/common/bloblist.c b/common/bloblist.c index bb49ecab92e..1290fff8504 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -118,7 +118,7 @@ static int bloblist_addrec(uint tag, int size, int align, /* Calculate the new allocated total */ new_alloced = data_start + ALIGN(size, align); - if (new_alloced >= hdr->size) { + if (new_alloced > hdr->size) { log(LOGC_BLOBLIST, LOGL_ERR, "Failed to allocate %x bytes size=%x, need size=%x\n", size, hdr->size, new_alloced); -- cgit v1.2.3