[lvm-devel] master - RAID: Fix segfault when attempting to replace RAID 4/5/6 device

Jonathan Brassow jbrassow at fedoraproject.org
Wed Jul 25 03:26:27 UTC 2012


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5555d2a000ed4e3d5a694896f3dc6a7290543f43
Commit:        5555d2a000ed4e3d5a694896f3dc6a7290543f43
Parent:        407198e17dc805dd9ce0583c8b1dbade71572af6
Author:        Jonathan Brassow <jbrassow at redhat.com>
AuthorDate:    Tue Jul 24 19:02:06 2012 -0500
Committer:     Jonathan Brassow <jbrassow at redhat.com>
CommitterDate: Tue Jul 24 19:02:06 2012 -0500

RAID: Fix segfault when attempting to replace RAID 4/5/6 device

Commit 8767435ef847831455fadc1f7e8f4d2d94aef0d5 allowed RAID 4/5/6
LV to be extended properly, but introduced a regression in device
replacement - a critical component of fault tolerance.

When only 1 or 2 drives are being replaced, the 'area_count' needed
can be equal to the parity_count.  The 'area_multiple' for RAID 4/5/6
was computed as 'area_count - parity_devs', which could result in
'area_multiple' being 0.  This would ultimately lead to a division by
zero error.  Therefore, in calc_area_multiple, it is important to take
into account the number of areas that are being requested - just as
we already do in _alloc_init.
---
 lib/metadata/lv_manip.c        |   11 ++++++++++-
 test/shell/lvconvert-repair.sh |   26 +++++++++++++++++++++++++-
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 0d89b4a..daa90da 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -698,8 +698,17 @@ static uint32_t _calc_area_multiple(const struct segment_type *segtype,
 		return area_count;
 
 	/* Parity RAID (e.g. RAID 4/5/6) */
-	if (segtype_is_raid(segtype) && segtype->parity_devs)
+	if (segtype_is_raid(segtype) && segtype->parity_devs) {
+		/*
+		 * As articulated in _alloc_init, we can tell by
+		 * the area_count whether a replacement drive is
+		 * being allocated; and if this is the case, then
+		 * there is no area_multiple that should be used.
+		 */
+		if (area_count <= segtype->parity_devs)
+			return 1;
 		return area_count - segtype->parity_devs;
+	}
 
 	/* Mirrored stripes */
 	if (stripes)
diff --git a/test/shell/lvconvert-repair.sh b/test/shell/lvconvert-repair.sh
index 947998c..0aeeffa 100644
--- a/test/shell/lvconvert-repair.sh
+++ b/test/shell/lvconvert-repair.sh
@@ -23,7 +23,7 @@ aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
 # fail multiple devices
 
 # 4-way, disk log => 2-way, disk log
-aux prepare_vg 5
+aux prepare_vg 8
 lvcreate -m 3 --ig -L 1 -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0
 aux disable_dev "$dev2" "$dev4"
 echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
@@ -111,4 +111,28 @@ lvconvert -y --repair $vg/mirror
 vgreduce --removemissing $vg
 aux enable_dev "$dev3"
 vgextend $vg "$dev3"
+lvremove -ff $vg
+
+# RAID5 single replace
+lvcreate --type raid5 -i 2 -l 2 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+aux wait_for_sync $vg $lv1
+aux disable_dev "$dev3"
+lvconvert -y --repair $vg/$lv1
+vgreduce --removemissing $vg
+aux enable_dev "$dev3"
+vgextend $vg "$dev3"
+lvremove -ff $vg
+
+# RAID6 double replace
+lvcreate --type raid5 -i 3 -l 2 -n $lv1 $vg \
+    "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+aux wait_for_sync $vg $lv1
+aux disable_dev "$dev4" "$dev5"
+lvconvert -y --repair $vg/$lv1
+vgreduce --removemissing $vg
+aux enable_dev "$dev4"
+aux enable_dev "$dev5"
+vgextend $vg "$dev4" "$dev5"
+lvremove -ff $vg
+
 vgremove -ff $vg




More information about the lvm-devel mailing list