Skip to content

Commit

Permalink
dm era: Update in-core bitset after committing the metadata
Browse files Browse the repository at this point in the history
commit 2099b14 upstream.

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: stable@vger.kernel.org # v3.15+
Signed-off-by: Nikos Tsironis <ntsironis@arrikto.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Nikos Tsironis authored and Greg Kroah-Hartman committed Mar 3, 2021
1 parent 372fb8e commit 1788a8b
Showing 1 changed file with 19 additions and 6 deletions.
25 changes: 19 additions & 6 deletions drivers/md/dm-era-target.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ static int writeset_test_and_set(struct dm_disk_bitset *info,
{
int r;

if (!test_and_set_bit(block, ws->bits)) {
if (!test_bit(block, ws->bits)) {
r = dm_bitset_set_bit(info, ws->md.root, block, &ws->md.root);
if (r) {
/* FIXME: fail mode */
Expand Down Expand Up @@ -1240,8 +1240,10 @@ static void process_deferred_bios(struct era *era)
int r;
struct bio_list deferred_bios, marked_bios;
struct bio *bio;
struct blk_plug plug;
bool commit_needed = false;
bool failed = false;
struct writeset *ws = era->md->current_writeset;

bio_list_init(&deferred_bios);
bio_list_init(&marked_bios);
Expand All @@ -1251,17 +1253,18 @@ static void process_deferred_bios(struct era *era)
bio_list_init(&era->deferred_bios);
spin_unlock(&era->deferred_lock);

if (bio_list_empty(&deferred_bios))
return;

while ((bio = bio_list_pop(&deferred_bios))) {
r = writeset_test_and_set(&era->md->bitset_info,
era->md->current_writeset,
r = writeset_test_and_set(&era->md->bitset_info, ws,
get_block(era, bio));
if (r < 0) {
/*
* This is bad news, we need to rollback.
* FIXME: finish.
*/
failed = true;

} else if (r == 0)
commit_needed = true;

Expand All @@ -1277,9 +1280,19 @@ static void process_deferred_bios(struct era *era)
if (failed)
while ((bio = bio_list_pop(&marked_bios)))
bio_io_error(bio);
else
while ((bio = bio_list_pop(&marked_bios)))
else {
blk_start_plug(&plug);
while ((bio = bio_list_pop(&marked_bios))) {
/*
* Only update the in-core writeset if the on-disk one
* was updated too.
*/
if (commit_needed)
set_bit(get_block(era, bio), ws->bits);
generic_make_request(bio);
}
blk_finish_plug(&plug);
}
}

static void process_rpc_calls(struct era *era)
Expand Down

0 comments on commit 1788a8b

Please sign in to comment.