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

[lvm-devel] [PATCH pvmove 3/9] Add split_parent_segments_for_layer()



Add split_parent_segments_for_layer().

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.

Changes since rev2:
  * Changed function names to more specific ones
      - split_parent_segments() -> split_parent_segments_for_layer()
      - _split_parent_segment() -> _split_parent_area()
  * Added cmd_context argument to split_parent_segments_for_layer.
  * Use build_parallel_areas() to find the lowest-level segment boundaries
    for layer LV.
  * Introduced _find_seg_pvs_by_le().
  * Add incompatible boundary check in _split_parent_area()
    (e.g. the layer segments are mistakenly merged.)

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.

Changes since rev2:
  * Changed function names to more specific ones
      - split_parent_segments() -> split_parent_segments_for_layer()
      - _split_parent_segment() -> _split_parent_area()
  * Added cmd_context argument to split_parent_segments_for_layer.
  * Use build_parallel_areas() to find the lowest-level segment boundaries
    for layer LV.
  * Introduced _find_seg_pvs_by_le().
  * Add incompatible boundary check in _split_parent_area()
    (e.g. the layer segments are mistakenly merged.)

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,8 @@ int insert_layer_for_segments_on_pv(stru
 				    uint32_t status,
 				    struct pv_list *pv,
 				    struct list *lvs_changed);
+int split_parent_segments_for_layer(struct cmd_context *cmd,
+				    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/lv_manip.c
===================================================================
--- LVM2.work.orig/lib/metadata/lv_manip.c
+++ LVM2.work/lib/metadata/lv_manip.c
@@ -43,6 +43,17 @@ struct seg_pvs {
 	uint32_t len;
 };
 
+static struct seg_pvs *_find_seg_pvs_by_le(struct list *list, uint32_t le)
+{
+	struct seg_pvs *spvs;
+
+	list_iterate_items(spvs, list)
+		if (le >= spvs->le && le < spvs->le + spvs->len)
+			return spvs;
+
+	return NULL;
+}
+
 /*
  * Find first unused LV number.
  */
@@ -2002,6 +2013,96 @@ int lv_remove_single(struct cmd_context 
 	return 1;
 }
 
+/*
+ * insert_layer_for_segments_on_pv() inserts a layer segment for a segment area.
+ * However, layer modification could split the underlying layer segment.
+ * This function splits the parent area according to keep the 1:1 relationship
+ * between the parent area and the underlying layer segment.
+ * Since the layer LV might have other layers below, build_parallel_areas()
+ * is used to find the lowest-level segment boundaries.
+ */
+static int _split_parent_area(struct lv_segment *seg, uint32_t s,
+			      struct list *layer_seg_pvs)
+{
+	uint32_t parent_area_len, parent_le, layer_le;
+	uint32_t area_multiple;
+	struct seg_pvs *spvs;
+
+	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 layer segment pointed at */
+		if (!(spvs = _find_seg_pvs_by_le(layer_seg_pvs, layer_le))) {
+			log_error("layer segment for %s:%" PRIu32 " not found",
+				  seg->lv->name, parent_le);
+			return 0;
+		}
+
+		if (spvs->le != layer_le) {
+			log_error("Incompatible layer boundary: "
+				  "%s:%" PRIu32 "[%" PRIu32 "] on %s:%" PRIu32,
+				  seg->lv->name, parent_le, s,
+				  seg_lv(seg, s)->name, layer_le);
+			return 0;
+		}
+
+		if (spvs->len < parent_area_len) {
+			parent_le += spvs->len * area_multiple;
+			if (!lv_split_segment(seg->lv, parent_le))
+				return_0;
+		}
+
+		parent_area_len -= spvs->len;
+		layer_le += spvs->len;
+	}
+
+	return 1;
+}
+
+/*
+ * Split the parent LV segments if the layer LV below it is splitted.
+ */
+int split_parent_segments_for_layer(struct cmd_context *cmd,
+				    struct logical_volume *layer_lv)
+{
+	struct lv_list *lvl;
+	struct logical_volume *parent_lv;
+	struct lv_segment *seg;
+	uint32_t s;
+	struct list *parallel_areas;
+
+	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, layer_lv)))
+		return_0;
+
+	/* 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_area(seg, s, parallel_areas))
+					return_0;
+			}
+		}
+	}
+
+	return 1;
+}
+
 
 /*
  * Extend and insert a linear layer LV beneath the source segment area.

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