public inbox for lvm2-cvs@sourceware.org
help / color / mirror / Atom feed
* LVM2 ./WHATS_NEW lib/metadata/lv_alloc.h lib/m ...
@ 2008-12-19 15:24 mbroz
  0 siblings, 0 replies; 3+ messages in thread
From: mbroz @ 2008-12-19 15:24 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	mbroz@sourceware.org	2008-12-19 15:24:53

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_alloc.h lv_manip.c metadata.h mirror.c 

Log message:
	Calculate mirror log size instead of hardcoding 1 extent size.
	
	It fails for 1k PE now.
	
	Patch adds log_region_size into allocation habdle struct
	and use it in _alloc_parallel_area() for proper log size calculation
	instead of hardcoded 1 extent - which can fail.
	
	Reproducer for incorrect log size calculation:
	DEV=/dev/sd[bcd]
	
	pvcreate $DEV
	vgcreate -s 1k vg_test $DEV
	lvcreate -m1 -L 12M -n mirr vg_test
	
	https://bugzilla.redhat.com/show_bug.cgi?id=477040
	
	The log size calculation is mostly copied from kernel code.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1012&r2=1.1013
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_alloc.h.diff?cvsroot=lvm2&r1=1.22&r2=1.23
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.160&r2=1.161
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.185&r2=1.186
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.79&r2=1.80

--- LVM2/WHATS_NEW	2008/12/19 15:23:03	1.1012
+++ LVM2/WHATS_NEW	2008/12/19 15:24:52	1.1013
@@ -1,5 +1,6 @@
 Version 2.02.44 - 
 ====================================
+  Calculate mirror log size instead of using 1 extent.
   Check if requested major/minor pair is already used.
   Fix incorrect return value in help function.
   Fix vgrename using UUID in case there are VGs with the same name.
--- LVM2/lib/metadata/lv_alloc.h	2008/11/03 22:14:29	1.22
+++ LVM2/lib/metadata/lv_alloc.h	2008/12/19 15:24:53	1.23
@@ -47,7 +47,7 @@
                                       const struct segment_type *segtype,
                                       uint32_t stripes,
                                       uint32_t mirrors, uint32_t log_count,
-				      uint32_t extents,
+				      uint32_t log_region_size, uint32_t extents,
                                       struct dm_list *allocatable_pvs,
 				      alloc_policy_t alloc,
 				      struct dm_list *parallel_areas);
--- LVM2/lib/metadata/lv_manip.c	2008/12/04 15:54:27	1.160
+++ LVM2/lib/metadata/lv_manip.c	2008/12/19 15:24:53	1.161
@@ -516,6 +516,7 @@
 	uint32_t area_count;		/* Number of parallel areas */
 	uint32_t area_multiple;		/* seg->len = area_len * area_multiple */
 	uint32_t log_count;		/* Number of parallel 1-extent logs */
+	uint32_t log_region_size;	/* region size for log device */
 	uint32_t total_area_len;	/* Total number of parallel extents */
 
 	struct dm_list *parallel_areas;	/* PVs to avoid */
@@ -543,6 +544,7 @@
 					uint32_t mirrors,
 					uint32_t stripes,
 					uint32_t log_count,
+					uint32_t log_region_size,
 					struct dm_list *parallel_areas)
 {
 	struct alloc_handle *ah;
@@ -582,6 +584,7 @@
 
 	ah->area_count = area_count;
 	ah->log_count = log_count;
+	ah->log_region_size = log_region_size;
 	ah->alloc = alloc;
 	ah->area_multiple = calc_area_multiple(segtype, area_count);
 
@@ -704,6 +707,28 @@
 }
 
 /*
+ * Returns log device size in extents, algorithm from kernel code
+ */
+#define BYTE_SHIFT 3
+static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint32_t area_len)
+{
+	size_t area_size, bitset_size, log_size, region_count;
+
+	area_size = area_len * pe_size;
+	region_count = dm_div_up(area_size, region_size);
+
+	/* Work out how many "unsigned long"s we need to hold the bitset. */
+	bitset_size = dm_round_up(region_count, sizeof(uint32_t) << BYTE_SHIFT);
+	bitset_size >>= BYTE_SHIFT;
+
+	/* Log device holds both header and bitset. */
+	log_size = dm_round_up((MIRROR_LOG_OFFSET << SECTOR_SHIFT) + bitset_size, 1 << SECTOR_SHIFT);
+	log_size >>= SECTOR_SHIFT;
+
+	return dm_div_up(log_size, pe_size);
+}
+
+/*
  * This function takes a list of pv_areas and adds them to allocated_areas.
  * If the complete area is not needed then it gets split.
  * The part used is removed from the pv_map so it can't be allocated twice.
@@ -745,7 +770,9 @@
 	if (log_area) {
 		ah->log_area.pv = log_area->map->pv;
 		ah->log_area.pe = log_area->start;
-		ah->log_area.len = MIRROR_LOG_SIZE;	/* FIXME Calculate & check this */
+		ah->log_area.len = mirror_log_extents(ah->log_region_size,
+						      pv_pe_size(log_area->map->pv),
+						      area_len);
 		consume_pv_area(log_area, ah->log_area.len);
 	}
 
@@ -817,7 +844,7 @@
 
 	/* FIXME only_single_area_segments used as workaround to skip log LV - needs new param? */
 	if (!only_single_area_segments && seg_is_mirrored(seg) && seg->log_lv) {
-		if (!(r = _for_each_pv(cmd, seg->log_lv, 0, MIRROR_LOG_SIZE,
+		if (!(r = _for_each_pv(cmd, seg->log_lv, 0, seg->log_lv->le_count?:1,
 				       NULL, 0, 0, 0, only_single_area_segments,
 				       fn, data)))
 			stack;
@@ -1256,7 +1283,7 @@
 				      const struct segment_type *segtype,
 				      uint32_t stripes,
 				      uint32_t mirrors, uint32_t log_count,
-				      uint32_t extents,
+				      uint32_t log_region_size, uint32_t extents,
 				      struct dm_list *allocatable_pvs,
 				      alloc_policy_t alloc,
 				      struct dm_list *parallel_areas)
@@ -1282,7 +1309,7 @@
 		alloc = vg->alloc;
 
 	if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, mirrors,
-			       stripes, log_count, parallel_areas)))
+			       stripes, log_count, log_region_size, parallel_areas)))
 		return_NULL;
 
 	if (!segtype_is_virtual(segtype) &&
@@ -1577,7 +1604,7 @@
 	if (segtype_is_virtual(segtype))
 		return lv_add_virtual_segment(lv, status, extents, segtype);
 
-	if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0,
+	if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0, 0,
 				    extents, allocatable_pvs, alloc, NULL)))
 		return_0;
 
--- LVM2/lib/metadata/metadata.h	2008/12/04 15:54:27	1.185
+++ LVM2/lib/metadata/metadata.h	2008/12/19 15:24:53	1.186
@@ -34,7 +34,18 @@
 //#define STRIPE_SIZE_LIMIT ((UINT_MAX >> 2) + 1)
 //#define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT)	/* 512 KB in sectors */
 //#define MAX_RESTRICTED_LVS 255	/* Used by FMT_RESTRICTED_LVIDS */
-#define MIRROR_LOG_SIZE 1	/* Extents */
+#define MIRROR_LOG_OFFSET	2	/* sectors */
+
+/*
+ * Ceiling(n / sz)
+ */
+#define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz))
+
+/*
+ * Ceiling(n / size) * size
+ */
+#define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
+
 
 /* Various flags */
 /* Note that the bits no longer necessarily correspond to LVM1 disk format */
--- LVM2/lib/metadata/mirror.c	2008/11/03 22:14:29	1.79
+++ LVM2/lib/metadata/mirror.c	2008/12/19 15:24:53	1.80
@@ -1171,7 +1171,7 @@
 							   lv->le_count,
 							   region_size);
 
-	if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1, mirrors, 0,
+	if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1, mirrors, 0, 0,
 				    lv->le_count, allocatable_pvs, alloc,
 				    parallel_areas))) {
 		log_error("Unable to allocate mirror extents for %s.", lv->name);
@@ -1388,7 +1388,7 @@
 
 	/* allocate destination extents */
 	ah = allocate_extents(lv->vg, NULL, segtype,
-			      0, 0, log_count, 0,
+			      0, 0, log_count, region_size, 0,
 			      allocatable_pvs, alloc, parallel_areas);
 	if (!ah) {
 		log_error("Unable to allocate extents for mirror log.");
@@ -1443,7 +1443,7 @@
 		return_0;
 
 	ah = allocate_extents(lv->vg, NULL, segtype,
-			      stripes, mirrors, log_count, lv->le_count,
+			      stripes, mirrors, log_count, region_size, lv->le_count,
 			      allocatable_pvs, alloc, parallel_areas);
 	if (!ah) {
 		log_error("Unable to allocate extents for mirror(s).");


^ permalink raw reply	[flat|nested] 3+ messages in thread

* LVM2 ./WHATS_NEW lib/metadata/lv_alloc.h lib/m ...
@ 2010-03-01 20:00 agk
  0 siblings, 0 replies; 3+ messages in thread
From: agk @ 2010-03-01 20:00 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2010-03-01 20:00:21

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_alloc.h lv_manip.c mirror.c 

Log message:
	Extend core allocation code in preparation for mirrored log areas.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1440&r2=1.1441
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_alloc.h.diff?cvsroot=lvm2&r1=1.25&r2=1.26
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.209&r2=1.210
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.107&r2=1.108

--- LVM2/WHATS_NEW	2010/02/26 13:07:43	1.1440
+++ LVM2/WHATS_NEW	2010/03/01 20:00:20	1.1441
@@ -1,5 +1,6 @@
 Version 2.02.62 -
 ====================================
+  Extend core allocation code in preparation for mirrored log areas.
   Rewrite clvmd init script.
   Remove lvs_in_vg_activated_by_uuid_only call.
   Run device info query device by uuid only.
--- LVM2/lib/metadata/lv_alloc.h	2009/12/04 17:48:32	1.25
+++ LVM2/lib/metadata/lv_alloc.h	2010/03/01 20:00:21	1.26
@@ -58,8 +58,7 @@
                    const struct segment_type *segtype,
                    uint32_t stripe_size,
                    uint64_t status,
-		   uint32_t region_size,
-                   struct logical_volume *log_lv);
+		   uint32_t region_size);
 
 int lv_add_mirror_areas(struct alloc_handle *ah,
 			struct logical_volume *lv, uint32_t le,
--- LVM2/lib/metadata/lv_manip.c	2010/02/17 23:36:45	1.209
+++ LVM2/lib/metadata/lv_manip.c	2010/03/01 20:00:21	1.210
@@ -507,16 +507,21 @@
 	struct dm_pool *mem;
 
 	alloc_policy_t alloc;		/* Overall policy */
+	uint32_t new_extents;		/* Number of new extents required */
 	uint32_t area_count;		/* Number of parallel areas */
 	uint32_t area_multiple;		/* seg->len = area_len * area_multiple */
-	uint32_t log_count;		/* Number of parallel 1-extent logs */
-	uint32_t log_region_size;	/* region size for log device */
+	uint32_t log_area_count;	/* Number of parallel logs */
+	uint32_t log_len;		/* Length of log */
+	uint32_t region_size;		/* Mirror region size */
 	uint32_t total_area_len;	/* Total number of parallel extents */
 
 	struct dm_list *parallel_areas;	/* PVs to avoid */
 
-	struct alloced_area log_area;	/* Extent used for log */
-	struct dm_list alloced_areas[0];	/* Lists of areas in each stripe */
+	/*
+	 * Contains area_count lists of areas allocated to data stripes
+	 * followed by log_area_count lists of areas allocated to log stripes.
+	 */
+	struct dm_list alloced_areas[0];
 };
 
 static uint32_t calc_area_multiple(const struct segment_type *segtype,
@@ -529,16 +534,40 @@
 }
 
 /*
+ * Returns log device size in extents, algorithm from kernel code
+ */
+#define BYTE_SHIFT 3
+static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint32_t area_len)
+{
+	size_t area_size, bitset_size, log_size, region_count;
+
+	area_size = area_len * pe_size;
+	region_count = dm_div_up(area_size, region_size);
+
+	/* Work out how many "unsigned long"s we need to hold the bitset. */
+	bitset_size = dm_round_up(region_count, sizeof(uint32_t) << BYTE_SHIFT);
+	bitset_size >>= BYTE_SHIFT;
+
+	/* Log device holds both header and bitset. */
+	log_size = dm_round_up((MIRROR_LOG_OFFSET << SECTOR_SHIFT) + bitset_size, 1 << SECTOR_SHIFT);
+	log_size >>= SECTOR_SHIFT;
+
+	return dm_div_up(log_size, pe_size);
+}
+
+/*
  * Preparation for a specific allocation attempt
  */
 static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
 					struct dm_pool *mem,
 					const struct segment_type *segtype,
 					alloc_policy_t alloc,
+					uint32_t new_extents,
 					uint32_t mirrors,
 					uint32_t stripes,
-					uint32_t log_count,
-					uint32_t log_region_size,
+					uint32_t log_area_count,
+					uint32_t extent_size,
+					uint32_t region_size,
 					struct dm_list *parallel_areas)
 {
 	struct alloc_handle *ah;
@@ -549,7 +578,7 @@
 		return NULL;
 	}
 
-	if (log_count && stripes > 1) {
+	if (log_area_count && stripes > 1) {
 		log_error("Can't mix striping with a mirror log yet.");
 		return NULL;
 	}
@@ -561,7 +590,7 @@
 	else
 		area_count = stripes;
 
-	if (!(ah = dm_pool_zalloc(mem, sizeof(*ah) + sizeof(ah->alloced_areas[0]) * area_count))) {
+	if (!(ah = dm_pool_zalloc(mem, sizeof(*ah) + sizeof(ah->alloced_areas[0]) * (area_count + log_area_count)))) {
 		log_error("allocation handle allocation failed");
 		return NULL;
 	}
@@ -576,13 +605,16 @@
 		return NULL;
 	}
 
+	ah->new_extents = new_extents;
 	ah->area_count = area_count;
-	ah->log_count = log_count;
-	ah->log_region_size = log_region_size;
+	ah->log_area_count = log_area_count;
+	ah->region_size = region_size;
 	ah->alloc = alloc;
 	ah->area_multiple = calc_area_multiple(segtype, area_count);
 
-	for (s = 0; s < ah->area_count; s++)
+	ah->log_len = log_area_count ? mirror_log_extents(ah->region_size, extent_size, ah->new_extents / ah->area_multiple) : 0;
+
+	for (s = 0; s < ah->area_count + ah->log_area_count; s++)
 		dm_list_init(&ah->alloced_areas[s]);
 
 	ah->parallel_areas = parallel_areas;
@@ -644,15 +676,13 @@
 				  uint32_t stripe_size,
 				  const struct segment_type *segtype,
 				  struct alloced_area *aa,
-				  uint32_t region_size,
-				  struct logical_volume *log_lv __attribute((unused)))
+				  uint32_t region_size)
 {
 	uint32_t s, extents, area_multiple;
 	struct lv_segment *seg;
 
 	area_multiple = calc_area_multiple(segtype, area_count);
 
-	/* log_lv gets set up elsehere */
 	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
 				     lv->le_count,
 				     aa[0].len * area_multiple,
@@ -685,15 +715,14 @@
 				   uint64_t status,
 				   uint32_t stripe_size,
 				   const struct segment_type *segtype,
-				   uint32_t region_size,
-				   struct logical_volume *log_lv)
+				   uint32_t region_size)
 {
 	struct alloced_area *aa;
 
 	dm_list_iterate_items(aa, &alloced_areas[0]) {
 		if (!_setup_alloced_segment(lv, status, area_count,
 					    stripe_size, segtype, aa,
-					    region_size, log_lv))
+					    region_size))
 			return_0;
 	}
 
@@ -701,42 +730,21 @@
 }
 
 /*
- * Returns log device size in extents, algorithm from kernel code
- */
-#define BYTE_SHIFT 3
-static uint32_t mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint32_t area_len)
-{
-	size_t area_size, bitset_size, log_size, region_count;
-
-	area_size = area_len * pe_size;
-	region_count = dm_div_up(area_size, region_size);
-
-	/* Work out how many "unsigned long"s we need to hold the bitset. */
-	bitset_size = dm_round_up(region_count, sizeof(uint32_t) << BYTE_SHIFT);
-	bitset_size >>= BYTE_SHIFT;
-
-	/* Log device holds both header and bitset. */
-	log_size = dm_round_up((MIRROR_LOG_OFFSET << SECTOR_SHIFT) + bitset_size, 1 << SECTOR_SHIFT);
-	log_size >>= SECTOR_SHIFT;
-
-	return dm_div_up(log_size, pe_size);
-}
-
-/*
  * This function takes a list of pv_areas and adds them to allocated_areas.
  * If the complete area is not needed then it gets split.
  * The part used is removed from the pv_map so it can't be allocated twice.
  */
 static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
-				struct pv_area **areas,
-				uint32_t *ix, struct pv_area *log_area,
-				uint32_t log_len)
+				struct pv_area **areas, uint32_t *allocated,
+				unsigned log_needs_allocating, uint32_t ix_log_offset)
 {
-	uint32_t area_len, remaining;
+	uint32_t area_len, len, remaining;
 	uint32_t s;
+	uint32_t ix_log_skip = 0; /* How many areas to skip in middle of array to reach log areas */
+	uint32_t total_area_count = ah->area_count + (log_needs_allocating ? ah->log_area_count : 0);
 	struct alloced_area *aa;
 
-	remaining = needed - *ix;
+	remaining = needed - *allocated;
 	area_len = remaining / ah->area_multiple;
 
 	/* Reduce area_len to the smallest of the areas */
@@ -744,32 +752,35 @@
 		if (area_len > areas[s]->count)
 			area_len = areas[s]->count;
 
-	if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) *
-			      (ah->area_count + (log_area ? 1 : 0))))) {
+	if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) * total_area_count))) {
 		log_error("alloced_area allocation failed");
 		return 0;
 	}
 
-	for (s = 0; s < ah->area_count; s++) {
-		aa[s].pv = areas[s]->map->pv;
-		aa[s].pe = areas[s]->start;
-		aa[s].len = area_len;
-		dm_list_add(&ah->alloced_areas[s], &aa[s].list);
-	}
+	/*
+	 * Areas consists of area_count areas for data stripes, then
+	 * ix_log_skip areas to skip, then log_area_count areas to use for the
+	 * log, then some areas too small for the log.
+	 */
+	len = area_len;
+	for (s = 0; s < total_area_count; s++) {
+		if (s == ah->area_count) {
+			ix_log_skip = ix_log_offset - ah->area_count;
+			len = ah->log_len;
+		}
 
-	ah->total_area_len += area_len;
+		aa[s].pv = areas[s + ix_log_skip]->map->pv;
+		aa[s].pe = areas[s + ix_log_skip]->start;
+		aa[s].len = len;
 
-	for (s = 0; s < ah->area_count; s++)
-		consume_pv_area(areas[s], area_len);
+		consume_pv_area(areas[s + ix_log_skip], len);
 
-	if (log_area) {
-		ah->log_area.pv = log_area->map->pv;
-		ah->log_area.pe = log_area->start;
-		ah->log_area.len = log_len;
-		consume_pv_area(log_area, ah->log_area.len);
+		dm_list_add(&ah->alloced_areas[s], &aa[s].list);
 	}
 
-	*ix += area_len * ah->area_multiple;
+	ah->total_area_len += area_len;
+
+	*allocated += area_len * ah->area_multiple;
 
 	return 1;
 }
@@ -990,15 +1001,16 @@
 	unsigned contiguous = 0, cling = 0, preferred_count = 0;
 	unsigned ix;
 	unsigned ix_offset = 0;	/* Offset for non-preferred allocations */
+	unsigned ix_log_offset; /* Offset to start of areas to use for log */
 	unsigned too_small_for_log_count; /* How many too small for log? */
 	uint32_t max_parallel;	/* Maximum extents to allocate */
 	uint32_t next_le;
 	struct seg_pvs *spvs;
 	struct dm_list *parallel_pvs;
 	uint32_t free_pes;
-	uint32_t log_len;
-	struct pv_area *log_area;
 	unsigned log_needs_allocating;
+	struct alloced_area *aa;
+	uint32_t s;
 
 	/* Is there enough total space? */
 	free_pes = pv_maps_size(pvms);
@@ -1062,9 +1074,11 @@
 
 			if (alloc != ALLOC_ANYWHERE) {
 				/* Don't allocate onto the log pv */
-				if (ah->log_count &&
-				    pvm->pv == ah->log_area.pv)
-					continue;	/* Next PV */
+				if (ah->log_area_count)
+					dm_list_iterate_items(aa, &ah->alloced_areas[ah->area_count])
+						for (s = 0; s < ah->log_area_count; s++)
+							if (!aa[s].pv)
+								goto next_pv;
 
 				/* Avoid PVs used by existing parallel areas */
 				if (parallel_pvs)
@@ -1102,7 +1116,7 @@
 				/* Is it big enough on its own? */
 				if (pva->count * ah->area_multiple <
 				    max_parallel - *allocated &&
-				    ((!can_split && !ah->log_count) ||
+				    ((!can_split && !ah->log_area_count) ||
 				     (already_found_one &&
 				      !(alloc == ALLOC_ANYWHERE))))
 					goto next_pv;
@@ -1123,11 +1137,11 @@
 		if ((contiguous || cling) && (preferred_count < ix_offset))
 			break;
 
-		log_needs_allocating = (ah->log_count && !ah->log_area.len) ?
-				       1 : 0;
+		log_needs_allocating = (ah->log_area_count &&
+					dm_list_empty(&ah->alloced_areas[ah->area_count])) ?  1 : 0;
 
 		if (ix + ix_offset < ah->area_count +
-		   (log_needs_allocating ? ah->log_count : 0))
+		   (log_needs_allocating ? ah->log_area_count : 0))
 			break;
 
 		/* sort the areas so we allocate from the biggest */
@@ -1138,38 +1152,28 @@
 		/*
 		 * First time around, if there's a log, allocate it on the
 		 * smallest device that has space for it.
-		 *
-		 * FIXME decide which PV to use at top of function instead
 		 */
-
 		too_small_for_log_count = 0;
+		ix_log_offset = 0;
 
-		if (!log_needs_allocating) {
-			log_len = 0;
-			log_area = NULL;
-		} else {
-			log_len = mirror_log_extents(ah->log_region_size,
-			    pv_pe_size((*areas)->map->pv),
-			    (max_parallel - *allocated) / ah->area_multiple);
-
+		/* FIXME This logic is due to its heritage and can be simplified! */
+		if (log_needs_allocating) {
 			/* How many areas are too small for the log? */
 			while (too_small_for_log_count < ix_offset + ix &&
 			       (*(areas + ix_offset + ix - 1 -
-				  too_small_for_log_count))->count < log_len)
+				  too_small_for_log_count))->count < ah->log_len)
 				too_small_for_log_count++;
-
-			log_area = *(areas + ix_offset + ix - 1 -
-				     too_small_for_log_count);
+			ix_log_offset = ix_offset + ix - too_small_for_log_count - ah->log_area_count;
 		}
 
 		if (ix + ix_offset < ah->area_count +
-		    (log_needs_allocating ? ah->log_count +
+		    (log_needs_allocating ? ah->log_area_count +
 					    too_small_for_log_count : 0))
 			/* FIXME With ALLOC_ANYWHERE, need to split areas */
 			break;
 
 		if (!_alloc_parallel_area(ah, max_parallel, areas, allocated,
-					  log_area, log_len))
+					  log_needs_allocating, ix_log_offset))
 			return_0;
 
 	} while (!contiguous && *allocated != needed && can_split);
@@ -1185,7 +1189,6 @@
 static int _allocate(struct alloc_handle *ah,
 		     struct volume_group *vg,
 		     struct logical_volume *lv,
-		     uint32_t new_extents,
 		     unsigned can_split,
 		     struct dm_list *allocatable_pvs)
 {
@@ -1197,8 +1200,9 @@
 	struct dm_list *pvms;
 	uint32_t areas_size;
 	alloc_policy_t alloc;
+	struct alloced_area *aa;
 
-	if (allocated >= new_extents && !ah->log_count) {
+	if (allocated >= ah->new_extents && !ah->log_area_count) {
 		log_error("_allocate called with no work to do!");
 		return 1;
 	}
@@ -1219,14 +1223,14 @@
 		stack;
 
 	areas_size = dm_list_size(pvms);
-	if (areas_size && areas_size < (ah->area_count + ah->log_count)) {
+	if (areas_size && areas_size < (ah->area_count + ah->log_area_count)) {
 		if (ah->alloc != ALLOC_ANYWHERE) {
 			log_error("Not enough PVs with free space available "
 				  "for parallel allocation.");
 			log_error("Consider --alloc anywhere if desperate.");
 			return 0;
 		}
-		areas_size = ah->area_count + ah->log_count;
+		areas_size = ah->area_count + ah->log_area_count;
 	}
 
 	/* Upper bound if none of the PVs in prev_lvseg is in pvms */
@@ -1245,29 +1249,31 @@
 		old_allocated = allocated;
 		if (!_find_parallel_space(ah, alloc, pvms, areas,
 					  areas_size, can_split,
-					  prev_lvseg, &allocated, new_extents))
+					  prev_lvseg, &allocated, ah->new_extents))
 			goto_out;
-		if ((allocated == new_extents) || (ah->alloc == alloc) ||
+		if ((allocated == ah->new_extents) || (ah->alloc == alloc) ||
 		    (!can_split && (allocated != old_allocated)))
 			break;
 	}
 
-	if (allocated != new_extents) {
+	if (allocated != ah->new_extents) {
 		log_error("Insufficient suitable %sallocatable extents "
 			  "for logical volume %s: %u more required",
 			  can_split ? "" : "contiguous ",
 			  lv ? lv->name : "",
-			  (new_extents - allocated) * ah->area_count
+			  (ah->new_extents - allocated) * ah->area_count
 			  / ah->area_multiple);
 		goto out;
 	}
 
-	if (ah->log_count && !ah->log_area.len) {
-		log_error("Insufficient extents for log allocation "
-			  "for logical volume %s.",
-			  lv ? lv->name : "");
-		goto out;
-	}
+	if (ah->log_area_count)
+		dm_list_iterate_items(aa, &ah->alloced_areas[ah->area_count])
+			if (!aa[0].pv) {
+				log_error("Insufficient extents for log allocation "
+					  "for logical volume %s.",
+					  lv ? lv->name : "");
+				goto out;
+			}
 
 	r = 1;
 
@@ -1306,12 +1312,13 @@
 				      const struct segment_type *segtype,
 				      uint32_t stripes,
 				      uint32_t mirrors, uint32_t log_count,
-				      uint32_t log_region_size, uint32_t extents,
+				      uint32_t region_size, uint32_t extents,
 				      struct dm_list *allocatable_pvs,
 				      alloc_policy_t alloc,
 				      struct dm_list *parallel_areas)
 {
 	struct alloc_handle *ah;
+	uint32_t new_extents;
 
 	if (segtype_is_virtual(segtype)) {
 		log_error("allocate_extents does not handle virtual segments");
@@ -1331,13 +1338,15 @@
 	if (alloc == ALLOC_INHERIT)
 		alloc = vg->alloc;
 
-	if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, mirrors,
-			       stripes, log_count, log_region_size, parallel_areas)))
+	new_extents = (lv ? lv->le_count : 0) + extents;
+	if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc,
+			       new_extents, mirrors, stripes, log_count,
+			       vg->extent_size, region_size,
+			       parallel_areas)))
 		return_NULL;
 
 	if (!segtype_is_virtual(segtype) &&
-	    !_allocate(ah, vg, lv, (lv ? lv->le_count : 0) + extents,
-		       1, allocatable_pvs)) {
+	    !_allocate(ah, vg, lv, 1, allocatable_pvs)) {
 		alloc_destroy(ah);
 		return_NULL;
 	}
@@ -1354,8 +1363,7 @@
 		   const struct segment_type *segtype,
 		   uint32_t stripe_size,
 		   uint64_t status,
-		   uint32_t region_size,
-		   struct logical_volume *log_lv)
+		   uint32_t region_size)
 {
 	if (!segtype) {
 		log_error("Missing segtype in lv_add_segment().");
@@ -1367,10 +1375,15 @@
 		return 0;
 	}
 
+	if ((status & MIRROR_LOG) && dm_list_size(&lv->segments)) {
+		log_error("Log segments can only be added to an empty LV");
+		return 0;
+	}
+
 	if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area],
 				     num_areas, status,
 				     stripe_size, segtype,
-				     region_size, log_lv))
+				     region_size))
 		return_0;
 
 	if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) {
@@ -1546,34 +1559,11 @@
  */
 int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
 {
-	struct lv_segment *seg;
+	const char *segtype_name = ah->log_area_count > 1 ? "mirror" : "striped";
 
-	if (dm_list_size(&log_lv->segments)) {
-		log_error("Log segments can only be added to an empty LV");
-		return 0;
-	}
-
-	if (!(seg = alloc_lv_segment(log_lv->vg->cmd->mem,
-				     get_segtype_from_string(log_lv->vg->cmd,
-							     "striped"),
-				     log_lv, 0, ah->log_area.len, MIRROR_LOG,
-				     0, NULL, 1, ah->log_area.len, 0, 0, 0))) {
-		log_error("Couldn't allocate new mirror log segment.");
-		return 0;
-	}
-
-	if (!set_lv_segment_area_pv(seg, 0, ah->log_area.pv, ah->log_area.pe))
-		return_0;
-
-	dm_list_add(&log_lv->segments, &seg->list);
-	log_lv->le_count += ah->log_area.len;
-	log_lv->size += (uint64_t) log_lv->le_count * log_lv->vg->extent_size;
-
-	if (log_lv->vg->fid->fmt->ops->lv_setup &&
-	    !log_lv->vg->fid->fmt->ops->lv_setup(log_lv->vg->fid, log_lv))
-		return_0;
-
-	return 1;
+	return lv_add_segment(ah, ah->area_count, ah->log_area_count, log_lv,
+			      get_segtype_from_string(log_lv->vg->cmd, segtype_name),
+			      0, MIRROR_LOG, 0);
 }
 
 static int _lv_extend_mirror(struct alloc_handle *ah,
@@ -1595,7 +1585,7 @@
 		if (!lv_add_segment(ah, m++, 1, seg_lv(seg, s),
 				    get_segtype_from_string(lv->vg->cmd,
 							    "striped"),
-				    0, 0, 0, NULL)) {
+				    0, 0, 0)) {
 			log_error("Aborting. Failed to extend %s.",
 				  seg_lv(seg, s)->name);
 			return 0;
@@ -1633,7 +1623,7 @@
 
 	if (mirrors < 2)
 		r = lv_add_segment(ah, 0, ah->area_count, lv, segtype,
-				   stripe_size, status, 0, NULL);
+				   stripe_size, status, 0);
 	else
 		r = _lv_extend_mirror(ah, lv, extents, 0);
 
--- LVM2/lib/metadata/mirror.c	2010/01/12 14:00:51	1.107
+++ LVM2/lib/metadata/mirror.c	2010/03/01 20:00:21	1.108
@@ -1202,7 +1202,7 @@
 		if (!lv_add_segment(ah, m, 1, img_lvs[m],
 				    get_segtype_from_string(lv->vg->cmd,
 							    "striped"),
-				    0, 0, 0, NULL)) {
+				    0, 0, 0)) {
 			log_error("Aborting. Failed to add mirror image segment "
 				  "to %s. Remove new LV and retry.",
 				  img_lvs[m]->name);


^ permalink raw reply	[flat|nested] 3+ messages in thread

* LVM2 ./WHATS_NEW lib/metadata/lv_alloc.h lib/m ...
@ 2007-12-20 15:42 agk
  0 siblings, 0 replies; 3+ messages in thread
From: agk @ 2007-12-20 15:42 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2007-12-20 15:42:55

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_alloc.h lv_manip.c metadata-exported.h 
	                 metadata.h mirror.c 
	scripts        : fsadm.sh 
	tools          : lvconvert.c lvcreate.c pvmove.c toollib.c 
	                 toollib.h 

Log message:
	Major restructuring of pvmove and lvconvert layer manipulation code

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.746&r2=1.747
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_alloc.h.diff?cvsroot=lvm2&r1=1.19&r2=1.20
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.136&r2=1.137
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.25&r2=1.26
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.174&r2=1.175
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.45&r2=1.46
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/scripts/fsadm.sh.diff?cvsroot=lvm2&r1=1.2&r2=1.3
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.47&r2=1.48
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.163&r2=1.164
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/pvmove.c.diff?cvsroot=lvm2&r1=1.44&r2=1.45
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/toollib.c.diff?cvsroot=lvm2&r1=1.118&r2=1.119
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/toollib.h.diff?cvsroot=lvm2&r1=1.52&r2=1.53

--- LVM2/WHATS_NEW	2007/12/17 12:31:49	1.746
+++ LVM2/WHATS_NEW	2007/12/20 15:42:55	1.747
@@ -1,5 +1,6 @@
 Version 2.02.30 -
 ===================================
+  Major restructuring of pvmove and lvconvert layer manipulation code.
   Replace tools/fsadm with scripts/fsadm.sh.
   Append fields to report/pvsegs_cols_verbose.
   Permit LV segment fields with PV segment reports.
--- LVM2/lib/metadata/lv_alloc.h	2007/12/05 22:11:19	1.19
+++ LVM2/lib/metadata/lv_alloc.h	2007/12/20 15:42:55	1.20
@@ -50,7 +50,6 @@
 				      uint32_t extents,
                                       struct list *allocatable_pvs,
 				      alloc_policy_t alloc,
-				      unsigned can_split,
 				      struct list *parallel_areas);
 
 int lv_add_segment(struct alloc_handle *ah,
@@ -58,27 +57,21 @@
 		   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,
+			uint32_t region_size);
+int lv_add_mirror_lvs(struct logical_volume *lv,
+		      struct logical_volume **sub_lvs,
+		      uint32_t num_extra_areas,
+		      uint32_t status, 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);
-int lv_add_mirror_segment(struct alloc_handle *ah,
-			  struct logical_volume *lv,
-			  struct logical_volume **sub_lvs,
-			  uint32_t mirrors,
-			  const struct segment_type *segtype,
-			  uint32_t status,
-			  uint32_t region_size,
-			  struct logical_volume *log_lv);
-int lv_add_more_mirrored_areas(struct logical_volume *lv,
-                               struct logical_volume **sub_lvs,
-                               uint32_t new_area_count,
-                               uint32_t status);
 
 void alloc_destroy(struct alloc_handle *ah);
 
--- LVM2/lib/metadata/lv_manip.c	2007/12/05 22:11:19	1.136
+++ LVM2/lib/metadata/lv_manip.c	2007/12/20 15:42:55	1.137
@@ -43,6 +43,17 @@
 	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.
  */
@@ -160,7 +171,9 @@
 		return;
 
 	if (seg_type(seg, s) == AREA_PV) {
-		release_pv_segment(seg_pvseg(seg, s), area_reduction);
+		if (release_pv_segment(seg_pvseg(seg, s), area_reduction) &&
+		    seg->area_len == area_reduction)
+			seg_type(seg, s) = AREA_UNASSIGNED;
 		return;
 	}
 
@@ -543,17 +556,12 @@
 				  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 */
@@ -561,22 +569,14 @@
 				     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;
 		}
@@ -600,8 +600,6 @@
 				   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)
 {
@@ -610,7 +608,6 @@
 	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;
@@ -1180,7 +1177,6 @@
 				      uint32_t extents,
 				      struct list *allocatable_pvs,
 				      alloc_policy_t alloc,
-				      unsigned can_split,
 				      struct list *parallel_areas)
 {
 	struct alloc_handle *ah;
@@ -1209,7 +1205,7 @@
 
 	if (!segtype_is_virtual(segtype) &&
 	    !_allocate(ah, vg, lv, (lv ? lv->le_count : 0) + extents,
-		       can_split, allocatable_pvs)) {
+		       1, allocatable_pvs)) {
 		stack;
 		alloc_destroy(ah);
 		return NULL;
@@ -1226,8 +1222,6 @@
 		   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)
@@ -1245,7 +1239,6 @@
 	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;
@@ -1267,110 +1260,135 @@
 }
 
 /*
- * Turn an empty LV into a mirror log.
- */
-int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
+ * "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 *seg;
+	struct lv_segment *newseg;
+	uint32_t s;
 
-	if (list_size(&log_lv->segments)) {
-		log_error("Log segments can only be added to an empty LV");
-		return 0;
+	if (!seg_is_striped(seg)) {
+		log_error("Can't convert non-striped segment to mirrored.");
+		return NULL;
 	}
 
-	if (!(seg = alloc_lv_segment(log_lv->vg->cmd->mem,
-				     get_segtype_from_string(log_lv->vg->cmd,
-							     "striped"),
-				     log_lv, 0, ah->log_area.len, MIRROR_LOG,
-				     0, NULL, 1, ah->log_area.len, 0, 0, 0))) {
-		log_error("Couldn't allocate new mirror log segment.");
-		return 0;
+	if (seg->area_count > 1) {
+		log_error("Can't convert striped segment with multiple areas "
+			  "to mirrored.");
+		return NULL;
 	}
 
-	if (!set_lv_segment_area_pv(seg, 0, ah->log_area.pv, ah->log_area.pe)) {
-		stack;
-		return 0;
+	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;
 	}
 
-	list_add(&log_lv->segments, &seg->list);
-	log_lv->le_count += ah->log_area.len;
-	log_lv->size += (uint64_t) log_lv->le_count *log_lv->vg->extent_size;
+	for (s = 0; s < seg->area_count; s++)
+		if (!move_lv_segment_area(newseg, s, seg, s))
+			return_NULL;
 
-	if (log_lv->vg->fid->fmt->ops->lv_setup &&
-	    !log_lv->vg->fid->fmt->ops->lv_setup(log_lv->vg->fid, log_lv)) {
-		stack;
-		return 0;
-	}
+	list_add(&seg->list, &newseg->list);
+	list_del(&seg->list);
 
-	return 1;
+	return newseg;
 }
 
 /*
- * Add a mirror segment
+ * Add new areas to mirrored segments
  */
-int lv_add_mirror_segment(struct alloc_handle *ah,
-			  struct logical_volume *lv,
-			  struct logical_volume **sub_lvs,
-			  uint32_t mirrors,
-			  const struct segment_type *segtype __attribute((unused)),
-			  uint32_t status __attribute((unused)),
-			  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)
 {
+	struct alloced_area *aa;
 	struct lv_segment *seg;
-	uint32_t m;
+	uint32_t current_le = le;
+	uint32_t s, old_area_count, new_area_count;
 
-	if (log_lv && list_empty(&log_lv->segments)) {
-		log_error("Log LV %s is empty.", log_lv->name);
-		return 0;
-	}
+	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;
+		}
 
-	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem,
-				     get_segtype_from_string(lv->vg->cmd,
-							     "mirror"),
-				     lv, lv->le_count, ah->total_area_len, 0,
-				     0, log_lv, mirrors, ah->total_area_len, 0,
-				     region_size, 0))) {
-		log_error("Couldn't allocate new mirror segment.");
-		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;
+			}
+		}
 
-	for (m = 0; m < mirrors; m++) {
-		set_lv_segment_area_lv(seg, m, sub_lvs[m], 0, MIRROR_IMAGE);
-		first_seg(sub_lvs[m])->mirror_seg = seg;
+		if (!seg_is_mirrored(seg) &&
+		    (!(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;
 	}
 
-	list_add(&lv->segments, &seg->list);
-	lv->le_count += ah->total_area_len;
-	lv->size += (uint64_t) lv->le_count *lv->vg->extent_size;
+	lv->status |= MIRRORED;
 
 	if (lv->vg->fid->fmt->ops->lv_setup &&
-	    !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) {
-		stack;
-		return 0;
-	}
+	    !lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv))
+		return_0;
 
 	return 1;
 }
 
 /*
- * Add parallel areas to an existing mirror
+ * Add mirror image LVs to mirrored segments
  */
-int lv_add_more_mirrored_areas(struct logical_volume *lv,
-			       struct logical_volume **sub_lvs,
-			       uint32_t num_extra_areas,
-			       uint32_t status)
+int lv_add_mirror_lvs(struct logical_volume *lv,
+		      struct logical_volume **sub_lvs,
+		      uint32_t num_extra_areas,
+		      uint32_t status, uint32_t region_size)
 {
 	struct lv_segment *seg;
 	uint32_t old_area_count, new_area_count;
 	uint32_t m;
+	struct segment_type *mirror_segtype;
 
-	if (list_size(&lv->segments) != 1) {
-		log_error("Mirrored LV must only have one segment.");
-		return 0;
+	seg = first_seg(lv);
+
+	if (list_size(&lv->segments) != 1 || seg_type(seg, 0) != AREA_LV) {
+		log_error("Mirror layer must be inserted before adding mirrors");
+		return_0;
 	}
 
-	seg = first_seg(lv);
+	mirror_segtype = get_segtype_from_string(lv->vg->cmd, "mirror");
+	if (seg->segtype != mirror_segtype)
+		if (!(seg = _convert_seg_to_mirror(seg, region_size, NULL)))
+			return_0;
+
+	if (region_size && region_size != seg->region_size) {
+		log_error("Conflicting region_size");
+		return 0;
+	}
 
 	old_area_count = seg->area_count;
 	new_area_count = old_area_count + num_extra_areas;
@@ -1381,6 +1399,11 @@
 		return 0;
 	}
 
+	for (m = 0; m < old_area_count; m++) {
+		seg_lv(seg, m)->status |= status;
+		first_seg(seg_lv(seg, m))->mirror_seg = seg;
+	}
+
 	for (m = old_area_count; m < new_area_count; m++) {
 		set_lv_segment_area_lv(seg, m, sub_lvs[m - old_area_count], 0, status);
 		first_seg(sub_lvs[m - old_area_count])->mirror_seg = seg;
@@ -1390,13 +1413,53 @@
 }
 
 /*
+ * Turn an empty LV into a mirror log.
+ */
+int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
+{
+	struct lv_segment *seg;
+
+	if (list_size(&log_lv->segments)) {
+		log_error("Log segments can only be added to an empty LV");
+		return 0;
+	}
+
+	if (!(seg = alloc_lv_segment(log_lv->vg->cmd->mem,
+				     get_segtype_from_string(log_lv->vg->cmd,
+							     "striped"),
+				     log_lv, 0, ah->log_area.len, MIRROR_LOG,
+				     0, NULL, 1, ah->log_area.len, 0, 0, 0))) {
+		log_error("Couldn't allocate new mirror log segment.");
+		return 0;
+	}
+
+	if (!set_lv_segment_area_pv(seg, 0, ah->log_area.pv, ah->log_area.pe)) {
+		stack;
+		return 0;
+	}
+
+	list_add(&log_lv->segments, &seg->list);
+	log_lv->le_count += ah->log_area.len;
+	log_lv->size += (uint64_t) log_lv->le_count *log_lv->vg->extent_size;
+
+	if (log_lv->vg->fid->fmt->ops->lv_setup &&
+	    !log_lv->vg->fid->fmt->ops->lv_setup(log_lv->vg->fid, log_lv)) {
+		stack;
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
  * Entry point for single-step LV allocation + extension.
  */
 int lv_extend(struct logical_volume *lv,
 	      const struct segment_type *segtype,
 	      uint32_t stripes, uint32_t stripe_size,
 	      uint32_t mirrors, uint32_t extents,
-	      struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
+	      struct physical_volume *mirrored_pv __attribute((unused)),
+	      uint32_t mirrored_pe __attribute((unused)),
 	      uint32_t status, struct list *allocatable_pvs,
 	      alloc_policy_t alloc)
 {
@@ -1404,23 +1467,17 @@
 	uint32_t m;
 	struct alloc_handle *ah;
 	struct lv_segment *seg;
-	unsigned can_split = 1;
 
 	if (segtype_is_virtual(segtype))
 		return lv_add_virtual_segment(lv, status, extents, segtype);
 
-	/* FIXME Temporary restriction during code reorganisation */
-	if (mirrored_pv)
-		can_split = 0;
-
 	if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0,
-				    extents, allocatable_pvs, alloc, can_split,
-				    NULL)))
+				    extents, allocatable_pvs, alloc, NULL)))
 		return_0;
 
 	if (mirrors < 2) {
 		if (!lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size,
-			    mirrored_pv, mirrored_pe, status, 0, NULL)) {
+			    status, 0, NULL)) {
 			stack;
 			goto out;
 		}
@@ -1430,7 +1487,7 @@
 			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;
@@ -1900,3 +1957,504 @@
 	log_print("Logical volume \"%s\" successfully removed", lv->name);
 	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;
+}
+
+/* Remove a layer from the LV */
+int remove_layers_for_segments(struct cmd_context *cmd,
+			       struct logical_volume *lv,
+			       struct logical_volume *layer_lv,
+			       uint32_t status_mask, struct list *lvs_changed)
+{
+	struct lv_segment *seg, *lseg;
+	uint32_t s;
+	int lv_changed = 0;
+	struct lv_list *lvl;
+
+	/* Find all segments that point at the temporary mirror */
+	list_iterate_items(seg, &lv->segments) {
+		for (s = 0; s < seg->area_count; s++) {
+			if (seg_type(seg, s) != AREA_LV ||
+			    seg_lv(seg, s) != layer_lv)
+				continue;
+
+			/* Find the layer segment pointed at */
+			if (!(lseg = find_seg_by_le(layer_lv, seg_le(seg, s)))) {
+				log_error("Layer segment found: %s:%" PRIu32,
+					  layer_lv->name, seg_le(seg, s));
+				return 0;
+			}
+
+			/* Check the segment params are compatible */
+			if (!seg_is_striped(lseg) || lseg->area_count != 1) {
+				log_error("Layer is not linear: %s:%" PRIu32,
+					  layer_lv->name, lseg->le);
+				return 0;
+			}
+			if ((lseg->status & status_mask) != status_mask) {
+				log_error("Layer status does not match: "
+					  "%s:%" PRIu32 " status: 0x%x/0x%x",
+					  layer_lv->name, lseg->le,
+					  lseg->status, status_mask);
+				return 0;
+			}
+			if (lseg->le != seg_le(seg, s) ||
+			    lseg->area_len != seg->area_len) {
+				log_error("Layer boundary mismatch: "
+					  "%s:%" PRIu32 "-%" PRIu32 " on "
+					  "%s:%" PRIu32 " / "
+					  "%" PRIu32 "-%" PRIu32 " / ",
+					  lv->name, seg->le, seg->area_len,
+					  layer_lv->name, seg_le(seg, s),
+					  lseg->le, lseg->area_len);
+				return 0;
+			}
+
+			if (!move_lv_segment_area(seg, s, lseg, 0))
+				return_0;
+
+			/* Replace mirror with error segment */
+			if (!(lseg->segtype =
+			      get_segtype_from_string(lv->vg->cmd, "error"))) {
+				log_error("Missing error segtype");
+				return 0;
+			}
+			lseg->area_count = 0;
+
+			/* First time, add LV to list of LVs affected */
+			if (!lv_changed && lvs_changed) {
+				if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
+					log_error("lv_list alloc failed");
+					return 0;
+				}
+				lvl->lv = lv;
+				list_add(lvs_changed, &lvl->list);
+				lv_changed = 1;
+			}
+		}
+	}
+	if (lv_changed && !lv_merge_segments(lv))
+		stack;
+
+	return 1;
+}
+
+/* Remove a layer */
+int remove_layers_for_segments_all(struct cmd_context *cmd,
+				   struct logical_volume *layer_lv,
+				   uint32_t status_mask,
+				   struct list *lvs_changed)
+{
+	struct lv_list *lvl;
+	struct logical_volume *lv1;
+
+	/* Loop through all LVs except the temporary mirror */
+	list_iterate_items(lvl, &layer_lv->vg->lvs) {
+		lv1 = lvl->lv;
+		if (lv1 == layer_lv)
+			continue;
+
+		if (!remove_layers_for_segments(cmd, lv1, layer_lv,
+						status_mask, lvs_changed))
+			return 0;
+	}
+
+	if (!lv_empty(layer_lv))
+		return_0;
+
+	return 1;
+}
+
+static void _move_lv_segments(struct logical_volume *lv_to,
+			      struct logical_volume *lv_from,
+			      uint32_t set_status, uint32_t reset_status)
+{
+	struct lv_segment *seg;
+
+	lv_to->segments = lv_from->segments;
+	lv_to->segments.n->p = &lv_to->segments;
+	lv_to->segments.p->n = &lv_to->segments;
+
+	list_iterate_items(seg, &lv_to->segments) {
+		seg->lv = lv_to;
+		seg->status &= ~reset_status;
+		seg->status |= set_status;
+	}
+
+	/* FIXME: how to handle snapshot segments? */
+
+	list_init(&lv_from->segments);
+
+	lv_to->le_count = lv_from->le_count;
+	lv_to->size = lv_from->size;
+
+	lv_from->le_count = 0;
+	lv_from->size = 0;
+}
+
+/* Remove a layer from the LV */
+/* FIXME: how to specify what should be removed if multiple layers stacked? */
+int remove_layer_from_lv(struct logical_volume *lv)
+{
+	struct logical_volume *orig_lv;
+
+	/*
+	 * Before removal, the layer should be cleaned up,
+	 * i.e. additional segments and areas should have been removed.
+	 */
+	if (list_size(&lv->segments) != 1 ||
+	    first_seg(lv)->area_count != 1 ||
+	    seg_type(first_seg(lv), 0) != AREA_LV)
+		return 0;
+
+	orig_lv = seg_lv(first_seg(lv), 0);
+	_move_lv_segments(lv, orig_lv, 0, 0);
+
+	return 1;
+}
+
+/*
+ * Create and insert a linear LV "above" lv_where.
+ * After the insertion, a new LV named lv_where->name + suffix is created
+ * and all segments of lv_where is moved to the new LV.
+ * lv_where will have a single segment which maps linearly to the new LV.
+ */
+struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
+					   struct logical_volume *lv_where,
+					   uint32_t status,
+					   const char *layer_suffix)
+{
+	struct logical_volume *layer_lv;
+	char *name;
+	size_t len;
+	struct segment_type *segtype;
+	struct lv_segment *mapseg;
+
+	if (!(segtype = get_segtype_from_string(lv_where->vg->cmd, "striped")))
+		return_NULL;
+
+	/* create an empty layer LV */
+
+	len = strlen(lv_where->name) + 32;
+	if (!(name = alloca(len))) {
+		log_error("layer name allocation failed. "
+			  "Remove new LV and retry.");
+		return NULL;
+	}
+
+	if (dm_snprintf(name, len, "%s%s", lv_where->name, layer_suffix) < 0) {
+		log_error("layer name allocation failed. "
+			  "Remove new LV and retry.");
+		return NULL;
+	}
+
+	if (!(layer_lv = lv_create_empty(name, NULL, LVM_READ | LVM_WRITE,
+					 ALLOC_INHERIT, 0, lv_where->vg))) {
+		log_error("Creation of layer LV failed");
+		return NULL;
+	}
+
+	log_very_verbose("Inserting layer %s for %s",
+			 layer_lv->name, lv_where->name);
+
+	_move_lv_segments(layer_lv, lv_where, 0, 0);
+
+	/* allocate a new linear segment */
+	if (!(mapseg = alloc_lv_segment(lv_where->vg->cmd->mem, segtype,
+					lv_where, 0, layer_lv->le_count,
+					status, 0, NULL, 1, layer_lv->le_count,
+					0, 0, 0)))
+		return_NULL;
+
+	/* map the new segment to the original underlying are */
+	set_lv_segment_area_lv(mapseg, 0, layer_lv, 0, 0);
+
+	/* add the new segment to the layer LV */
+	list_add(&lv_where->segments, &mapseg->list);
+	lv_where->le_count = layer_lv->le_count;
+	lv_where->size = lv_where->le_count * lv_where->vg->extent_size;
+
+	return layer_lv;
+}
+
+/*
+ * Extend and insert a linear layer LV beneath the source segment area.
+ */
+static int _extend_layer_lv_for_segment(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;
+
+	/* FIXME Incomplete message? Needs more context */
+	log_very_verbose("Inserting %s:%" PRIu32 "-%" PRIu32 " of %s/%s",
+			 pv_dev_name(src_pv),
+			 src_pe, src_pe + seg->area_len - 1,
+			 seg->lv->vg->name, seg->lv->name);
+
+	/* 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 (!move_lv_segment_area(mapseg, 0, seg, s))
+		return_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 _match_seg_area_to_pe_range(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;
+
+		/* FIXME Missing context in this message - add LV/seg details */
+		log_debug("Matched PE range %s:%" PRIu32 "-%" PRIu32 " against "
+			  "%s %" PRIu32 " len %" PRIu32, dev_name(pvl->pv->dev),
+			  per->start, per_end, dev_name(seg_dev(seg, s)),
+			  seg_pe(seg, s), seg->area_len);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * For each segment in lv_where that uses a PV in pvl directly,
+ * split the segment if it spans more than one underlying PV.
+ */
+static int _align_segment_boundary_to_pe_range(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))
+					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))
+					return_0;
+			}
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * Scan lv_where for segments on a PV in pvl, and for each one found
+ * append a linear segment to lv_layer and insert it between the two.
+ *
+ * If pvl is empty, a layer is placed under the whole of lv_where.
+ * 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_to_pe_range(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 (!_match_seg_area_to_pe_range(seg, s, pvl))
+				continue;
+
+			/* First time, add LV to list of LVs affected */
+			if (!lv_used && lvs_changed) {
+				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_for_segment(layer_lv, seg, s,
+							  status)) {
+				log_error("Failed to insert segment in layer "
+					  "LV %s under %s:%" PRIu32 "-%" PRIu32,
+					  layer_lv->name, lv_where->name,
+					  seg->le, seg->le + seg->len);
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
--- LVM2/lib/metadata/metadata-exported.h	2007/11/15 22:11:18	1.25
+++ LVM2/lib/metadata/metadata-exported.h	2007/12/20 15:42:55	1.26
@@ -379,6 +379,31 @@
 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);
+int remove_layers_for_segments(struct cmd_context *cmd,
+			       struct logical_volume *lv,
+			       struct logical_volume *layer_lv,
+			       uint32_t status_mask, struct list *lvs_changed);
+int remove_layers_for_segments_all(struct cmd_context *cmd,
+				   struct logical_volume *layer_lv,
+				   uint32_t status_mask,
+				   struct list *lvs_changed);
+int split_parent_segments_for_layer(struct cmd_context *cmd,
+				    struct logical_volume *layer_lv);
+int remove_layer_from_lv(struct logical_volume *lv);
+struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
+					   struct logical_volume *lv_where,
+					   uint32_t status,
+					   const char *layer_suffix);
+
 /* 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);
@@ -422,32 +447,42 @@
 /*
 * Mirroring functions
 */
+int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
+		   uint32_t mirrors, uint32_t stripes,
+		   uint32_t region_size, uint32_t log_count,
+		   struct list *pvs, alloc_policy_t alloc, uint32_t flags);
+int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
+		      uint32_t mirrors, uint32_t log_count,
+		      struct list *pvs, uint32_t status_mask);
+/* conversion flags */
+#define MIRROR_BY_SEG	0x00000001U	/* segment-by-segment mirror */
+#define MIRROR_BY_LV	0x00000002U	/* mirror by mimage LVs */
+
+uint32_t lv_mirror_count(struct logical_volume *lv);
 struct alloc_handle;
 uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
                                     uint32_t region_size);
-int create_mirror_layers(struct alloc_handle *ah,
-			 uint32_t first_area,
-			 uint32_t num_mirrors,
-			 struct logical_volume *lv,
-			 const struct segment_type *segtype,
-			 uint32_t status,
-			 uint32_t region_size,
-			 struct logical_volume *log_lv);
+int remove_mirrors_from_segments(struct logical_volume *lv,
+				 uint32_t new_mirrors, uint32_t status_mask);
+int add_mirrors_to_segments(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);
+int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
+		      uint32_t mirrors, uint32_t stripes, uint32_t region_size,
+		      struct list *allocatable_pvs, alloc_policy_t alloc,
+		      uint32_t log_count);
+int remove_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
+		      struct list *removable_pvs);
+int add_mirror_log(struct cmd_context *cmd, struct logical_volume *lv,
+		   uint32_t log_count, uint32_t region_size,
+		   struct list *allocatable_pvs, alloc_policy_t alloc);
+
 int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
 			      struct list *removable_pvs, unsigned remove_log);
 
-int insert_pvmove_mirrors(struct cmd_context *cmd,
-			  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 remove_pvmove_mirrors(struct volume_group *vg,
-			  struct logical_volume *lv_mirr);
 struct logical_volume *find_pvmove_lv(struct volume_group *vg,
 				      struct device *dev, uint32_t lv_type);
 struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
--- LVM2/lib/metadata/metadata.h	2007/11/05 17:17:55	1.174
+++ LVM2/lib/metadata/metadata.h	2007/12/20 15:42:55	1.175
@@ -295,11 +295,6 @@
 /*
  * Mirroring functions
  */
-int add_mirror_layers(struct alloc_handle *ah,
-		      uint32_t num_mirrors,
-		      uint32_t existing_mirrors,
-		      struct logical_volume *lv,
-		      const struct segment_type *segtype);
 
 /*
  * Given mirror image or mirror log segment, find corresponding mirror segment 
--- LVM2/lib/metadata/mirror.c	2007/11/22 13:57:21	1.45
+++ LVM2/lib/metadata/mirror.c	2007/12/20 15:42:55	1.46
@@ -18,6 +18,7 @@
 #include "toolcontext.h"
 #include "segtype.h"
 #include "display.h"
+#include "archiver.h"
 #include "activate.h"
 #include "lv_alloc.h"
 #include "lvm-string.h"
@@ -31,6 +32,14 @@
 #define MIRROR_ALLOCATE          1
 #define MIRROR_ALLOCATE_ANYWHERE 2
 
+/*
+ * Returns the number of mirrors of the LV
+ */
+uint32_t lv_mirror_count(struct logical_volume *lv)
+{
+	return (lv->status & MIRRORED) ? first_seg(lv)->area_count : 1;
+}
+
 struct lv_segment *find_mirror_seg(struct lv_segment *seg)
 {
 	return seg->mirror_seg;
@@ -56,29 +65,6 @@
 	return region_size;
 }
 
-static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volume *lv_from)
-{
-	struct lv_segment *seg;
-
-	lv_to->segments = lv_from->segments;
-	lv_to->segments.n->p = &lv_to->segments;
-	lv_to->segments.p->n = &lv_to->segments;
-
-	list_iterate_items(seg, &lv_to->segments)
-		seg->lv = lv_to;
-
-/* FIXME set or reset seg->mirror_seg (according to status)? */
-
-	list_init(&lv_from->segments);
-
-	lv_to->le_count = lv_from->le_count;
-	lv_to->size = lv_from->size;
-
-	lv_from->le_count = 0;
-	lv_from->size = 0;
-}
-
-
 /*
  * Delete independent/orphan LV, it must acquire lock.
  */
@@ -196,7 +182,7 @@
 	if (num_mirrors == 1) {
 		lv1 = seg_lv(mirrored_seg, 0);
 		extents = lv1->le_count;
-		_move_lv_segments(mirrored_seg->lv, lv1);
+		remove_layer_from_lv(mirrored_seg->lv);
 		mirrored_seg->lv->status &= ~MIRRORED;
 		mirrored_seg->lv->status &= ~MIRROR_NOTSYNCED;
 		remove_log = 1;
@@ -352,7 +338,7 @@
 			      struct list *removable_pvs, unsigned remove_log)
 {
 	int r;
-	int insync = 0;
+	int in_sync = 0;
 	int log_policy, dev_policy;
 	uint32_t old_num_mirrors = mirrored_seg->area_count;
 	int had_log = (mirrored_seg->log_lv) ? 1 : 0;
@@ -364,14 +350,14 @@
 		log_error("WARNING: Unable to determine mirror sync status of %s/%s.",
 			  mirrored_seg->lv->vg->name, mirrored_seg->lv->name);
 	else if (sync_percent >= 100.0)
-		insync = 1;
+		in_sync = 1;
 
 	/*
 	 * While we are only removing devices, we can have sync set.
 	 * Setting this is only useful if we are moving to core log
 	 * otherwise the disk log will contain the sync information
 	 */
-	init_mirror_in_sync(insync);
+	init_mirror_in_sync(in_sync);
 
 	r = remove_mirror_images(mirrored_seg, num_mirrors,
 				 removable_pvs, remove_log);
@@ -388,7 +374,7 @@
 	r = replace_mirror_images(mirrored_seg,
 				  (dev_policy != MIRROR_REMOVE) ?
 				  old_num_mirrors : num_mirrors,
-				  log_policy, insync);
+				  log_policy, in_sync);
 
 	if (!r)
 		/* Failed to replace device(s) */
@@ -414,12 +400,10 @@
 	return 1;
 }
 
-static int _create_layers_for_mirror(struct alloc_handle *ah,
-				     uint32_t first_area,
-				     uint32_t num_mirrors,
-				     struct logical_volume *lv,
-				     const struct segment_type *segtype __attribute((unused)),
-				     struct logical_volume **img_lvs)
+static int _create_mimage_lvs(struct alloc_handle *ah,
+			      uint32_t num_mirrors,
+			      struct logical_volume *lv,
+			      struct logical_volume **img_lvs)
 {
 	uint32_t m;
 	char *img_name;
@@ -447,13 +431,10 @@
 			return 0;
 		}
 
-		if (m < first_area)
-			continue;
-
-		if (!lv_add_segment(ah, m - first_area, 1, img_lvs[m],
+		if (!lv_add_segment(ah, m, 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);
@@ -464,318 +445,47 @@
 	return 1;
 }
 
-int create_mirror_layers(struct alloc_handle *ah,
-			 uint32_t first_area,
-			 uint32_t num_mirrors,
-			 struct logical_volume *lv,
-			 const struct segment_type *segtype,
-			 uint32_t status __attribute((unused)),
-			 uint32_t region_size,
-			 struct logical_volume *log_lv)
-{
-	struct logical_volume **img_lvs;
-	
-	if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
-		log_error("img_lvs allocation failed. "
-			  "Remove new LV and retry.");
-		return 0;
-	}
-
-	if (!_create_layers_for_mirror(ah, first_area, num_mirrors, lv,
-				       segtype, img_lvs)) {
-		stack;
-		return 0;
-	}
-
-	/* Already got the parent mirror segment? */
-	if (lv->status & MIRRORED)
-		return lv_add_more_mirrored_areas(lv, img_lvs, num_mirrors,
-						  MIRROR_IMAGE);
-
-	/* Already got a non-mirrored area to be converted? */
-	if (first_area)
-		_move_lv_segments(img_lvs[0], lv);
-
-	if (!lv_add_mirror_segment(ah, lv, img_lvs, num_mirrors, segtype,
-				   0, region_size, log_lv)) {
-		log_error("Aborting. Failed to add mirror segment. "
-			  "Remove new LV and retry.");
-		return 0;
-	}
-
-	lv->status |= MIRRORED;
-
-	return 1;
-}
-
-int add_mirror_layers(struct alloc_handle *ah,
-		      uint32_t num_mirrors,
-		      uint32_t existing_mirrors __attribute((unused)),
-		      struct logical_volume *lv,
-		      const struct segment_type *segtype)
-{
-	struct logical_volume **img_lvs;
-
-	if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
-		log_error("img_lvs allocation failed. "
-			  "Remove new LV and retry.");
-		return 0;
-	}
-
-	if (!_create_layers_for_mirror(ah, 0, num_mirrors,
-				       lv, segtype,
-				       img_lvs)) {
-		stack;
-		return 0;
-	}
-
-	return lv_add_more_mirrored_areas(lv, img_lvs, num_mirrors, 0);
-}
-
-static int _alloc_and_insert_pvmove_seg(struct logical_volume *lv_mirr,
-					struct lv_segment *seg, uint32_t s,
-					struct list *allocatable_pvs,
-					alloc_policy_t alloc,
-					const struct segment_type *segtype)
-{
-	struct physical_volume *pv = seg_pv(seg, s);
-	uint32_t start_le = lv_mirr->le_count;
-	uint32_t pe = seg_pe(seg, s);
-
-	log_very_verbose("Moving %s:%u-%u of %s/%s", pv_dev_name(pv),
-			 pe, pe + seg->area_len - 1,
-			 seg->lv->vg->name, seg->lv->name);
-
-	release_lv_segment_area(seg, s, seg->area_len);
-
-	if (!lv_extend(lv_mirr, segtype, 1,
-	       	seg->area_len, 0u, seg->area_len,
-	       	pv, pe,
-	       	PVMOVE, allocatable_pvs,
-	       	alloc)) {
-		log_error("Unable to allocate "
-			  "temporary LV for pvmove.");
-		return 0;
-	}
-
-	set_lv_segment_area_lv(seg, s, lv_mirr, start_le, 0);
-
-	return 1;
-}
-
-/* 
- * Replace any LV segments on given PV with temporary mirror.
- * Returns list of LVs changed.
+/*
+ * Remove mirrors from each segment.
+ * 'new_mirrors' is the number of mirrors after the removal. '0' for linear.
+ * If 'status_mask' is non-zero, the removal happens only when all segments
+ * has the status bits on.
  */
-int insert_pvmove_mirrors(struct cmd_context *cmd,
-			  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 remove_mirrors_from_segments(struct logical_volume *lv,
+				 uint32_t new_mirrors, uint32_t status_mask)
 {
 	struct lv_segment *seg;
-	struct lv_list *lvl;
-	struct pv_list *pvl;
-	int lv_used = 0;
-	uint32_t s, extent_count = 0u;
-	const struct segment_type *segtype;
-	struct pe_range *per;
-	uint32_t pe_start, pe_end, per_end, stripe_multiplier;
-
-	/* Only 1 PV may feature in source_pvl */
-	pvl = list_item(source_pvl->n, struct pv_list);
-
-	if (!(segtype = get_segtype_from_string(lv->vg->cmd, "mirror"))) {
-		stack;
-		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;
-        }
+	uint32_t s;
 
-	/* Split LV segments to match PE ranges */
+	/* Check the segment params are compatible */
 	list_iterate_items(seg, &lv->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 need moving? */
-			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, seg->le +
-						      (per->start - pe_start) *
-						      stripe_multiplier)) {
-					stack;
-					return 0;
-				}
-
-				if ((per_end != pe_end &&
-				     per_end < pe_end) &&
-				    !lv_split_segment(lv, seg->le +
-						      (per_end - pe_start + 1) *
-						      stripe_multiplier)) {
-					stack;
-					return 0;
-				}
-			}
+		if (!seg_is_mirrored(seg)) {
+			log_error("Segment is not mirrored: %s:%" PRIu32,
+				  lv->name, seg->le);
+			return 0;
+		} if ((seg->status & status_mask) != status_mask) {
+			log_error("Segment status does not match: %s:%" PRIu32
+				  " status:0x%x/0x%x", lv->name, seg->le,
+				  seg->status, status_mask);
+			return 0;
 		}
 	}
 
-	/* Work through all segments on the supplied PV */
+	/* Convert the segments */
 	list_iterate_items(seg, &lv->segments) {
-		for (s = 0; s < seg->area_count; s++) {
-			if (seg_type(seg, s) != AREA_PV ||
-			    seg_dev(seg, s) != pvl->pv->dev)
-				continue;
-
-			pe_start = seg_pe(seg, s);
-
-			/* Do these PEs need moving? */
-			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);
-
-				/* 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;
-					list_add(lvs_changed, &lvl->list);
-					lv_used = 1;
-				}
-	
-				if (!_alloc_and_insert_pvmove_seg(lv_mirr, seg, s,
-								  allocatable_pvs,
-								  alloc, segtype))
-					return_0;
-
-				extent_count += seg->area_len;
-	
-				lv->status |= LOCKED;
-
-				break;
-			}
+		if (!new_mirrors && seg->extents_copied == seg->area_len) {
+			if (!move_lv_segment_area(seg, 0, seg, 1))
+				return_0;
 		}
-	}
-
-	log_verbose("Moving %u extents of logical volume %s/%s", extent_count,
-		    lv->vg->name, lv->name);
-
-	return 1;
-}
-
-/* Remove a temporary mirror */
-int remove_pvmove_mirrors(struct volume_group *vg,
-			  struct logical_volume *lv_mirr)
-{
-	struct lv_list *lvl;
-	struct logical_volume *lv1;
-	struct lv_segment *seg, *mir_seg;
-	uint32_t s, c;
-
-	/* Loop through all LVs except the temporary mirror */
-	list_iterate_items(lvl, &vg->lvs) {
-		lv1 = lvl->lv;
-		if (lv1 == lv_mirr)
-			continue;
-
-		/* Find all segments that point at the temporary mirror */
-		list_iterate_items(seg, &lv1->segments) {
-			for (s = 0; s < seg->area_count; s++) {
-				if (seg_type(seg, s) != AREA_LV ||
-				    seg_lv(seg, s) != lv_mirr)
-					continue;
 
-				/* Find the mirror segment pointed at */
-				if (!(mir_seg = find_seg_by_le(lv_mirr,
-							       seg_le(seg, s)))) {
-					/* FIXME Error message */
-					log_error("No segment found with LE");
-					return 0;
-				}
-
-				/* Check the segment params are compatible */
-				/* FIXME Improve error mesg & remove restrcn */
-				if (!seg_is_mirrored(mir_seg) ||
-				    !(mir_seg->status & PVMOVE) ||
-				    mir_seg->le != seg_le(seg, s) ||
-				    mir_seg->area_count != 2 ||
-				    mir_seg->area_len != seg->area_len) {
-					log_error("Incompatible segments");
-					return 0;
-				}
-
-				/* Replace original segment with newly-mirrored
-				 * area (or original if reverting)
-				 */
-				if (mir_seg->extents_copied == 
-				        mir_seg->area_len)
-					c = 1;
-				else
-					c = 0;
-
-				if (!move_lv_segment_area(seg, s, mir_seg, c)) {
-					stack;
-					return 0;
-				}
-
-				release_lv_segment_area(mir_seg, c ? 0 : 1U, mir_seg->area_len);
+		for (s = new_mirrors + 1; s < seg->area_count; s++)
+			release_lv_segment_area(seg, s, seg->area_len);
 
-				/* Replace mirror with error segment */
-				if (!
-				    (mir_seg->segtype =
-				     get_segtype_from_string(vg->cmd,
-							     "error"))) {
-					log_error("Missing error segtype");
-					return 0;
-				}
-				mir_seg->area_count = 0;
-
-				/* FIXME Assumes only one pvmove at a time! */
-				lv1->status &= ~LOCKED;
-			}
-		}
-		if (!lv_merge_segments(lv1))
-			stack;
-
-	}
+		seg->area_count = new_mirrors + 1;
 
-	if (!lv_empty(lv_mirr)) {
-		stack;
-		return 0;
+		if (!new_mirrors)
+			seg->segtype = get_segtype_from_string(lv->vg->cmd,
+							       "striped");
 	}
 
 	return 1;
@@ -943,3 +653,568 @@
 	return 1;
 }
 
+/*
+ * Add mirrors to "linear" or "mirror" segments
+ */
+int add_mirrors_to_segments(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);
+
+	if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1, mirrors, 0,
+				    lv->le_count, allocatable_pvs, alloc,
+				    parallel_areas))) {
+		log_error("Unable to allocate mirror extents for %s.", lv->name);
+		return 0;
+	}
+
+	if (!lv_add_mirror_areas(ah, lv, 0, adjusted_region_size)) {
+		log_error("Failed to add mirror areas to %s", lv->name);
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Convert mirror log
+ *
+ * FIXME: Can't handle segment-by-segment mirror (like pvmove)
+ */
+int remove_mirror_log(struct cmd_context *cmd,
+		      struct logical_volume *lv,
+		      struct list *removable_pvs)
+{
+	float sync_percent;
+
+	/* Unimplemented features */
+	if (list_size(&lv->segments) != 1) {
+		log_error("Multiple-segment mirror is not supported");
+		return 0;
+	}
+
+	/* Had disk log, switch to core. */
+	if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) {
+		log_error("Unable to determine mirror sync status.");
+		return 0;
+	}
+
+	if (sync_percent >= 100.0)
+		init_mirror_in_sync(1);
+	else {
+		/* A full resync will take place */
+		lv->status &= ~MIRROR_NOTSYNCED;
+		init_mirror_in_sync(0);
+	}
+
+	if (!remove_mirror_images(first_seg(lv), lv_mirror_count(lv),
+				  removable_pvs, 1U))
+		return_0;
+
+	return 1;
+}
+
+/*
+ * Initialize the LV with 'value'.
+ */
+static int _set_lv(struct cmd_context *cmd, struct logical_volume *lv,
+	   uint64_t sectors, int value)
+{
+	struct device *dev;
+	char *name;
+
+	/*
+	 * FIXME:
+	 * <clausen> also, more than 4k
+	 * <clausen> say, reiserfs puts it's superblock 32k in, IIRC
+	 * <ejt_> k, I'll drop a fixme to that effect
+	 *	   (I know the device is at least 4k, but not 32k)
+	 */
+	if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) {
+		log_error("Name allocation failed - device not cleared");
+		return 0;
+	}
+
+	if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
+			 lv->vg->name, lv->name) < 0) {
+		log_error("Name too long - device not cleared (%s)", lv->name);
+		return 0;
+	}
+
+	log_verbose("Clearing start of logical volume \"%s\"", lv->name);
+
+	if (!(dev = dev_cache_get(name, NULL))) {
+		log_error("%s: not found: device not cleared", name);
+		return 0;
+	}
+
+	if (!dev_open_quiet(dev))
+		return 0;
+
+	dev_set(dev, UINT64_C(0),
+		sectors ? (size_t) sectors << SECTOR_SHIFT : (size_t) 4096,
+		value);
+	dev_flush(dev);
+	dev_close_immediate(dev);
+
+	return 1;
+}
+
+/*
+ * This function writes a new header to the mirror log header to the lv
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+#include "xlate.h"
+#define MIRROR_MAGIC 0x4D695272
+#define MIRROR_DISK_VERSION 2
+
+static int _write_log_header(struct cmd_context *cmd, struct logical_volume *lv)
+{
+	struct device *dev;
+	char *name;
+	struct { /* The mirror log header */
+		uint32_t magic;
+		uint32_t version;
+		uint64_t nr_regions;
+	} log_header;
+
+	log_header.magic = xlate32(MIRROR_MAGIC);
+	log_header.version = xlate32(MIRROR_DISK_VERSION);
+	log_header.nr_regions = xlate64((uint64_t)-1);
+
+	if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) {
+		log_error("Name allocation failed - log header not written (%s)",
+			lv->name);
+		return 0;
+	}
+
+	if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
+			 lv->vg->name, lv->name) < 0) {
+		log_error("Name too long - log header not written (%s)", lv->name);
+		return 0;
+	}
+
+	log_verbose("Writing log header to device, %s", lv->name);
+
+	if (!(dev = dev_cache_get(name, NULL))) {
+		log_error("%s: not found: log header not written", name);
+		return 0;
+	}
+
+	if (!dev_open_quiet(dev))
+		return 0;
+
+	if (!dev_write(dev, UINT64_C(0), sizeof(log_header), &log_header)) {
+		log_error("Failed to write log header to %s", name);
+		dev_close_immediate(dev);
+		return 0;
+	}
+
+	dev_close_immediate(dev);
+
+	return 1;
+}
+
+/*
+ * Initialize mirror log contents
+ */
+static int _init_mirror_log(struct cmd_context *cmd,
+			    struct logical_volume *log_lv, int in_sync,
+			    struct list *tags)
+{
+	struct str_list *sl;
+
+	if (!activation() && in_sync) {
+		log_error("Aborting. Unable to create in-sync mirror log "
+			  "while activation is disabled.");
+		return 0;
+	}
+
+	/* Temporary tag mirror log for activation */
+	list_iterate_items(sl, tags)
+		if (!str_list_add(cmd->mem, &log_lv->tags, sl->str)) {
+			log_error("Aborting. Unable to tag mirror log.");
+			return 0;
+		}
+
+	/* store mirror log on disk(s) */
+	if (!vg_write(log_lv->vg))
+		return_0;
+
+	backup(log_lv->vg);
+
+	if (!vg_commit(log_lv->vg))
+		return_0;
+
+	if (!activate_lv(cmd, log_lv)) {
+		log_error("Aborting. Failed to activate mirror log.");
+		goto revert_new_lv;
+	}
+
+	/* Remove the temporary tags */
+	list_iterate_items(sl, tags)
+		if (!str_list_del(&log_lv->tags, sl->str))
+			log_error("Failed to remove tag %s from mirror log.",
+				  sl->str);
+
+	if (activation() && !_set_lv(cmd, log_lv, log_lv->size,
+				    in_sync ? -1 : 0)) {
+		log_error("Aborting. Failed to wipe mirror log.");
+		goto deactivate_and_revert_new_lv;
+	}
+
+	if (activation() && !_write_log_header(cmd, log_lv)) {
+		log_error("Aborting. Failed to write mirror log header.");
+		goto deactivate_and_revert_new_lv;
+	}
+
+	if (!deactivate_lv(cmd, log_lv)) {
+		log_error("Aborting. Failed to deactivate mirror log. "
+			  "Manual intervention required.");
+		return 0;
+	}
+
+	log_lv->status &= ~VISIBLE_LV;
+
+	return 1;
+
+deactivate_and_revert_new_lv:
+	if (!deactivate_lv(cmd, log_lv)) {
+		log_error("Unable to deactivate mirror log LV. "
+			  "Manual intervention required.");
+		return 0;
+	}
+
+revert_new_lv:
+	if (!lv_remove(log_lv) || !vg_write(log_lv->vg) ||
+	    (backup(log_lv->vg), !vg_commit(log_lv->vg)))
+		log_error("Manual intervention may be required to remove "
+			  "abandoned log LV before retrying.");
+	return 0;
+}
+
+static struct logical_volume *_create_mirror_log(struct cmd_context *cmd,
+					 struct logical_volume *lv,
+					 struct alloc_handle *ah,
+					 alloc_policy_t alloc,
+					 const char *lv_name)
+{
+	struct logical_volume *log_lv;
+	char *log_name;
+	size_t len;
+
+	len = strlen(lv_name) + 32;
+	if (!(log_name = alloca(len))) {
+		log_error("log_name allocation failed.");
+		return NULL;
+	}
+
+	if (dm_snprintf(log_name, len, "%s_mlog", lv->name) < 0) {
+		log_error("log_name allocation failed.");
+		return NULL;
+	}
+
+	if (!(log_lv = lv_create_empty(log_name, NULL,
+				       VISIBLE_LV | LVM_READ | LVM_WRITE,
+				       alloc, 0, lv->vg)))
+		return_NULL;
+
+	if (!lv_add_log_segment(ah, log_lv))
+		return_NULL;
+
+	return log_lv;
+}
+
+static struct logical_volume *_set_up_mirror_log(struct cmd_context *cmd,
+						 struct alloc_handle *ah,
+						 struct logical_volume *lv,
+						 uint32_t log_count,
+						 uint32_t region_size,
+						 alloc_policy_t alloc,
+						 int in_sync)
+{
+	struct logical_volume *log_lv;
+
+	init_mirror_in_sync(in_sync);
+
+	if (!(log_lv = _create_mirror_log(cmd, lv, ah, alloc, lv->name))) {
+		log_error("Failed to create mirror log.");
+		return NULL;
+	}
+
+	if (!_init_mirror_log(cmd, log_lv, in_sync, &lv->tags)) {
+		log_error("Failed to create mirror log.");
+		return NULL;
+	}
+
+	return log_lv;
+}
+
+static void _add_mirror_log(struct logical_volume *lv,
+			    struct logical_volume *log_lv)
+{
+	first_seg(lv)->log_lv = log_lv;
+	log_lv->status |= MIRROR_LOG;
+	first_seg(log_lv)->mirror_seg = first_seg(lv);
+}
+
+int add_mirror_log(struct cmd_context *cmd,
+		   struct logical_volume *lv,
+		   uint32_t log_count,
+		   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;
+	float sync_percent;
+	int in_sync;
+	struct logical_volume *log_lv;
+
+	/* Unimplemented features */
+	if (log_count > 1) {
+		log_error("log_count > 1 is not supported");
+		return 0;
+	}
+	if (list_size(&lv->segments) != 1) {
+		log_error("Multiple-segment mirror is not supported");
+		return 0;
+	}
+
+	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
+		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->vg, NULL, segtype,
+			      0, 0, log_count, 0,
+			      allocatable_pvs, alloc, parallel_areas);
+	if (!ah) {
+		log_error("Unable to allocate temporary LV for pvmove.");
+		return 0;
+	}
+
+	/* check sync status */
+	if (lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL) &&
+	    sync_percent >= 100.0)
+		in_sync = 1;
+	else
+		in_sync = 0;
+
+	if (!(log_lv = _set_up_mirror_log(cmd, ah, lv, log_count,
+					  region_size, alloc, in_sync)))
+		return_0;
+
+	_add_mirror_log(lv, log_lv);
+
+	alloc_destroy(ah);
+	return 1;
+}
+
+/*
+ * Convert "linear" LV to "mirror".
+ */
+int add_mirror_images(struct cmd_context *cmd, struct logical_volume *lv,
+		      uint32_t mirrors, uint32_t stripes, uint32_t region_size,
+		      struct list *allocatable_pvs, alloc_policy_t alloc,
+		      uint32_t log_count)
+{
+	struct alloc_handle *ah;
+	const struct segment_type *segtype;
+	struct list *parallel_areas;
+	struct logical_volume **img_lvs, *log_lv;
+
+	if (stripes > 1) {
+		log_error("stripes > 1 is not supported");
+		return 0;
+	}
+
+	/*
+	 * allocate destination extents
+	 */
+
+	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
+		return_0;
+
+	if (!(segtype = get_segtype_from_string(cmd, "mirror")))
+		return_0;
+
+	ah = allocate_extents(lv->vg, NULL, segtype,
+			      stripes, mirrors, log_count, lv->le_count,
+			      allocatable_pvs, alloc, parallel_areas);
+	if (!ah) {
+		log_error("Unable to allocate extents for mirror(s).");
+		return 0;
+	}
+
+	/*
+	 * create and initialize mirror log
+	 */
+	if (log_count &&
+	    !(log_lv = _set_up_mirror_log(cmd, ah, lv, log_count,
+					  region_size, alloc, 0)))
+		return_0;
+
+	/* The log initialization involves vg metadata commit.
+	   So from here on, if failure occurs, the log must be explicitly
+	   removed and the updated vg metadata should be committed. */
+
+	/*
+	 * insert a mirror layer
+	 */
+	if (list_size(&lv->segments) != 1 ||
+	    seg_type(first_seg(lv), 0) != AREA_LV)
+		if (!insert_layer_for_lv(cmd, lv, 0, "_mimage_%d"))
+			goto out_remove_log;
+
+	/*
+	 * create mirror image LVs
+	 */
+	if (!(img_lvs = alloca(sizeof(*img_lvs) * mirrors))) {
+		log_error("img_lvs allocation failed. "
+			  "Remove new LV and retry.");
+		goto out_remove_log;
+	}
+
+	if (!_create_mimage_lvs(ah, mirrors, lv, img_lvs))
+		goto out_remove_log;
+
+	if (!lv_add_mirror_lvs(lv, img_lvs, mirrors,
+			       MIRROR_IMAGE | (lv->status & LOCKED),
+			       region_size)) {
+		log_error("Aborting. Failed to add mirror segment. "
+			  "Remove new LV and retry.");
+		goto out_remove_imgs;
+	}
+
+	if (log_count)
+		_add_mirror_log(lv, log_lv);
+
+	lv->status |= MIRRORED;
+
+	alloc_destroy(ah);
+	return 1;
+
+  out_remove_log:
+	if (!lv_remove(log_lv) || !vg_write(log_lv->vg) ||
+	    (backup(log_lv->vg), !vg_commit(log_lv->vg)))
+		log_error("Manual intervention may be required to remove "
+			  "abandoned log LV before retrying.");
+
+  out_remove_imgs:
+	return 0;
+}
+
+/*
+ * Generic interface for adding mirror and/or mirror log.
+ * 'mirror' is the number of mirrors to be added.
+ * 'pvs' is either allocatable pvs.
+ */
+int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
+		   uint32_t mirrors, uint32_t stripes,
+		   uint32_t region_size, uint32_t log_count,
+		   struct list *pvs, alloc_policy_t alloc, uint32_t flags)
+{
+	if (!mirrors && !log_count) {
+		log_error("No conversion is requested");
+		return 0;
+	}
+
+	if (flags & MIRROR_BY_SEG) {
+		if (log_count) {
+			log_error("Persistent log is not supported on "
+				  "segment-by-segment mirroring");
+			return 0;
+		}
+		if (stripes > 1) {
+			log_error("Striped-mirroring is not supported on "
+				  "segment-by-segment mirroring");
+			return 0;
+		}
+
+		return add_mirrors_to_segments(cmd, lv, mirrors,
+					       region_size, pvs, alloc);
+	} else if (flags & MIRROR_BY_LV) {
+		if (!mirrors)
+			return add_mirror_log(cmd, lv, log_count,
+					      region_size, pvs, alloc);
+		return add_mirror_images(cmd, lv, mirrors,
+					 stripes, region_size,
+					 pvs, alloc, log_count);
+	}
+
+	log_error("Unsupported mirror conversion type");
+	return 0;
+}
+
+/*
+ * Generic interface for removing mirror and/or mirror log.
+ * 'mirror' is the number of mirrors to be removed.
+ * 'pvs' is removable pvs.
+ */
+int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
+		      uint32_t mirrors, uint32_t log_count, struct list *pvs,
+		      uint32_t status_mask)
+{
+	uint32_t new_mirrors;
+	struct lv_segment *seg;
+
+	if (!mirrors && !log_count) {
+		log_error("No conversion is requested");
+		return 0;
+	}
+
+	seg = first_seg(lv);
+	if (!seg_is_mirrored(seg)) {
+		log_error("Not a mirror segment");
+		return 0;
+	}
+
+	if (seg->area_count <= mirrors) {
+		log_error("Removing more than existing: %d <= %d",
+			  seg->area_count, mirrors);
+		return 0;
+	}
+	new_mirrors = seg->area_count - mirrors - 1;
+
+	/* MIRROR_BY_LV */
+	if (seg_type(seg, 0) == AREA_LV &&
+	    seg_lv(seg, 0)->status & MIRROR_IMAGE) {
+		return remove_mirror_images(first_seg(lv), new_mirrors + 1,
+					    pvs, log_count ? 1U : 0);
+	}
+
+	/* MIRROR_BY_SEG */
+	if (log_count) {
+		log_error("Persistent log is not supported on "
+			  "segment-by-segment mirroring");
+		return 0;
+	}
+	return remove_mirrors_from_segments(lv, new_mirrors, status_mask);
+}
+
--- LVM2/scripts/fsadm.sh	2007/12/17 14:47:22	1.2
+++ LVM2/scripts/fsadm.sh	2007/12/20 15:42:55	1.3
@@ -40,8 +40,8 @@
 UMOUNT=umount
 MKDIR=mkdir
 RM=rm
-BLOCKDEV=blockdev
-BLKID=blkid
+BLOCKDEV=echo 
+BLKID=echo
 GREP=grep
 READLINK=readlink
 FSCK=fsck
@@ -133,7 +133,7 @@
 # detect filesystem on the given device
 # dereference device name if it is symbolic link
 detect_fs() {
-	VOLUME=$($READLINK -e -n "$1")
+	VOLUME=$($READLINK -n "$1")
 	# use /dev/null as cache file to be sure about the result
 	FSTYPE=$($BLKID -c /dev/null -o value -s TYPE "$VOLUME" || error "Cannot get FSTYPE of \"$VOLUME\"")
 	verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\""
--- LVM2/tools/lvconvert.c	2007/12/05 22:11:20	1.47
+++ LVM2/tools/lvconvert.c	2007/12/20 15:42:55	1.48
@@ -232,10 +232,6 @@
 {
 	struct lv_segment *seg;
 	uint32_t existing_mirrors;
-	struct alloc_handle *ah = NULL;
-	struct logical_volume *log_lv;
-	struct list *parallel_areas;
-	float sync_percent;
 	const char *mirrorlog;
 	unsigned corelog = 0;
 
@@ -312,8 +308,8 @@
 			return 1;
 		}
 
-		if (!remove_mirror_images(seg, 1,
-					  lp->pv_count ? lp->pvh : NULL, 1))
+		if (!lv_remove_mirrors(cmd, lv, existing_mirrors - 1, 1,
+				       lp->pv_count ? lp->pvh : NULL, 0))
 			return_0;
 		goto commit_changes;
 	}
@@ -332,33 +328,13 @@
 			}
 		}
 
-		if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
-			return_0;
-
-		if (!(ah = allocate_extents(lv->vg, NULL, lp->segtype,
-					    1, lp->mirrors - 1,
-					    corelog ? 0U : 1U,
-					    lv->le_count, lp->pvh, lp->alloc,
-					    1, parallel_areas)))
-			return_0;
-
-		lp->region_size = adjusted_mirror_region_size(lv->vg->extent_size,
-							      lv->le_count,
-							      lp->region_size);
-
-		log_lv = NULL;
-		if (!corelog &&
-		    !(log_lv = create_mirror_log(cmd, lv->vg, ah,
-						 lp->alloc,
-						 lv->name, 0, &lv->tags))) {
-			log_error("Failed to create mirror log.");
-			return 0;
-		}
-
-		if (!create_mirror_layers(ah, 1, lp->mirrors, lv,
-					  lp->segtype, 0,
-					  lp->region_size,
-					  log_lv))
+		if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, 1,
+				    adjusted_mirror_region_size(
+						lv->vg->extent_size,
+						lv->le_count,
+						lp->region_size),
+				    corelog ? 0U : 1U, lp->pvh, lp->alloc,
+				    MIRROR_BY_LV))
 			return_0;
 		goto commit_changes;
 	}
@@ -375,54 +351,15 @@
 
 	if (lp->mirrors == existing_mirrors) {
 		if (!seg->log_lv && !corelog) {
-			/* No disk log present, add one. */
-			if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
+			if (!add_mirror_log(cmd, lv, 1,
+					    adjusted_mirror_region_size(
+							lv->vg->extent_size,
+							lv->le_count,
+							lp->region_size),
+					    lp->pvh, lp->alloc))
 				return_0;
-			if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) {
-				log_error("Unable to determine mirror sync status.");
-				return 0;
-			}
-
-			if (!(ah = allocate_extents(lv->vg, NULL, lp->segtype, 0,
-						    0, 1, 0, lp->pvh, lp->alloc,
-						    1, parallel_areas))) {
-				stack;
-				return 0;
-			}
-
-			if (sync_percent >= 100.0)
-				init_mirror_in_sync(1);
-			else
-				init_mirror_in_sync(0);
-
-			if (!(log_lv = create_mirror_log(cmd, lv->vg, ah,
-							 lp->alloc, lv->name,
-							 (sync_percent >= 100.0) ?
-							 1 : 0, &lv->tags))) {
-				log_error("Failed to create mirror log.");
-				return 0;
-			}
-			seg->log_lv = log_lv;
-			log_lv->status |= MIRROR_LOG;
-			first_seg(log_lv)->mirror_seg = seg;
 		} else if (seg->log_lv && corelog) {
-			/* Had disk log, switch to core. */
-			if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) {
-				log_error("Unable to determine mirror sync status.");
-				return 0;
-			}
-
-			if (sync_percent >= 100.0)
-				init_mirror_in_sync(1);
-			else {
-				/* A full resync will take place */
-				lv->status &= ~MIRROR_NOTSYNCED;
-				init_mirror_in_sync(0);
-			}
-
-			if (!remove_mirror_images(seg, lp->mirrors,
-						  lp->pv_count ?
-						  lp->pvh : NULL, 1))
+			if (!remove_mirror_log(cmd, lv, lp->pvh))
 				return_0;
 		} else {
 			/* No change */
@@ -442,9 +379,8 @@
 		return 0;
 	} else {
 		/* Reduce number of mirrors */
-		if (!remove_mirror_images(seg, lp->mirrors,
-					  lp->pv_count ?
-					  lp->pvh : NULL, 0))
+		if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
+				       0, lp->pv_count ? lp->pvh : NULL, 0))
 			return_0;
 	}
 
--- LVM2/tools/lvcreate.c	2007/12/05 22:11:20	1.163
+++ LVM2/tools/lvcreate.c	2007/12/20 15:42:55	1.164
@@ -409,7 +409,7 @@
 			return 0;
 		}
 
-		if (!(lp->segtype = get_segtype_from_string(cmd, "mirror"))) {
+		if (!(lp->segtype = get_segtype_from_string(cmd, "striped"))) {
 			stack;
 			return 0;
 		}
@@ -524,11 +524,10 @@
 	uint32_t size_rest;
 	uint32_t status = 0;
 	uint64_t tmp_size;
-	struct logical_volume *lv, *org = NULL, *log_lv = NULL;
+	struct logical_volume *lv, *org = NULL;
 	struct list *pvh, tags;
 	const char *tag = NULL;
 	int origin_active = 0;
-	struct alloc_handle *ah = NULL;
 	char lv_name_buf[128];
 	const char *lv_name;
 	struct lvinfo info;
@@ -745,38 +744,6 @@
 		}
 	}
 
-	if (lp->mirrors > 1) {
-		/* FIXME Calculate how many extents needed for the log */
-
-		if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
-					    lp->mirrors, lp->corelog ? 0U : 1U,
-					    lp->extents, pvh, lp->alloc, 1, NULL)))
-			return_0;
-
-		lp->region_size = adjusted_mirror_region_size(vg->extent_size,
-							      lp->extents,
-							      lp->region_size);
-
-		init_mirror_in_sync(lp->nosync);
-
-		if (lp->nosync) {
-			log_warn("WARNING: New mirror won't be synchronised. "
-				  "Don't read what you didn't write!");
-			status |= MIRROR_NOTSYNCED;
-		}
-
-		list_init(&tags);
-		if (tag)
-			str_list_add(cmd->mem, &tags, tag);
-
-		if (!lp->corelog &&
-		    !(log_lv = create_mirror_log(cmd, vg, ah, lp->alloc,
-						 lv_name, lp->nosync, &tags))) {
-			log_error("Failed to create mirror log.");
-			return 0;
-		}
-	}
-
 	if (!(lv = lv_create_empty(lv_name ? lv_name : "lvol%d", NULL,
 				   status, lp->alloc, 0, vg))) {
 		stack;
@@ -802,19 +769,34 @@
 		goto error;
 	}
 
+	if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
+		       1, lp->extents, NULL, 0u, 0u, pvh, lp->alloc))
+		return_0;
+
 	if (lp->mirrors > 1) {
-		if (!create_mirror_layers(ah, 0, lp->mirrors, lv,
-					  lp->segtype, 0,
-					  lp->region_size, log_lv)) {
-			stack;
-			goto error;
+		init_mirror_in_sync(lp->nosync);
+
+		if (lp->nosync) {
+			log_warn("WARNING: New mirror won't be synchronised. "
+				  "Don't read what you didn't write!");
+			status |= MIRROR_NOTSYNCED;
 		}
 
-		alloc_destroy(ah);
-		ah = NULL;
-	} else if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
-		       lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc))
-		return_0;
+		list_init(&tags);
+		if (tag)
+			str_list_add(cmd->mem, &tags, tag);
+
+		if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, lp->stripes,
+				    adjusted_mirror_region_size(
+						vg->extent_size,
+						lv->le_count,
+						lp->region_size),
+				    lp->corelog ? 0U : 1U, pvh, lp->alloc,
+				    MIRROR_BY_LV)) {
+			stack;
+			goto revert_new_lv;
+		}
+	}
 
 	/* store vg on disk(s) */
 	if (!vg_write(vg))
@@ -901,8 +883,6 @@
 	return 1;
 
 error:
-	if (ah)
-		alloc_destroy(ah);
 	return 0;
 
 deactivate_and_revert_new_lv:
--- LVM2/tools/pvmove.c	2007/12/05 22:11:20	1.44
+++ LVM2/tools/pvmove.c	2007/12/20 15:42:55	1.45
@@ -106,6 +106,40 @@
 	return allocatable_pvs;
 }
 
+/*
+ * Replace any LV segments on given PV with temporary mirror.
+ * Returns list of LVs changed.
+ */
+static int _insert_pvmove_mirrors(struct cmd_context *cmd,
+				  struct logical_volume *lv_mirr,
+				  struct list *source_pvl,
+				  struct logical_volume *lv,
+				  struct list *lvs_changed)
+
+{
+	struct pv_list *pvl;
+	uint32_t prev_le_count;
+
+	/* Only 1 PV may feature in source_pvl */
+	pvl = list_item(source_pvl->n, struct pv_list);
+
+	prev_le_count = lv_mirr->le_count;
+	if (!insert_layer_for_segments_on_pv(cmd, lv, lv_mirr, PVMOVE,
+					     pvl, lvs_changed))
+		return_0;
+
+	/* check if layer was inserted */
+	if (lv_mirr->le_count - prev_le_count) {
+		lv->status |= LOCKED;
+
+		log_verbose("Moving %u extents of logical volume %s/%s",
+			    lv_mirr->le_count - prev_le_count,
+			    lv->vg->name, lv->name);
+	}
+
+	return 1;
+}
+
 /* Create new LV with mirror segments for the required copies */
 static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
 						struct volume_group *vg,
@@ -117,6 +151,7 @@
 {
 	struct logical_volume *lv_mirr, *lv;
 	struct lv_list *lvl;
+	uint32_t log_count = 0;
 
 	/* FIXME Cope with non-contiguous => splitting existing segments */
 	if (!(lv_mirr = lv_create_empty("pvmove%d", NULL,
@@ -161,14 +196,8 @@
 			log_print("Skipping locked LV %s", lv->name);
 			continue;
 		}
-		/* FIXME Just insert the layer below - no allocation */
-		// This knows nothing about pvmove
-		// insert_layer_for_segments_on_pv(cmd, lv, source_pvl, lv_mirr, *lvs_changed)
-		//   - for each lv segment using that pv
-		//     - call new fn insert_internal_layer()
-		if (!insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
-					   allocatable_pvs, alloc,
-					   *lvs_changed)) {
+		if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
+					    *lvs_changed)) {
 			stack;
 			return NULL;
 		}
@@ -180,9 +209,16 @@
 		return NULL;
 	}
 
-	/* FIXME Do allocation and convert to mirror */
-	// again, this knows nothing about pvmove: it's a normal lvconvert lv_mirr to mirror with in-core log
-	// - a flag passed in requires that parent segs get split after the allocation (with failure if not possible)
+	if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, log_count,
+			    allocatable_pvs, alloc, MIRROR_BY_SEG)) {
+		log_error("Failed to convert pvmove LV to mirrored");
+		return_NULL;
+	}
+
+	if (!split_parent_segments_for_layer(cmd, lv_mirr)) {
+		log_error("Failed to split segments being moved");
+		return_NULL;
+	}
 
 	return lv_mirr;
 }
@@ -381,13 +417,22 @@
 			  struct list *lvs_changed)
 {
 	int r = 1;
+	struct list lvs_completed;
+	struct lv_list *lvl;
 
 	/* Update metadata to remove mirror segments and break dependencies */
-	if (!remove_pvmove_mirrors(vg, lv_mirr)) {
+	list_init(&lvs_completed);
+	if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) ||
+	    !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE,
+					    &lvs_completed)) {
 		log_error("ABORTING: Removal of temporary mirror failed");
 		return 0;
 	}
 
+	list_iterate_items(lvl, &lvs_completed)
+		/* FIXME Assumes only one pvmove at a time! */
+		lvl->lv->status &= ~LOCKED;
+
 	/* Store metadata without dependencies on mirror segments */
 	if (!vg_write(vg)) {
 		log_error("ABORTING: Failed to write new data locations "
@@ -488,6 +533,17 @@
 	char *pv_name = NULL;
 	char *colon;
 	int ret;
+	const struct segment_type *segtype;
+
+	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;
+        }
 
 	if (argc) {
 		pv_name = argv[0];
--- LVM2/tools/toollib.c	2007/11/16 21:16:20	1.118
+++ LVM2/tools/toollib.c	2007/12/20 15:42:55	1.119
@@ -1241,26 +1241,6 @@
 	return 1;
 }
 
-int generate_log_name_format(struct volume_group *vg __attribute((unused)),
-			     const char *lv_name, char *buffer, size_t size)
-{
-	if (dm_snprintf(buffer, size, "%s_mlog", lv_name) < 0) {
-		stack;
-		return 0;
-	}
-
-	/* FIXME I think we can cope without this.  Cf. _add_lv_to_dtree()
-	if (find_lv_in_vg(vg, buffer) &&
-	    dm_snprintf(buffer, size, "%s_mlog_%%d",
-			 lv_name) < 0) {
-		stack;
-		return 0;
-	}
-	*******/
-
-	return 1;
-}
-
 /*
  * Initialize the LV with 'value'.
  */
@@ -1307,149 +1287,3 @@
 	return 1;
 }
 
-/*
- * This function writes a new header to the mirror log header to the lv
- *
- * Returns: 1 on success, 0 on failure
- */
-static int _write_log_header(struct cmd_context *cmd, struct logical_volume *lv)
-{
-	struct device *dev;
-	char *name;
-	struct { /* The mirror log header */
-		uint32_t magic;
-		uint32_t version;
-		uint64_t nr_regions;
-	} log_header;
-
-	log_header.magic = xlate32(MIRROR_MAGIC);
-	log_header.version = xlate32(MIRROR_DISK_VERSION);
-	log_header.nr_regions = xlate64((uint64_t)-1);
-
-	if (!(name = dm_pool_alloc(cmd->mem, PATH_MAX))) {
-		log_error("Name allocation failed - log header not written (%s)",
-			lv->name);
-		return 0;
-	}
-
-	if (dm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
-			 lv->vg->name, lv->name) < 0) {
-		log_error("Name too long - log header not written (%s)", lv->name);
-		return 0;
-	}
-
-	log_verbose("Writing log header to device, %s", lv->name);
-
-	if (!(dev = dev_cache_get(name, NULL))) {
-		log_error("%s: not found: log header not written", name);
-		return 0;
-	}
-
-	if (!dev_open_quiet(dev))
-		return 0;
-
-	if (!dev_write(dev, UINT64_C(0), sizeof(log_header), &log_header)) {
-		log_error("Failed to write log header to %s", name);
-		dev_close_immediate(dev);
-		return 0;
-	}
-
-	dev_close_immediate(dev);
-
-	return 1;
-}
-
-struct logical_volume *create_mirror_log(struct cmd_context *cmd,
-					 struct volume_group *vg,
-					 struct alloc_handle *ah,
-					 alloc_policy_t alloc,
-					 const char *lv_name,
-					 int in_sync,
-					 struct list *tags)
-{
-	struct logical_volume *log_lv;
-	char *log_name;
-	size_t len;
-	struct str_list *sl;
-
-	if (!activation() && in_sync) {
-		log_error("Aborting. Unable to create in-sync mirror log "
-			  "while activation is disabled.");
-		return NULL;
-	}
-
-	len = strlen(lv_name) + 32;
-	if (!(log_name = alloca(len)) ||
-	    !(generate_log_name_format(vg, lv_name, log_name, len))) {
-		log_error("log_name allocation failed.");
-		return NULL;
-	}
-
-	if (!(log_lv = lv_create_empty(log_name, NULL,
-				       VISIBLE_LV | LVM_READ | LVM_WRITE,
-				       alloc, 0, vg)))
-		return_NULL;
-
-	if (!lv_add_log_segment(ah, log_lv))
-		return_NULL;
-
-	/* Temporary tag mirror log */
-	list_iterate_items(sl, tags)
-		if (!str_list_add(cmd->mem, &log_lv->tags, sl->str)) {
-			log_error("Aborting. Unable to tag mirror log.");
-			return NULL;
-		}
-
-	/* store mirror log on disk(s) */
-	if (!vg_write(vg))
-		return_NULL;
-
-	backup(vg);
-
-	if (!vg_commit(vg))
-		return_NULL;
-
-	if (!activate_lv(cmd, log_lv)) {
-		log_error("Aborting. Failed to activate mirror log.");
-		goto revert_new_lv;
-	}
-
-	list_iterate_items(sl, tags)
-		if (!str_list_del(&log_lv->tags, sl->str))
-			log_error("Failed to remove tag %s from mirror log.",
-				  sl->str);
-
-	if (activation() && !set_lv(cmd, log_lv, log_lv->size,
-				    in_sync ? -1 : 0)) {
-		log_error("Aborting. Failed to wipe mirror log.");
-		goto deactivate_and_revert_new_lv;
-	}
-
-	if (activation() && !_write_log_header(cmd, log_lv)) {
-		log_error("Aborting. Failed to write mirror log header.");
-		goto deactivate_and_revert_new_lv;
-	}
-
-	if (!deactivate_lv(cmd, log_lv)) {
-		log_error("Aborting. Failed to deactivate mirror log. "
-			  "Manual intervention required.");
-		return NULL;
-	}
-
-	log_lv->status &= ~VISIBLE_LV;
-
-	return log_lv;
-
-deactivate_and_revert_new_lv:
-	if (!deactivate_lv(cmd, log_lv)) {
-		log_error("Unable to deactivate mirror log LV. "
-			  "Manual intervention required.");
-		return NULL;
-	}
-
-revert_new_lv:
-	if (!lv_remove(log_lv) || !vg_write(vg) || (backup(vg), !vg_commit(vg)))
-		log_error("Manual intervention may be required to remove "
-			  "abandoned log LV before retrying.");
-	return NULL;
-}
--- LVM2/tools/toollib.h	2007/11/14 18:41:05	1.52
+++ LVM2/tools/toollib.h	2007/12/20 15:42:55	1.53
@@ -98,17 +98,6 @@
 
 int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name);
 
-int generate_log_name_format(struct volume_group *vg, const char *lv_name,
-                             char *buffer, size_t size);
-
-struct logical_volume *create_mirror_log(struct cmd_context *cmd,
-					 struct volume_group *vg,
-					 struct alloc_handle *ah,
-					 alloc_policy_t alloc,
-					 const char *lv_name,
-					 int in_sync,
-					 struct list *tags);
-
 int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
 	   uint64_t sectors, int value);
 


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-03-01 20:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-12-19 15:24 LVM2 ./WHATS_NEW lib/metadata/lv_alloc.h lib/m mbroz
  -- strict thread matches above, loose matches on Subject: below --
2010-03-01 20:00 agk
2007-12-20 15:42 agk

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).