From: Takahiro Yasui <tyasui@redhat.com> Date: Thu, 14 Jan 2010 23:51:44 -0500 Subject: [md] fix kernel panic releasing bio after recovery failed Message-id: <4B4FAE10.2060000@redhat.com> Patchwork-id: 22562 O-Subject: [RHEL5.5 PATCH] bz555171: fix kernel panic at releasing bio on recovery failed region Bugzilla: 555171 RH-Acked-by: Mikulas Patocka <mpatocka@redhat.com> RH-Acked-by: Alasdair G Kergon <agk@redhat.com> BZ#: ---- https://bugzilla.redhat.com/show_bug.cgi?id=555171 Description: ----------- Fix kernel panic when bio on a recovery failed region is released. When recovery process of a region failed, rh_recovery_end() function changes the state of the region from RM_RH_RECOVERING to DM_RH_NOSYNC. When recovery_complete() is executed between rh_update_states() and do_writes() in do_mirror(), bios are processed with the region state, DM_RH_NOSYNC. However, the region data is freed without checking its pending count when rh_update_states() is called next time. When bios are finished by mirror_end_io(), __rh_lookup() in rh_dec() returns NULL even though a valid return value are expected. This patch removes the state change of the recovery failed region from DM_RH_RECOVERING to DM_RH_NOSYNC in rh_recovery_end(). Upstream status: ---------------- Posted on dm-devel https://www.redhat.com/archives/dm-devel/2010-January/msg00047.html Brew Build: ----------- https://brewweb.devel.redhat.com/taskinfo?taskID=2198860 Test status: ------------ Patch was tested with kernel-2.6.18-182.el5, and confirmed that no kernel panic happens when dmsetup suspend is executed. Thanks, Takahiro Yasui Signed-off-by: Takahiro Yasui <tyasui@redhat.com> diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 6b5b527..23c1d65 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -637,10 +637,8 @@ static void rh_recovery_end(struct region *reg, int success) if (success || (rh->log->type->get_failure_response(rh->log) == DMLOG_IOERR_IGNORE)) list_add(®->list, ®->rh->recovered_regions); - else { - reg->state = RH_NOSYNC; + else list_add(®->list, ®->rh->failed_recovered_regions); - } spin_unlock_irq(&rh->region_lock); wake(rh->ms);