Skip to content

Commit de89afc

Browse files
ntsironsnitm
authored andcommitted
dm era: Recover committed writeset after crash
Following a system crash, dm-era fails to recover the committed writeset for the current era, leading to lost writes. That is, we lose the information about what blocks were written during the affected era. dm-era assumes that the writeset of the current era is archived when the device is suspended. So, when resuming the device, it just moves on to the next era, ignoring the committed writeset. This assumption holds when the device is properly shut down. But, when the system crashes, the code that suspends the target never runs, so the writeset for the current era is not archived. There are three issues that cause the committed writeset to get lost: 1. dm-era doesn't load the committed writeset when opening the metadata 2. The code that resizes the metadata wipes the information about the committed writeset (assuming it was loaded at step 1) 3. era_preresume() starts a new era, without taking into account that the current era might not have been archived, due to a system crash. To fix this: 1. Load the committed writeset when opening the metadata 2. Fix the code that resizes the metadata to make sure it doesn't wipe the loaded writeset 3. Fix era_preresume() to check for a loaded writeset and archive it, before starting a new era. Fixes: eec4057 ("dm: add era target") Cc: [email protected] # v3.15+ Signed-off-by: Nikos Tsironis <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent d9928ac commit de89afc

File tree

1 file changed

+9
-8
lines changed

1 file changed

+9
-8
lines changed

drivers/md/dm-era-target.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ static size_t bitset_size(unsigned nr_bits)
7171
*/
7272
static int writeset_alloc(struct writeset *ws, dm_block_t nr_blocks)
7373
{
74-
ws->md.nr_bits = nr_blocks;
75-
ws->md.root = INVALID_WRITESET_ROOT;
7674
ws->bits = vzalloc(bitset_size(nr_blocks));
7775
if (!ws->bits) {
7876
DMERR("%s: couldn't allocate in memory bitset", __func__);
@@ -85,12 +83,14 @@ static int writeset_alloc(struct writeset *ws, dm_block_t nr_blocks)
8583
/*
8684
* Wipes the in-core bitset, and creates a new on disk bitset.
8785
*/
88-
static int writeset_init(struct dm_disk_bitset *info, struct writeset *ws)
86+
static int writeset_init(struct dm_disk_bitset *info, struct writeset *ws,
87+
dm_block_t nr_blocks)
8988
{
9089
int r;
9190

92-
memset(ws->bits, 0, bitset_size(ws->md.nr_bits));
91+
memset(ws->bits, 0, bitset_size(nr_blocks));
9392

93+
ws->md.nr_bits = nr_blocks;
9494
r = setup_on_disk_bitset(info, ws->md.nr_bits, &ws->md.root);
9595
if (r) {
9696
DMERR("%s: setup_on_disk_bitset failed", __func__);
@@ -579,6 +579,7 @@ static int open_metadata(struct era_metadata *md)
579579
md->nr_blocks = le32_to_cpu(disk->nr_blocks);
580580
md->current_era = le32_to_cpu(disk->current_era);
581581

582+
ws_unpack(&disk->current_writeset, &md->current_writeset->md);
582583
md->writeset_tree_root = le64_to_cpu(disk->writeset_tree_root);
583584
md->era_array_root = le64_to_cpu(disk->era_array_root);
584585
md->metadata_snap = le64_to_cpu(disk->metadata_snap);
@@ -870,7 +871,6 @@ static int metadata_era_archive(struct era_metadata *md)
870871
}
871872

872873
ws_pack(&md->current_writeset->md, &value);
873-
md->current_writeset->md.root = INVALID_WRITESET_ROOT;
874874

875875
keys[0] = md->current_era;
876876
__dm_bless_for_disk(&value);
@@ -882,6 +882,7 @@ static int metadata_era_archive(struct era_metadata *md)
882882
return r;
883883
}
884884

885+
md->current_writeset->md.root = INVALID_WRITESET_ROOT;
885886
md->archived_writesets = true;
886887

887888
return 0;
@@ -898,7 +899,7 @@ static int metadata_new_era(struct era_metadata *md)
898899
int r;
899900
struct writeset *new_writeset = next_writeset(md);
900901

901-
r = writeset_init(&md->bitset_info, new_writeset);
902+
r = writeset_init(&md->bitset_info, new_writeset, md->nr_blocks);
902903
if (r) {
903904
DMERR("%s: writeset_init failed", __func__);
904905
return r;
@@ -951,7 +952,7 @@ static int metadata_commit(struct era_metadata *md)
951952
int r;
952953
struct dm_block *sblock;
953954

954-
if (md->current_writeset->md.root != SUPERBLOCK_LOCATION) {
955+
if (md->current_writeset->md.root != INVALID_WRITESET_ROOT) {
955956
r = dm_bitset_flush(&md->bitset_info, md->current_writeset->md.root,
956957
&md->current_writeset->md.root);
957958
if (r) {
@@ -1565,7 +1566,7 @@ static int era_preresume(struct dm_target *ti)
15651566

15661567
start_worker(era);
15671568

1568-
r = in_worker0(era, metadata_new_era);
1569+
r = in_worker0(era, metadata_era_rollover);
15691570
if (r) {
15701571
DMERR("%s: metadata_era_rollover failed", __func__);
15711572
return r;

0 commit comments

Comments
 (0)