提交 270f99f2 编写于 作者: A Akilesh Kailash 提交者: Yang Yingliang

dm snapshot: flush merged data before committing metadata

stable inclusion
from linux-4.19.169
commit aef593d2c87598839d6200772c5aee8a9ecdcd9f

--------------------------------

commit fcc42338 upstream.

If the origin device has a volatile write-back cache and the following
events occur:

1: After finishing merge operation of one set of exceptions,
   merge_callback() is invoked.
2: Update the metadata in COW device tracking the merge completion.
   This update to COW device is flushed cleanly.
3: System crashes and the origin device's cache where the recent
   merge was completed has not been flushed.

During the next cycle when we read the metadata from the COW device,
we will skip reading those metadata whose merge was completed in
step (1). This will lead to data loss/corruption.

To address this, flush the origin device post merge IO before
updating the metadata.

Cc: stable@vger.kernel.org
Signed-off-by: NAkilesh Kailash <akailash@google.com>
Signed-off-by: NMike Snitzer <snitzer@redhat.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
上级 ca9833a7
...@@ -137,6 +137,11 @@ struct dm_snapshot { ...@@ -137,6 +137,11 @@ struct dm_snapshot {
* for them to be committed. * for them to be committed.
*/ */
struct bio_list bios_queued_during_merge; struct bio_list bios_queued_during_merge;
/*
* Flush data after merge.
*/
struct bio flush_bio;
}; };
/* /*
...@@ -1061,6 +1066,17 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s) ...@@ -1061,6 +1066,17 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s)
static void error_bios(struct bio *bio); static void error_bios(struct bio *bio);
static int flush_data(struct dm_snapshot *s)
{
struct bio *flush_bio = &s->flush_bio;
bio_reset(flush_bio);
bio_set_dev(flush_bio, s->origin->bdev);
flush_bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
return submit_bio_wait(flush_bio);
}
static void merge_callback(int read_err, unsigned long write_err, void *context) static void merge_callback(int read_err, unsigned long write_err, void *context)
{ {
struct dm_snapshot *s = context; struct dm_snapshot *s = context;
...@@ -1074,6 +1090,11 @@ static void merge_callback(int read_err, unsigned long write_err, void *context) ...@@ -1074,6 +1090,11 @@ static void merge_callback(int read_err, unsigned long write_err, void *context)
goto shut; goto shut;
} }
if (flush_data(s) < 0) {
DMERR("Flush after merge failed: shutting down merge");
goto shut;
}
if (s->store->type->commit_merge(s->store, if (s->store->type->commit_merge(s->store,
s->num_merging_chunks) < 0) { s->num_merging_chunks) < 0) {
DMERR("Write error in exception store: shutting down merge"); DMERR("Write error in exception store: shutting down merge");
...@@ -1198,6 +1219,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1198,6 +1219,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
s->first_merging_chunk = 0; s->first_merging_chunk = 0;
s->num_merging_chunks = 0; s->num_merging_chunks = 0;
bio_list_init(&s->bios_queued_during_merge); bio_list_init(&s->bios_queued_during_merge);
bio_init(&s->flush_bio, NULL, 0);
/* Allocate hash table for COW data */ /* Allocate hash table for COW data */
if (init_hash_tables(s)) { if (init_hash_tables(s)) {
...@@ -1391,6 +1413,8 @@ static void snapshot_dtr(struct dm_target *ti) ...@@ -1391,6 +1413,8 @@ static void snapshot_dtr(struct dm_target *ti)
mutex_destroy(&s->lock); mutex_destroy(&s->lock);
bio_uninit(&s->flush_bio);
dm_put_device(ti, s->cow); dm_put_device(ti, s->cow);
dm_put_device(ti, s->origin); dm_put_device(ti, s->origin);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册