Skip to content

Commit

Permalink
libnvdimm, btt: ensure that initializing metadata clears poison
Browse files Browse the repository at this point in the history
If we had badblocks/poison in the metadata area of a BTT, recreating the
BTT would not clear the poison in all cases, notably the flog area. This
is because rw_bytes will only clear errors if the request being sent
down is 512B aligned and sized.

Make sure that when writing the map and info blocks, the rw_bytes being
sent are of the correct size/alignment. For the flog, instead of doing
the smaller log_entry writes only, first do a 'wipe' of the entire area
by writing zeroes in large enough chunks so that errors get cleared.

Cc: Andy Rudoff <[email protected]>
Cc: Dan Williams <[email protected]>
Signed-off-by: Vishal Verma <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
  • Loading branch information
stellarhopper authored and djbw committed May 11, 2017
1 parent 3ae3d67 commit b177fe8
Showing 1 changed file with 47 additions and 7 deletions.
54 changes: 47 additions & 7 deletions drivers/nvdimm/btt.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ static int btt_info_write(struct arena_info *arena, struct btt_sb *super)
{
int ret;

/*
* infooff and info2off should always be at least 512B aligned.
* We rely on that to make sure rw_bytes does error clearing
* correctly, so make sure that is the case.
*/
WARN_ON_ONCE(!IS_ALIGNED(arena->infooff, 512));
WARN_ON_ONCE(!IS_ALIGNED(arena->info2off, 512));

ret = arena_write_bytes(arena, arena->info2off, super,
sizeof(struct btt_sb), 0);
if (ret)
Expand Down Expand Up @@ -394,9 +402,17 @@ static int btt_map_init(struct arena_info *arena)
if (!zerobuf)
return -ENOMEM;

/*
* mapoff should always be at least 512B aligned. We rely on that to
* make sure rw_bytes does error clearing correctly, so make sure that
* is the case.
*/
WARN_ON_ONCE(!IS_ALIGNED(arena->mapoff, 512));

while (mapsize) {
size_t size = min(mapsize, chunk_size);

WARN_ON_ONCE(size < 512);
ret = arena_write_bytes(arena, arena->mapoff + offset, zerobuf,
size, 0);
if (ret)
Expand All @@ -418,11 +434,36 @@ static int btt_map_init(struct arena_info *arena)
*/
static int btt_log_init(struct arena_info *arena)
{
size_t logsize = arena->info2off - arena->logoff;
size_t chunk_size = SZ_4K, offset = 0;
struct log_entry log;
void *zerobuf;
int ret;
u32 i;
struct log_entry log, zerolog;

memset(&zerolog, 0, sizeof(zerolog));
zerobuf = kzalloc(chunk_size, GFP_KERNEL);
if (!zerobuf)
return -ENOMEM;
/*
* logoff should always be at least 512B aligned. We rely on that to
* make sure rw_bytes does error clearing correctly, so make sure that
* is the case.
*/
WARN_ON_ONCE(!IS_ALIGNED(arena->logoff, 512));

while (logsize) {
size_t size = min(logsize, chunk_size);

WARN_ON_ONCE(size < 512);
ret = arena_write_bytes(arena, arena->logoff + offset, zerobuf,
size, 0);
if (ret)
goto free;

offset += size;
logsize -= size;
cond_resched();
}

for (i = 0; i < arena->nfree; i++) {
log.lba = cpu_to_le32(i);
Expand All @@ -431,13 +472,12 @@ static int btt_log_init(struct arena_info *arena)
log.seq = cpu_to_le32(LOG_SEQ_INIT);
ret = __btt_log_write(arena, i, 0, &log, 0);
if (ret)
return ret;
ret = __btt_log_write(arena, i, 1, &zerolog, 0);
if (ret)
return ret;
goto free;
}

return 0;
free:
kfree(zerobuf);
return ret;
}

static int btt_freelist_init(struct arena_info *arena)
Expand Down

0 comments on commit b177fe8

Please sign in to comment.