dm raid1: hold all write bios when leg fails
Hold all write bios when leg fails and errors are handled
When using a userspace daemon such as dmeventd to handle errors, we must
delay completing bios until it has done its job.
This patch prevents the following race:
- primary leg fails
- write "1" fail, the write is held, secondary leg is set default
- write "2" goes straight to the secondary leg
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Takahiro Yasui <tyasui@redhat.com>
Tested-by: Takahiro Yasui <tyasui@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index e363335..f8d7b3a 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -69,6 +69,7 @@
region_t nr_regions;
int in_sync;
int log_failure;
+ int leg_failure;
atomic_t suspend;
atomic_t default_mirror; /* Default mirror */
@@ -211,6 +212,8 @@
struct mirror_set *ms = m->ms;
struct mirror *new;
+ ms->leg_failure = 1;
+
/*
* error_count is used for nothing more than a
* simple way to tell if a device has encountered
@@ -734,8 +737,12 @@
dm_rh_delay(ms->rh, bio);
while ((bio = bio_list_pop(&nosync))) {
- map_bio(get_default_mirror(ms), bio);
- generic_make_request(bio);
+ if (unlikely(ms->leg_failure) && errors_handled(ms))
+ hold_bio(ms, bio);
+ else {
+ map_bio(get_default_mirror(ms), bio);
+ generic_make_request(bio);
+ }
}
}
@@ -848,6 +855,7 @@
ms->nr_regions = dm_sector_div_up(ti->len, region_size);
ms->in_sync = 0;
ms->log_failure = 0;
+ ms->leg_failure = 0;
atomic_set(&ms->suspend, 0);
atomic_set(&ms->default_mirror, DEFAULT_MIRROR);