diff options
author | Jonathan Brassow <jbrassow@redhat.com> | 2012-07-24 19:02:06 -0500 |
---|---|---|
committer | Jonathan Brassow <jbrassow@redhat.com> | 2012-07-24 19:02:06 -0500 |
commit | 5555d2a000ed4e3d5a694896f3dc6a7290543f43 (patch) | |
tree | b70ba0e6a36641baaa1575df935830b8989b0109 /lib | |
parent | 407198e17dc805dd9ce0583c8b1dbade71572af6 (diff) | |
download | lvm2-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.c | 11 |
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) |