diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2009-12-10 18:52:06 -0500 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2009-12-10 18:52:06 -0500 |
commit | 929be8fcb4b4b65d038e73d3bb34715851a95ca2 (patch) | |
tree | 7c008317d90232b5b2d3869b9fa68c1ec023d7f6 /drivers/md/dm-raid1.c | |
parent | 60f355ead31e2be8d06ac8acb163df91a1c64e3b (diff) |
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>
Diffstat (limited to 'drivers/md/dm-raid1.c')
-rw-r--r-- | drivers/md/dm-raid1.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index e363335e8d81..f8d7b3aa46c6 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -69,6 +69,7 @@ struct mirror_set { | |||
69 | region_t nr_regions; | 69 | region_t nr_regions; |
70 | int in_sync; | 70 | int in_sync; |
71 | int log_failure; | 71 | int log_failure; |
72 | int leg_failure; | ||
72 | atomic_t suspend; | 73 | atomic_t suspend; |
73 | 74 | ||
74 | atomic_t default_mirror; /* Default mirror */ | 75 | atomic_t default_mirror; /* Default mirror */ |
@@ -211,6 +212,8 @@ static void fail_mirror(struct mirror *m, enum dm_raid1_error error_type) | |||
211 | struct mirror_set *ms = m->ms; | 212 | struct mirror_set *ms = m->ms; |
212 | struct mirror *new; | 213 | struct mirror *new; |
213 | 214 | ||
215 | ms->leg_failure = 1; | ||
216 | |||
214 | /* | 217 | /* |
215 | * error_count is used for nothing more than a | 218 | * error_count is used for nothing more than a |
216 | * simple way to tell if a device has encountered | 219 | * simple way to tell if a device has encountered |
@@ -734,8 +737,12 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) | |||
734 | dm_rh_delay(ms->rh, bio); | 737 | dm_rh_delay(ms->rh, bio); |
735 | 738 | ||
736 | while ((bio = bio_list_pop(&nosync))) { | 739 | while ((bio = bio_list_pop(&nosync))) { |
737 | map_bio(get_default_mirror(ms), bio); | 740 | if (unlikely(ms->leg_failure) && errors_handled(ms)) |
738 | generic_make_request(bio); | 741 | hold_bio(ms, bio); |
742 | else { | ||
743 | map_bio(get_default_mirror(ms), bio); | ||
744 | generic_make_request(bio); | ||
745 | } | ||
739 | } | 746 | } |
740 | } | 747 | } |
741 | 748 | ||
@@ -848,6 +855,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, | |||
848 | ms->nr_regions = dm_sector_div_up(ti->len, region_size); | 855 | ms->nr_regions = dm_sector_div_up(ti->len, region_size); |
849 | ms->in_sync = 0; | 856 | ms->in_sync = 0; |
850 | ms->log_failure = 0; | 857 | ms->log_failure = 0; |
858 | ms->leg_failure = 0; | ||
851 | atomic_set(&ms->suspend, 0); | 859 | atomic_set(&ms->suspend, 0); |
852 | atomic_set(&ms->default_mirror, DEFAULT_MIRROR); | 860 | atomic_set(&ms->default_mirror, DEFAULT_MIRROR); |
853 | 861 | ||