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

[lvm-devel] [PATCH pvmove 2/6] Add convert_segments_mirrored()



Add convert_segments_mirrored().

The function converts each segment in the LV to mirrored.

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

Thanks,
-- 
Jun'ichi Nomura, NEC Corporation of America
Function to convert each segment of LV to mirrored.

Index: LVM2.work/lib/metadata/metadata-exported.h
===================================================================
--- LVM2.work.orig/lib/metadata/metadata-exported.h
+++ LVM2.work/lib/metadata/metadata-exported.h
@@ -443,6 +443,11 @@ int create_mirror_layers(struct alloc_ha
 			 uint32_t status,
 			 uint32_t region_size,
 			 struct logical_volume *log_lv);
+int convert_segments_mirrored(struct cmd_context *cmd,
+			      struct logical_volume *lv,
+			      uint32_t mirrors, uint32_t region_size,
+			      struct list *allocatable_pvs,
+			      alloc_policy_t alloc);
 
 int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
 			 struct list *removable_pvs, unsigned remove_log);
Index: LVM2.work/lib/metadata/mirror.c
===================================================================
--- LVM2.work.orig/lib/metadata/mirror.c
+++ LVM2.work/lib/metadata/mirror.c
@@ -943,3 +943,42 @@ int fixup_imported_mirrors(struct volume
 	return 1;
 }
 
+/*
+ * Convert "linear" LV to "mirror".
+ */
+int convert_segments_mirrored(struct cmd_context *cmd,
+			      struct logical_volume *lv,
+			      uint32_t mirrors,
+			      uint32_t region_size,
+			      struct list *allocatable_pvs,
+			      alloc_policy_t alloc)
+{
+	struct alloc_handle *ah;
+	const struct segment_type *segtype;
+	struct list *parallel_areas;
+	uint32_t adjusted_region_size;
+
+	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
+		return_0;
+
+	if (!(segtype = get_segtype_from_string(cmd, "mirror")))
+		return_0;
+
+	adjusted_region_size = adjusted_mirror_region_size(lv->vg->extent_size,
+							   lv->le_count,
+							   region_size);
+
+	/* allocate destination extents */
+	ah = allocate_extents(lv->vg, NULL, segtype,
+			      1, mirrors, 0, lv->le_count,
+			      allocatable_pvs, alloc, 1, parallel_areas);
+	if (!ah) {
+		log_error("Unable to allocate mirror extents.");
+		return 0;
+	}
+
+	if (!lv_add_mirror_areas(ah, lv, 0, adjusted_region_size))
+		return_0;
+
+	return 1;
+}
Index: LVM2.work/lib/metadata/lv_alloc.h
===================================================================
--- LVM2.work.orig/lib/metadata/lv_alloc.h
+++ LVM2.work/lib/metadata/lv_alloc.h
@@ -64,6 +64,10 @@ int lv_add_segment(struct alloc_handle *
 		   uint32_t region_size,
                    struct logical_volume *log_lv);
 
+int lv_add_mirror_areas(struct alloc_handle *ah,
+			struct logical_volume *lv, uint32_t le,
+			uint32_t region_size);
+
 int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv);
 int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status,
                            uint32_t extents, const struct segment_type *segtype);
Index: LVM2.work/lib/metadata/lv_manip.c
===================================================================
--- LVM2.work.orig/lib/metadata/lv_manip.c
+++ LVM2.work/lib/metadata/lv_manip.c
@@ -1267,6 +1267,111 @@ int lv_add_segment(struct alloc_handle *
 }
 
 /*
+ * "mirror" segment type doesn't support split.
+ * So, when adding mirrors to linear LV segment, first split it,
+ * then convert it to "mirror" and add areas.
+ */
+static struct lv_segment *_convert_seg_to_mirror(struct lv_segment *seg,
+						 uint32_t region_size,
+						 struct logical_volume *log_lv)
+{
+	struct lv_segment *newseg;
+	uint32_t s;
+
+	if (seg->segtype != get_segtype_from_string(seg->lv->vg->cmd, "striped")) {
+		log_error("Can't convert non-striped segment to mirrored.");
+		return NULL;
+	}
+
+	if (seg->area_count > 1) {
+		log_error("Can't convert striped segment with multiple areas "
+			  "to mirrored.");
+		return NULL;
+	}
+
+	if (!(newseg = alloc_lv_segment(seg->lv->vg->cmd->mem,
+					get_segtype_from_string(seg->lv->vg->cmd, "mirror"),
+					seg->lv, seg->le, seg->len,
+					seg->status, seg->stripe_size,
+					log_lv,
+					seg->area_count, seg->area_len,
+					seg->chunk_size, region_size,
+					seg->extents_copied))) {
+		log_error("Couldn't allocate converted LV segment");
+		return NULL;
+	}
+
+	for (s = 0; s < seg->area_count; s++)
+		if (!move_lv_segment_area(newseg, s, seg, s))
+			return_NULL;
+
+	list_add(&seg->list, &newseg->list);
+	list_del(&seg->list);
+
+	return newseg;
+}
+
+/*
+ * Add new areas to mirrored segments
+ */
+int lv_add_mirror_areas(struct alloc_handle *ah,
+			struct logical_volume *lv, uint32_t le,
+			uint32_t region_size)
+{
+	struct alloced_area *aa;
+	struct lv_segment *seg;
+	uint32_t current_le = le;
+	uint32_t s, old_area_count, new_area_count;
+	struct segment_type *mirror_segtype;
+
+	mirror_segtype = get_segtype_from_string(lv->vg->cmd, "mirror");
+
+	list_iterate_items(aa, &ah->alloced_areas[0]) {
+		if (!(seg = find_seg_by_le(lv, current_le))) {
+			log_error("Failed to find segment for %s extent %"
+				  PRIu32, lv->name, current_le);
+			return 0;
+		}
+
+		/* Allocator assures aa[0].len <= seg->area_len */
+		if (aa[0].len < seg->area_len) {
+			if (!lv_split_segment(lv, seg->le + aa[0].len)) {
+				log_error("Failed to split segment at %s "
+					  "extent %" PRIu32, lv->name, le);
+				return 0;
+			}
+		}
+
+		if (seg->segtype != mirror_segtype)
+			if (!(seg = _convert_seg_to_mirror(seg, region_size,
+							   NULL)))
+				return_0;
+
+		old_area_count = seg->area_count;
+		new_area_count = old_area_count + ah->area_count;
+
+		if (!_lv_segment_add_areas(lv, seg, new_area_count))
+			return_0;
+
+		for (s = 0; s < ah->area_count; s++) {
+			if (!set_lv_segment_area_pv(seg, s + old_area_count,
+						    aa[s].pv, aa[s].pe))
+				return_0;
+		}
+
+		current_le += seg->area_len;
+	}
+
+	lv->status |= MIRRORED;
+
+	if (lv->vg->fid->fmt->ops->lv_setup &&
+	    !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv))
+		return_0;
+
+	return 1;
+}
+
+/*
  * Turn an empty LV into a mirror log.
  */
 int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)

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