Add a --rewrite-log option to ndctl check-namespace which reads the active log entries, and rewrites them as though initializing a new BTT. This allows us to convert an old (pre 4.15) format of log/padding layout to a new one that is compatible with other BTT implementations.
In the btt-pad-compat unit test, add testing for the format conversion operation. Cc: Dan Williams <[email protected]> Signed-off-by: Vishal Verma <[email protected]> --- Documentation/ndctl/ndctl-check-namespace.txt | 11 +++++ ndctl/check.c | 70 ++++++++++++++++++++++++++- ndctl/namespace.c | 6 ++- test/btt-pad-compat.sh | 9 ++++ 4 files changed, 93 insertions(+), 3 deletions(-) diff --git a/Documentation/ndctl/ndctl-check-namespace.txt b/Documentation/ndctl/ndctl-check-namespace.txt index 49353b1..ea4183a 100644 --- a/Documentation/ndctl/ndctl-check-namespace.txt +++ b/Documentation/ndctl/ndctl-check-namespace.txt @@ -42,6 +42,17 @@ OPTIONS Perform metadata repairs if possible. Without this option, the raw namespace contents will not be touched. +-L:: +--rewrite-log:: + Regenerate the BTT log and write it to media. This can be used to + convert from the old (pre 4.15) padding format that was incompatible + with other BTT implementations to the updated format. This requires + the --repair option to be provided. + + WARNING: Do not interrupt this operation as it can potentially cause + unrecoverable metadata corruption. It is highly recommended to create + a backup of the raw namespace before attempting this. + -f:: --force:: Unless this option is specified, a check-namespace operation diff --git a/ndctl/check.c b/ndctl/check.c index d3aa1aa..09dd125 100644 --- a/ndctl/check.c +++ b/ndctl/check.c @@ -46,6 +46,7 @@ struct check_opts { bool verbose; bool force; bool repair; + bool logfix; }; struct btt_chk { @@ -246,6 +247,12 @@ static void btt_log_group_read(struct arena_info *a, u32 lane, memcpy(log, &a->map.log[lane], LOG_GRP_SIZE); } +static void btt_log_group_write(struct arena_info *a, u32 lane, + struct log_group *log) +{ + memcpy(&a->map.log[lane], log, LOG_GRP_SIZE); +} + static u32 log_seq(struct log_group *log, int log_idx) { return le32_to_cpu(log->ent[log_idx].seq); @@ -358,6 +365,7 @@ enum btt_errcodes { BTT_LOG_MAP_ERR, BTT_MAP_OOB, BTT_BITMAP_ERROR, + BTT_LOGFIX_ERR, }; static void btt_xlat_status(struct arena_info *a, int errcode) @@ -405,6 +413,11 @@ static void btt_xlat_status(struct arena_info *a, int errcode) "arena %d: bitmap error: internal blocks are incorrectly referenced\n", a->num); break; + case BTT_LOGFIX_ERR: + err(a->bttc, + "arena %d: rewrite-log error: log may be in an unknown/unrecoverable state\n", + a->num); + break; default: err(a->bttc, "arena %d: unknown error: %d\n", a->num, errcode); @@ -563,6 +576,44 @@ static int btt_check_bitmap(struct arena_info *a) return rc; } +static int btt_rewrite_log(struct arena_info *a) +{ + struct log_group log; + int rc; + u32 i; + + info(a->bttc, "arena %d: rewriting log\n", a->num); + /* + * To rewrite the log, we implicitly use the 'new' padding scheme of + * (0, 1) but resetting the log to a completely initial state (i.e. + * slot-0 contains a made-up entry containing the 'free' block from + * the existing current log entry, and a sequence number of '1'. All + * other slots are zeroed. + * + * This way of rewriting the log is the most flexible as it can be + * (ab)used to convert a new padding format back to the old one. + * Since it only recreates slot-0, which is common between both + * existing formats, an older kernel will simply initialize the free + * list using those slot-0 entries, and run with it as though slot-2 + * is the other valid slot. + */ + memset(&log, 0, LOG_GRP_SIZE); + for (i = 0; i < a->nfree; i++) { + struct log_entry ent; + + rc = btt_log_read(a, i, &ent); + if (rc) + return BTT_LOGFIX_ERR; + + log.ent[0].lba = ent.lba; + log.ent[0].old_map = ent.old_map; + log.ent[0].new_map = ent.new_map; + log.ent[0].seq = 1; + btt_log_group_write(a, i, &log); + } + return 0; +} + static int btt_check_arenas(struct btt_chk *bttc) { struct arena_info *a = NULL; @@ -591,6 +642,12 @@ static int btt_check_arenas(struct btt_chk *bttc) rc = btt_check_bitmap(a); if (rc) break; + + if (bttc->opts->logfix) { + rc = btt_rewrite_log(a); + if (rc) + break; + } } if (a && rc != BTT_OK) { @@ -1094,13 +1151,14 @@ static int btt_recover_first_sb(struct btt_chk *bttc) } int namespace_check(struct ndctl_namespace *ndns, bool verbose, bool force, - bool repair) + bool repair, bool logfix) { const char *devname = ndctl_namespace_get_devname(ndns); struct check_opts __opts = { .verbose = verbose, .force = force, .repair = repair, + .logfix = logfix, }, *opts = &__opts; int raw_mode, rc, disabled_flag = 0, open_flags; struct btt_sb *btt_sb; @@ -1127,6 +1185,16 @@ int namespace_check(struct ndctl_namespace *ndns, bool verbose, bool force, goto out_bttc; } + if (opts->logfix) { + if (!opts->repair) { + err(bttc, "--rewrite-log also requires --repair\n"); + rc = -EINVAL; + goto out_bttc; + } + info(bttc, + "WARNING: interruption may cause unrecoverable metadata corruption\n"); + } + bttc->opts = opts; bttc->sys_page_size = sysconf(_SC_PAGESIZE); bttc->rawsize = ndctl_namespace_get_size(ndns); diff --git a/ndctl/namespace.c b/ndctl/namespace.c index d31244b..6b19f28 100644 --- a/ndctl/namespace.c +++ b/ndctl/namespace.c @@ -39,6 +39,7 @@ static bool verbose; static bool force; static bool repair; +static bool logfix; static struct parameters { bool do_scan; bool mode_default; @@ -121,6 +122,7 @@ OPT_BOOLEAN('L', "autolabel", ¶m.autolabel, "automatically initialize labels #define CHECK_OPTIONS() \ OPT_BOOLEAN('R', "repair", &repair, "perform metadata repairs"), \ +OPT_BOOLEAN('L', "rewrite-log", &logfix, "regenerate the log"), \ OPT_BOOLEAN('f', "force", &force, "check namespace even if currently active") static const struct option base_options[] = { @@ -985,7 +987,7 @@ static int namespace_reconfig(struct ndctl_region *region, } int namespace_check(struct ndctl_namespace *ndns, bool verbose, bool force, - bool repair); + bool repair, bool logfix); static int do_xaction_namespace(const char *namespace, enum device_action action, struct ndctl_ctx *ctx) @@ -1049,7 +1051,7 @@ static int do_xaction_namespace(const char *namespace, break; case ACTION_CHECK: rc = namespace_check(ndns, verbose, - force, repair); + force, repair, logfix); if (rc < 0) return rc; break; diff --git a/test/btt-pad-compat.sh b/test/btt-pad-compat.sh index cbfe990..d10efe3 100755 --- a/test/btt-pad-compat.sh +++ b/test/btt-pad-compat.sh @@ -193,6 +193,15 @@ do_tests() cycle_ns "$dev" verify_idx 0 2 + # rewrite log using ndctl, verify conversion to new format + ndctl check-namespace --rewrite-log --repair --force --verbose $dev + do_random_io "/dev/$blockdev" + cycle_ns "$dev" + verify_idx 0 1 + + # check-namespace again to make sure everything is ok + ndctl check-namespace --force --verbose $dev + # the old format btt metadata was created with a null parent uuid, # making it 'stickier' than a normally created btt. Be sure to clean # it up by wiping the info block -- 2.14.3 _______________________________________________ Linux-nvdimm mailing list [email protected] https://lists.01.org/mailman/listinfo/linux-nvdimm
