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

[lvm-devel] [PATCH pvmove 1/6] Add insert_layer_for_segments_on_pv()



Add insert_layer_for_segments_on_pv().

The function can be used to insert a layer below the LV,
only for the segments on a specified PV.

Part of the code is derived from pvmove.

Thanks,
-- 
Jun'ichi Nomura, NEC Corporation of America
Inserting a layer below LV segments which is on a specified PV.

Index: LVM2.work/lib/metadata/metadata-exported.h
===================================================================
--- LVM2.work.orig/lib/metadata/metadata-exported.h
+++ LVM2.work/lib/metadata/metadata-exported.h
@@ -379,6 +379,16 @@ int lv_remove_single(struct cmd_context 
 int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
 	      const char *new_name);
 
+/*
+ * Functions for layer manipulation
+ */
+int insert_layer_for_segments_on_pv(struct cmd_context *cmd,
+				    struct logical_volume *lv_where,
+				    struct logical_volume *layer_lv,
+				    uint32_t status,
+				    struct pv_list *pv,
+				    struct list *lvs_changed);
+
 /* Find a PV within a given VG */
 struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
 pv_t *find_pv_in_vg_by_uuid(struct volume_group *vg, struct id *id);
Index: LVM2.work/lib/metadata/lv_manip.c
===================================================================
--- LVM2.work.orig/lib/metadata/lv_manip.c
+++ LVM2.work/lib/metadata/lv_manip.c
@@ -1900,3 +1900,202 @@ int lv_remove_single(struct cmd_context 
 	log_print("Logical volume \"%s\" successfully removed", lv->name);
 	return 1;
 }
+
+
+/*
+ * Extend and insert a linear layer LV beneath the source segment area.
+ */
+static int _extend_layer_lv(struct logical_volume *layer_lv,
+			    struct lv_segment *seg, uint32_t s,
+			    uint32_t status)
+{
+	struct lv_segment *mapseg;
+	struct segment_type *segtype;
+	struct physical_volume *src_pv = seg_pv(seg, s);
+	uint32_t src_pe = seg_pe(seg, s);
+
+	if (seg_type(seg, s) != AREA_PV && seg_type(seg, s) != AREA_LV)
+		return_0;
+
+	if (!(segtype = get_segtype_from_string(layer_lv->vg->cmd, "striped")))
+		return_0;
+
+	log_very_verbose("Inserting %s:%u-%u of %s/%s", pv_dev_name(src_pv),
+			 src_pe, src_pe + seg->area_len - 1,
+			 seg->lv->vg->name, seg->lv->name);
+
+	/* remove source area from its lvsegment */
+	release_lv_segment_area(seg, s, seg->area_len);
+
+	/* allocate a new segment */
+	if (!(mapseg = alloc_lv_segment(layer_lv->vg->cmd->mem, segtype,
+					layer_lv, layer_lv->le_count,
+					seg->area_len, status, 0,
+					NULL, 1, seg->area_len, 0, 0, 0)))
+		return_0;
+
+	/* map the new segment to the original underlying are */
+	if (seg_type(seg, s) == AREA_PV) {
+		if (!set_lv_segment_area_pv(mapseg, 0,
+					    seg_pv(seg, s), seg_pe(seg, s)))
+			return_0;
+	} else if (seg_type(seg, s) == AREA_LV)
+		set_lv_segment_area_lv(mapseg, 0,
+				       seg_lv(seg, s), seg_le(seg, s), 0);
+
+	/* add the new segment to the layer LV */
+	list_add(&layer_lv->segments, &mapseg->list);
+	layer_lv->le_count += seg->area_len;
+	layer_lv->size += seg->area_len * layer_lv->vg->extent_size;
+
+	/* map the original area to the new segment */
+	set_lv_segment_area_lv(seg, s, layer_lv, mapseg->le, 0);
+
+	return 1;
+}
+
+/*
+ * Match the segment area to PEs in the pvl
+ * (the segment area boundary should be aligned to PE ranges by
+ *  _adjust_layer_segments() so that there is no partial overlap.)
+ */
+static int _seg_pv_match(struct lv_segment *seg, uint32_t s,
+			 struct pv_list *pvl)
+{
+	struct pe_range *per;
+	uint32_t pe_start, per_end;
+
+	if (!pvl)
+		return 1;
+
+	if (seg_type(seg, s) != AREA_PV || seg_dev(seg, s) != pvl->pv->dev)
+		return 0;
+
+	pe_start = seg_pe(seg, s);
+
+	/* Do these PEs match to any of the PEs in pvl? */
+	list_iterate_items(per, pvl->pe_ranges) {
+		per_end = per->start + per->count - 1;
+
+		if ((pe_start < per->start) || (pe_start > per_end))
+			continue;
+
+		log_debug("Matched PE range %u-%u against "
+			  "%s %u len %u", per->start, per_end,
+			  dev_name(seg_dev(seg, s)), seg_pe(seg, s),
+			  seg->area_len);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * If the layer is going to be inserted for segments on a pv,
+ * check the segment boundaries and split the segment if it's
+ * different from the boundary of underlying PV segment.
+ */
+static int _align_segment_boundary(struct logical_volume *lv_where,
+				   struct pv_list *pvl)
+{
+	struct lv_segment *seg;
+	struct pe_range *per;
+	uint32_t pe_start, pe_end, per_end, stripe_multiplier, s;
+
+	if (!pvl)
+		return 1;
+
+	/* Split LV segments to match PE ranges */
+	list_iterate_items(seg, &lv_where->segments) {
+		for (s = 0; s < seg->area_count; s++) {
+			if (seg_type(seg, s) != AREA_PV ||
+			    seg_dev(seg, s) != pvl->pv->dev)
+				continue;
+
+			/* Do these PEs match with the condition? */
+			list_iterate_items(per, pvl->pe_ranges) {
+				pe_start = seg_pe(seg, s);
+				pe_end = pe_start + seg->area_len - 1;
+				per_end = per->start + per->count - 1;
+
+				/* No overlap? */
+				if ((pe_end < per->start) ||
+				    (pe_start > per_end))
+					continue;
+
+				if (seg_is_striped(seg))
+					stripe_multiplier = seg->area_count;
+				else
+					stripe_multiplier = 1;
+
+				if ((per->start != pe_start &&
+				     per->start > pe_start) &&
+				    !lv_split_segment(lv_where, seg->le +
+						      (per->start - pe_start) *
+						      stripe_multiplier)) {
+					stack;
+					return 0;
+				}
+
+				if ((per_end != pe_end &&
+				     per_end < pe_end) &&
+				    !lv_split_segment(lv_where, seg->le +
+						      (per_end - pe_start + 1) *
+						      stripe_multiplier)) {
+					stack;
+					return 0;
+				}
+			}
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * Insert linear LV segments below lv_where and
+ * the inserted segments will be appended to layer_lv,
+ * only if the underlying PV matches to pvl (if not empty),
+ *
+ * If the layer is inserted, lv_where is added to lvs_changed.
+ */
+int insert_layer_for_segments_on_pv(struct cmd_context *cmd,
+				    struct logical_volume *lv_where,
+				    struct logical_volume *layer_lv,
+				    uint32_t status,
+				    struct pv_list *pvl,
+				    struct list *lvs_changed)
+{
+	struct lv_segment *seg;
+	struct lv_list *lvl;
+	int lv_used = 0;
+	uint32_t s;
+
+	if (!_align_segment_boundary(lv_where, pvl))
+		return_0;
+
+	/* Work through all segments on the supplied PV */
+	list_iterate_items(seg, &lv_where->segments) {
+		for (s = 0; s < seg->area_count; s++) {
+			if (!_seg_pv_match(seg, s, pvl))
+				continue;
+
+			/* First time, add LV to list of LVs affected */
+			if (!lv_used) {
+				if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
+					log_error("lv_list alloc failed");
+					return 0;
+				}
+				lvl->lv = lv_where;
+				list_add(lvs_changed, &lvl->list);
+				lv_used = 1;
+			}
+
+			if (!_extend_layer_lv(layer_lv, seg, s, status))
+				return 0;
+		}
+	}
+
+	return 1;
+}

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