Update the check-namespace command to check/detect both v1.1 and v2.0 BTTs. Also update the btt-check.sh test to work for both.
Signed-off-by: Vishal Verma <[email protected]> --- ndctl/check.c | 94 +++++++++++++++++++++++++++++++++++++++++++++---------- ndctl/check.h | 5 ++- test/btt-check.sh | 4 +-- 3 files changed, 83 insertions(+), 20 deletions(-) diff --git a/ndctl/check.c b/ndctl/check.c index 3775c2e..0b564ed 100644 --- a/ndctl/check.c +++ b/ndctl/check.c @@ -766,14 +766,29 @@ static void btt_remove_mappings(struct btt_chk *bttc) } } -static int btt_recover_first_sb(struct btt_chk *bttc) +static int btt_sb_get_expected_offset(struct btt_sb *btt_sb) +{ + u16 version_major, version_minor; + + version_major = le16_to_cpu(btt_sb->version_major); + version_minor = le16_to_cpu(btt_sb->version_minor); + + if (version_major == 1 && version_minor == 1) + return BTT1_START_OFFSET; + else if (version_major == 2 && version_minor == 0) + return BTT2_START_OFFSET; + else + return -ENXIO; +} + +static int __btt_recover_first_sb(struct btt_chk *bttc, int off) { int rc, est_arenas = 0; u64 offset, remaining; struct btt_sb *btt_sb; /* Estimate the number of arenas */ - remaining = bttc->rawsize - bttc->start_off; + remaining = bttc->rawsize - off; while (remaining) { if (remaining < ARENA_MIN_SIZE && est_arenas == 0) return -EINVAL; @@ -800,7 +815,7 @@ static int btt_recover_first_sb(struct btt_chk *bttc) if (btt_sb == NULL) return -ENOMEM; /* Read the original first info block into btt_sb[0] */ - rc = btt_read_info(bttc, &btt_sb[0], bttc->start_off); + rc = btt_read_info(bttc, &btt_sb[0], off); if (rc) goto out; @@ -809,13 +824,26 @@ static int btt_recover_first_sb(struct btt_chk *bttc) offset = rounddown(bttc->rawsize - remaining, SZ_4K) - BTT_INFO_SIZE; else - offset = ARENA_MAX_SIZE - BTT_INFO_SIZE + bttc->start_off; + offset = ARENA_MAX_SIZE - BTT_INFO_SIZE + off; info(bttc, "Attempting recover info-block from end-of-arena offset %#lx\n", offset); rc = btt_info_read_verify(bttc, &btt_sb[1], offset); if (rc == 0) { - rc = btt_write_info(bttc, &btt_sb[1], bttc->start_off); + int expected_offset = btt_sb_get_expected_offset(&btt_sb[1]); + + /* + * The fact that the btt_sb is self-consistent doesn't tell us + * what BTT version it was, if restoring from the end of the + * arena. (i.e. a consistent sb may be found for any valid + * start offset). Use the version information in the sb to + * determine what the expected start offset is. + */ + if ((expected_offset < 0) || (expected_offset != off)) { + rc = -ENXIO; + goto out; + } + rc = btt_write_info(bttc, &btt_sb[1], off); goto out; } @@ -844,7 +872,7 @@ static int btt_recover_first_sb(struct btt_chk *bttc) btt_sb[1].checksum = btt_sb[0].checksum; rc = btt_info_verify(bttc, &btt_sb[1]); if (rc == 0) { - rc = btt_write_info(bttc, &btt_sb[1], bttc->start_off); + rc = btt_write_info(bttc, &btt_sb[1], off); goto out; } } @@ -855,7 +883,7 @@ static int btt_recover_first_sb(struct btt_chk *bttc) */ offset = le32_to_cpu(btt_sb[0].info2off); if (offset > min(bttc->rawsize - BTT_INFO_SIZE, - ARENA_MAX_SIZE - BTT_INFO_SIZE + bttc->start_off)) { + ARENA_MAX_SIZE - BTT_INFO_SIZE + off)) { rc = -ENXIO; goto out; } @@ -863,9 +891,9 @@ static int btt_recover_first_sb(struct btt_chk *bttc) info(bttc, "Attempting to recover info-block from info2 offset %#lx\n", offset); rc = btt_info_read_verify(bttc, &btt_sb[1], - offset + bttc->start_off); + offset + off); if (rc == 0) { - rc = btt_write_info(bttc, &btt_sb[1], bttc->start_off); + rc = btt_write_info(bttc, &btt_sb[1], off); goto out; } } else @@ -875,6 +903,25 @@ static int btt_recover_first_sb(struct btt_chk *bttc) return rc; } +static int btt_recover_first_sb(struct btt_chk *bttc) +{ + int offsets[BTT_NUM_OFFSETS] = { + BTT1_START_OFFSET, + BTT2_START_OFFSET, + }; + int i, rc; + + for (i = 0; i < BTT_NUM_OFFSETS; i++) { + rc = __btt_recover_first_sb(bttc, offsets[i]); + if (rc == 0) { + bttc->start_off = offsets[i]; + return rc; + } + } + + return rc; +} + int namespace_check(struct ndctl_namespace *ndns, struct check_opts *opts) { const char *devname = ndctl_namespace_get_devname(ndns); @@ -902,7 +949,6 @@ int namespace_check(struct ndctl_namespace *ndns, struct check_opts *opts) } bttc->opts = opts; - bttc->start_off = BTT_START_OFFSET; bttc->sys_page_size = sysconf(_SC_PAGESIZE); bttc->rawsize = ndctl_namespace_get_size(ndns); ndctl_namespace_get_uuid(ndns, bttc->parent_uuid); @@ -980,17 +1026,31 @@ int namespace_check(struct ndctl_namespace *ndns, struct check_opts *opts) goto out_close; } - rc = btt_info_read_verify(bttc, btt_sb, bttc->start_off); + /* Try reading a BTT1 info block first */ + rc = btt_info_read_verify(bttc, btt_sb, BTT1_START_OFFSET); + if (rc == 0) + bttc->start_off = BTT1_START_OFFSET; if (rc) { - rc = btt_recover_first_sb(bttc); + /* Try reading a BTT2 info block */ + rc = btt_info_read_verify(bttc, btt_sb, BTT2_START_OFFSET); + if (rc == 0) + bttc->start_off = BTT2_START_OFFSET; if (rc) { - err(bttc, "Unable to recover any BTT info blocks\n"); - goto out_close; + rc = btt_recover_first_sb(bttc); + if (rc) { + err(bttc, "Unable to recover any BTT info blocks\n"); + goto out_close; + } + /* + * btt_recover_first_sb will have set bttc->start_off + * based on the version it found + */ + rc = btt_info_read_verify(bttc, btt_sb, bttc->start_off); + if (rc) + goto out_close; } - rc = btt_info_read_verify(bttc, btt_sb, bttc->start_off); - if (rc) - goto out_close; } + rc = btt_discover_arenas(bttc); if (rc) goto out_close; diff --git a/ndctl/check.h b/ndctl/check.h index f0200db..00b11b2 100644 --- a/ndctl/check.h +++ b/ndctl/check.h @@ -27,9 +27,12 @@ #define ARENA_MIN_SIZE (1UL << 24) /* 16 MB */ #define ARENA_MAX_SIZE (1ULL << 39) /* 512 GB */ #define BTT_INFO_SIZE 4096 -#define BTT_START_OFFSET 4096 #define IB_FLAG_ERROR_MASK 0x00000001 +#define BTT_NUM_OFFSETS 2 +#define BTT1_START_OFFSET 4096 +#define BTT2_START_OFFSET 0 + struct log_entry { le32 lba; le32 old_map; diff --git a/test/btt-check.sh b/test/btt-check.sh index 5ec224b..d309448 100755 --- a/test/btt-check.sh +++ b/test/btt-check.sh @@ -146,10 +146,10 @@ test_bad_info() echo "=== ${FUNCNAME[0]} ===" set_raw echo "wiping info block" - dd if=/dev/zero of=/dev/$raw_bdev bs=$bs count=1 seek=1 + dd if=/dev/zero of=/dev/$raw_bdev bs=$bs count=2 seek=0 unset_raw $ndctl disable-namespace $dev - $ndctl check-namespace $dev 2>&1 | grep "info block at offset 0x1000 needs to be restored" + $ndctl check-namespace $dev 2>&1 | grep -E "info block at offset .* needs to be restored" $ndctl check-namespace --repair $dev $ndctl enable-namespace $dev post_repair_test -- 2.9.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
