From 9bdfb30720ee7a5ea66bd47d5f5834fffce73681 Mon Sep 17 00:00:00 2001 From: Jonathan Earl Brassow Date: Thu, 23 Feb 2012 03:57:23 +0000 Subject: [PATCH] Fix allocation code to allow replacement of single RAID 4/5/6 device. The code fail to account for the case where we just need a single device in a RAID 4/5/6 array. There is no good way to tell the allocation functions that we don't need parity devices when we are allocating just a single device. So, I've used a bit of a hack. If we are allocating an area_count that is <= the parity count, then we can assume we are simply allocating a replacement device (i.e. no need to include parity devices in the calculations). This should make sense in most cases. If we need to allocate replacement devices due to failure (or moving), we will never allocate more than the parity count; or we would cause the array to become unusable. If we are creating a new device, we should always create more stripes than parity devices. --- WHATS_NEW | 1 + lib/metadata/lv_manip.c | 8 +++++--- lib/metadata/raid_manip.c | 6 +++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 2b22b3164..6a55c8b3f 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.93 - ==================================== + Fix allocation code to allow replacement of single RAID 4/5/6 device. Check all tags and LV names are in a valid form in vg_validate. Add tmpfiles.d style configuration for lvm2 lock and run directory. Add configure --with-tmpfilesdir for dir holding volatile-file configuration. diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index a8a52a49a..a743c075f 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -737,7 +737,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd, struct dm_list *parallel_areas) { struct alloc_handle *ah; - uint32_t s, area_count, alloc_count; + uint32_t s, area_count, alloc_count, parity_count; size_t size = 0; /* FIXME Caller should ensure this */ @@ -752,7 +752,9 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd, area_count = stripes; size = sizeof(*ah); - alloc_count = area_count + segtype->parity_devs; + parity_count = (area_count <= segtype->parity_devs) ? 0 : + segtype->parity_devs; + alloc_count = area_count + parity_count; if (segtype_is_raid(segtype) && metadata_area_count) /* RAID has a meta area for each device */ alloc_count *= 2; @@ -787,7 +789,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd, else ah->new_extents = 0; ah->area_count = area_count; - ah->parity_count = segtype->parity_devs; + ah->parity_count = parity_count; ah->region_size = region_size; ah->alloc = alloc; ah->area_multiple = _calc_area_multiple(segtype, area_count, stripes); diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c index 50918a8cb..e60af1769 100644 --- a/lib/metadata/raid_manip.c +++ b/lib/metadata/raid_manip.c @@ -493,6 +493,7 @@ static int _alloc_image_components(struct logical_volume *lv, { uint32_t s; uint32_t region_size; + uint32_t extents; struct lv_segment *seg = first_seg(lv); const struct segment_type *segtype; struct alloc_handle *ah; @@ -518,8 +519,11 @@ static int _alloc_image_components(struct logical_volume *lv, else if (!(segtype = get_segtype_from_string(lv->vg->cmd, "raid1"))) return_0; + extents = (segtype->parity_devs) ? + (lv->le_count / (seg->area_count - segtype->parity_devs)) : + lv->le_count; if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0, count, count, - region_size, lv->le_count, pvs, + region_size, extents, pvs, lv->alloc, parallel_areas))) return_0;