[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[lvm-devel] [PATCH pvmove 3/6] Add split_parent_segments()



Add split_parent_segments().

The function walks through LVs in the VG.
For each lv segment, check if it's on multiple layer segments.
If so, split the lv segment so that only 1 layer segment is under
the lv segment.

For example, a segment on pvmove layer is a source segment of the move.
If there are multiple underlying pvmove segments, it means the
destination is splitted and the source segment should be splitted
when the move completes.
The function is a helper for cases like this.

This is a generalized version of _split_source_lv_segment()
in the previous post:
https://www.redhat.com/archives/lvm-devel/2007-November/msg00035.html

Thanks,
-- 
Jun'ichi Nomura, NEC Corporation of America
Split segments of parent LVs if the inserted layer segment is splitted.

e.g. if pvmove is inserted but the destination segment is splitted,
     the segment to be moved has to be splitted.

Index: LVM2.work/lib/metadata/metadata-exported.h
===================================================================
--- LVM2.work.orig/lib/metadata/metadata-exported.h
+++ LVM2.work/lib/metadata/metadata-exported.h
@@ -388,6 +388,7 @@ int insert_layer_for_segments_on_pv(stru
 				    uint32_t status,
 				    struct pv_list *pv,
 				    struct list *lvs_changed);
+int split_parent_segments(struct logical_volume *layer_lv);
 
 /* Find a PV within a given VG */
 struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
Index: LVM2.work/lib/metadata/mirror.c
===================================================================
--- LVM2.work.orig/lib/metadata/mirror.c
+++ LVM2.work/lib/metadata/mirror.c
@@ -563,6 +563,75 @@ static int _alloc_and_insert_pvmove_seg(
 	return 1;
 }
 
+static int _split_parent_segment(struct logical_volume *layer_lv,
+				 struct lv_segment *seg, uint32_t s)
+{
+	struct lv_segment *layer_seg;
+	uint32_t parent_area_len, parent_le, layer_le;
+	uint32_t area_multiple;
+
+	if (seg_is_striped(seg))
+		area_multiple = seg->area_count;
+	else
+		area_multiple = 1;
+
+	parent_area_len = seg->area_len;
+	parent_le = seg->le;
+	layer_le = seg_le(seg, s);
+
+	while (parent_area_len > 0) {
+		/* Find the mirror segment pointed at */
+		if (!(layer_seg = find_seg_by_le(layer_lv, layer_le))) {
+			log_error("layer segment for %s:%" PRIu32 " not found",
+				  seg->lv->name, parent_le);
+			return 0;
+		}
+
+		if (layer_seg->area_len < parent_area_len) {
+			parent_le += layer_seg->area_len * area_multiple;
+			if (!lv_split_segment(seg->lv, parent_le))
+				return_0;
+		}
+
+		parent_area_len -= layer_seg->area_len;
+		layer_le += layer_seg->area_len;
+	}
+
+	return 1;
+}
+
+/*
+ * Split the parent LV segments if the layer LV below it is splitted.
+ */
+int split_parent_segments(struct logical_volume *layer_lv)
+{
+	struct lv_list *lvl;
+	struct logical_volume *parent_lv;
+	struct lv_segment *seg;
+	uint32_t s;
+
+	/* Loop through all LVs except itself */
+	list_iterate_items(lvl, &layer_lv->vg->lvs) {
+		parent_lv = lvl->lv;
+		if (parent_lv == layer_lv)
+			continue;
+
+		/* Find all segments that point at the layer LV */
+		list_iterate_items(seg, &parent_lv->segments) {
+			for (s = 0; s < seg->area_count; s++) {
+				if (seg_type(seg, s) != AREA_LV ||
+				    seg_lv(seg, s) != layer_lv)
+					continue;
+
+				if (!_split_parent_segment(layer_lv, seg, s))
+					return_0;
+			}
+		}
+	}
+
+	return 1;
+}
+
 /* 
  * Replace any LV segments on given PV with temporary mirror.
  * Returns list of LVs changed.

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]