diff options
Diffstat (limited to 'lib/metadata/lv_manip.c')
-rw-r--r-- | lib/metadata/lv_manip.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 298d307f3..9a9e547be 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -4454,6 +4454,38 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah, return 1; } +/* Check either RAID images and metas are being allocated redundantly. */ +static int _lv_raid_redundant(struct logical_volume *lv, + struct dm_list *allocatable_pvs, int meta) +{ + uint32_t nlvs, s; + struct lv_segment *seg = first_seg(lv); + struct pv_list *pvl; + + if (meta && !seg->meta_areas) + return 1; + + dm_list_iterate_items(pvl, allocatable_pvs) { + nlvs = 0; + + for (s = 0; s < seg->area_count; s++) { + struct logical_volume *slv = meta ? seg_metalv(seg, s) : seg_lv(seg, s); + + if (slv && lv_is_on_pv(slv, pvl->pv) && nlvs++) + return 0; + } + } + + return 1; +} + +/* Check both RAID images and metas are being allocated redundantly. */ +static int _lv_raid_redundant_allocation(struct logical_volume *lv, struct dm_list *allocatable_pvs) +{ + return _lv_raid_redundant(lv, allocatable_pvs, 0) && + _lv_raid_redundant(lv, allocatable_pvs, 1); +} + /* * Entry point for single-step LV allocation + extension. * Extents is the number of logical extents to append to the LV unless @@ -4556,6 +4588,15 @@ int lv_extend(struct logical_volume *lv, mirrors, stripes, stripe_size))) goto_out; + if (segtype_is_raid(segtype) && + alloc != ALLOC_ANYWHERE && + !(r = _lv_raid_redundant_allocation(lv, allocatable_pvs))) { + log_error("Insufficient suitable allocatable extents for logical volume %s", display_lvname(lv)); + if (!lv_remove(lv) || !vg_write(lv->vg) || !vg_commit(lv->vg)) + return_0; + goto out; + } + if (lv_raid_has_integrity(lv)) { if (!lv_extend_integrity_in_raid(lv, allocatable_pvs)) { r = 0; |