summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJonathan Brassow <jbrassow@redhat.com>2012-07-24 19:02:06 -0500
committerJonathan Brassow <jbrassow@redhat.com>2012-07-24 19:02:06 -0500
commit5555d2a000ed4e3d5a694896f3dc6a7290543f43 (patch)
treeb70ba0e6a36641baaa1575df935830b8989b0109 /lib
parent407198e17dc805dd9ce0583c8b1dbade71572af6 (diff)
downloadlvm2-5555d2a000ed4e3d5a694896f3dc6a7290543f43.tar.gz
lvm2-5555d2a000ed4e3d5a694896f3dc6a7290543f43.tar.xz
lvm2-5555d2a000ed4e3d5a694896f3dc6a7290543f43.zip
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/metadata/lv_manip.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 0d89b4ab..daa90da9 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)