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

[lvm-devel] [PATCH pvmove 3/3] use generic mirror allocation for pvmove



Extent allocation code used to have special support for pvmove
since pvmove already knows PV area to use for mirrored segment.

This patch changes the pvmove's logic to the way similar to
what lvconvert does for mirrored LV.
Not only clean up the allocation code, it also allows
splitted allocation for destination areas.

Thanks,
-- 
Jun'ichi Nomura, NEC Corporation of America
Generalize pvmove mirror allocation.

  - Remove pvmove-special-casings (mirrored_pv, mirrroed_pe, extra_areas)
    from lv_add_segment() and its sub routines.

  - Changed the pvmove allocation logic to what lvconvert does
      BEFORE)
        1. Create an empty pvmove LV
        2. For each source area,
             2.1. Allocate destination area for given source area
             2.2. Add a segment to pvmove LV to mirror the source
                  and the destination
             2.3. Insert the segment below the original source area
      AFTER)
        1. Create an empty pvmove LV
        2. For each source area,
           Insert a linear mapping layer (pvmove LV) below the source area
        3. Allocate a mirror (destination areas) for the pvmove LV
        4. Extend the linear segment to mirror segment adding the mirror

Index: LVM2.work/lib/metadata/lv_alloc.h
===================================================================
--- LVM2.work.orig/lib/metadata/lv_alloc.h
+++ LVM2.work/lib/metadata/lv_alloc.h
@@ -57,12 +57,13 @@ int lv_add_segment(struct alloc_handle *
 		   struct logical_volume *lv,
                    const struct segment_type *segtype,
                    uint32_t stripe_size,
-                   struct physical_volume *mirrored_pv,
-                   uint32_t mirrored_pe,
                    uint32_t status,   
 		   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);
+
 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
@@ -538,17 +538,12 @@ static int _setup_alloced_segment(struct
 				  uint32_t stripe_size,
 				  const struct segment_type *segtype,
 				  struct alloced_area *aa,
-				  struct physical_volume *mirrored_pv,
-				  uint32_t mirrored_pe,
 				  uint32_t region_size,
 				  struct logical_volume *log_lv __attribute((unused)))
 {
-	uint32_t s, extents, area_multiple, extra_areas = 0;
+	uint32_t s, extents, area_multiple;
 	struct lv_segment *seg;
 
-	if (mirrored_pv)
-		extra_areas = 1;
-
 	area_multiple = calc_area_multiple(segtype, area_count);
 
 	/* log_lv gets set up elsehere */
@@ -556,22 +551,14 @@ static int _setup_alloced_segment(struct
 				     lv->le_count,
 				     aa[0].len * area_multiple,
 				     status, stripe_size, NULL,
-				     area_count + extra_areas,
+				     area_count,
 				     aa[0].len, 0u, region_size, 0u))) {
 		log_error("Couldn't allocate new LV segment.");
 		return 0;
 	}
 
-	if (extra_areas) {
-		if (!set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe)) {
-			stack;
-			return 0;
-		}
-	}
-
 	for (s = 0; s < area_count; s++) {
-		if (!set_lv_segment_area_pv(seg, s + extra_areas, aa[s].pv,
-					    aa[s].pe)) {
+		if (!set_lv_segment_area_pv(seg, s, aa[s].pv, aa[s].pe)) {
 			stack;
 			return 0;
 		}
@@ -595,8 +582,6 @@ static int _setup_alloced_segments(struc
 				   uint32_t status,
 				   uint32_t stripe_size,
 				   const struct segment_type *segtype,
-				   struct physical_volume *mirrored_pv,
-				   uint32_t mirrored_pe,
 				   uint32_t region_size,
 				   struct logical_volume *log_lv)
 {
@@ -605,7 +590,6 @@ static int _setup_alloced_segments(struc
 	list_iterate_items(aa, &alloced_areas[0]) {
 		if (!_setup_alloced_segment(lv, status, area_count,
 					    stripe_size, segtype, aa,
-					    mirrored_pv, mirrored_pe,
 					    region_size, log_lv)) {
 			stack;
 			return 0;
@@ -1222,8 +1206,6 @@ int lv_add_segment(struct alloc_handle *
 		   struct logical_volume *lv,
 		   const struct segment_type *segtype,
 		   uint32_t stripe_size,
-		   struct physical_volume *mirrored_pv,
-		   uint32_t mirrored_pe,
 		   uint32_t status,
 		   uint32_t region_size,
 		   struct logical_volume *log_lv)
@@ -1241,7 +1223,6 @@ int lv_add_segment(struct alloc_handle *
 	if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area],
 				     num_areas, status,
 				     stripe_size, segtype,
-				     mirrored_pv, mirrored_pe,
 				     region_size, log_lv)) {
 		stack;
 		return 0;
@@ -1263,6 +1244,107 @@ 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)
+{
+	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,
+					seg->log_lv,
+					seg->area_count, seg->area_len,
+					seg->chunk_size, seg->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)
+{
+	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)))
+				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)
@@ -1411,7 +1493,7 @@ int lv_extend(struct logical_volume *lv,
 
 	if (mirrors < 2) {
 		if (!lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size,
-			    NULL, 0, status, 0, NULL)) {
+			    status, 0, NULL)) {
 			stack;
 			goto out;
 		}
@@ -1421,7 +1503,7 @@ int lv_extend(struct logical_volume *lv,
 			if (!lv_add_segment(ah, m, 1, seg_lv(seg, m),
 					    get_segtype_from_string(lv->vg->cmd,
 								    "striped"),
-					    0, NULL, 0, 0, 0, NULL)) {
+					    0, 0, 0, NULL)) {
 				log_error("Aborting. Failed to extend %s.",
 					  seg_lv(seg, m)->name);
 				return 0;
Index: LVM2.work/lib/metadata/metadata-exported.h
===================================================================
--- LVM2.work.orig/lib/metadata/metadata-exported.h
+++ LVM2.work/lib/metadata/metadata-exported.h
@@ -442,9 +442,11 @@ int insert_pvmove_mirrors(struct cmd_con
 			  struct logical_volume *lv_mirr,
 			  struct list *source_pvl,
 			  struct logical_volume *lv,
-			  struct list *allocatable_pvs,
-			  alloc_policy_t alloc,
 			  struct list *lvs_changed);
+int add_pvmove_destinations(struct cmd_context *cmd,
+                            struct logical_volume *lv_mirr,
+                            struct list *allocatable_pvs,
+                            alloc_policy_t alloc);
 int remove_pvmove_mirrors(struct volume_group *vg,
 			  struct logical_volume *lv_mirr);
 struct logical_volume *find_pvmove_lv(struct volume_group *vg,
Index: LVM2.work/lib/metadata/mirror.c
===================================================================
--- LVM2.work.orig/lib/metadata/mirror.c
+++ LVM2.work/lib/metadata/mirror.c
@@ -453,7 +453,7 @@ static int _create_layers_for_mirror(str
 		if (!lv_add_segment(ah, m - first_area, 1, img_lvs[m],
 				    get_segtype_from_string(lv->vg->cmd,
 							    "striped"),
-				    0, NULL, 0, 0, 0, NULL)) {
+				    0, 0, 0, NULL)) {
 			log_error("Aborting. Failed to add mirror image segment "
 				  "to %s. Remove new LV and retry.",
 				  img_lvs[m]->name);
@@ -534,61 +534,47 @@ int add_mirror_layers(struct alloc_handl
 
 /* FIXME More generalization? */
 /*
- * Add given segment area (source area) to the pvmove LV.
- *   1. disconnect the source area from its current LV segment
- *   2. allocate destination PEs
- *   3. add the disconnected source area and allocated PEs to lv_mirr
- *   4. direct the original LV segment area to the pvmove segment
+ * Extend and insert a linear pvmove layer beneath the source segment area.
+ *
+ * (For now, it has to be "linear", because "mirror" segment type
+ *  doesn't support split.)
  */
 static int add_area_to_pvmove(struct logical_volume *lv_mirr,
-			      struct lv_segment *seg, uint32_t s,
-			      struct list *allocatable_pvs,
-			      alloc_policy_t alloc)
+			      struct lv_segment *seg, uint32_t s)
 {
-	const struct segment_type *segtype;
-	uint32_t start_le = lv_mirr->le_count;
+	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);
-	struct alloc_handle *ah;
 
-	if (!(segtype = get_segtype_from_string(seg->lv->vg->cmd, "mirror"))) {
-		stack;
-		return 0;
-	}
+	if (seg_type(seg, s) != AREA_PV)
+		return_0;
 
-	if (activation() && segtype->ops->target_present &&
-	    !segtype->ops->target_present(NULL)) {
-		log_error("%s: Required device-mapper target(s) not "
-			  "detected in your kernel", segtype->name);
-		return 0;
-	}
+	if (!(segtype = get_segtype_from_string(lv_mirr->vg->cmd, "striped")))
+		return_0;
 
 	log_very_verbose("Moving %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);
 
-	/* FIXME: pvmove cannot split the original segment */
-	alloc = ALLOC_CONTIGUOUS;
-
-	/* allocate destination extents */
-	ah = allocate_extents(lv_mirr->vg, NULL, segtype,
-			      1, 0, 0, seg->area_len,
-			      allocatable_pvs, alloc, NULL);
-	if (!ah) {
-		log_error("Unable to allocate temporary LV for pvmove.");
-		return 0;
-	}
-
 	/* remove source area from its lvsegment */
 	release_lv_segment_area(seg, s, seg->area_len);
 
 	/* add a new segment with the source and destination extents */
-	if (!lv_add_segment(ah, 0, 1, lv_mirr, segtype,
-			    seg->area_len, src_pv, src_pe,
-			    PVMOVE, 0, NULL))
+	if (!(mapseg = alloc_lv_segment(lv_mirr->vg->cmd->mem, segtype,
+					lv_mirr, lv_mirr->le_count,
+					seg->area_len, PVMOVE, 0,
+					NULL, 1, seg->area_len, 0, 0, 0)))
 		return_0;
 
-	set_lv_segment_area_lv(seg, s, lv_mirr, start_le, 0);
+	if (!set_lv_segment_area_pv(mapseg, 0, seg_pv(seg, s), seg_pe(seg, s)))
+		return_0;
+
+	list_add(&lv_mirr->segments, &mapseg->list);
+	lv_mirr->le_count += seg->area_len;
+	lv_mirr->size += seg->area_len * lv_mirr->vg->extent_size;
+
+	set_lv_segment_area_lv(seg, s, lv_mirr, mapseg->le, 0);
 
 	return 1;
 }
@@ -641,8 +627,6 @@ int insert_pvmove_mirrors(struct cmd_con
 			  struct logical_volume *lv_mirr,
 			  struct list *source_pvl,
 			  struct logical_volume *lv,
-			  struct list *allocatable_pvs,
-			  alloc_policy_t alloc,
 			  struct list *lvs_changed)
 {
 	struct lv_segment *seg;
@@ -734,8 +718,7 @@ int insert_pvmove_mirrors(struct cmd_con
 					lv_used = 1;
 				}
 	
-				if (!add_area_to_pvmove(lv_mirr, seg, s,
-							allocatable_pvs, alloc))
+				if (!add_area_to_pvmove(lv_mirr, seg, s))
 					return 0;
 
 				extent_count += seg->area_len;
@@ -753,6 +736,49 @@ int insert_pvmove_mirrors(struct cmd_con
 	return 1;
 }
 
+/*
+ * Allocate pvmove destination areas and
+ * convert "linear" pvmove LV to "mirror".
+ */
+int add_pvmove_destinations(struct cmd_context *cmd,
+			    struct logical_volume *lv_mirr,
+			    struct list *allocatable_pvs,
+			    alloc_policy_t alloc)
+{
+	struct alloc_handle *ah;
+	const struct segment_type *segtype;
+	struct list *parallel_areas;
+
+	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv_mirr)))
+		return_0;
+
+	if (!(segtype = get_segtype_from_string(cmd, "mirror")))
+		return_0;
+
+	if (activation() && segtype->ops->target_present &&
+	    !segtype->ops->target_present(NULL)) {
+		log_error("%s: Required device-mapper target(s) not "
+			  "detected in your kernel", segtype->name);
+		return 0;
+	}
+
+	/* allocate destination extents */
+	ah = allocate_extents(lv_mirr->vg, NULL, segtype, 1, 1, 0,
+			      lv_mirr->le_count,
+			      allocatable_pvs, alloc, parallel_areas);
+	if (!ah) {
+		log_error("Unable to allocate temporary LV for pvmove.");
+		return 0;
+	}
+
+	if (!lv_add_mirror_areas(ah, lv_mirr, 0)) {
+		log_error("Unable to allocate destinations of pvmove.");
+		return 0;
+	}
+
+	return 1;
+}
+
 /* Remove a temporary mirror */
 int remove_pvmove_mirrors(struct volume_group *vg,
 			  struct logical_volume *lv_mirr)
Index: LVM2.work/tools/pvmove.c
===================================================================
--- LVM2.work.orig/tools/pvmove.c
+++ LVM2.work/tools/pvmove.c
@@ -162,7 +162,6 @@ static struct logical_volume *_set_up_pv
 			continue;
 		}
 		if (!insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
-					   allocatable_pvs, alloc,
 					   *lvs_changed)) {
 			stack;
 			return NULL;
@@ -175,6 +174,9 @@ static struct logical_volume *_set_up_pv
 		return NULL;
 	}
 
+	if (!add_pvmove_destinations(cmd, lv_mirr, allocatable_pvs, alloc))
+		return_NULL;
+
 	return lv_mirr;
 }
 

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