[Skiboot] [PATCH] libflash/blocklevel: Allow double ecc protecting a region
Michael Neuling
mikey at neuling.org
Thu Jul 7 14:58:26 AEST 2016
On Thu, 2016-07-07 at 13:24 +1000, Cyril Bur wrote:
> Currently the policy for calling ECC protecting a range at the
> blocklevel layer is that the requested region be completely
> unprotected otherwise the call will return an error. It turns out that
> duplicate calls to ffs_init() with true as the last parameter (for the
> same blocklevel structure) will cause duplicate attempts to
> ecc_protect() ranges.
>
> Change the policy within blocklevel to allow duplicate protecting.
> In fact the new policy almost guarantees no failure (baring something
> odd like malloc() failing). It will detect that the range is currently
> already fully protected and do nothing, detect that part of the range
> is or is not and extend the existing range or detect that a range fits
> perfectly between two ranges in which case it will merge the ranges.
>
> Signed-off-by: Cyril Bur <cyril.bur at au1.ibm.com>
Stewart,
So this works for me but it depends on Alistairs patch (74ba834) being
reapplied to mainline.
Acked-by: Michael Neuling <mikey at neuling.org>
Mikey
> ---
> Fixes issue exposed by Alistairs patch: 74ba834 ("flash: Use blocklevel to do ECC reads")
>
> libflash/blocklevel.c | 87 ++++++++++++++++++++++++++-------------------------
> libflash/libffs.c | 2 +-
> 2 files changed, 46 insertions(+), 43 deletions(-)
>
> diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
> index 9591194..f39531a 100644
> --- a/libflash/blocklevel.c
> +++ b/libflash/blocklevel.c
> @@ -327,50 +327,57 @@ out_free:
> return rc;
> }
>
> -static int insert_bl_prot_range(struct blocklevel_range *ranges, struct bl_prot_range range)
> +static bool insert_bl_prot_range(struct blocklevel_range *ranges, struct bl_prot_range range)
> {
> - struct bl_prot_range *new_ranges;
> - struct bl_prot_range *old_ranges = ranges->prot;
> - int i, count = ranges->n_prot;
> + int pos, len, i;
> + bool found = false;
> + struct bl_prot_range *new_ranges = ranges->prot;
>
> - /* Try to merge into an existing range */
> - for (i = 0; i < count; i++) {
> - if (!(range.start + range.len == old_ranges[i].start ||
> - old_ranges[i].start + old_ranges[i].len == range.start))
> - continue;
> -
> - if (range.start + range.len == old_ranges[i].start)
> - old_ranges[i].start = range.start;
> -
> - old_ranges[i].len += range.len;
> -
> - /*
> - * Check the inserted range isn't wedged between two ranges, if it
> - * is, merge as well
> - */
> - i++;
> - if (i < count && range.start + range.len == old_ranges[i].start) {
> - old_ranges[i - 1].len += old_ranges[i].len;
> + pos = range.start;
> + len = range.len;
> + for (i = 0; i < ranges->n_prot && !found; i++) {
> + /* Fits entirely within the range */
> + if (ranges->prot[i].start <= pos &&
> + ranges->prot[i].start + ranges->prot[i].len >= pos + len) {
> + found = true;
> + break; /* Might as well, the next two conditions can't be true */
> + }
>
> - for (; i + 1 < count; i++)
> - old_ranges[i] = old_ranges[i + 1];
> - ranges->n_prot--;
> + if (ranges->prot[i].start <= pos &&
> + ranges->prot[i].start + ranges->prot[i].len > pos) {
> + ranges->prot[i].len += len;
> + found = true;
> + if (++i == ranges->n_prot) break;
> }
>
> - return 0;
> + if (ranges->prot[i].start >= pos &&
> + ranges->prot[i].start < pos + len) {
> + /* If it is adjacent to two ranges */
> + if (found) {
> + int j;
> + ranges->prot[i - 1].len += len + ranges->prot[i].len;
> + for (j = i; j < ranges->n_prot - 1; j++)
> + memcpy(&ranges->prot[j] , &ranges->prot[j + 1], sizeof(range));
> + ranges->n_prot--;
> + } else {
> + ranges->prot[i].start = pos;
> + ranges->prot[i].len += len;
> + found = true;
> + }
> + }
> }
>
> - if (ranges->n_prot == ranges->total_prot) {
> - new_ranges = realloc(ranges->prot, sizeof(range) * ((ranges->n_prot) + PROT_REALLOC_NUM));
> - if (new_ranges)
> - ranges->total_prot += PROT_REALLOC_NUM;
> - } else {
> - new_ranges = old_ranges;
> - }
> - if (new_ranges) {
> - memcpy(new_ranges + ranges->n_prot, &range, sizeof(range));
> - ranges->prot = new_ranges;
> - ranges->n_prot++;
> + if (!found) {
> + if (ranges->n_prot == ranges->total_prot) {
> + new_ranges = realloc(ranges->prot, sizeof(range) * ((ranges->n_prot) + PROT_REALLOC_NUM));
> + if (new_ranges)
> + ranges->total_prot += PROT_REALLOC_NUM;
> + }
> + if (new_ranges) {
> + memcpy(&new_ranges[ranges->n_prot], &range, sizeof(range));
> + ranges->prot = new_ranges;
> + ranges->n_prot++;
> + }
> }
>
> return !new_ranges;
> @@ -385,11 +392,7 @@ int blocklevel_ecc_protect(struct blocklevel_device *bl, uint32_t start, uint32_
> */
> struct bl_prot_range range = { .start = start, .len = len };
>
> - /*
> - * Refuse to add regions that are already protected or are partially
> - * protected
> - */
> - if (len < BYTES_PER_ECC || ecc_protected(bl, start, len))
> + if (len < BYTES_PER_ECC)
> return -1;
> return insert_bl_prot_range(&bl->ecc_prot, range);
> }
> diff --git a/libflash/libffs.c b/libflash/libffs.c
> index 8134962..97b48c4 100644
> --- a/libflash/libffs.c
> +++ b/libflash/libffs.c
> @@ -194,7 +194,7 @@ int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,
> if (ecc) {
> rc = blocklevel_ecc_protect(bl, start, total_size);
> if (rc) {
> - FL_ERR("Failed to blocklevel_ecc_protect(0x%08x, 0x%08x)\n",
> + FL_ERR("FFS: Failed to blocklevel_ecc_protect(0x%08x, 0x%08x)\n",
> start, total_size);
> goto out;
> }
More information about the Skiboot
mailing list