Signed-off-by: Mikulas Patocka --- drivers/md/dm-raid1.c | 53 ++++++++++++++++++++--------------------- drivers/md/dm-region-hash.c | 6 ---- include/linux/dm-region-hash.h | 3 -- 3 files changed, 29 insertions(+), 33 deletions(-) Index: linux-2.6.31-rc3-devel/drivers/md/dm-raid1.c =================================================================== --- linux-2.6.31-rc3-devel.orig/drivers/md/dm-raid1.c 2009-07-20 20:48:45.000000000 +0200 +++ linux-2.6.31-rc3-devel/drivers/md/dm-raid1.c 2009-07-20 20:52:26.000000000 +0200 @@ -532,7 +532,6 @@ static void write_callback(unsigned long unsigned i, ret = 0; struct bio *bio = (struct bio *) context; struct mirror_set *ms; - int uptodate = 0; unsigned long flags; ms = bio_get_m(bio)->ms; @@ -544,33 +543,23 @@ static void write_callback(unsigned long * This way we handle both writes to SYNC and NOSYNC * regions with the same code. */ - if (likely(!error)) - goto out; + if (likely(!error)) { + bio_endio(bio, ret); + return; + } for (i = 0; i < ms->nr_mirrors; i++) if (test_bit(i, &error)) fail_mirror(ms->mirror + i, DM_RAID1_WRITE_ERROR); - else - uptodate = 1; - if (unlikely(!uptodate)) { - DMERR("All replicated volumes dead, failing I/O"); - /* None of the writes succeeded, fail the I/O. */ - ret = -EIO; - } else if (errors_handled(ms)) { - /* - * Need to raise event. Since raising - * events can block, we need to do it in - * the main thread. - */ - spin_lock_irqsave(&ms->lock, flags); - bio_list_add(&ms->failures, bio); - spin_unlock_irqrestore(&ms->lock, flags); - wakeup_mirrord(ms); - return; - } -out: - bio_endio(bio, ret); + /* + * In either case we must mark the region as NOSYNC. + * That would block, so do it in the thread. + */ + spin_lock_irqsave(&ms->lock, flags); + bio_list_add(&ms->failures, bio); + spin_unlock_irqrestore(&ms->lock, flags); + wakeup_mirrord(ms); } static void do_write(struct mirror_set *ms, struct bio *bio) @@ -716,10 +705,22 @@ static void do_failures(struct mirror_se while ((bio = bio_list_pop(failures))) { if (!ms->log_failure) { ms->in_sync = 0; - dm_rh_mark_nosync(ms->rh, bio, bio->bi_size, 0); - } else { - hold_bio(ms, bio); + dm_rh_mark_nosync(ms->rh, bio); } + /* + * If we are not using dmeventd, we must fail the I/O. + * (the failed leg might come online again after reboot and + * it would be replicated back to the good leg). + * + * If all the legs are dead, fail the I/O too. + * + * If some of the legs survived, hold the bio until dmeventd + * does its job. + */ + if (!errors_handled(ms) || !get_valid_mirror(ms)) + bio_endio(bio, -EIO); + else + hold_bio(ms, bio); } } Index: linux-2.6.31-rc3-devel/drivers/md/dm-region-hash.c =================================================================== --- linux-2.6.31-rc3-devel.orig/drivers/md/dm-region-hash.c 2009-07-20 20:48:45.000000000 +0200 +++ linux-2.6.31-rc3-devel/drivers/md/dm-region-hash.c 2009-07-20 20:48:58.000000000 +0200 @@ -386,8 +386,6 @@ static void complete_resync_work(struct /* dm_rh_mark_nosync * @ms * @bio - * @done - * @error * * The bio was written on some mirror(s) but failed on other mirror(s). * We can successfully endio the bio but should avoid the region being @@ -395,8 +393,7 @@ static void complete_resync_work(struct * * This function is _not_ safe in interrupt context! */ -void dm_rh_mark_nosync(struct dm_region_hash *rh, - struct bio *bio, unsigned done, int error) +void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio) { unsigned long flags; struct dm_dirty_log *log = rh->log; @@ -428,7 +425,6 @@ void dm_rh_mark_nosync(struct dm_region_ BUG_ON(!list_empty(®->list)); spin_unlock_irqrestore(&rh->region_lock, flags); - bio_endio(bio, error); if (recovering) complete_resync_work(reg, 0); } Index: linux-2.6.31-rc3-devel/include/linux/dm-region-hash.h =================================================================== --- linux-2.6.31-rc3-devel.orig/include/linux/dm-region-hash.h 2009-07-20 20:48:45.000000000 +0200 +++ linux-2.6.31-rc3-devel/include/linux/dm-region-hash.h 2009-07-20 20:48:58.000000000 +0200 @@ -78,8 +78,7 @@ void dm_rh_dec(struct dm_region_hash *rh /* Delay bios on regions. */ void dm_rh_delay(struct dm_region_hash *rh, struct bio *bio); -void dm_rh_mark_nosync(struct dm_region_hash *rh, - struct bio *bio, unsigned done, int error); +void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio); /* * Region recovery control.