Skip to content

Commit fcc4233

Browse files
Akilesh Kailashsnitm
authored andcommitted
dm snapshot: flush merged data before committing metadata
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: Akilesh Kailash <akailash@google.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
1 parent d68b295 commit fcc4233

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

drivers/md/dm-snap.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ struct dm_snapshot {
141141
* for them to be committed.
142142
*/
143143
struct bio_list bios_queued_during_merge;
144+
145+
/*
146+
* Flush data after merge.
147+
*/
148+
struct bio flush_bio;
144149
};
145150

146151
/*
@@ -1121,6 +1126,17 @@ static void snapshot_merge_next_chunks(struct dm_snapshot *s)
11211126

11221127
static void error_bios(struct bio *bio);
11231128

1129+
static int flush_data(struct dm_snapshot *s)
1130+
{
1131+
struct bio *flush_bio = &s->flush_bio;
1132+
1133+
bio_reset(flush_bio);
1134+
bio_set_dev(flush_bio, s->origin->bdev);
1135+
flush_bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
1136+
1137+
return submit_bio_wait(flush_bio);
1138+
}
1139+
11241140
static void merge_callback(int read_err, unsigned long write_err, void *context)
11251141
{
11261142
struct dm_snapshot *s = context;
@@ -1134,6 +1150,11 @@ static void merge_callback(int read_err, unsigned long write_err, void *context)
11341150
goto shut;
11351151
}
11361152

1153+
if (flush_data(s) < 0) {
1154+
DMERR("Flush after merge failed: shutting down merge");
1155+
goto shut;
1156+
}
1157+
11371158
if (s->store->type->commit_merge(s->store,
11381159
s->num_merging_chunks) < 0) {
11391160
DMERR("Write error in exception store: shutting down merge");
@@ -1318,6 +1339,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
13181339
s->first_merging_chunk = 0;
13191340
s->num_merging_chunks = 0;
13201341
bio_list_init(&s->bios_queued_during_merge);
1342+
bio_init(&s->flush_bio, NULL, 0);
13211343

13221344
/* Allocate hash table for COW data */
13231345
if (init_hash_tables(s)) {
@@ -1504,6 +1526,8 @@ static void snapshot_dtr(struct dm_target *ti)
15041526

15051527
dm_exception_store_destroy(s->store);
15061528

1529+
bio_uninit(&s->flush_bio);
1530+
15071531
dm_put_device(ti, s->cow);
15081532

15091533
dm_put_device(ti, s->origin);

0 commit comments

Comments
 (0)