Skip to content

Commit 4ae280b

Browse files
ntsironsnitm
authored andcommitted
dm thin: fix bug where bio that overwrites thin block ignores FUA
When provisioning a new data block for a virtual block, either because the block was previously unallocated or because we are breaking sharing, if the whole block of data is being overwritten the bio that triggered the provisioning is issued immediately, skipping copying or zeroing of the data block. When this bio completes the new mapping is inserted in to the pool's metadata by process_prepared_mapping(), where the bio completion is signaled to the upper layers. This completion is signaled without first committing the metadata. If the bio in question has the REQ_FUA flag set and the system crashes right after its completion and before the next metadata commit, then the write is lost despite the REQ_FUA flag requiring that I/O completion for this request must only be signaled after the data has been committed to non-volatile storage. Fix this by deferring the completion of overwrite bios, with the REQ_FUA flag set, until after the metadata has been committed. Cc: stable@vger.kernel.org Signed-off-by: Nikos Tsironis <ntsironis@arrikto.com> Acked-by: Joe Thornber <ejt@redhat.com> Acked-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
1 parent ff0c129 commit 4ae280b

File tree

1 file changed

+50
-5
lines changed

1 file changed

+50
-5
lines changed

drivers/md/dm-thin.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ struct pool {
257257

258258
spinlock_t lock;
259259
struct bio_list deferred_flush_bios;
260+
struct bio_list deferred_flush_completions;
260261
struct list_head prepared_mappings;
261262
struct list_head prepared_discards;
262263
struct list_head prepared_discards_pt2;
@@ -956,6 +957,39 @@ static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m)
956957
mempool_free(m, &m->tc->pool->mapping_pool);
957958
}
958959

960+
static void complete_overwrite_bio(struct thin_c *tc, struct bio *bio)
961+
{
962+
struct pool *pool = tc->pool;
963+
unsigned long flags;
964+
965+
/*
966+
* If the bio has the REQ_FUA flag set we must commit the metadata
967+
* before signaling its completion.
968+
*/
969+
if (!bio_triggers_commit(tc, bio)) {
970+
bio_endio(bio);
971+
return;
972+
}
973+
974+
/*
975+
* Complete bio with an error if earlier I/O caused changes to the
976+
* metadata that can't be committed, e.g, due to I/O errors on the
977+
* metadata device.
978+
*/
979+
if (dm_thin_aborted_changes(tc->td)) {
980+
bio_io_error(bio);
981+
return;
982+
}
983+
984+
/*
985+
* Batch together any bios that trigger commits and then issue a
986+
* single commit for them in process_deferred_bios().
987+
*/
988+
spin_lock_irqsave(&pool->lock, flags);
989+
bio_list_add(&pool->deferred_flush_completions, bio);
990+
spin_unlock_irqrestore(&pool->lock, flags);
991+
}
992+
959993
static void process_prepared_mapping(struct dm_thin_new_mapping *m)
960994
{
961995
struct thin_c *tc = m->tc;
@@ -988,7 +1022,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
9881022
*/
9891023
if (bio) {
9901024
inc_remap_and_issue_cell(tc, m->cell, m->data_block);
991-
bio_endio(bio);
1025+
complete_overwrite_bio(tc, bio);
9921026
} else {
9931027
inc_all_io_entry(tc->pool, m->cell->holder);
9941028
remap_and_issue(tc, m->cell->holder, m->data_block);
@@ -2317,7 +2351,7 @@ static void process_deferred_bios(struct pool *pool)
23172351
{
23182352
unsigned long flags;
23192353
struct bio *bio;
2320-
struct bio_list bios;
2354+
struct bio_list bios, bio_completions;
23212355
struct thin_c *tc;
23222356

23232357
tc = get_first_thin(pool);
@@ -2328,26 +2362,36 @@ static void process_deferred_bios(struct pool *pool)
23282362
}
23292363

23302364
/*
2331-
* If there are any deferred flush bios, we must commit
2332-
* the metadata before issuing them.
2365+
* If there are any deferred flush bios, we must commit the metadata
2366+
* before issuing them or signaling their completion.
23332367
*/
23342368
bio_list_init(&bios);
2369+
bio_list_init(&bio_completions);
2370+
23352371
spin_lock_irqsave(&pool->lock, flags);
23362372
bio_list_merge(&bios, &pool->deferred_flush_bios);
23372373
bio_list_init(&pool->deferred_flush_bios);
2374+
2375+
bio_list_merge(&bio_completions, &pool->deferred_flush_completions);
2376+
bio_list_init(&pool->deferred_flush_completions);
23382377
spin_unlock_irqrestore(&pool->lock, flags);
23392378

2340-
if (bio_list_empty(&bios) &&
2379+
if (bio_list_empty(&bios) && bio_list_empty(&bio_completions) &&
23412380
!(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool)))
23422381
return;
23432382

23442383
if (commit(pool)) {
2384+
bio_list_merge(&bios, &bio_completions);
2385+
23452386
while ((bio = bio_list_pop(&bios)))
23462387
bio_io_error(bio);
23472388
return;
23482389
}
23492390
pool->last_commit_jiffies = jiffies;
23502391

2392+
while ((bio = bio_list_pop(&bio_completions)))
2393+
bio_endio(bio);
2394+
23512395
while ((bio = bio_list_pop(&bios)))
23522396
generic_make_request(bio);
23532397
}
@@ -2954,6 +2998,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
29542998
INIT_DELAYED_WORK(&pool->no_space_timeout, do_no_space_timeout);
29552999
spin_lock_init(&pool->lock);
29563000
bio_list_init(&pool->deferred_flush_bios);
3001+
bio_list_init(&pool->deferred_flush_completions);
29573002
INIT_LIST_HEAD(&pool->prepared_mappings);
29583003
INIT_LIST_HEAD(&pool->prepared_discards);
29593004
INIT_LIST_HEAD(&pool->prepared_discards_pt2);

0 commit comments

Comments
 (0)