summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/metadata/lv_manip.c41
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;