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