Skip to content

Commit 2099b14

Browse files
ntsironsnitm
authored andcommitted
dm era: Update in-core bitset after committing the metadata
In case of a system crash, dm-era might fail to mark blocks as written in its metadata, although the corresponding writes to these blocks were passed down to the origin device and completed successfully. Consider the following sequence of events: 1. We write to a block that has not been yet written in the current era 2. era_map() checks the in-core bitmap for the current era and sees that the block is not marked as written. 3. The write is deferred for submission after the metadata have been updated and committed. 4. The worker thread processes the deferred write (process_deferred_bios()) and marks the block as written in the in-core bitmap, **before** committing the metadata. 5. The worker thread starts committing the metadata. 6. We do more writes that map to the same block as the write of step (1) 7. era_map() checks the in-core bitmap and sees that the block is marked as written, **although the metadata have not been committed yet**. 8. These writes are passed down to the origin device immediately and the device reports them as completed. 9. The system crashes, e.g., power failure, before the commit from step (5) finishes. When the system recovers and we query the dm-era target for the list of written blocks it doesn't report the aforementioned block as written, although the writes of step (6) completed successfully. The issue is that era_map() decides whether to defer or not a write based on non committed information. The root cause of the bug is that we update the in-core bitmap, **before** committing the metadata. Fix this by updating the in-core bitmap **after** successfully committing the metadata. 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 de89afc commit 2099b14

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

drivers/md/dm-era-target.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ static int writeset_test_and_set(struct dm_disk_bitset *info,
134134
{
135135
int r;
136136

137-
if (!test_and_set_bit(block, ws->bits)) {
137+
if (!test_bit(block, ws->bits)) {
138138
r = dm_bitset_set_bit(info, ws->md.root, block, &ws->md.root);
139139
if (r) {
140140
/* FIXME: fail mode */
@@ -1226,8 +1226,10 @@ static void process_deferred_bios(struct era *era)
12261226
int r;
12271227
struct bio_list deferred_bios, marked_bios;
12281228
struct bio *bio;
1229+
struct blk_plug plug;
12291230
bool commit_needed = false;
12301231
bool failed = false;
1232+
struct writeset *ws = era->md->current_writeset;
12311233

12321234
bio_list_init(&deferred_bios);
12331235
bio_list_init(&marked_bios);
@@ -1237,17 +1239,18 @@ static void process_deferred_bios(struct era *era)
12371239
bio_list_init(&era->deferred_bios);
12381240
spin_unlock(&era->deferred_lock);
12391241

1242+
if (bio_list_empty(&deferred_bios))
1243+
return;
1244+
12401245
while ((bio = bio_list_pop(&deferred_bios))) {
1241-
r = writeset_test_and_set(&era->md->bitset_info,
1242-
era->md->current_writeset,
1246+
r = writeset_test_and_set(&era->md->bitset_info, ws,
12431247
get_block(era, bio));
12441248
if (r < 0) {
12451249
/*
12461250
* This is bad news, we need to rollback.
12471251
* FIXME: finish.
12481252
*/
12491253
failed = true;
1250-
12511254
} else if (r == 0)
12521255
commit_needed = true;
12531256

@@ -1263,9 +1266,19 @@ static void process_deferred_bios(struct era *era)
12631266
if (failed)
12641267
while ((bio = bio_list_pop(&marked_bios)))
12651268
bio_io_error(bio);
1266-
else
1267-
while ((bio = bio_list_pop(&marked_bios)))
1269+
else {
1270+
blk_start_plug(&plug);
1271+
while ((bio = bio_list_pop(&marked_bios))) {
1272+
/*
1273+
* Only update the in-core writeset if the on-disk one
1274+
* was updated too.
1275+
*/
1276+
if (commit_needed)
1277+
set_bit(get_block(era, bio), ws->bits);
12681278
submit_bio_noacct(bio);
1279+
}
1280+
blk_finish_plug(&plug);
1281+
}
12691282
}
12701283

12711284
static void process_rpc_calls(struct era *era)

0 commit comments

Comments
 (0)