Skip to content

Commit

Permalink
gard: Fix data corruption when clearing single records
Browse files Browse the repository at this point in the history
Attempting to clear a specific gard record leads to corruption of the target
record rather than the expected removal:

    $ ./opal-gard -f romulus.pnor list
    No GARD entries to display
    $ ./opal-gard -f romulus.pnor create /sys0/node0/proc1
    $ ./opal-gard -f romulus.pnor list
     ID       | Error    | Type       | Path
    ---------------------------------------------------------
     00000001 | 00000000 | Manual     | /Sys0/Node0/Proc1
    =========================================================
    $ ./opal-gard -f romulus.pnor clear 00000001
    Clearing gard record 0x00000001...done
    $ ./opal-gard -f romulus.pnor list
     ID       | Error    | Type       | Path
    ---------------------------------------------------------
     00000001 | 00000000 | Unknown    | /Sys0/Node0/Proc1
    =========================================================

The GUARD partition needs to be compacted when clearing records as the
end of the list is a sentinel represented by the erased-flash state. The
compaction strategy is to read the trailing records and write them to
the offset of the record to be removed, followed by writing the sentinel
record at the offset of what was previously the last valid record.

The corruption occurs due to incorrect calculation of the offset at which the
trailing records will be written.

Cc: Skiboot Stable <skiboot-stable@lists.ozlabs.org>
Fixes: 5616c42 ("libflash/blocklevel: Make read/write be ECC agnostic for callers")
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
  • Loading branch information
amboar authored and oohal committed Oct 14, 2019
1 parent cc34635 commit e08fee3
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 1 deletion.
2 changes: 1 addition & 1 deletion external/gard/gard.c
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ static int do_clear_i(struct gard_ctx *ctx, int pos, struct gard_record *gard, v
return rc;
}

rc = blocklevel_smart_write(ctx->bl, buf_pos - sizeof(gard), buf, buf_len);
rc = blocklevel_smart_write(ctx->bl, buf_pos - sizeof(*gard), buf, buf_len);
free(buf);
if (rc) {
fprintf(stderr, "Couldn't write to flash at 0x%08x for len 0x%08x\n",
Expand Down
Empty file.
7 changes: 7 additions & 0 deletions external/gard/test/results/10-clear-single.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Clearing the entire gard partition...done
ID | Error | Type | Path
---------------------------------------------------------
00000001 | 00000000 | Manual | /Sys0/Node0/Proc1
=========================================================
Clearing gard record 0x00000001...done
No GARD entries to display
23 changes: 23 additions & 0 deletions external/gard/test/tests/10-clear-single
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh

set -e

DATA=$(mktemp)

cleanup() {
rm -f $DATA
}

trap cleanup EXIT

dd if=/dev/zero of=$DATA bs=$((0x1000)) count=5 2>/dev/null

run_binary "./opal-gard" "-p -e -f $DATA clear all"
run_binary "./opal-gard" "-p -e -f $DATA create /sys0/node0/proc1"
run_binary "./opal-gard" "-p -e -f $DATA list"
run_binary "./opal-gard" "-p -e -f $DATA clear 00000001"
run_binary "./opal-gard" "-p -e -f $DATA list"

diff_with_result

pass_test

0 comments on commit e08fee3

Please sign in to comment.