public inbox for lvm2-cvs@sourceware.org
help / color / mirror / Atom feed
* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2012-02-15 15:18 zkabelac
  0 siblings, 0 replies; 36+ messages in thread
From: zkabelac @ 2012-02-15 15:18 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	zkabelac@sourceware.org	2012-02-15 15:18:44

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h 
	liblvm         : lvm_lv.c 
	tools          : lvchange.c lvcreate.c lvmcmdline.c toollib.c 
	                 toollib.h vgchange.c 

Log message:
	Initialize dmeventd monitoring for every command
	
	Read lvm.conf setting for monitoring for each command. So we should not
	activate monitoring if the default compilation is set to monitor during
	lvconvert commnads.
	
	Patch also removes check for  clustered VG and allows to disable monitoring
	for clustered VG with the assumption, the problem with monitoring and dmeventd
	flag passing for INGNORE is already fixed.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2294&r2=1.2295
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.361&r2=1.362
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.230&r2=1.231
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/liblvm/lvm_lv.c.diff?cvsroot=lvm2&r1=1.38&r2=1.39
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvchange.c.diff?cvsroot=lvm2&r1=1.137&r2=1.138
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.253&r2=1.254
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvmcmdline.c.diff?cvsroot=lvm2&r1=1.150&r2=1.151
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/toollib.c.diff?cvsroot=lvm2&r1=1.240&r2=1.241
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/toollib.h.diff?cvsroot=lvm2&r1=1.77&r2=1.78
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/vgchange.c.diff?cvsroot=lvm2&r1=1.129&r2=1.130

--- LVM2/WHATS_NEW	2012/02/15 13:49:51	1.2294
+++ LVM2/WHATS_NEW	2012/02/15 15:18:43	1.2295
@@ -1,5 +1,6 @@
 Version 2.02.92 - 
 ====================================
+  Read monitoring config settings for every lvm command.
   Initialize monitoring support only for thin pools and skip thin volumes.
   Make conversion from a synced 'mirror' to 'raid1' not cause a full resync.
   Properly test buffer for unit check in units_to_bytes().
--- LVM2/lib/metadata/lv_manip.c	2012/02/13 11:25:56	1.361
+++ LVM2/lib/metadata/lv_manip.c	2012/02/15 15:18:43	1.362
@@ -4378,8 +4378,6 @@
 		goto out;
 	}
 
-	init_dmeventd_monitor(lp->activation_monitoring);
-
 	if (seg_is_thin(lp)) {
 		/* For snapshot, suspend active thin origin first */
 		if (org && lv_is_active(org)) {
--- LVM2/lib/metadata/metadata-exported.h	2012/02/12 23:01:19	1.230
+++ LVM2/lib/metadata/metadata-exported.h	2012/02/15 15:18:43	1.231
@@ -574,7 +574,6 @@
 	int minor; /* all */
 	int log_count; /* mirror */
 	int nosync; /* mirror */
-	int activation_monitoring; /* all */
 	activation_change_t activate; /* non-snapshot, non-mirror */
 
 	const char *origin; /* snap */
--- LVM2/liblvm/lvm_lv.c	2012/02/13 11:25:56	1.38
+++ LVM2/liblvm/lvm_lv.c	2012/02/15 15:18:43	1.39
@@ -110,7 +110,6 @@
 	lp->zero = 1;
 	lp->major = -1;
 	lp->minor = -1;
-	lp->activation_monitoring = DEFAULT_DMEVENTD_MONITOR;
 	lp->activate = CHANGE_AY;
 	lp->vg_name = vg->name;
 	lp->lv_name = lvname; /* FIXME: check this for safety */
--- LVM2/tools/lvchange.c	2011/12/01 00:04:21	1.137
+++ LVM2/tools/lvchange.c	2012/02/15 15:18:44	1.138
@@ -524,7 +524,7 @@
 			   void *handle __attribute__((unused)))
 {
 	int doit = 0, docmds = 0;
-	int dmeventd_mode, archived = 0;
+	int archived = 0;
 	struct logical_volume *origin;
 	char snaps_msg[128];
 
@@ -595,11 +595,6 @@
 		return ECMD_FAILED;
 	}
 
-	if (!get_activation_monitoring_mode(cmd, lv->vg, &dmeventd_mode))
-		return ECMD_FAILED;
-
-	init_dmeventd_monitor(dmeventd_mode);
-
 	/*
 	 * FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
 	 * If --poll is explicitly provided use it; otherwise polling
--- LVM2/tools/lvcreate.c	2012/02/01 01:54:20	1.253
+++ LVM2/tools/lvcreate.c	2012/02/15 15:18:44	1.254
@@ -726,10 +726,6 @@
 		return 0;
 	}
 
-	if (!get_activation_monitoring_mode(cmd, NULL,
-					    &lp->activation_monitoring))
-		return_0;
-
 	if (!_lvcreate_name_params(lp, cmd, &argc, &argv) ||
 	    !_read_size_params(lp, lcp, cmd) ||
 	    !get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) ||
--- LVM2/tools/lvmcmdline.c	2012/02/13 12:07:51	1.150
+++ LVM2/tools/lvmcmdline.c	2012/02/15 15:18:44	1.151
@@ -935,6 +935,7 @@
 	init_test(cmd->current_settings.test);
 	init_full_scan_done(0);
 	init_mirror_in_sync(0);
+	init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
 
 	init_msg_prefix(cmd->default_settings.msg_prefix);
 	init_cmd_name(cmd->default_settings.cmd_name);
@@ -996,6 +997,7 @@
 {
 	int ret = 0;
 	int locking_type;
+	int monitoring;
 	struct dm_config_tree *old_cft;
 
 	init_error_message_produced(0);
@@ -1041,6 +1043,10 @@
 		goto_out;
 	_apply_settings(cmd);
 
+	if (!get_activation_monitoring_mode(cmd, &monitoring))
+		goto_out;
+	init_dmeventd_monitor(monitoring);
+
 	log_debug("Processing: %s", cmd->cmd_line);
 
 #ifdef O_DIRECT_SUPPORT
--- LVM2/tools/toollib.c	2012/02/10 01:28:28	1.240
+++ LVM2/tools/toollib.c	2012/02/15 15:18:44	1.241
@@ -1490,7 +1490,6 @@
 }
 
 int get_activation_monitoring_mode(struct cmd_context *cmd,
-				   struct volume_group *vg,
 				   int *monitoring_mode)
 {
 	*monitoring_mode = DEFAULT_DMEVENTD_MONITOR;
@@ -1511,16 +1510,6 @@
 					DEFAULT_DMEVENTD_MONITOR))
 		*monitoring_mode = DMEVENTD_MONITOR_IGNORE;
 
-	if (vg && vg_is_clustered(vg) &&
-	    *monitoring_mode == DMEVENTD_MONITOR_IGNORE) {
-		log_error("%s is incompatible with clustered Volume Group "
-			  "\"%s\": Skipping.",
-			  (arg_count(cmd, ignoremonitoring_ARG) ?
-			   "--ignoremonitoring" : "activation/monitoring=0"),
-			  vg->name);
-		return 0;
-	}
-	
 	return 1;
 }
 
--- LVM2/tools/toollib.h	2011/02/18 14:47:31	1.77
+++ LVM2/tools/toollib.h	2012/02/15 15:18:44	1.78
@@ -110,7 +110,6 @@
 			     struct pvcreate_params *pp);
 
 int get_activation_monitoring_mode(struct cmd_context *cmd,
-				   struct volume_group *vg,
 				   int *monitoring_mode);
 int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
 		      uint32_t *stripe_size);
--- LVM2/tools/vgchange.c	2011/11/07 10:58:13	1.129
+++ LVM2/tools/vgchange.c	2012/02/15 15:18:44	1.130
@@ -447,7 +447,6 @@
 			   struct volume_group *vg,
 			   void *handle __attribute__((unused)))
 {
-	int dmeventd_mode;
 	int archived = 0;
 	int i;
 
@@ -473,11 +472,6 @@
 		return ECMD_FAILED;
 	}
 
-	if (!get_activation_monitoring_mode(cmd, vg, &dmeventd_mode))
-		return ECMD_FAILED;
-
-	init_dmeventd_monitor(dmeventd_mode);
-
 	/*
 	 * FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
 	 * If --poll is explicitly provided use it; otherwise polling


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2012-02-23 17:36 jbrassow
  0 siblings, 0 replies; 36+ messages in thread
From: jbrassow @ 2012-02-23 17:36 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	jbrassow@sourceware.org	2012-02-23 17:36:37

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c raid_manip.c 
	tools          : lvcreate.c 

Log message:
	Require number of stripes to be greater than parity devices in higher RAID.
	
	Also, add some comments to code that I recently added that may be unclear
	otherwise.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2303&r2=1.2304
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.364&r2=1.365
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/raid_manip.c.diff?cvsroot=lvm2&r1=1.23&r2=1.24
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.254&r2=1.255

--- LVM2/WHATS_NEW	2012/02/23 11:24:07	1.2303
+++ LVM2/WHATS_NEW	2012/02/23 17:36:35	1.2304
@@ -1,5 +1,6 @@
 Version 2.02.93 - 
 ====================================
+  Require number of stripes to be greater than parity devices in higher RAID.
   Add LVMetaD systemd units.
   Fix allocation code to allow replacement of single RAID 4/5/6 device.
   Check all tags and LV names are in a valid form in vg_validate.
--- LVM2/lib/metadata/lv_manip.c	2012/02/23 03:57:23	1.364
+++ LVM2/lib/metadata/lv_manip.c	2012/02/23 17:36:36	1.365
@@ -752,6 +752,22 @@
 		area_count = stripes;
 
 	size = sizeof(*ah);
+
+	/*
+	 * It is a requirement that RAID 4/5/6 are created with a number of
+	 * stripes that is greater than the number of parity devices.  (e.g
+	 * RAID4/5 must have at least 2 stripes and RAID6 must have at least
+	 * 3.)  It is also a constraint that, when replacing individual devices
+	 * in a RAID 4/5/6 array, no more devices can be replaced than
+	 * there are parity devices.  (Otherwise, there would not be enough
+	 * redundancy to maintain the array.)  Understanding these two
+	 * constraints allows us to infer whether the caller of this function
+	 * is intending to allocate an entire array or just replacement
+	 * component devices.  In the former case, we must account for the
+	 * necessary parity_count.  In the later case, we do not need to
+	 * account for the extra parity devices because the array already
+	 * exists and they only want replacement drives.
+	 */
 	parity_count = (area_count <= segtype->parity_devs) ? 0 :
 		segtype->parity_devs;
 	alloc_count = area_count + parity_count;
--- LVM2/lib/metadata/raid_manip.c	2012/02/23 03:57:23	1.23
+++ LVM2/lib/metadata/raid_manip.c	2012/02/23 17:36:36	1.24
@@ -519,9 +519,18 @@
 	else if (!(segtype = get_segtype_from_string(lv->vg->cmd, "raid1")))
 		return_0;
 
+	/*
+	 * The number of extents is based on the RAID type.  For RAID1,
+	 * each of the rimages is the same size - 'le_count'.  However
+	 * for RAID 4/5/6, the stripes add together (NOT including the parity
+	 * devices) to equal 'le_count'.  Thus, when we are allocating
+	 * individual devies, we must specify how large the individual device
+	 * is along with the number we want ('count').
+	 */
 	extents = (segtype->parity_devs) ?
 		(lv->le_count / (seg->area_count - segtype->parity_devs)) :
 		lv->le_count;
+
 	if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0, count, count,
 				    region_size, extents, pvs,
 				    lv->alloc, parallel_areas)))
--- LVM2/tools/lvcreate.c	2012/02/15 15:18:44	1.254
+++ LVM2/tools/lvcreate.c	2012/02/23 17:36:36	1.255
@@ -485,9 +485,10 @@
 	 *
 	 * For RAID 4/5/6, these values must be set.
 	 */
-	if (!segtype_is_mirrored(lp->segtype) && (lp->stripes < 2)) {
-		log_error("Number of stripes to %s not specified",
-			  lp->segtype->name);
+	if (!segtype_is_mirrored(lp->segtype) &&
+	    (lp->stripes <= lp->segtype->parity_devs)) {
+		log_error("Number of stripes must be at least %d for %s",
+			  lp->segtype->parity_devs + 1, lp->segtype->name);
 		return 0;
 	}
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2012-02-23  3:57 jbrassow
  0 siblings, 0 replies; 36+ messages in thread
From: jbrassow @ 2012-02-23  3:57 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	jbrassow@sourceware.org	2012-02-23 03:57:23

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c raid_manip.c 

Log message:
	Fix allocation code to allow replacement of single RAID 4/5/6 device.
	
	The code fail to account for the case where we just need a single device
	in a RAID 4/5/6 array.  There is no good way to tell the allocation functions
	that we don't need parity devices when we are allocating just a single device.
	So, I've used a bit of a hack.  If we are allocating an area_count that is <=
	the parity count, then we can assume we are simply allocating a replacement
	device (i.e. no need to include parity devices in the calculations).  This
	should make sense in most cases.  If we need to allocate replacement devices
	due to failure (or moving), we will never allocate more than the parity count;
	or we would cause the array to become unusable.  If we are creating a new device,
	we should always create more stripes than parity devices.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2301&r2=1.2302
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.363&r2=1.364
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/raid_manip.c.diff?cvsroot=lvm2&r1=1.22&r2=1.23

--- LVM2/WHATS_NEW	2012/02/23 00:11:01	1.2301
+++ LVM2/WHATS_NEW	2012/02/23 03:57:23	1.2302
@@ -1,5 +1,6 @@
 Version 2.02.93 - 
 ====================================
+  Fix allocation code to allow replacement of single RAID 4/5/6 device.
   Check all tags and LV names are in a valid form in vg_validate.
   Add tmpfiles.d style configuration for lvm2 lock and run directory.
   Add configure --with-tmpfilesdir for dir holding volatile-file configuration.
--- LVM2/lib/metadata/lv_manip.c	2012/02/22 17:14:39	1.363
+++ LVM2/lib/metadata/lv_manip.c	2012/02/23 03:57:23	1.364
@@ -737,7 +737,7 @@
 					struct dm_list *parallel_areas)
 {
 	struct alloc_handle *ah;
-	uint32_t s, area_count, alloc_count;
+	uint32_t s, area_count, alloc_count, parity_count;
 	size_t size = 0;
 
 	/* FIXME Caller should ensure this */
@@ -752,7 +752,9 @@
 		area_count = stripes;
 
 	size = sizeof(*ah);
-	alloc_count = area_count + segtype->parity_devs;
+	parity_count = (area_count <= segtype->parity_devs) ? 0 :
+		segtype->parity_devs;
+	alloc_count = area_count + parity_count;
 	if (segtype_is_raid(segtype) && metadata_area_count)
 		/* RAID has a meta area for each device */
 		alloc_count *= 2;
@@ -787,7 +789,7 @@
 	else
 		ah->new_extents = 0;
 	ah->area_count = area_count;
-	ah->parity_count = segtype->parity_devs;
+	ah->parity_count = parity_count;
 	ah->region_size = region_size;
 	ah->alloc = alloc;
 	ah->area_multiple = _calc_area_multiple(segtype, area_count, stripes);
--- LVM2/lib/metadata/raid_manip.c	2012/02/13 11:10:37	1.22
+++ LVM2/lib/metadata/raid_manip.c	2012/02/23 03:57:23	1.23
@@ -493,6 +493,7 @@
 {
 	uint32_t s;
 	uint32_t region_size;
+	uint32_t extents;
 	struct lv_segment *seg = first_seg(lv);
 	const struct segment_type *segtype;
 	struct alloc_handle *ah;
@@ -518,8 +519,11 @@
 	else if (!(segtype = get_segtype_from_string(lv->vg->cmd, "raid1")))
 		return_0;
 
+	extents = (segtype->parity_devs) ?
+		(lv->le_count / (seg->area_count - segtype->parity_devs)) :
+		lv->le_count;
 	if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0, count, count,
-				    region_size, lv->le_count, pvs,
+				    region_size, extents, pvs,
 				    lv->alloc, parallel_areas)))
 		return_0;
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2012-02-08 13:05 zkabelac
  0 siblings, 0 replies; 36+ messages in thread
From: zkabelac @ 2012-02-08 13:05 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	zkabelac@sourceware.org	2012-02-08 13:05:39

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata.h thin_manip.c 

Log message:
	Thin add pool_below_threshold
	
	Test both data and metadata percent usage.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2272&r2=1.2273
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.357&r2=1.358
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.265&r2=1.266
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/thin_manip.c.diff?cvsroot=lvm2&r1=1.32&r2=1.33

--- LVM2/WHATS_NEW	2012/02/08 13:02:07	1.2272
+++ LVM2/WHATS_NEW	2012/02/08 13:05:38	1.2273
@@ -1,5 +1,6 @@
 Version 2.02.91 -
 ===================================
+  Add pool_below_threshold() function to check thin pool percent status.
   Fix test for snap percent for failing merge when removing LV.
   Switch int to void return for str_list_del().
   Fix error path handling in _build_desc().
--- LVM2/lib/metadata/lv_manip.c	2012/02/08 13:02:07	1.357
+++ LVM2/lib/metadata/lv_manip.c	2012/02/08 13:05:39	1.358
@@ -4054,7 +4054,6 @@
 	struct logical_volume *lv, *org = NULL;
 	struct logical_volume *pool_lv;
 	struct lv_list *lvl;
-	percent_t percent;
 	int origin_active = 0;
 	struct lvinfo info;
 
@@ -4375,26 +4374,20 @@
 	if (seg_is_thin(lp)) {
 		/* For snapshot, suspend active thin origin first */
 		if (org && lv_is_active(org)) {
-			/* Check if the pool is bellow threshold (Works only for active thin) */
-			if (!lv_thin_pool_percent(first_seg(org)->pool_lv, 0, &percent)) {
-				stack;
-				goto revert_new_lv;
-			}
-			percent /= PERCENT_1;
-			if (percent >= (find_config_tree_int(cmd, "activation/thin_pool_autoextend_threshold",
-							     DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD))) {
-				log_error("Failed to create snapshot, pool is filled over "
-					  "the autoextend threshold (%d%%).", percent);
+			if (!pool_below_threshold(first_seg(first_seg(org)->pool_lv))) {
+				log_error("Cannot create thin snapshot. Pool %s/%s is filled "
+					  "over the autoextend threshold.",
+					  org->vg->name, first_seg(org)->pool_lv->name);
 				goto revert_new_lv;
 			}
 			if (!suspend_lv_origin(cmd, org)) {
-				log_error("Failed to suspend thin snapshot origin %s.",
-					  org->name);
+				log_error("Failed to suspend thin snapshot origin %s/%s.",
+					  org->vg->name, org->name);
 				goto revert_new_lv;
 			}
 			if (!resume_lv_origin(cmd, org)) { /* deptree updates thin-pool */
-				log_error("Failed to resume thin snapshot origin %s.",
-					  org->name);
+				log_error("Failed to resume thin snapshot origin %s/%s.",
+					  org->vg->name, org->name);
 				goto revert_new_lv;
 			}
 			/* At this point remove pool messages, snapshot is active */
--- LVM2/lib/metadata/metadata.h	2012/01/25 08:55:19	1.265
+++ LVM2/lib/metadata/metadata.h	2012/02/08 13:05:39	1.266
@@ -464,6 +464,7 @@
 			int auto_increment);
 int pool_has_message(const struct lv_segment *seg,
 		     const struct logical_volume *lv, uint32_t device_id);
+int pool_below_threshold(const struct lv_segment *pool_seg);
 int extend_pool(struct logical_volume *lv, const struct segment_type *segtype,
 		struct alloc_handle *ah, uint32_t stripes, uint32_t stripe_size);
 
--- LVM2/lib/metadata/thin_manip.c	2012/01/25 09:17:15	1.32
+++ LVM2/lib/metadata/thin_manip.c	2012/02/08 13:05:39	1.33
@@ -19,6 +19,7 @@
 #include "segtype.h"
 #include "lv_alloc.h"
 #include "archiver.h"
+#include "defaults.h"
 
 int attach_pool_metadata_lv(struct lv_segment *pool_seg, struct logical_volume *metadata_lv)
 {
@@ -215,6 +216,35 @@
 	return 0;
 }
 
+int pool_below_threshold(const struct lv_segment *pool_seg)
+{
+	percent_t percent;
+	int threshold = PERCENT_1 *
+		find_config_tree_int(pool_seg->lv->vg->cmd,
+				     "activation/thin_pool_autoextend_threshold",
+				     DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD);
+
+	/* Data */
+	if (!lv_thin_pool_percent(pool_seg->lv, 0, &percent)) {
+		stack;
+		return 0;
+	}
+
+	if (percent >= threshold)
+		return 0;
+
+	/* Metadata */
+	if (!lv_thin_pool_percent(pool_seg->lv, 1, &percent)) {
+		stack;
+		return 0;
+	}
+
+	if (percent >= threshold)
+		return 0;
+
+	return 1;
+}
+
 struct lv_segment *find_pool_seg(const struct lv_segment *seg)
 {
 	struct lv_segment *pool_seg;


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2012-02-01  2:10 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2012-02-01  2:10 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2012-02-01 02:10:46

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c pv_map.c pv_map.h 

Log message:
	Track unreserved space for all alloc policies and then permit NORMAL to place
	log and data on same single PV.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2248&r2=1.2249
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.354&r2=1.355
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/pv_map.c.diff?cvsroot=lvm2&r1=1.36&r2=1.37
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/pv_map.h.diff?cvsroot=lvm2&r1=1.14&r2=1.15

--- LVM2/WHATS_NEW	2012/01/31 21:21:53	1.2248
+++ LVM2/WHATS_NEW	2012/02/01 02:10:45	1.2249
@@ -1,5 +1,6 @@
 Version 2.02.90 - 
 ===================================
+  Allow ALLOC_NORMAL to track reserved extents for log and data on same PV.
   Automatically detect whether corosync clvmd needs to use confdb or cmap.
   Fix data% report for thin volume used as origin for non-thin snapshot.
 
--- LVM2/lib/metadata/lv_manip.c	2012/01/26 21:39:32	1.354
+++ LVM2/lib/metadata/lv_manip.c	2012/02/01 02:10:46	1.355
@@ -1458,22 +1458,18 @@
 			     const struct alloc_parms *alloc_parms, struct alloc_state *alloc_state,
 			     unsigned already_found_one, unsigned iteration_count, unsigned log_iteration_count)
 {
-	unsigned s;
-
 	/* Skip fully-reserved areas (which are not currently removed from the list). */
 	if (!pva->unreserved)
 		return NEXT_AREA;
 
-	if (iteration_count + log_iteration_count) {
+	/* FIXME Should this test be removed? */
+	if (iteration_count)
 		/*
-		 * Don't use an area twice.
-		 * Only ALLOC_ANYWHERE currently supports that, by destroying the data structures,
-		 * which is OK because they are not needed again afterwards.
-		 */
+		* Don't use an area twice.
+		*/
 		for (s = 0; s < alloc_state->areas_size; s++)
 			if (alloc_state->areas[s].pva == pva)
 				return NEXT_AREA;
-	}
 
 	/* If maximise_cling is set, perform several checks, otherwise perform exactly one. */
 	if (!iteration_count && !log_iteration_count && alloc_parms->flags & (A_CONTIGUOUS | A_CLING | A_CLING_TO_ALLOCED)) {
@@ -1531,28 +1527,23 @@
 {
 	uint32_t required = max_to_allocate / ah->area_multiple;
 
-	/* FIXME Maintain unreserved all the time, so other policies can split areas too. */
-
+	/*
+	 * Update amount unreserved - effectively splitting an area 
+	 * into two or more parts.  If the whole stripe doesn't fit,
+	 * reduce amount we're looking for.
+	 */
 	if (alloc == ALLOC_ANYWHERE) {
-		/*
-		 * Update amount unreserved - effectively splitting an area 
-		 * into two or more parts.  If the whole stripe doesn't fit,
-		 * reduce amount we're looking for.
-		 */
 		if (ix_pva - 1 >= ah->area_count)
 			required = ah->log_len;
-		if (required >= pva->unreserved) {
-			required = pva->unreserved;
-			pva->unreserved = 0;
-		} else {
-			pva->unreserved -= required;
-			reinsert_reduced_pv_area(pva);
-		}
+	} else if (required < ah->log_len)
+		required = ah->log_len;
+
+	if (required >= pva->unreserved) {
+		required = pva->unreserved;
+		pva->unreserved = 0;
 	} else {
-		if (required < ah->log_len)
-			required = ah->log_len;
-		if (required > pva->count)
-			required = pva->count;
+		pva->unreserved -= required;
+		reinsert_changed_pv_area(pva);
 	}
 
 	return required;
@@ -1576,8 +1567,7 @@
 			alloc_state->areas[s].pva = NULL;
 	}
 
-	_reserve_area(&alloc_state->areas[ix_pva - 1], pva, required, ix_pva, 
-		  (alloc == ALLOC_ANYWHERE) ? pva->unreserved : pva->count - required);
+	_reserve_area(&alloc_state->areas[ix_pva - 1], pva, required, ix_pva, pva->unreserved);
 
 	return 1;
 }
@@ -1590,6 +1580,19 @@
 		alloc_state->areas[s].pva = NULL;
 }
 
+static void _reset_unreserved(struct dm_list *pvms)
+{
+	struct pv_map *pvm;
+	struct pv_area *pva;
+
+	dm_list_iterate_items(pvm, pvms)
+		dm_list_iterate_items(pva, &pvm->areas)
+			if (pva->unreserved != pva->count) {
+				pva->unreserved = pva->count;
+				reinsert_changed_pv_area(pva);
+			}
+}
+
 static void _report_needed_allocation_space(struct alloc_handle *ah,
 					    struct alloc_state *alloc_state)
 {
@@ -1653,6 +1656,7 @@
 			  alloc_parms->flags & A_CLING_TO_ALLOCED ? "" : "not ");
 
 	_clear_areas(alloc_state);
+	_reset_unreserved(pvms);
 
 	_report_needed_allocation_space(ah, alloc_state);
 
@@ -2590,6 +2594,7 @@
 		log_count = 1;
 	} else if (segtype_is_raid(segtype) && !lv->le_count)
 		log_count = mirrors * stripes;
+	/* FIXME log_count should be 1 for mirrors */
 
 	if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors,
 				    log_count, region_size, extents,
@@ -4341,6 +4346,7 @@
 		}
 	}
 
+	/* FIXME Log allocation and attachment should have happened inside lv_extend. */
 	if (lp->log_count &&
 	    !seg_is_raid(first_seg(lv)) && seg_is_mirrored(first_seg(lv))) {
 		if (!add_mirror_log(cmd, lv, lp->log_count,
--- LVM2/lib/metadata/pv_map.c	2010/03/25 21:19:27	1.36
+++ LVM2/lib/metadata/pv_map.c	2012/02/01 02:10:46	1.37
@@ -205,10 +205,10 @@
 }
 
 /*
- * Remove an area from list and reinsert it based on its new smaller size
- * after a provisional allocation.
+ * Remove an area from list and reinsert it based on its new size
+ * after a provisional allocation (or reverting one).
  */
-void reinsert_reduced_pv_area(struct pv_area *pva)
+void reinsert_changed_pv_area(struct pv_area *pva)
 {
 	_remove_area(pva);
 	_insert_area(&pva->map->areas, pva, 1);
--- LVM2/lib/metadata/pv_map.h	2010/07/09 15:21:10	1.14
+++ LVM2/lib/metadata/pv_map.h	2012/02/01 02:10:46	1.15
@@ -31,7 +31,7 @@
 	uint32_t start;
 	uint32_t count;
 
-	/* Number of extents unreserved during ALLOC_ANYWHERE allocation. */
+	/* Number of extents unreserved during a single allocation pass. */
 	uint32_t unreserved;
 
 	struct dm_list list;		/* pv_map.areas */
@@ -66,7 +66,7 @@
 			    struct dm_list *allocatable_pvs);
 
 void consume_pv_area(struct pv_area *area, uint32_t to_go);
-void reinsert_reduced_pv_area(struct pv_area *pva);
+void reinsert_changed_pv_area(struct pv_area *pva);
 
 uint32_t pv_maps_size(struct dm_list *pvms);
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2011-10-22 16:42 zkabelac
  0 siblings, 0 replies; 36+ messages in thread
From: zkabelac @ 2011-10-22 16:42 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	zkabelac@sourceware.org	2011-10-22 16:42:11

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

Log message:
	Make move_lv_segment non-static
	
	This function could be useful for other _manip source files.
	
	Use dm_list manipulation function for provided functionality,
	which make the code more readable and avoid touching list
	internal details here.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2166&r2=1.2167
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.300&r2=1.301
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.259&r2=1.260

--- LVM2/WHATS_NEW	2011/10/21 15:49:45	1.2166
+++ LVM2/WHATS_NEW	2011/10/22 16:42:10	1.2167
@@ -1,5 +1,6 @@
 Version 2.02.89 - 
 ==================================
+  Make move_lv_segment non-static function and use dm_list function.
   Pass exclusive LV locks to all nodes in the cluster.
   Improve lvcreate man documentation of the chunksize option.
   Improve man page style for lvcreate.
--- LVM2/lib/metadata/lv_manip.c	2011/10/21 11:38:35	1.300
+++ LVM2/lib/metadata/lv_manip.c	2011/10/22 16:42:11	1.301
@@ -3446,23 +3446,20 @@
 	return 1;
 }
 
-static int _move_lv_segments(struct logical_volume *lv_to,
-			     struct logical_volume *lv_from,
-			     uint64_t set_status, uint64_t reset_status)
+int move_lv_segments(struct logical_volume *lv_to,
+		     struct logical_volume *lv_from,
+		     uint64_t set_status, uint64_t reset_status)
 {
 	struct lv_segment *seg;
 
-	dm_list_iterate_items(seg, &lv_to->segments) {
+	dm_list_iterate_items(seg, &lv_to->segments)
 		if (seg->origin) {
-			log_error("Can't move snapshot segment");
+			log_error("Can't move snapshot segment.");
 			return 0;
 		}
-	}
 
-	if (!dm_list_empty(&lv_from->segments))
-		lv_to->segments = lv_from->segments;
-	lv_to->segments.n->p = &lv_to->segments;
-	lv_to->segments.p->n = &lv_to->segments;
+	dm_list_init(&lv_to->segments);
+	dm_list_splice(&lv_to->segments, &lv_from->segments);
 
 	dm_list_iterate_items(seg, &lv_to->segments) {
 		seg->lv = lv_to;
@@ -3470,8 +3467,6 @@
 		seg->status |= set_status;
 	}
 
-	dm_list_init(&lv_from->segments);
-
 	lv_to->le_count = lv_from->le_count;
 	lv_to->size = lv_from->size;
 
@@ -3512,7 +3507,7 @@
 	if (!lv_empty(parent))
 		return_0;
 
-	if (!_move_lv_segments(parent, layer_lv, 0, 0))
+	if (!move_lv_segments(parent, layer_lv, 0, 0))
 		return_0;
 
 	/* Replace the empty layer with error segment */
@@ -3602,7 +3597,7 @@
 	log_very_verbose("Inserting layer %s for %s",
 			 layer_lv->name, lv_where->name);
 
-	if (!_move_lv_segments(layer_lv, lv_where, 0, 0))
+	if (!move_lv_segments(layer_lv, lv_where, 0, 0))
 		return_NULL;
 
 	if (!(segtype = get_segtype_from_string(cmd, "striped")))
--- LVM2/lib/metadata/metadata.h	2011/10/19 16:39:09	1.259
+++ LVM2/lib/metadata/metadata.h	2011/10/22 16:42:11	1.260
@@ -420,6 +420,9 @@
                     int (*fn)(struct cmd_context *cmd,
                               struct logical_volume *lv, void *data),
                     void *data);
+int move_lv_segments(struct logical_volume *lv_to,
+		     struct logical_volume *lv_from,
+		     uint64_t set_status, uint64_t reset_status);
 
 /*
  * Calculate readahead from underlying PV devices


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2011-09-06 18:49 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2011-09-06 18:49 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2011-09-06 18:49:33

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h metadata.h 
	                 mirror.c raid_manip.c 
	tools          : lvconvert.c polldaemon.c polldaemon.h 

Log message:
	Start using 64-bit status flags - most of the code already handles them.
	tdata -> tpool
	remove commented out definitions from metadata.h
	formatting clean-ups

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2093&r2=1.2094
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.279&r2=1.280
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.204&r2=1.205
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.251&r2=1.252
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.160&r2=1.161
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/raid_manip.c.diff?cvsroot=lvm2&r1=1.11&r2=1.12
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.171&r2=1.172
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/polldaemon.c.diff?cvsroot=lvm2&r1=1.45&r2=1.46
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/polldaemon.h.diff?cvsroot=lvm2&r1=1.11&r2=1.12

--- LVM2/WHATS_NEW	2011/09/06 18:24:27	1.2093
+++ LVM2/WHATS_NEW	2011/09/06 18:49:31	1.2094
@@ -1,5 +1,6 @@
 Version 2.02.89 - 
 ==================================
+  Begin using 64-bit status field flags.
   Detect sscanf recovering_region input error in cmirrord pull_state().
   Fix error path bitmap leak in cmirrord import_checkpoint().
   Log unlink() error in cmirrord remove_lockfile().
--- LVM2/lib/metadata/lv_manip.c	2011/09/06 15:39:46	1.279
+++ LVM2/lib/metadata/lv_manip.c	2011/09/06 18:49:32	1.280
@@ -1675,7 +1675,7 @@
 						if (alloc_state->areas[s].pva && alloc_state->areas[s].pva->map->pv == pvm->pv)
 							goto next_pv;
 				/* On a second pass, avoid PVs already used in an uncommitted area */
- 				} else if (iteration_count)
+				} else if (iteration_count)
 					for (s = 0; s < devices_needed; s++)
 						if (alloc_state->areas[s].pva && alloc_state->areas[s].pva->map->pv == pvm->pv)
 							goto next_pv;
@@ -1907,8 +1907,8 @@
 		return 1;
 	}
 
-        if (ah->area_multiple > 1 &&
-            (ah->new_extents - alloc_state.allocated) % ah->area_count) {
+	if (ah->area_multiple > 1 &&
+	    (ah->new_extents - alloc_state.allocated) % ah->area_count) {
 		log_error("Number of extents requested (%d) needs to be divisible by %d.",
 			  ah->new_extents - alloc_state.allocated, ah->area_count);
 		return 0;
@@ -2306,7 +2306,7 @@
  * If we used AREA_PVs under the mirror layer of a log, we could
  * assemble it all at once by calling 'lv_add_segment' with the
  * appropriate segtype (mirror/stripe), like this:
- * 	lv_add_segment(ah, ah->area_count, ah->log_area_count,
+ *	lv_add_segment(ah, ah->area_count, ah->log_area_count,
  *		       log_lv, segtype, 0, MIRROR_LOG, 0);
  *
  * For now, we use the same mechanism to build a mirrored log as we
@@ -2353,7 +2353,7 @@
 	} else if (segtype_is_thin_pool(segtype)) {
 		// lv->status |= THIN_POOL;
 		// status = THIN_IMAGE;
-		layer_name = "tdata";
+		layer_name = "tpool";
 	} else
 		return_0;
 
@@ -3775,7 +3775,7 @@
 	dev_flush(dev);
 
 	if (!dev_close_immediate(dev))
-                stack;
+		stack;
 
 	return 1;
 }
@@ -4198,7 +4198,7 @@
 		lp->pool = lv->name;
 	
 		if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
-		return_0;
+			return_0;
 	}
 
 	if (!(lv = _lv_create_an_lv(vg, lp, lp->lv_name)))
--- LVM2/lib/metadata/metadata-exported.h	2011/09/06 00:26:43	1.204
+++ LVM2/lib/metadata/metadata-exported.h	2011/09/06 18:49:32	1.205
@@ -42,55 +42,55 @@
 /* Various flags */
 /* Note that the bits no longer necessarily correspond to LVM1 disk format */
 
-#define PARTIAL_VG		0x00000001U	/* VG */
-#define EXPORTED_VG          	0x00000002U	/* VG PV */
-#define RESIZEABLE_VG        	0x00000004U	/* VG */
-
-/*
- * Since the RAID flags are LV (and seg) only and the above three
- * are VG/PV only, these flags are reused.
- */
-#define RAID                    0x00000001U	/* LV */
-#define RAID_META               0x00000002U	/* LV */
-#define RAID_IMAGE              0x00000004U	/* LV */
+#define PARTIAL_VG		UINT64_C(0x00000001)	/* VG */
+#define EXPORTED_VG		UINT64_C(0x00000002)	/* VG PV */
+#define RESIZEABLE_VG		UINT64_C(0x00000004)	/* VG */
 
 /* May any free extents on this PV be used or must they be left free? */
-#define ALLOCATABLE_PV         	0x00000008U	/* PV */
+#define ALLOCATABLE_PV		UINT64_C(0x00000008)	/* PV */
 
-//#define SPINDOWN_LV          	0x00000010U	/* LV */
-//#define BADBLOCK_ON       	0x00000020U	/* LV */
-#define VISIBLE_LV		0x00000040U	/* LV */
-#define FIXED_MINOR		0x00000080U	/* LV */
+//#define SPINDOWN_LV		UINT64_C(0x00000010)	/* LV */
+//#define BADBLOCK_ON		UINT64_C(0x00000020)	/* LV */
+#define VISIBLE_LV		UINT64_C(0x00000040)	/* LV */
+#define FIXED_MINOR		UINT64_C(0x00000080)	/* LV */
 /* FIXME Remove when metadata restructuring is completed */
-#define SNAPSHOT		0x00001000U	/* LV - internal use only */
-#define PVMOVE			0x00002000U	/* VG LV SEG */
-#define LOCKED			0x00004000U	/* LV */
-#define MIRRORED		0x00008000U	/* LV - internal use only */
-//#define VIRTUAL			0x00010000U	/* LV - internal use only */
-#define MIRROR_LOG		0x00020000U	/* LV */
-#define MIRROR_IMAGE		0x00040000U	/* LV */
-#define LV_NOTSYNCED		0x00080000U	/* LV */
-//#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
-#define CONVERTING		0x00400000U	/* LV */
-
-#define MISSING_PV              0x00800000U	/* PV */
-#define PARTIAL_LV              0x01000000U	/* LV - derived flag, not
-						   written out in metadata*/
-
-//#define POSTORDER_FLAG	0x02000000U /* Not real flags, reserved for
-//#define POSTORDER_OPEN_FLAG	0x04000000U    temporary use inside vg_read_internal. */
-//#define VIRTUAL_ORIGIN	0x08000000U	/* LV - internal use only */
-
-#define MERGING			0x10000000U	/* LV SEG */
-
-#define REPLICATOR		0x20000000U	/* LV -internal use only for replicator */
-#define REPLICATOR_LOG		0x40000000U	/* LV -internal use only for replicator-dev */
-#define UNLABELLED_PV           0x80000000U     /* PV -this PV had no label written yet */
-
-#define LVM_READ              	0x00000100U	/* LV VG */
-#define LVM_WRITE             	0x00000200U	/* LV VG */
-#define CLUSTERED         	0x00000400U	/* VG */
-//#define SHARED            	0x00000800U	/* VG */
+#define SNAPSHOT		UINT64_C(0x00001000)	/* LV - internal use only */
+#define PVMOVE			UINT64_C(0x00002000)	/* VG LV SEG */
+#define LOCKED			UINT64_C(0x00004000)	/* LV */
+#define MIRRORED		UINT64_C(0x00008000)	/* LV - internal use only */
+//#define VIRTUAL		UINT64_C(0x00010000)	/* LV - internal use only */
+#define MIRROR_LOG		UINT64_C(0x00020000)	/* LV */
+#define MIRROR_IMAGE		UINT64_C(0x00040000)	/* LV */
+#define LV_NOTSYNCED		UINT64_C(0x00080000)	/* LV */
+//#define PRECOMMITTED		UINT64_C(0x00200000)	/* VG - internal use only */
+#define CONVERTING		UINT64_C(0x00400000)	/* LV */
+
+#define MISSING_PV		UINT64_C(0x00800000)	/* PV */
+#define PARTIAL_LV		UINT64_C(0x01000000)	/* LV - derived flag, not
+							   written out in metadata*/
+
+//#define POSTORDER_FLAG	UINT64_C(0x02000000) /* Not real flags, reserved for
+//#define POSTORDER_OPEN_FLAG	UINT64_C(0x04000000)    temporary use inside vg_read_internal. */
+//#define VIRTUAL_ORIGIN	UINT64_C(0x08000000)	/* LV - internal use only */
+
+#define MERGING			UINT64_C(0x10000000)	/* LV SEG */
+
+#define REPLICATOR		UINT64_C(0x20000000)	/* LV -internal use only for replicator */
+#define REPLICATOR_LOG		UINT64_C(0x40000000)	/* LV -internal use only for replicator-dev */
+#define UNLABELLED_PV		UINT64_C(0x80000000)	/* PV -this PV had no label written yet */
+
+#define RAID			UINT64_C(0x0000000100000000)	/* LV */
+#define RAID_META		UINT64_C(0x0000000200000000)	/* LV */
+#define RAID_IMAGE		UINT64_C(0x0000000400000000)	/* LV */
+
+#define THIN_VOLUME		UINT64_C(0x0000001000000000)	/* LV */
+#define THIN_POOL		UINT64_C(0x0000002000000000)	/* LV */
+
+#define LVM_READ		0x00000100U	/* LV VG 32-bit */
+#define LVM_WRITE		0x00000200U	/* LV VG 32-bit */
+
+#define CLUSTERED		UINT64_C(0x00000400)	/* VG */
+//#define SHARED		UINT64_C(0x00000800)	/* VG */
 
 /* Format features flags */
 #define FMT_SEGMENTS		0x00000001U	/* Arbitrary segment params? */
@@ -112,10 +112,10 @@
 /* vg_read and vg_read_for_update flags */
 #define READ_ALLOW_INCONSISTENT	0x00010000U
 #define READ_ALLOW_EXPORTED	0x00020000U
-#define READ_WITHOUT_LOCK       0x00040000U
+#define READ_WITHOUT_LOCK	0x00040000U
 
 /* A meta-flag, useful with toollib for_each_* functions. */
-#define READ_FOR_UPDATE 	0x00100000U
+#define READ_FOR_UPDATE		0x00100000U
 
 /* vg's "read_status" field */
 #define FAILED_INCONSISTENT	0x00000001U
@@ -189,19 +189,19 @@
  */
 
 /* PV-based format instance */
-#define FMT_INSTANCE_PV 		0x00000000U
+#define FMT_INSTANCE_PV			0x00000000U
 
 /* VG-based format instance */
-#define FMT_INSTANCE_VG 		0x00000001U
+#define FMT_INSTANCE_VG			0x00000001U
 
 /* Include any existing PV mdas during format_instance initialisation */
-#define FMT_INSTANCE_MDAS 		0x00000002U
+#define FMT_INSTANCE_MDAS		0x00000002U
 
 /* Include any auxiliary mdas during format_instance intialisation */
-#define FMT_INSTANCE_AUX_MDAS 		0x00000004U
+#define FMT_INSTANCE_AUX_MDAS		0x00000004U
 
 /* Include any other format-specific mdas during format_instance initialisation */
-#define FMT_INSTANCE_PRIVATE_MDAS 	0x00000008U
+#define FMT_INSTANCE_PRIVATE_MDAS	0x00000008U
 
 struct format_instance {
 	unsigned ref_count;	/* Refs to this fid from VG and PV structs */
@@ -265,9 +265,9 @@
 
 	struct logical_volume *replicator; /* Reference to replicator */
 
-	const char *name;               /* Site name */
+	const char *name;		/* Site name */
 	const char *vg_name;		/* VG name */
-	struct volume_group *vg;        /* resolved vg  (activate/deactive) */
+	struct volume_group *vg;	/* resolved vg  (activate/deactive) */
 	unsigned site_index;
 	replicator_state_t state;	/* Active or pasive state of site */
 	dm_replicator_mode_t op_mode;	/* Operation mode sync or async fail|warn|drop|stall */
@@ -301,7 +301,7 @@
 	uint64_t status;
 
 	/* FIXME Fields depend on segment type */
-	uint32_t stripe_size;   /* For stripe and RAID - in sectors */
+	uint32_t stripe_size;	/* For stripe and RAID - in sectors */
 	uint32_t area_count;
 	uint32_t area_len;
 	uint32_t chunk_size;	/* For snapshots - in sectors */
@@ -388,7 +388,7 @@
 int vg_commit(struct volume_group *vg);
 int vg_revert(struct volume_group *vg);
 struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vg_name,
-			     const char *vgid, int warnings, int *consistent);
+				      const char *vgid, int warnings, int *consistent);
 struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
 				int warnings,
 				int scan_label_only);
@@ -425,9 +425,9 @@
  * Return a handle to VG metadata.
  */
 struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
-              const char *vgid, uint32_t flags);
+			     const char *vgid, uint32_t flags);
 struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
-                         const char *vgid, uint32_t flags);
+			 const char *vgid, uint32_t flags);
 
 /* 
  * Test validity of a VG handle.
@@ -450,7 +450,7 @@
 				  uint64_t pvmetadatasize,
 				  unsigned metadataignore);
 int pv_resize(struct physical_volume *pv, struct volume_group *vg,
-             uint64_t size);
+	      uint64_t size);
 int pv_analyze(struct cmd_context *cmd, const char *pv_name,
 	       uint64_t label_sector);
 
@@ -495,7 +495,7 @@
 
 /* Write out LV contents */
 int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
-           uint64_t sectors, int value);
+	   uint64_t sectors, int value);
 
 int lv_change_tag(struct logical_volume *lv, const char *tag, int add_tag);
 
@@ -699,7 +699,7 @@
 int lv_is_mirrored(const struct logical_volume *lv);
 uint32_t lv_mirror_count(const struct logical_volume *lv);
 uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
-                                    uint32_t region_size);
+				    uint32_t region_size);
 int remove_mirrors_from_segments(struct logical_volume *lv,
 				 uint32_t new_mirrors, uint64_t status_mask);
 int add_mirrors_to_segments(struct cmd_context *cmd, struct logical_volume *lv,
@@ -773,12 +773,12 @@
 void lv_release_replicator_vgs(struct logical_volume *lv);
 
 struct logical_volume *find_pvmove_lv(struct volume_group *vg,
-				      struct device *dev, uint32_t lv_type);
+				      struct device *dev, uint64_t lv_type);
 struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
 						  struct volume_group *vg,
 						  const char *name,
 						  const char *uuid,
-						  uint32_t lv_type);
+						  uint64_t lv_type);
 struct logical_volume *find_pvmove_lv_in_lv(struct logical_volume *lv);
 const char *get_pvmove_pvname_from_lv(struct logical_volume *lv);
 const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr);
--- LVM2/lib/metadata/metadata.h	2011/09/01 10:25:22	1.251
+++ LVM2/lib/metadata/metadata.h	2011/09/06 18:49:32	1.252
@@ -49,54 +49,23 @@
 
 
 /* Various flags */
+/* See metadata-exported.h for the complete list. */
 /* Note that the bits no longer necessarily correspond to LVM1 disk format */
 
-//#define PARTIAL_VG		0x00000001U	/* VG */
-//#define EXPORTED_VG          	0x00000002U	/* VG PV */
-//#define RESIZEABLE_VG        	0x00000004U	/* VG */
-
 /* May any free extents on this PV be used or must they be left free? */
-//#define ALLOCATABLE_PV         	0x00000008U	/* PV */
 
-#define SPINDOWN_LV          	0x00000010U	/* LV */
-#define BADBLOCK_ON       	0x00000020U	/* LV */
-//#define VISIBLE_LV		0x00000040U	/* LV */
-//#define FIXED_MINOR		0x00000080U	/* LV */
-/* FIXME Remove when metadata restructuring is completed */
-//#define SNAPSHOT		0x00001000U	/* LV - internal use only */
-//#define PVMOVE			0x00002000U	/* VG LV SEG */
-//#define LOCKED			0x00004000U	/* LV */
-//#define MIRRORED		0x00008000U	/* LV - internal use only */
-#define VIRTUAL			0x00010000U	/* LV - internal use only */
-//#define MIRROR_LOG		0x00020000U	/* LV */
-//#define MIRROR_IMAGE		0x00040000U	/* LV */
-//#define MIRROR_NOTSYNCED	0x00080000U	/* LV */
-#define PRECOMMITTED		0x00200000U	/* VG - internal use only */
-//#define CONVERTING		0x00400000U	/* LV */
-
-//#define MISSING_PV		0x00800000U	/* PV */
-//#define PARTIAL_LV		0x01000000U	/* LV - derived flag, not
-//						   written out in metadata*/
-
-#define POSTORDER_FLAG		0x02000000U /* Not real flags, reserved for  */
-#define POSTORDER_OPEN_FLAG	0x04000000U /* temporary use inside vg_read_internal. */
-#define VIRTUAL_ORIGIN		0x08000000U	/* LV - internal use only */
-
-//#define LVM_READ              	0x00000100U	/* LV VG */
-//#define LVM_WRITE             	0x00000200U	/* LV VG */
-//#define CLUSTERED         	0x00000400U	/* VG */
-#define SHARED            	0x00000800U	/* VG */
+#define SPINDOWN_LV          	UINT64_C(0x00000010)	/* LV */
+#define BADBLOCK_ON       	UINT64_C(0x00000020)	/* LV */
+#define VIRTUAL			UINT64_C(0x00010000)	/* LV - internal use only */
+#define PRECOMMITTED		UINT64_C(0x00200000)	/* VG - internal use only */
+#define POSTORDER_FLAG		UINT64_C(0x02000000) /* Not real flags, reserved for  */
+#define POSTORDER_OPEN_FLAG	UINT64_C(0x04000000) /* temporary use inside vg_read_internal. */
+#define VIRTUAL_ORIGIN		UINT64_C(0x08000000)	/* LV - internal use only */
+
+#define SHARED            	UINT64_C(0x00000800)	/* VG */
 
 /* Format features flags */
-//#define FMT_SEGMENTS		0x00000001U	/* Arbitrary segment params? */
-//#define FMT_MDAS		0x00000002U	/* Proper metadata areas? */
-//#define FMT_TAGS		0x00000004U	/* Tagging? */
-//#define FMT_UNLIMITED_VOLS	0x00000008U	/* Unlimited PVs/LVs? */
-//#define FMT_RESTRICTED_LVIDS	0x00000010U	/* LVID <= 255 */
-//#define FMT_ORPHAN_ALLOCATABLE	0x00000020U	/* Orphan PV allocatable? */
 #define FMT_PRECOMMIT		0x00000040U	/* Supports pre-commit? */
-//#define FMT_RESIZE_PV		0x00000080U	/* Supports pvresize? */
-//#define FMT_UNLIMITED_STRIPESIZE 0x00000100U	/* Unlimited stripe size? */
 
 struct dm_config_tree;
 struct metadata_area;
--- LVM2/lib/metadata/mirror.c	2011/09/01 19:22:11	1.160
+++ LVM2/lib/metadata/mirror.c	2011/09/06 18:49:32	1.161
@@ -1528,7 +1528,7 @@
 
 struct logical_volume *find_pvmove_lv(struct volume_group *vg,
 				      struct device *dev,
-				      uint32_t lv_type)
+				      uint64_t lv_type)
 {
 	struct lv_list *lvl;
 	struct logical_volume *lv;
@@ -1558,7 +1558,7 @@
 						  struct volume_group *vg,
 						  const char *name,
 						  const char *uuid __attribute__((unused)),
-						  uint32_t lv_type)
+						  uint64_t lv_type)
 {
 	struct physical_volume *pv;
 	struct logical_volume *lv;
--- LVM2/lib/metadata/raid_manip.c	2011/08/19 19:35:50	1.11
+++ LVM2/lib/metadata/raid_manip.c	2011/09/06 18:49:32	1.12
@@ -359,7 +359,7 @@
  */
 static int _alloc_image_component(struct logical_volume *lv,
 				  struct alloc_handle *ah, uint32_t first_area,
-				  uint32_t type, struct logical_volume **new_lv)
+				  uint64_t type, struct logical_volume **new_lv)
 {
 	uint64_t status;
 	size_t len = strlen(lv->name) + 32;
--- LVM2/tools/lvconvert.c	2011/08/18 19:43:09	1.171
+++ LVM2/tools/lvconvert.c	2011/09/06 18:49:32	1.172
@@ -342,7 +342,7 @@
 						struct volume_group *vg,
 						const char *name,
 						const char *uuid,
-						uint32_t lv_type __attribute__((unused)))
+						uint64_t lv_type __attribute__((unused)))
 {
 	struct logical_volume *lv = find_lv(vg, name);
 
--- LVM2/tools/polldaemon.c	2011/08/10 20:25:31	1.45
+++ LVM2/tools/polldaemon.c	2011/09/06 18:49:32	1.46
@@ -283,7 +283,7 @@
  */
 int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
 		unsigned background,
-		uint32_t lv_type, struct poll_functions *poll_fns,
+		uint64_t lv_type, struct poll_functions *poll_fns,
 		const char *progress_title)
 {
 	struct daemon_parms parms;
--- LVM2/tools/polldaemon.h	2010/01/22 21:59:43	1.11
+++ LVM2/tools/polldaemon.h	2011/09/06 18:49:32	1.12
@@ -36,7 +36,7 @@
 					       struct volume_group *vg,
 					       const char *name,
 					       const char *uuid,
-					       uint32_t lv_type);
+					       uint64_t lv_type);
 	progress_t (*poll_progress)(struct cmd_context *cmd,
 				    struct logical_volume *lv,
 				    const char *name,
@@ -59,13 +59,13 @@
 	unsigned outstanding_count;
 	unsigned progress_display;
 	const char *progress_title;
-	uint32_t lv_type;
+	uint64_t lv_type;
 	struct poll_functions *poll_fns;
 };
 
 int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
 		unsigned background,
-		uint32_t lv_type, struct poll_functions *poll_fns,
+		uint64_t lv_type, struct poll_functions *poll_fns,
 		const char *progress_title);
 
 progress_t poll_mirror_progress(struct cmd_context *cmd,


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2011-08-18 19:41 jbrassow
  0 siblings, 0 replies; 36+ messages in thread
From: jbrassow @ 2011-08-18 19:41 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	jbrassow@sourceware.org	2011-08-18 19:41:22

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c raid_manip.c 
	lib/raid       : raid.c 
	libdm          : libdevmapper.h libdm-deptree.c 

Log message:
	Add support for m-way to n-way up-convert in RAID1 (no linear to n-way yet)
	
	This patch adds the ability to upconvert a raid1 array - say from 2-way to
	3-way.  It does not yet support upconverting linear to n-way.
	
	The 'raid' device-mapper target allows for individual components (images) of
	an array to be specified for rebuild.  This mechanism is used when adding
	new images to the array so that the new images can be resync'ed while the
	rest of the images in the array can remain 'in-sync'.  (There is no
	mirror-on-mirror layering required.)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2077&r2=1.2078
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.273&r2=1.274
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/raid_manip.c.diff?cvsroot=lvm2&r1=1.7&r2=1.8
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/raid/raid.c.diff?cvsroot=lvm2&r1=1.6&r2=1.7
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/libdm/libdevmapper.h.diff?cvsroot=lvm2&r1=1.142&r2=1.143
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/libdm/libdm-deptree.c.diff?cvsroot=lvm2&r1=1.105&r2=1.106

--- LVM2/WHATS_NEW	2011/08/18 19:38:26	1.2077
+++ LVM2/WHATS_NEW	2011/08/18 19:41:21	1.2078
@@ -1,5 +1,6 @@
 Version 2.02.88 - 
 ==================================
+  Add support for m-way to n-way up-convert in RAID1 (no linear to n-way yet)
   Add --trackchanges support to --splitmirrors option for RAID1
   Add --splitmirrors support for RAID1 (1 image only)
   When down-converting RAID1, don't activate sub-lvs between suspend/resume
--- LVM2/lib/metadata/lv_manip.c	2011/08/11 19:38:00	1.273
+++ LVM2/lib/metadata/lv_manip.c	2011/08/18 19:41:21	1.274
@@ -1027,7 +1027,8 @@
 			log_debug("Allocating parallel metadata area %" PRIu32
 				  " on %s start PE %" PRIu32
 				  " length %" PRIu32 ".",
-				  s, pv_dev_name(aa[s].pv), aa[s].pe,
+				  (s - (ah->area_count + ah->parity_count)),
+				  pv_dev_name(aa[s].pv), aa[s].pe,
 				  ah->log_len);
 
 			consume_pv_area(pva, ah->log_len);
@@ -1536,6 +1537,35 @@
 		alloc_state->areas[s].pva = NULL;
 }
 
+static void _report_needed_allocation_space(struct alloc_handle *ah,
+					    struct alloc_state *alloc_state)
+{
+	const char *metadata_type;
+	uint32_t p_areas_count, p_area_size;
+	uint32_t metadata_count, metadata_size;
+
+	p_area_size = (ah->new_extents - alloc_state->allocated);
+	p_area_size /= ah->area_multiple;
+	p_area_size -= (ah->alloc_and_split_meta) ? ah->log_len : 0;
+	p_areas_count = ah->area_count + ah->parity_count;
+
+	metadata_size = ah->log_len;
+	if (ah->alloc_and_split_meta) {
+		metadata_type = "RAID metadata area";
+		metadata_count = p_areas_count;
+	} else {
+		metadata_type = "mirror log";
+		metadata_count = alloc_state->log_area_count_still_needed;
+	}
+
+	log_debug("Still need %" PRIu32 " total extents:",
+		p_area_size * p_areas_count + metadata_size * metadata_count);
+	log_debug("  %" PRIu32 " (%" PRIu32 " data/%" PRIu32
+		  " parity) parallel areas of %" PRIu32 " extents each",
+		  p_areas_count, ah->area_count, ah->parity_count, p_area_size);
+	log_debug("  %" PRIu32 " %ss of %" PRIu32 " extents each",
+		  metadata_count, metadata_type, metadata_size);
+}
 /*
  * Returns 1 regardless of whether any space was found, except on error.
  */
@@ -1571,13 +1601,7 @@
 
 	_clear_areas(alloc_state);
 
-	log_debug("Still need %" PRIu32 " extents for %" PRIu32 " parallel areas and %" PRIu32 " log areas of %" PRIu32 " extents. "
-		  "(Total %" PRIu32 " extents.)",
-		  (ah->new_extents - alloc_state->allocated) / ah->area_multiple,
-		  devices_needed, alloc_state->log_area_count_still_needed,
-		  alloc_state->log_area_count_still_needed ? ah->log_len : 0,
-		  (ah->new_extents - alloc_state->allocated) * devices_needed / ah->area_multiple +
-			alloc_state->log_area_count_still_needed * ah->log_len);
+	_report_needed_allocation_space(ah, alloc_state);
 
 	/* ix holds the number of areas found on other PVs */
 	do {
@@ -1769,6 +1793,7 @@
 static int _find_max_parallel_space_for_one_policy(struct alloc_handle *ah, struct alloc_parms *alloc_parms,
 						   struct dm_list *pvms, struct alloc_state *alloc_state)
 {
+	uint32_t max_tmp;
 	uint32_t max_to_allocate;	/* Maximum extents to allocate this time */
 	uint32_t old_allocated;
 	uint32_t next_le;
@@ -1791,8 +1816,20 @@
 				if (next_le >= spvs->le + spvs->len)
 					continue;
 
-				if (max_to_allocate + alloc_state->allocated > (spvs->le + spvs->len) * ah->area_multiple)
+				max_tmp = max_to_allocate +
+					alloc_state->allocated;
+
+				/*
+				 * Because a request that groups metadata and
+				 * data together will be split, we must adjust
+				 * the comparison accordingly.
+				 */
+				if (ah->alloc_and_split_meta)
+					max_tmp -= ah->log_len;
+				if (max_tmp > (spvs->le + spvs->len) * ah->area_multiple) {
 					max_to_allocate = (spvs->le + spvs->len) * ah->area_multiple - alloc_state->allocated;
+					max_to_allocate += ah->alloc_and_split_meta ? ah->log_len : 0;
+				}
 				parallel_pvs = &spvs->pvs;
 				break;
 			}
--- LVM2/lib/metadata/raid_manip.c	2011/08/18 19:38:27	1.7
+++ LVM2/lib/metadata/raid_manip.c	2011/08/18 19:41:21	1.8
@@ -196,6 +196,81 @@
 }
 
 /*
+ * clear_lv
+ * @lv
+ *
+ * If LV is active:
+ *        clear first block of device
+ * otherwise:
+ *        activate, clear, deactivate
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+static int clear_lv(struct logical_volume *lv)
+{
+	int was_active = lv_is_active(lv);
+
+	if (!was_active && !activate_lv(lv->vg->cmd, lv)) {
+		log_error("Failed to activate %s for clearing",
+			  lv->name);
+		return 0;
+	}
+
+	log_verbose("Clearing metadata area of %s/%s",
+		    lv->vg->name, lv->name);
+	/*
+	 * Rather than wiping lv->size, we can simply
+	 * wipe '1' to remove the superblock of any previous
+	 * RAID devices.  It is much quicker.
+	 */
+	if (!set_lv(lv->vg->cmd, lv, 1, 0)) {
+		log_error("Failed to zero %s", lv->name);
+		return 0;
+	}
+
+	if (!was_active && !deactivate_lv(lv->vg->cmd, lv)) {
+		log_error("Failed to deactivate %s", lv->name);
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Makes on-disk metadata changes */
+static int clear_lvs(struct dm_list *lv_list)
+{
+	struct lv_list *lvl;
+	struct volume_group *vg = NULL;
+
+	if (dm_list_empty(lv_list)) {
+		log_debug(INTERNAL_ERROR "Empty list of LVs given for clearing");
+		return 1;
+	}
+
+	dm_list_iterate_items(lvl, lv_list) {
+		if (!lv_is_visible(lvl->lv)) {
+			log_error(INTERNAL_ERROR
+				  "LVs must be set visible before clearing");
+			return 0;
+		}
+		vg = lvl->lv->vg;
+	}
+
+	/*
+	 * FIXME: only vg_[write|commit] if LVs are not already written
+	 * as visible in the LVM metadata (which is never the case yet).
+	 */
+	if (!vg || !vg_write(vg) || !vg_commit(vg))
+		return_0;
+
+	dm_list_iterate_items(lvl, lv_list)
+		if (!clear_lv(lvl->lv))
+			return 0;
+
+	return 1;
+}
+
+/*
  * _shift_and_rename_image_components
  * @seg: Top-level RAID segment
  *
@@ -278,14 +353,234 @@
 	return 1;
 }
 
+/*
+ * Create an LV of specified type.  Set visible after creation.
+ * This function does not make metadata changes.
+ */
+static int _alloc_image_component(struct logical_volume *lv,
+				  struct alloc_handle *ah, uint32_t first_area,
+				  uint32_t type, struct logical_volume **new_lv)
+{
+	uint64_t status;
+	size_t len = strlen(lv->name) + 32;
+	char img_name[len];
+	struct logical_volume *tmp_lv;
+	const struct segment_type *segtype;
+
+	if (type == RAID_META) {
+		if (dm_snprintf(img_name, len, "%s_rmeta_%%d", lv->name) < 0)
+			return_0;
+	} else if (type == RAID_IMAGE) {
+		if (dm_snprintf(img_name, len, "%s_rimage_%%d", lv->name) < 0)
+			return_0;
+	} else {
+		log_error(INTERNAL_ERROR
+			  "Bad type provided to _alloc_raid_component");
+		return 0;
+	}
+
+	if (!ah) {
+		first_area = 0;
+		log_error(INTERNAL_ERROR
+			  "Stand-alone %s area allocation not implemented",
+			  (type == RAID_META) ? "metadata" : "data");
+		return 0;
+	}
+
+	status = LVM_READ | LVM_WRITE | LV_NOTSYNCED | type;
+	tmp_lv = lv_create_empty(img_name, NULL, status, ALLOC_INHERIT, lv->vg);
+	if (!tmp_lv) {
+		log_error("Failed to allocate new raid component, %s", img_name);
+		return 0;
+	}
+
+	segtype = get_segtype_from_string(lv->vg->cmd, "striped");
+	if (!lv_add_segment(ah, first_area, 1, tmp_lv, segtype, 0, status, 0)) {
+		log_error("Failed to add segment to LV, %s", img_name);
+		return 0;
+	}
+
+	lv_set_visible(tmp_lv);
+	*new_lv = tmp_lv;
+	return 1;
+}
+
+static int _alloc_image_components(struct logical_volume *lv,
+				   struct dm_list *pvs, uint32_t count,
+				   struct dm_list *new_meta_lvs,
+				   struct dm_list *new_data_lvs)
+{
+	uint32_t s;
+	struct lv_segment *seg = first_seg(lv);
+	struct alloc_handle *ah;
+	struct dm_list *parallel_areas;
+	struct logical_volume *tmp_lv;
+	struct lv_list *lvl_array;
+
+	lvl_array = dm_pool_alloc(lv->vg->vgmem,
+				  sizeof(*lvl_array) * count * 2);
+	if (!lvl_array)
+		return_0;
+
+	if (!(parallel_areas = build_parallel_areas_from_lv(lv, 0)))
+		return_0;
+
+	if (!(ah = allocate_extents(lv->vg, NULL, seg->segtype, 0, count, count,
+				    seg->region_size, lv->le_count, pvs,
+				    lv->alloc, parallel_areas)))
+		return_0;
+
+	for (s = 0; s < count; s++) {
+		/*
+		 * The allocation areas are grouped together.  First
+		 * come the rimage allocated areas, then come the metadata
+		 * allocated areas.  Thus, the metadata areas are pulled
+		 * from 's + count'.
+		 */
+		if (!_alloc_image_component(lv, ah, s + count,
+					    RAID_META, &tmp_lv))
+			return_0;
+		lvl_array[s + count].lv = tmp_lv;
+		dm_list_add(new_meta_lvs, &(lvl_array[s + count].list));
+
+		if (!_alloc_image_component(lv, ah, s, RAID_IMAGE, &tmp_lv))
+			return_0;
+		lvl_array[s].lv = tmp_lv;
+		dm_list_add(new_data_lvs, &(lvl_array[s].list));
+	}
+	alloc_destroy(ah);
+	return 1;
+}
+
 static int raid_add_images(struct logical_volume *lv,
 			   uint32_t new_count, struct dm_list *pvs)
 {
-	/* Not implemented */
-	log_error("Unable to add images to LV, %s/%s",
-		  lv->vg->name, lv->name);
+	uint32_t s;
+	uint32_t old_count = lv_raid_image_count(lv);
+	uint32_t count = new_count - old_count;
+	struct cmd_context *cmd = lv->vg->cmd;
+	struct lv_segment *seg = first_seg(lv);
+	struct dm_list meta_lvs, data_lvs;
+	struct lv_list *lvl;
+	struct lv_segment_area *new_areas;
+
+	dm_list_init(&meta_lvs); /* For image addition */
+	dm_list_init(&data_lvs); /* For image addition */
+
+	if (!seg_is_raid(seg)) {
+		log_error("Unable to add RAID images to %s of segment type %s",
+			  lv->name, seg->segtype->name);
+		return 0;
+	}
+
+	if (!_alloc_image_components(lv, pvs, count, &meta_lvs, &data_lvs)) {
+		log_error("Failed to allocate new image components");
+		return 0;
+	}
+
+	/* Metadata LVs must be cleared before being added to the array */
+	if (!clear_lvs(&meta_lvs))
+		goto fail;
+
+/*
+FIXME: It would be proper to activate the new LVs here, instead of having
+them activated by the suspend.  However, this causes residual device nodes
+to be left for these sub-lvs.
+	dm_list_iterate_items(lvl, &meta_lvs)
+		if (!do_correct_activate(lv, lvl->lv))
+			return_0;
+	dm_list_iterate_items(lvl, &data_lvs)
+		if (!do_correct_activate(lv, lvl->lv))
+			return_0;
+*/
+	/* Expand areas array */
+	if (!(new_areas = dm_pool_zalloc(lv->vg->cmd->mem,
+					 new_count * sizeof(*new_areas))))
+		goto fail;
+	memcpy(new_areas, seg->areas, seg->area_count * sizeof(*seg->areas));
+	seg->areas = new_areas;
+	seg->area_count = new_count;
+
+	/* Expand meta_areas array */
+	if (!(new_areas = dm_pool_zalloc(lv->vg->cmd->mem,
+					 new_count * sizeof(*new_areas))))
+		goto fail;
+	memcpy(new_areas, seg->meta_areas,
+	       seg->area_count * sizeof(*seg->meta_areas));
+	seg->meta_areas = new_areas;
+
+	/* Set segment areas for metadata sub_lvs */
+	s = old_count;
+	dm_list_iterate_items(lvl, &meta_lvs) {
+		log_debug("Adding %s to %s",
+			  lvl->lv->name, lv->name);
+		if (!set_lv_segment_area_lv(seg, s, lvl->lv, 0,
+					    lvl->lv->status)) {
+			log_error("Failed to add %s to %s",
+				  lvl->lv->name, lv->name);
+			goto fail;
+		}
+		s++;
+	}
 
-	return 0;
+	/* Set segment areas for data sub_lvs */
+	s = old_count;
+	dm_list_iterate_items(lvl, &data_lvs) {
+		log_debug("Adding %s to %s",
+			  lvl->lv->name, lv->name);
+		if (!set_lv_segment_area_lv(seg, s, lvl->lv, 0,
+					    lvl->lv->status)) {
+			log_error("Failed to add %s to %s",
+				  lvl->lv->name, lv->name);
+			goto fail;
+		}
+		s++;
+	}
+
+	/*
+	 * FIXME: Failure handling during these points is harder.
+	 */
+	dm_list_iterate_items(lvl, &meta_lvs)
+		lv_set_hidden(lvl->lv);
+	dm_list_iterate_items(lvl, &data_lvs)
+		lv_set_hidden(lvl->lv);
+
+	if (!vg_write(lv->vg)) {
+		log_error("Failed to write changes to %s in %s",
+			  lv->name, lv->vg->name);
+		return 0;
+	}
+
+	if (!suspend_lv(cmd, lv)) {
+		log_error("Failed to suspend %s/%s before committing changes",
+			  lv->vg->name, lv->name);
+		return 0;
+	}
+
+	if (!vg_commit(lv->vg)) {
+		log_error("Failed to commit changes to %s in %s",
+			  lv->name, lv->vg->name);
+		return 0;
+	}
+
+	if (!resume_lv(cmd, lv)) {
+		log_error("Failed to resume %s/%s after committing changes",
+			  lv->vg->name, lv->name);
+		return 0;
+	}
+
+	return 1;
+
+fail:
+	/* Cleanly remove newly allocated LVs that failed insertion attempt */
+
+	dm_list_iterate_items(lvl, &meta_lvs)
+		if (!lv_remove(lvl->lv))
+			return_0;
+	dm_list_iterate_items(lvl, &data_lvs)
+		if (!lv_remove(lvl->lv))
+			return_0;
+	return_0;
 }
 
 /*
@@ -386,7 +681,7 @@
 		    (extract > 1) ? "images" : "image",
 		    lv->vg->name, lv->name);
 
-	lvl_array = dm_pool_alloc(lv->vg->cmd->mem,
+	lvl_array = dm_pool_alloc(lv->vg->vgmem,
 				  sizeof(*lvl_array) * extract * 2);
 	if (!lvl_array)
 		return_0;
@@ -429,56 +724,21 @@
 	return 1;
 }
 
-/*
- * lv_raid_change_image_count
- * @lv
- * @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
- * @pvs: The list of PVs that are candidates for removal (or empty list)
- *
- * RAID arrays have 'images' which are composed of two parts, they are:
- *    - 'rimage': The data/parity holding portion
- *    - 'rmeta' : The metadata holding portion (i.e. superblock/bitmap area)
- * This function adds or removes _both_ portions of the image and commits
- * the results.
- *
- * Returns: 1 on success, 0 on failure
- */
-int lv_raid_change_image_count(struct logical_volume *lv,
-			       uint32_t new_count, struct dm_list *pvs)
+static int raid_remove_images(struct logical_volume *lv,
+			      uint32_t new_count, struct dm_list *pvs)
 {
-	uint32_t old_count = lv_raid_image_count(lv);
-	struct lv_segment *seg = first_seg(lv);
 	struct dm_list removal_list;
 	struct lv_list *lvl;
 
 	dm_list_init(&removal_list);
 
-	if (!seg_is_mirrored(seg)) {
-		log_error("Unable to change image count of non-mirrored RAID.");
+	if (!raid_extract_images(lv, new_count, pvs, 1,
+				 &removal_list, &removal_list)) {
+		log_error("Failed to extract images from %s/%s",
+			  lv->vg->name, lv->name);
 		return 0;
 	}
 
-	if (old_count == new_count) {
-		log_verbose("%s/%s already has image count of %d",
-			    lv->vg->name, lv->name, new_count);
-		return 1;
-	}
-
-	if (old_count > new_count) {
-		if (!raid_extract_images(lv, new_count, pvs, 1,
-					 &removal_list, &removal_list)) {
-			log_error("Failed to extract images from %s/%s",
-				  lv->vg->name, lv->name);
-			return 0;
-		}
-	} else {
-		if (!raid_add_images(lv, new_count, pvs)) {
-			log_error("Failed to add images to %s/%s",
-				  lv->vg->name, lv->name);
-			return 0;
-		}
-	}
-
 	/* Convert to linear? */
 	if ((new_count == 1) && !raid_remove_top_layer(lv, &removal_list)) {
 		log_error("Failed to remove RAID layer after linear conversion");
@@ -532,6 +792,43 @@
 	return 1;
 }
 
+/*
+ * lv_raid_change_image_count
+ * @lv
+ * @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
+ * @pvs: The list of PVs that are candidates for removal (or empty list)
+ *
+ * RAID arrays have 'images' which are composed of two parts, they are:
+ *    - 'rimage': The data/parity holding portion
+ *    - 'rmeta' : The metadata holding portion (i.e. superblock/bitmap area)
+ * This function adds or removes _both_ portions of the image and commits
+ * the results.
+ *
+ * Returns: 1 on success, 0 on failure
+ */
+int lv_raid_change_image_count(struct logical_volume *lv,
+			       uint32_t new_count, struct dm_list *pvs)
+{
+	uint32_t old_count = lv_raid_image_count(lv);
+	struct lv_segment *seg = first_seg(lv);
+
+	if (!seg_is_mirrored(seg)) {
+		log_error("Unable to change image count of non-mirrored RAID.");
+		return 0;
+	}
+
+	if (old_count == new_count) {
+		log_error("%s/%s already has image count of %d",
+			  lv->vg->name, lv->name, new_count);
+		return 1;
+	}
+
+	if (old_count > new_count)
+		return raid_remove_images(lv, new_count, pvs);
+
+	return raid_add_images(lv, new_count, pvs);
+}
+
 int lv_raid_split(struct logical_volume *lv, const char *split_name,
 		  uint32_t new_count, struct dm_list *splittable_pvs)
 {
--- LVM2/lib/raid/raid.c	2011/08/13 04:28:34	1.6
+++ LVM2/lib/raid/raid.c	2011/08/18 19:41:21	1.7
@@ -161,20 +161,37 @@
 		      struct dm_tree_node *node, uint64_t len,
 		      uint32_t *pvmove_mirror_count __attribute__((unused)))
 {
+	uint32_t s;
+	uint64_t rebuilds = 0;
+
 	if (!seg->area_count) {
 		log_error(INTERNAL_ERROR "_raid_add_target_line called "
 			  "with no areas for %s.", seg->lv->name);
 		return 0;
 	}
 
+	/*
+	 * 64 device restriction imposed by kernel as well.  It is
+	 * not strictly a userspace limitation.
+	 */
+	if (seg->area_count > 64) {
+		log_error("Unable to handle more than 64 devices in a "
+			  "single RAID array");
+		return 0;
+	}
+
 	if (!seg->region_size) {
 		log_error("Missing region size for mirror segment.");
 		return 0;
 	}
 
+	for (s = 0; s < seg->area_count; s++)
+		if (seg_lv(seg, s)->status & LV_NOTSYNCED)
+			rebuilds |= 1 << s;
+
 	if (!dm_tree_node_add_raid_target(node, len, _raid_name(seg),
 					  seg->region_size, seg->stripe_size,
-					  0, 0))
+					  rebuilds, 0))
 		return_0;
 
 	return add_areas_line(dm, seg, node, 0u, seg->area_count);
--- LVM2/libdm/libdevmapper.h	2011/08/18 19:38:27	1.142
+++ LVM2/libdm/libdevmapper.h	2011/08/18 19:41:22	1.143
@@ -472,7 +472,7 @@
 				 const char *raid_type,
 				 uint32_t region_size,
 				 uint32_t stripe_size,
-				 uint64_t reserved1,
+				 uint64_t rebuilds,
 				 uint64_t reserved2);
 
 /*
--- LVM2/libdm/libdm-deptree.c	2011/08/18 19:38:27	1.105
+++ LVM2/libdm/libdm-deptree.c	2011/08/18 19:41:22	1.106
@@ -149,6 +149,8 @@
 	unsigned rdevice_count;		/* Replicator */
 	struct dm_tree_node *replicator;/* Replicator-dev */
 	uint64_t rdevice_index;		/* Replicator-dev */
+
+	uint64_t rebuilds;              /* raid */
 };
 
 /* Per-device properties */
@@ -1724,6 +1726,7 @@
 				   uint64_t *seg_start, char *params,
 				   size_t paramsize)
 {
+	uint32_t i, *tmp;
 	int param_count = 1; /* mandatory 'chunk size'/'stripe size' arg */
 	int pos = 0;
 
@@ -1733,6 +1736,10 @@
 	if (seg->region_size)
 		param_count += 2;
 
+	tmp = (uint32_t *)(&seg->rebuilds); /* rebuilds is 64-bit */
+	param_count += 2 * hweight32(tmp[0]);
+	param_count += 2 * hweight32(tmp[1]);
+
 	if ((seg->type == SEG_RAID1) && seg->stripe_size)
 		log_error("WARNING: Ignoring RAID1 stripe size");
 
@@ -1747,6 +1754,10 @@
 	if (seg->region_size)
 		EMIT_PARAMS(pos, " region_size %u", seg->region_size);
 
+	for (i = 0; i < (seg->area_count / 2); i++)
+		if (seg->rebuilds & (1 << i))
+			EMIT_PARAMS(pos, " rebuild %u", i);
+
 	/* Print number of metadata/data device pairs */
 	EMIT_PARAMS(pos, " %u", seg->area_count/2);
 
@@ -1862,7 +1873,8 @@
 
 	log_debug("Adding target to (%" PRIu32 ":%" PRIu32 "): %" PRIu64
 		  " %" PRIu64 " %s %s", major, minor,
-		  *seg_start, seg->size, dm_segtypes[seg->type].target, params);
+		  *seg_start, seg->size, target_type_is_raid ? "raid" :
+		  dm_segtypes[seg->type].target, params);
 
 	if (!dm_task_add_target(dmt, *seg_start, seg->size,
 				target_type_is_raid ? "raid" :
@@ -2354,7 +2366,7 @@
 				 const char *raid_type,
 				 uint32_t region_size,
 				 uint32_t stripe_size,
-				 uint64_t reserved1,
+				 uint64_t rebuilds,
 				 uint64_t reserved2)
 {
 	int i;
@@ -2372,6 +2384,7 @@
 	seg->region_size = region_size;
 	seg->stripe_size = stripe_size;
 	seg->area_count = 0;
+	seg->rebuilds = rebuilds;
 
 	return 1;
 }


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2011-08-11  3:29 jbrassow
  0 siblings, 0 replies; 36+ messages in thread
From: jbrassow @ 2011-08-11  3:29 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	jbrassow@sourceware.org	2011-08-11 03:29:52

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h 

Log message:
	Fix renaming of RAID logical volumes.
	
	The function 'for_each_sub_lv', which rename uses, was not handling the
	RAID metadata areas.  Thus, the metadata LVs were not being renamed.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2058&r2=1.2059
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.271&r2=1.272
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.196&r2=1.197

--- LVM2/WHATS_NEW	2011/08/10 20:25:29	1.2058
+++ LVM2/WHATS_NEW	2011/08/11 03:29:51	1.2059
@@ -1,5 +1,6 @@
 Version 2.02.87 - 
 ===============================
+  Fix renaming of RAID logical volumes.
   Replace free_vg with release_vg and move it to vg.c.
   Remove INCONSISTENT_VG flag from the code.
   Remove lock from cache even if unlock fails.
--- LVM2/lib/metadata/lv_manip.c	2011/08/10 16:44:17	1.271
+++ LVM2/lib/metadata/lv_manip.c	2011/08/11 03:29:52	1.272
@@ -2595,6 +2595,19 @@
 			if (!for_each_sub_lv(cmd, seg_lv(seg, s), fn, data))
 				return_0;
 		}
+
+		if (!seg_is_raid(seg))
+			continue;
+
+		/* RAID has meta_areas */
+		for (s = 0; s < seg->area_count; s++) {
+			if (seg_metatype(seg, s) != AREA_LV)
+				continue;
+			if (!fn(cmd, seg_metalv(seg, s), data))
+				return_0;
+			if (!for_each_sub_lv(cmd, seg_metalv(seg, s), fn, data))
+				return_0;
+		}
 	}
 
 	return 1;
--- LVM2/lib/metadata/metadata-exported.h	2011/08/10 20:25:30	1.196
+++ LVM2/lib/metadata/metadata-exported.h	2011/08/11 03:29:52	1.197
@@ -330,6 +330,7 @@
 #define seg_pv(seg, s)		(seg)->areas[(s)].u.pv.pvseg->pv
 #define seg_lv(seg, s)		(seg)->areas[(s)].u.lv.lv
 #define seg_metalv(seg, s)	(seg)->meta_areas[(s)].u.lv.lv
+#define seg_metatype(seg, s)	(seg)->meta_areas[(s)].type
 
 struct pe_range {
 	struct dm_list list;


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2011-06-23 14:01 jbrassow
  0 siblings, 0 replies; 36+ messages in thread
From: jbrassow @ 2011-06-23 14:01 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	jbrassow@sourceware.org	2011-06-23 14:00:59

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

Log message:
	Fix to preserve exclusive activation of mirror while up-converting.
	
	When an LVM mirror is up-converted (an additional image added), it creates
	a temporary mirror stack.  The lower-level mirror in the stack that is
	created was not being activated exclusively - violating the exclusive nature
	of the original mirror.  We now check for exclusive activation of a mirror
	before converting it, and if found, we ensure that the temporary mirror
	is also exclusively activated.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.2025&r2=1.2026
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.263&r2=1.264
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.155&r2=1.156

--- LVM2/WHATS_NEW	2011/06/23 10:53:24	1.2025
+++ LVM2/WHATS_NEW	2011/06/23 14:00:58	1.2026
@@ -1,5 +1,6 @@
 Version 2.02.86 -  
 =================================
+  Fix to preserve exclusive activation of mirror while up-converting.
   Reject allocation if number of extents is not divisible by area count.
   Fix issue preventing cluster mirror creation.
   Disable udev fallback by default and add activation/udev_fallback to lvm.conf.
--- LVM2/lib/metadata/lv_manip.c	2011/06/23 10:53:24	1.263
+++ LVM2/lib/metadata/lv_manip.c	2011/06/23 14:00:58	1.264
@@ -3103,11 +3103,13 @@
 					   uint64_t status,
 					   const char *layer_suffix)
 {
+	int r;
 	struct logical_volume *layer_lv;
 	char *name;
 	size_t len;
 	struct segment_type *segtype;
 	struct lv_segment *mapseg;
+	unsigned exclusive = 0;
 
 	/* create an empty layer LV */
 	len = strlen(lv_where->name) + 32;
@@ -3129,6 +3131,9 @@
 		return NULL;
 	}
 
+	if (lv_is_active_exclusive_locally(lv_where))
+		exclusive = 1;
+
 	if (lv_is_active(lv_where) && strstr(name, "_mimagetmp")) {
 		log_very_verbose("Creating transient LV %s for mirror conversion in VG %s.", name, lv_where->vg->name);
 
@@ -3150,8 +3155,15 @@
 			return NULL;
 		}
 
-		if (!activate_lv(cmd, layer_lv)) {
-			log_error("Failed to resume transient error LV %s for mirror conversion in VG %s.", name, lv_where->vg->name);
+		if (exclusive)
+			r = activate_lv_excl(cmd, layer_lv);
+		else
+			r = activate_lv(cmd, layer_lv);
+
+		if (!r) {
+			log_error("Failed to resume transient LV"
+				  " %s for mirror conversion in VG %s.",
+				  name, lv_where->vg->name);
 			return NULL;
 		}
 	}
--- LVM2/lib/metadata/mirror.c	2011/06/22 21:31:21	1.155
+++ LVM2/lib/metadata/mirror.c	2011/06/23 14:00:59	1.156
@@ -419,8 +419,13 @@
 		}
 	}
 
-	if (!activate_lv(cmd, lv))
-		return_0;
+	if (lv_is_active_exclusive_locally(lv)) {
+		if (!activate_lv_excl(cmd, lv))
+			return_0;
+	} else {
+		if (!activate_lv(cmd, lv))
+			return_0;
+	}
 
 	if (!deactivate_lv(cmd, lv))
 		return_0;


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2011-04-09 19:05 zkabelac
  0 siblings, 0 replies; 36+ messages in thread
From: zkabelac @ 2011-04-09 19:05 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	zkabelac@sourceware.org	2011-04-09 19:05:24

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c mirror.c 
	tools          : lvconvert.c 

Log message:
	Fix incorrect tests for dm_snprintf() failure
	
	As the memory is preallocated based on arg size in these cases,
	the error would be quite hard to trigger here anyway.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1969&r2=1.1970
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.257&r2=1.258
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.148&r2=1.149
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.160&r2=1.161

--- LVM2/WHATS_NEW	2011/04/08 14:40:18	1.1969
+++ LVM2/WHATS_NEW	2011/04/09 19:05:23	1.1970
@@ -1,5 +1,6 @@
 Version 2.02.85 - 
 ===================================
+  Fix incorrect tests for dm_snprintf() failure.
   Fix some unmatching sign comparation gcc warnings in the code.
   Allow lv_extend() to work on zero length intrinsically layered LVs.
   Keep the cache content when the exported vg buffer is matching.
--- LVM2/lib/metadata/lv_manip.c	2011/04/08 14:40:19	1.257
+++ LVM2/lib/metadata/lv_manip.c	2011/04/09 19:05:24	1.258
@@ -2296,7 +2296,7 @@
 		log_error("Failed to allocate space for new name");
 		return 0;
 	}
-	if (!dm_snprintf(new_name, len, "%s%s", lv_name_new, suffix)) {
+	if (dm_snprintf(new_name, len, "%s%s", lv_name_new, suffix) < 0) {
 		log_error("Failed to create new name");
 		return 0;
 	}
--- LVM2/lib/metadata/mirror.c	2011/04/08 14:40:20	1.148
+++ LVM2/lib/metadata/mirror.c	2011/04/09 19:05:24	1.149
@@ -1787,7 +1787,7 @@
 	} else if ((lv_name = strstr(lv->name, MIRROR_SYNC_LAYER))) {
 		len = lv_name - lv->name + 1;
 		if (!(tmp_name = alloca(len)) ||
-		    !dm_snprintf(tmp_name, len, "%s", lv->name)) {
+		    (dm_snprintf(tmp_name, len, "%s", lv->name) < 0)) {
 			log_error("mirror log name allocation failed");
 			return 0;
 		}
--- LVM2/tools/lvconvert.c	2011/04/08 14:40:21	1.160
+++ LVM2/tools/lvconvert.c	2011/04/09 19:05:24	1.161
@@ -481,7 +481,7 @@
 	if (!uuid || !lv_full_name)
 		return_0;
 
-	if (!dm_snprintf(lv_full_name, len, "%s/%s", lv->vg->name, lv->name))
+	if (dm_snprintf(lv_full_name, len, "%s/%s", lv->vg->name, lv->name) < 0)
 		return_0;
 
 	memcpy(uuid, &lv->lvid, sizeof(lv->lvid));


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2011-01-24 14:19 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2011-01-24 14:19 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2011-01-24 14:19:05

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c mirror.c 
	lib/misc       : lvm-globals.c 

Log message:
	Fix lvchange --test to exit cleanly.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1887&r2=1.1888
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.244&r2=1.245
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.140&r2=1.141
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/misc/lvm-globals.c.diff?cvsroot=lvm2&r1=1.7&r2=1.8

--- LVM2/WHATS_NEW	2011/01/24 13:38:31	1.1887
+++ LVM2/WHATS_NEW	2011/01/24 14:19:05	1.1888
@@ -1,5 +1,6 @@
 Version 2.02.82 -
 ===================================
+  Fix lvchange --test to exit cleanly.
   Add change_tag to toollib.
   Allow multiple pvchange command line options to be specified together.
   Add -f (don't fork) option to clvmd and fix clvmd -d<num> description.
--- LVM2/lib/metadata/lv_manip.c	2011/01/12 20:42:51	1.244
+++ LVM2/lib/metadata/lv_manip.c	2011/01/24 14:19:05	1.245
@@ -3321,6 +3321,11 @@
 
 	backup(vg);
 
+	if (test_mode()) {
+		log_verbose("Test mode: Skipping activation and zeroing.");
+		goto out;
+	}
+
 	init_dmeventd_monitor(lp->activation_monitoring);
 
 	if (lp->snapshot) {
@@ -3399,6 +3404,7 @@
 	/* FIXME out of sequence */
 	backup(vg);
 
+out:
 	log_print("Logical volume \"%s\" created", lv->name);
 
 	/*
--- LVM2/lib/metadata/mirror.c	2011/01/11 17:21:01	1.140
+++ LVM2/lib/metadata/mirror.c	2011/01/24 14:19:05	1.141
@@ -285,6 +285,11 @@
 	uint64_t orig_status = log_lv->status;
 	int was_active = 0;
 
+	if (test_mode()) {
+		log_verbose("Test mode: Skipping mirror log initialisation.");
+		return 1;
+	}
+
 	if (!activation() && in_sync) {
 		log_error("Aborting. Unable to create in-sync mirror log "
 			  "while activation is disabled.");
--- LVM2/lib/misc/lvm-globals.c	2010/10/13 15:40:39	1.7
+++ LVM2/lib/misc/lvm-globals.c	2011/01/24 14:19:05	1.8
@@ -51,7 +51,7 @@
 void init_test(int level)
 {
 	if (!_test && level)
-		log_print("Test mode: Metadata will NOT be updated.");
+		log_print("Test mode: Metadata will NOT be updated and volumes will not be (de)activated.");
 	_test = level;
 }
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2011-01-11 17:05 jbrassow
  0 siblings, 0 replies; 36+ messages in thread
From: jbrassow @ 2011-01-11 17:05 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	jbrassow@sourceware.org	2011-01-11 17:05:10

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c mirror.c 
	test           : t-lvconvert-mirror-basic.sh 
	                 t-lvconvert-repair-policy.sh 
	                 t-lvconvert-repair-replace.sh 
	                 t-lvconvert-repair.sh t-lvconvert-twostep.sh 
	tools          : lvconvert.c lvcreate.c 

Log message:
	Add disk to mirrored log type conversion.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1875&r2=1.1876
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.242&r2=1.243
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.138&r2=1.139
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-lvconvert-mirror-basic.sh.diff?cvsroot=lvm2&r1=1.5&r2=1.6
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-lvconvert-repair-policy.sh.diff?cvsroot=lvm2&r1=1.6&r2=1.7
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-lvconvert-repair-replace.sh.diff?cvsroot=lvm2&r1=1.2&r2=1.3
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-lvconvert-repair.sh.diff?cvsroot=lvm2&r1=1.9&r2=1.10
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-lvconvert-twostep.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.154&r2=1.155
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.227&r2=1.228

--- LVM2/WHATS_NEW	2011/01/10 21:12:54	1.1875
+++ LVM2/WHATS_NEW	2011/01/11 17:05:08	1.1876
@@ -1,5 +1,6 @@
 Version 2.02.81 -
 ===================================
+  Add disk to mirrored log type conversion.
 
 Version 2.02.80 - 10th January 2011
 ===================================
--- LVM2/lib/metadata/lv_manip.c	2011/01/10 14:02:31	1.242
+++ LVM2/lib/metadata/lv_manip.c	2011/01/11 17:05:09	1.243
@@ -1557,8 +1557,7 @@
 			       parallel_areas)))
 		return_NULL;
 
-	if (!segtype_is_virtual(segtype) &&
-	    !_allocate(ah, vg, lv, 1, allocatable_pvs)) {
+	if (!_allocate(ah, vg, lv, 1, allocatable_pvs)) {
 		alloc_destroy(ah);
 		return_NULL;
 	}
--- LVM2/lib/metadata/mirror.c	2010/11/30 11:53:32	1.138
+++ LVM2/lib/metadata/mirror.c	2011/01/11 17:05:09	1.139
@@ -1295,7 +1295,7 @@
 			      struct logical_volume **img_lvs,
 			      int log)
 {
-	uint32_t m;
+	uint32_t m, first_area;
 	char *img_name;
 	size_t len;
 	
@@ -1322,10 +1322,13 @@
 		}
 
 		if (log) {
-			if (!lv_add_log_segment(ah, m * stripes + 1, img_lvs[m], 0)) {
-				log_error("Aborting. Failed to add mirror image segment "
-					  "to %s. Remove new LV and retry.",
-					  img_lvs[m]->name);
+			first_area = m * stripes + (log - 1);
+
+			if (!lv_add_log_segment(ah, first_area, img_lvs[m], 0)) {
+				/* error msg already from lv_add_log_segment */
+				log_verbose("Failed to add mirror image segment"
+					    " to %s. Remove new LV and retry.",
+					    img_lvs[m]->name);
 				return 0;
 			}
 		} else {
@@ -1760,7 +1763,7 @@
 	}
 
 	if ((log_count > 1) &&
-	    !_form_mirror(cmd, ah, log_lv, log_count-1, 1, 0, region_size, 1)) {
+	    !_form_mirror(cmd, ah, log_lv, log_count-1, 1, 0, region_size, 2)) {
 		log_error("Failed to form mirrored log.");
 		return NULL;
 	}
@@ -1792,6 +1795,7 @@
 	int in_sync;
 	struct logical_volume *log_lv;
 	struct lvinfo info;
+	int old_log_count;
 	int r = 0;
 
 	if (dm_list_size(&lv->segments) != 1) {
@@ -1811,6 +1815,15 @@
 		return 0;
 	}
 
+	log_lv = first_seg(lv)->log_lv;
+	old_log_count = (log_lv) ? lv_mirror_count(log_lv) : 0;
+	if (old_log_count == log_count) {
+		log_verbose("Mirror already has a %s log",
+			    !log_count ? "core" :
+			    (log_count == 1) ? "disk" : "mirrored");
+		return 1;
+	}
+
 	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv, 0)))
 		return_0;
 
@@ -1826,13 +1839,24 @@
 
 	/* allocate destination extents */
 	ah = allocate_extents(lv->vg, NULL, segtype,
-			      0, 0, log_count, region_size, 0,
+			      0, 0, log_count - old_log_count, region_size, 0,
 			      allocatable_pvs, alloc, parallel_areas);
 	if (!ah) {
 		log_error("Unable to allocate extents for mirror log.");
 		return 0;
 	}
 
+	if (old_log_count) {
+		/* Converting from disk to mirrored log */
+		if (!_form_mirror(cmd, ah, log_lv, log_count - 1, 1, 0,
+				  region_size, 1)) {
+			log_error("Failed to convert mirror log");
+			return 0;
+		}
+		r = 1;
+		goto out;
+	}
+
 	/* check sync status */
 	if (lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL) &&
 	    (sync_percent == PERCENT_100))
--- LVM2/test/t-lvconvert-mirror-basic.sh	2011/01/05 00:16:20	1.5
+++ LVM2/test/t-lvconvert-mirror-basic.sh	2011/01/11 17:05:09	1.6
@@ -54,12 +54,6 @@
 	local active=true
 	local i
 
-	if [ "$start_log_type" = "disk" ] &&
-		[ "$finish_log_type" = "mirrored" ]; then
-		echo "FIXME:  disk -> mirrored log conversion not yet supported by LVM"
-		return 0
-	fi
-
 	test "$5" = "active" && active=false
 	#test $finish_count -gt $start_count && up=true
 
--- LVM2/test/t-lvconvert-repair-policy.sh	2011/01/05 00:16:20	1.6
+++ LVM2/test/t-lvconvert-repair-policy.sh	2011/01/11 17:05:09	1.7
@@ -55,7 +55,8 @@
 cleanup $dev1
 
 # Fail a leg of a mirror w/ no available spare
-# Expected result: 2-way with corelog
+# Expected result: linear
+#                  (or 2-way with leg/log overlap if alloc anywhere)
 aux disable_dev $dev2 $dev4
 repair 'activation { mirror_image_fault_policy = "replace" }'
 check mirror $vg mirror
--- LVM2/test/t-lvconvert-repair-replace.sh	2011/01/05 00:16:20	1.2
+++ LVM2/test/t-lvconvert-repair-replace.sh	2011/01/11 17:05:09	1.3
@@ -13,6 +13,7 @@
 
 aux prepare_vg 6
 
+# 3-way, disk log
 # multiple failures, full replace
 lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg $dev1 $dev2 $dev3 $dev4:0-1
 aux disable_dev $dev1 $dev2
@@ -23,8 +24,37 @@
 check mirror $vg 3way
 aux enable_dev $dev1 $dev2
 
+vgremove -ff $vg; vgcreate -c n $vg $dev1 $dev2 $dev3 $dev4 $dev5 $dev6
+
+# 2-way, mirrored log
+# Double log failure, full replace
+lvcreate --mirrorlog mirrored -m 1 --ig -L 1 -n 2way $vg \
+    $dev1 $dev2 $dev3:0 $dev4:0
+aux disable_dev $dev3 $dev4
+echo y | lvconvert --repair $vg/2way 2>&1 | tee 2way.out
+lvs -a -o +devices | not grep unknown
+not grep "WARNING: Failed" 2way.out
+vgreduce --removemissing $vg
+check mirror $vg 2way
+aux enable_dev $dev3 $dev4
+
+vgremove -ff $vg; vgcreate -c n $vg $dev1 $dev2 $dev3 $dev4 $dev5 $dev6
+
+# 3-way, mirrored log
+# Single log failure, replace
+lvcreate --mirrorlog mirrored -m 2 --ig -L 1 -n 3way $vg \
+    $dev1 $dev2 $dev3 $dev4:0 $dev5:0
+aux disable_dev $dev4
+echo y | lvconvert --repair $vg/3way 2>&1 | tee 3way.out
+lvs -a -o +devices | not grep unknown
+not grep "WARNING: Failed" 3way.out
+vgreduce --removemissing $vg
+check mirror $vg 3way
+aux enable_dev $dev4
+
 vgremove -ff $vg; vgcreate -c n $vg $dev1 $dev2 $dev3 $dev4 $dev5
 
+# 3-way, disk log
 # multiple failures, partial replace
 lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg $dev1 $dev2 $dev3 $dev4
 aux disable_dev $dev1 $dev2
--- LVM2/test/t-lvconvert-repair.sh	2011/01/05 00:16:20	1.9
+++ LVM2/test/t-lvconvert-repair.sh	2011/01/11 17:05:09	1.10
@@ -14,6 +14,7 @@
 
 # fail multiple devices
 
+# 4-way, disk log => 2-way, disk log
 aux prepare_vg 5
 lvcreate -m 3 --ig -L 1 -n 4way $vg $dev1 $dev2 $dev3 $dev4 $dev5:0
 aux disable_dev $dev2 $dev4
@@ -23,6 +24,7 @@
 aux enable_dev $dev2 $dev4
 check mirror $vg 4way $dev5
 
+# 3-way, disk log => linear
 aux prepare_vg 5
 lvcreate -m 2 --ig -L 1 -n 3way $vg
 aux disable_dev $dev1 $dev2
@@ -37,6 +39,7 @@
 
 # fail just log and get it removed
 
+# 3-way, disk log => 3-way, core log
 aux prepare_vg 5
 lvcreate -m 2 --ig -L 1 -n 3way $vg $dev1 $dev2 $dev3 $dev4:0
 aux disable_dev $dev4
@@ -48,6 +51,20 @@
 vgreduce --removemissing $vg
 aux enable_dev $dev4
 
+# 3-way, mirrored log => 3-way, core log
+aux prepare_vg 5
+lvcreate -m 2 --mirrorlog mirrored --ig -L 1 -n 3way $vg \
+    $dev1 $dev2 $dev3 $dev4:0 $dev5:0
+aux disable_dev $dev4 $dev5
+echo n | lvconvert --repair $vg/3way
+check mirror $vg 3way core
+lvs -a -o +devices | not grep unknown
+lvs -a -o +devices | not grep mlog
+dmsetup ls | grep $PREFIX | not grep mlog
+vgreduce --removemissing $vg
+aux enable_dev $dev4 $dev5
+
+# 2-way, disk log => 2-way, core log
 aux prepare_vg 5
 lvcreate -m 1 --ig -L 1 -n 2way $vg $dev1 $dev2 $dev3:0
 aux disable_dev $dev3
--- LVM2/test/t-lvconvert-twostep.sh	2011/01/05 00:16:20	1.2
+++ LVM2/test/t-lvconvert-twostep.sh	2011/01/11 17:05:09	1.3
@@ -12,10 +12,15 @@
 . lib/test
 
 aux prepare_vg 4
+
 lvcreate -m 1 --mirrorlog disk --ig -L 1 -n mirror $vg
 not lvconvert -m 2 --mirrorlog core $vg/mirror $dev3 2>&1 | tee errs
 grep "two steps" errs
+
 lvconvert -m 2 $vg/mirror $dev3
 lvconvert --mirrorlog core $vg/mirror
 not lvconvert -m 1 --mirrorlog disk $vg/mirror $dev3 2>&1 | tee errs
 grep "two steps" errs
+
+not lvconvert -m 1 --mirrorlog mirrored $vg/mirror $dev3 $dev4 2>&1 | tee errs
+grep "two steps" errs
--- LVM2/tools/lvconvert.c	2011/01/05 23:18:47	1.154
+++ LVM2/tools/lvconvert.c	2011/01/11 17:05:10	1.155
@@ -718,6 +718,7 @@
 				    operable_pvs, 0U);
 }
 
+static int _reload_lv(struct cmd_context *cmd, struct logical_volume *lv);
 static int _lv_update_log_type(struct cmd_context *cmd,
 			       struct lvconvert_params *lp,
 			       struct logical_volume *lv,
@@ -738,14 +739,6 @@
 						  lv->le_count,
 						  lp->region_size);
 
-	/* Add a log where there is none */
-	if (!old_log_count) {
-		if (!add_mirror_log(cmd, original_lv, log_count,
-				    region_size, operable_pvs, lp->alloc))
-			return_0;
-		return 1;
-	}
-
 	/* Remove an existing log completely */
 	if (!log_count) {
 		if (!remove_mirror_log(cmd, original_lv, operable_pvs,
@@ -759,9 +752,17 @@
 
 	/* Adding redundancy to the log */
 	if (old_log_count < log_count) {
-		log_error("Adding log redundancy not supported yet.");
-		log_error("Try converting the log to 'core' first.");
-		return_0;
+		if (!add_mirror_log(cmd, original_lv, log_count,
+				    region_size, operable_pvs, lp->alloc))
+			return_0;
+		/*
+		 * FIXME: This simple approach won't work in cluster mirrors,
+		 *        but it doesn't matter because we don't support
+		 *        mirrored logs in cluster mirrors.
+		 */
+		if (old_log_count)
+			return _reload_lv(cmd, log_lv);
+		return 1;
 	}
 
 	/* Reducing redundancy of the log */
@@ -1109,7 +1110,8 @@
 
 		/* FIXME: can't have multiple mlogs. force corelog. */
 		if (!lv_add_mirrors(cmd, lv,
-				    new_mimage_count - old_mimage_count, lp->stripes, lp->stripe_size,
+				    new_mimage_count - old_mimage_count,
+				    lp->stripes, lp->stripe_size,
 				    region_size, 0U, operable_pvs, lp->alloc,
 				    MIRROR_BY_LV)) {
 			layer_lv = seg_lv(first_seg(lv), 0);
--- LVM2/tools/lvcreate.c	2010/12/08 20:50:51	1.227
+++ LVM2/tools/lvcreate.c	2011/01/11 17:05:10	1.228
@@ -538,8 +538,6 @@
 	struct lvcreate_cmdline_params lcp;
 	struct volume_group *vg;
 
-	memset(&lp, 0, sizeof(lp));
-
 	if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv))
 		return EINVALID_CMD_LINE;
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2010-10-14 20:03 jbrassow
  0 siblings, 0 replies; 36+ messages in thread
From: jbrassow @ 2010-10-14 20:03 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	jbrassow@sourceware.org	2010-10-14 20:03:13

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

Log message:
	Fix for bug 637936: killing both redundant logs causes deadlock
	
	Problem:
	When both legs of a mirrored log fail, neither the log nor the parent
	mirror can proceed.  The repair code must be careful to replace the
	log with an error target before operating on the parent - otherwise,
	the parent can get stuck trying to suspend because it can't push through
	any writes.  The steps to replace the log device with an error target
	were incomplete and resulted in the replacement not happening at all!
	
	The code originally had all the necessary logic to complete the
	replacement task, but was pulled out in a effort to clean-up that
	section of code, while fixing another bug:
	<offending commit msg>
	In addition, I added following three changes.
	
	- Removed tmp_orphan_lvs handling procedure
	It seems that _delete_lv() can handle detached_log_lv properly
	without adding mirror legs in mirrored log to tmp_orphan_lvs.
	Therefore, I removed the procedure.
	
	- Removed vg_write()/vg_commit()
	Metadata is saved by vg_write()/vg_commit() just after detached_log_lv
	is handled. Therefore, I removed vg_write()/vg_commit().
	</offending commit msg>
	
	http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c?cvsroot=lvm2&f=h#rev1.130
	
	I've reverted the "clean-up" changes associated with that fix, but not what
	that commit was actually fixing.
	
	Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>
	Reviewed-by: Petr Rockai <prockai@redhat.com>

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1761&r2=1.1762
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.233&r2=1.234
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.135&r2=1.136

--- LVM2/WHATS_NEW	2010/10/13 21:26:37	1.1761
+++ LVM2/WHATS_NEW	2010/10/14 20:03:12	1.1762
@@ -1,5 +1,6 @@
 Version 2.02.75 - 
 =====================================
+  Fix hang when repairing a mirrored-log that had both devs fail.
   Convey need for snapshot-merge target in lvconvert error message and man page.
   Add "devices/disable_after_error_count" to lvm.conf.
   Give correct error message when creating a too-small snapshot.
--- LVM2/lib/metadata/lv_manip.c	2010/10/13 13:52:53	1.233
+++ LVM2/lib/metadata/lv_manip.c	2010/10/14 20:03:12	1.234
@@ -462,6 +462,15 @@
 	if (!lv_empty(lv))
 		return_0;
 
+	/*
+	 * Since we are replacing the whatever-was-there with
+	 * an error segment, we should also clear any flags
+	 * that suggest it is anything other than "error".
+	 */
+	lv->status &= ~MIRRORED;
+
+	/* FIXME: Should we bug if we find a log_lv attached? */
+
 	if (!lv_add_virtual_segment(lv, 0, len,
 				    get_segtype_from_string(lv->vg->cmd,
 							    "error")))
--- LVM2/lib/metadata/mirror.c	2010/10/12 16:41:17	1.135
+++ LVM2/lib/metadata/mirror.c	2010/10/14 20:03:13	1.136
@@ -896,18 +896,40 @@
 	 */
 	if (detached_log_lv && lv_is_mirrored(detached_log_lv) &&
 	    (detached_log_lv->status & PARTIAL_LV)) {
+		struct lv_segment *seg = first_seg(detached_log_lv);
+
 		log_very_verbose("%s being removed due to failures",
 				 detached_log_lv->name);
 
+		/*
+		 * We are going to replace the mirror with an
+		 * error segment, but before we do, we must remember
+		 * all of the LVs that must be deleted later (i.e.
+		 * the sub-lv's)
+		 */
+		for (m = 0; m < seg->area_count; m++) {
+			seg_lv(seg, m)->status &= ~MIRROR_IMAGE;
+			lv_set_visible(seg_lv(seg, m));
+			if (!(lvl = dm_pool_alloc(lv->vg->cmd->mem,
+						  sizeof(*lvl)))) {
+				log_error("dm_pool_alloc failed");
+				return 0;
+			}
+			lvl->lv = seg_lv(seg, m);
+			dm_list_add(&tmp_orphan_lvs, &lvl->list);
+		}
+
 		if (!replace_lv_with_error_segment(detached_log_lv)) {
 			log_error("Failed error target substitution for %s",
 				  detached_log_lv->name);
 			return 0;
 		}
 
-		/*
-		 * Flush all I/Os held by mirrored log.
-		 */
+		if (!vg_write(detached_log_lv->vg)) {
+			log_error("intermediate VG write failed.");
+			return 0;
+		}
+
 		if (!suspend_lv(detached_log_lv->vg->cmd,
 				detached_log_lv)) {
 			log_error("Failed to suspend %s",
@@ -915,8 +937,14 @@
 			return 0;
  		}
 
-		if (!resume_lv(detached_log_lv->vg->cmd,
-			       detached_log_lv)) {
+		if (!vg_commit(detached_log_lv->vg)) {
+			if (!resume_lv(detached_log_lv->vg->cmd,
+				       detached_log_lv))
+				stack;
+			return_0;
+		}
+
+		if (!resume_lv(detached_log_lv->vg->cmd, detached_log_lv)) {
 			log_error("Failed to resume %s",
 				  detached_log_lv->name);
 			return_0;


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2010-04-23 19:27 snitzer
  0 siblings, 0 replies; 36+ messages in thread
From: snitzer @ 2010-04-23 19:27 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	snitzer@sourceware.org	2010-04-23 19:27:11

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h metadata.c 
	test           : t-snapshot-merge.sh 
	tools          : lvremove.c 

Log message:
	Disallow the direct removal of a merging snapshot.
	
	Allow lv_remove_with_dependencies() to know the top-level LV that was
	requested to be removed (otherwise it recurses and we lose context).
	
	A merging snapshot cannot be removed directly but the associated origin
	can be.  Disallow removal of a merging snapshot unless the associated
	origin is also being removed.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1536&r2=1.1537
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.228&r2=1.229
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.142&r2=1.143
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.c.diff?cvsroot=lvm2&r1=1.337&r2=1.338
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-snapshot-merge.sh.diff?cvsroot=lvm2&r1=1.5&r2=1.6
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvremove.c.diff?cvsroot=lvm2&r1=1.59&r2=1.60

--- LVM2/WHATS_NEW	2010/04/23 14:16:32	1.1536
+++ LVM2/WHATS_NEW	2010/04/23 19:27:10	1.1537
@@ -1,5 +1,6 @@
 Version 2.02.64 -
 =================================
+  Disallow the direct removal of a merging snapshot.
   Set appropriate udev flags for reserved LVs.
   Don't preload the origin when removing a snapshot whose merge is pending.
   Disallow the addition of mirror images while a conversion is happening.
--- LVM2/lib/metadata/lv_manip.c	2010/04/09 01:00:11	1.228
+++ LVM2/lib/metadata/lv_manip.c	2010/04/23 19:27:10	1.229
@@ -2306,16 +2306,25 @@
  * remove LVs with its dependencies - LV leaf nodes should be removed first
  */
 int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *lv,
-				const force_t force)
+				const force_t force, unsigned level)
 {
 	struct dm_list *snh, *snht;
 
-        if (lv_is_origin(lv)) {
+	if (lv_is_cow(lv)) {
+		/* A merging snapshot cannot be removed directly */
+		if (lv_is_merging_cow(lv) && !level) {
+			log_error("Can't remove merging snapshot logical volume \"%s\"",
+				  lv->name);
+			return 0;
+		}
+	}
+
+	if (lv_is_origin(lv)) {
 		/* remove snapshot LVs first */
 		dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) {
 			if (!lv_remove_with_dependencies(cmd, dm_list_struct_base(snh, struct lv_segment,
-									       origin_list)->cow,
-							 force))
+										  origin_list)->cow,
+							 force, level + 1))
 				return 0;
 		}
 	}
--- LVM2/lib/metadata/metadata-exported.h	2010/04/14 13:09:17	1.142
+++ LVM2/lib/metadata/metadata-exported.h	2010/04/23 19:27:10	1.143
@@ -534,7 +534,7 @@
 		     force_t force);
 
 int lv_remove_with_dependencies(struct cmd_context *cmd, struct logical_volume *lv,
-				force_t force);
+				force_t force, unsigned level);
 
 int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
 	      const char *new_name);
--- LVM2/lib/metadata/metadata.c	2010/04/14 13:09:17	1.337
+++ LVM2/lib/metadata/metadata.c	2010/04/23 19:27:10	1.338
@@ -484,7 +484,7 @@
 
 	while ((lst = dm_list_first(&vg->lvs))) {
 		lvl = dm_list_item(lst, struct lv_list);
-		if (!lv_remove_with_dependencies(cmd, lvl->lv, force))
+		if (!lv_remove_with_dependencies(cmd, lvl->lv, force, 0))
 		    return 0;
 	}
 
--- LVM2/test/t-snapshot-merge.sh	2010/04/23 02:57:43	1.5
+++ LVM2/test/t-snapshot-merge.sh	2010/04/23 19:27:11	1.6
@@ -44,17 +44,22 @@
 aux prepare_vg 1 100
 
 
-# full merge of a single LV
+# test full merge of a single LV
 setup_merge $vg $lv1
-
 # now that snapshot LV is created: test if snapshot-merge target is available
 $(dmsetup targets | grep -q snapshot-merge) || exit 200
-
 lvs -a
 lvconvert --merge $vg/$(snap_lv_name_ $lv1)
 lvremove -f $vg/$lv1
 
 
+# test that an actively merging snapshot may not be removed
+setup_merge $vg $lv1
+lvconvert -i+100 --merge --background $vg/$(snap_lv_name_ $lv1)
+not lvremove -f $vg/$(snap_lv_name_ $lv1)
+lvremove -f $vg/$lv1
+
+
 # "onactivate merge" test
 setup_merge $vg $lv1
 lvs -a
@@ -99,6 +104,7 @@
 lvconvert --merge $vg/$(snap_lv_name_ $lv1)
 lvremove -f $vg/$lv1
 
+
 # test merging multiple snapshots that share the same tag
 setup_merge $vg $lv1
 setup_merge $vg $lv2
--- LVM2/tools/lvremove.c	2009/09/14 22:47:49	1.59
+++ LVM2/tools/lvremove.c	2010/04/23 19:27:11	1.60
@@ -26,7 +26,7 @@
         if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
                 lv = origin;
 
-	if (!lv_remove_with_dependencies(cmd, lv, arg_count(cmd, force_ARG))) {
+	if (!lv_remove_with_dependencies(cmd, lv, arg_count(cmd, force_ARG), 0)) {
 		stack;
 		return ECMD_FAILED;
 	}


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2010-04-09  1:00 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2010-04-09  1:00 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2010-04-09 01:00:11

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c merge.c metadata-exported.h mirror.c 
	tools          : lvconvert.c lvcreate.c lvresize.c pvmove.c 

Log message:
	Permit mimage LVs to be striped in lvcreate and lvresize.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1506&r2=1.1507
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.227&r2=1.228
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/merge.c.diff?cvsroot=lvm2&r1=1.40&r2=1.41
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.138&r2=1.139
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.111&r2=1.112
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.124&r2=1.125
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.218&r2=1.219
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvresize.c.diff?cvsroot=lvm2&r1=1.120&r2=1.121
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/pvmove.c.diff?cvsroot=lvm2&r1=1.75&r2=1.76

--- LVM2/WHATS_NEW	2010/04/08 00:28:57	1.1506
+++ LVM2/WHATS_NEW	2010/04/09 01:00:10	1.1507
@@ -1,5 +1,6 @@
 Version 2.02.63 -  
 ================================
+  Permit mimage LVs to be striped in lvcreate and lvresize.
   Fix pvmove allocation to take existing parallel stripes into account.
   Add pvmove_source_seg to struct lv_segment.
   Fix incorrect removal of symlinks after LV deactivation fails.
--- LVM2/lib/metadata/lv_manip.c	2010/04/08 00:56:26	1.227
+++ LVM2/lib/metadata/lv_manip.c	2010/04/09 01:00:11	1.228
@@ -526,13 +526,22 @@
 	struct dm_list alloced_areas[0];
 };
 
-static uint32_t calc_area_multiple(const struct segment_type *segtype,
-				   const uint32_t area_count)
+static uint32_t _calc_area_multiple(const struct segment_type *segtype,
+				    const uint32_t area_count, const uint32_t stripes)
 {
-	if (!segtype_is_striped(segtype) || !area_count)
+	if (!area_count)
 		return 1;
 
-	return area_count;
+	/* Striped */
+	if (segtype_is_striped(segtype))
+		return area_count;
+
+	/* Mirrored stripes */
+	if (stripes)
+		return stripes;
+
+	/* Mirrored */
+	return 1;
 }
 
 /*
@@ -559,6 +568,8 @@
 
 /*
  * Preparation for a specific allocation attempt
+ * stripes and mirrors refer to the parallel areas used for data.
+ * If log_area_count > 1 it is always mirrored (not striped).
  */
 static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
 					struct dm_pool *mem,
@@ -575,20 +586,14 @@
 	struct alloc_handle *ah;
 	uint32_t s, area_count;
 
-	if (stripes > 1 && mirrors > 1) {
-		log_error("Striped mirrors are not supported yet");
-		return NULL;
-	}
-
-	if (log_area_count && stripes > 1) {
-		log_error("Can't mix striping with a mirror log yet.");
-		return NULL;
-	}
+	/* FIXME Caller should ensure this */
+	if (mirrors && !stripes)
+		stripes = 1;
 
 	if (segtype_is_virtual(segtype))
 		area_count = 0;
 	else if (mirrors > 1)
-		area_count = mirrors;
+		area_count = mirrors * stripes;
 	else
 		area_count = stripes;
 
@@ -617,7 +622,7 @@
 	ah->log_area_count = log_area_count;
 	ah->region_size = region_size;
 	ah->alloc = alloc;
-	ah->area_multiple = calc_area_multiple(segtype, area_count);
+	ah->area_multiple = _calc_area_multiple(segtype, area_count, stripes);
 
 	ah->log_len = log_area_count ? mirror_log_extents(ah->region_size, extent_size, ah->new_extents / ah->area_multiple) : 0;
 
@@ -688,7 +693,7 @@
 	uint32_t s, extents, area_multiple;
 	struct lv_segment *seg;
 
-	area_multiple = calc_area_multiple(segtype, area_count);
+	area_multiple = _calc_area_multiple(segtype, area_count, 0);
 
 	if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
 				     lv->le_count,
@@ -801,6 +806,20 @@
 	return 1;
 }
 
+/* For striped mirrors, all the areas are counted, through the mirror layer */
+static uint32_t _stripes_per_mimage(struct lv_segment *seg)
+{
+	struct lv_segment *last_lvseg;
+
+	if (seg_is_mirrored(seg) && seg->area_count && seg_type(seg, 0) == AREA_LV) {
+		last_lvseg = dm_list_item(dm_list_last(&seg_lv(seg, 0)->segments), struct lv_segment);
+		if (seg_is_striped(last_lvseg))
+			return last_lvseg->area_count;
+	}
+
+	return 1;
+}
+
 /*
  * Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len.
  * If any constituent area contains more than one segment, max_seg_len is
@@ -821,6 +840,7 @@
 {
 	uint32_t s;
 	uint32_t remaining_seg_len, area_len, area_multiple;
+	uint32_t stripes_per_mimage = 1;
 	int r = 1;
 
 	if (!seg && !(seg = find_seg_by_le(lv, le))) {
@@ -838,9 +858,13 @@
 	if (max_seg_len && *max_seg_len > remaining_seg_len)
 		*max_seg_len = remaining_seg_len;
 
-	area_multiple = calc_area_multiple(seg->segtype, seg->area_count);
+	area_multiple = _calc_area_multiple(seg->segtype, seg->area_count, 0);
 	area_len = remaining_seg_len / area_multiple ? : 1;
 
+	/* For striped mirrors, all the areas are counted, through the mirror layer */
+	if (top_level_area_index == -1)
+		stripes_per_mimage = _stripes_per_mimage(seg);
+
 	for (s = first_area;
 	     s < seg->area_count && (!max_areas || s <= max_areas);
 	     s++) {
@@ -848,15 +872,14 @@
 			if (!(r = _for_each_pv(cmd, seg_lv(seg, s),
 					       seg_le(seg, s) +
 					       (le - seg->le) / area_multiple,
-					       area_len, NULL, max_seg_len,
-					       only_single_area_segments ? 0 : 0,
-					       only_single_area_segments ? 1U : 0U,
-					       top_level_area_index != -1 ? top_level_area_index : (int) s,
+					       area_len, NULL, max_seg_len, 0,
+					       (stripes_per_mimage == 1) && only_single_area_segments ? 1U : 0U,
+					       top_level_area_index != -1 ? top_level_area_index : (int) s * stripes_per_mimage,
 					       only_single_area_segments, fn,
 					       data)))
 				stack;
 		} else if (seg_type(seg, s) == AREA_PV)
-			if (!(r = fn(cmd, seg_pvseg(seg, s), top_level_area_index != -1 ? (uint32_t) top_level_area_index : s, data)))
+			if (!(r = fn(cmd, seg_pvseg(seg, s), top_level_area_index != -1 ? (uint32_t) top_level_area_index + s : s, data)))
 				stack;
 		if (r != 1)
 			return r;
@@ -947,6 +970,11 @@
 	pvmatch->areas[s].pva = pvmatch->pva;
 	pvmatch->areas[s].used = pvmatch->pva->count;
 
+	log_debug("Trying allocation area %" PRIu32 " on %s start PE %" PRIu32
+		  " length %" PRIu32 ".",
+		  s, dev_name(pvmatch->pva->map->pv->dev), pvmatch->pva->start, 
+		  pvmatch->pva->count);
+
 	return 2;	/* Finished */
 }
 
@@ -1032,13 +1060,14 @@
 	uint32_t free_pes;
 	struct alloced_area *aa;
 	uint32_t s;
+	uint32_t total_extents_needed = (needed - *allocated) * ah->area_count / ah->area_multiple;
 
 	/* Is there enough total space? */
 	free_pes = pv_maps_size(pvms);
-	if (needed - *allocated > free_pes) {
+	if (total_extents_needed > free_pes) {
 		log_error("Insufficient free space: %" PRIu32 " extents needed,"
 			  " but only %" PRIu32 " available",
-			  needed - *allocated, free_pes);
+			  total_extents_needed, free_pes);
 		return 0;
 	}
 
@@ -1046,7 +1075,7 @@
 
 	/* Are there any preceding segments we must follow on from? */
 	if (prev_lvseg) {
-		ix_offset = prev_lvseg->area_count;
+		ix_offset = _stripes_per_mimage(prev_lvseg) * prev_lvseg->area_count;
 		if ((alloc == ALLOC_CONTIGUOUS))
 			contiguous = 1;
 		else if ((alloc == ALLOC_CLING))
@@ -1201,20 +1230,25 @@
 						  (alloc == ALLOC_ANYWHERE) ? pva->unreserved : pva->count - required);
 				}
 			next_pv:
-				if (alloc == ALLOC_ANYWHERE &&
-				    ix + ix_offset >= ah->area_count + (*log_needs_allocating ? ah->log_area_count : 0))
+				/* With ALLOC_ANYWHERE we ignore further PVs once we have at least enough areas */
+				/* With cling and contiguous we stop if we found a match for *all* the areas */
+				/* FIXME Rename these variables! */
+				if ((alloc == ALLOC_ANYWHERE &&
+				    ix + ix_offset >= ah->area_count + (*log_needs_allocating ? ah->log_area_count : 0)) ||
+				    (preferred_count == ix_offset &&
+				     (ix_offset == ah->area_count + (*log_needs_allocating ? ah->log_area_count : 0))))
 					break;
 			}
 		} while (alloc == ALLOC_ANYWHERE && last_ix != ix && ix < ah->area_count + (*log_needs_allocating ? ah->log_area_count : 0));
 
-		if ((contiguous || cling) && (preferred_count < ix_offset))
+		if (preferred_count < ix_offset)
 			break;
 
 		if (ix + ix_offset < ah->area_count +
 		   (*log_needs_allocating ? ah->log_area_count : 0))
 			break;
 
-		/* sort the areas so we allocate from the biggest */
+		/* Sort the areas so we allocate from the biggest */
 		if (ix > 1)
 			qsort((*areas_ptr) + ix_offset, ix, sizeof(**areas_ptr),
 			      _comp_area);
@@ -1310,7 +1344,7 @@
 	/* Upper bound if none of the PVs in prev_lvseg is in pvms */
 	/* FIXME Work size out properly */
 	if (prev_lvseg)
-		areas_size += prev_lvseg->area_count;
+		areas_size += _stripes_per_mimage(prev_lvseg) * prev_lvseg->area_count;
 
 	/* Allocate an array of pv_areas to hold the largest space on each PV */
 	if (!(areas = dm_malloc(sizeof(*areas) * areas_size))) {
@@ -1322,10 +1356,14 @@
 	for (alloc = ALLOC_CONTIGUOUS; alloc < ALLOC_INHERIT; alloc++) {
 		old_allocated = allocated;
 		log_debug("Trying allocation using %s policy.  "
-			  "Need %" PRIu32 " extents for %" PRIu32 " parallel areas and %" PRIu32 " log extents.",
+			  "Need %" PRIu32 " extents for %" PRIu32 " parallel areas and %" PRIu32 " log areas of %" PRIu32 " extents. "
+			  "(Total %" PRIu32 " extents.)",
 			  get_alloc_string(alloc),
 			  (ah->new_extents - allocated) / ah->area_multiple,
-			  ah->area_count, log_needs_allocating ? ah->log_area_count : 0);
+			  ah->area_count, log_needs_allocating ? ah->log_area_count : 0,
+			  log_needs_allocating ? ah->log_len : 0,
+			  (ah->new_extents - allocated) * ah->area_count / ah->area_multiple +
+				(log_needs_allocating ? ah->log_area_count * ah->log_len : 0));
 		if (!_find_parallel_space(ah, alloc, pvms, &areas,
 					  &areas_size, can_split,
 					  prev_lvseg, &allocated, &log_needs_allocating, ah->new_extents))
@@ -1665,7 +1703,8 @@
 
 static int _lv_extend_mirror(struct alloc_handle *ah,
 			     struct logical_volume *lv,
-			     uint32_t extents, uint32_t first_area)
+			     uint32_t extents, uint32_t first_area,
+			     uint32_t stripes, uint32_t stripe_size)
 {
 	struct lv_segment *seg;
 	uint32_t m, s;
@@ -1673,20 +1712,21 @@
 	seg = first_seg(lv);
 	for (m = first_area, s = 0; s < seg->area_count; s++) {
 		if (is_temporary_mirror_layer(seg_lv(seg, s))) {
-			if (!_lv_extend_mirror(ah, seg_lv(seg, s), extents, m))
+			if (!_lv_extend_mirror(ah, seg_lv(seg, s), extents, m, stripes, stripe_size))
 				return_0;
 			m += lv_mirror_count(seg_lv(seg, s));
 			continue;
 		}
 
-		if (!lv_add_segment(ah, m++, 1, seg_lv(seg, s),
+		if (!lv_add_segment(ah, m, stripes, seg_lv(seg, s),
 				    get_segtype_from_string(lv->vg->cmd,
 							    "striped"),
-				    0, 0, 0)) {
+				    stripe_size, 0, 0)) {
 			log_error("Aborting. Failed to extend %s.",
 				  seg_lv(seg, s)->name);
 			return 0;
 		}
+		m += stripes;
 	}
 	seg->area_len += extents;
 	seg->len += extents;
@@ -1722,7 +1762,7 @@
 		r = lv_add_segment(ah, 0, ah->area_count, lv, segtype,
 				   stripe_size, status, 0);
 	else
-		r = _lv_extend_mirror(ah, lv, extents, 0);
+		r = _lv_extend_mirror(ah, lv, extents, 0, stripes, stripe_size);
 
 	alloc_destroy(ah);
 	return r;
@@ -2095,7 +2135,7 @@
 		/* FIXME Unnecessary nesting! */
 		if (!_for_each_pv(cmd, use_pvmove_parent_lv ? seg->pvmove_source_seg->lv : lv,
 				  use_pvmove_parent_lv ? seg->pvmove_source_seg->le : current_le,
-				  use_pvmove_parent_lv ? spvs->len * calc_area_multiple(seg->pvmove_source_seg->segtype, seg->pvmove_source_seg->area_count) : spvs->len,
+				  use_pvmove_parent_lv ? spvs->len * _calc_area_multiple(seg->pvmove_source_seg->segtype, seg->pvmove_source_seg->area_count, 0) : spvs->len,
 				  use_pvmove_parent_lv ? seg->pvmove_source_seg : NULL,
 				  &spvs->len,
 				  0, 0, -1, 0, _add_pvs, (void *) spvs))
@@ -3148,6 +3188,7 @@
 
 	if (lp->mirrors > 1) {
 		if (!lv_add_mirrors(cmd, lv, lp->mirrors - 1, lp->stripes,
+				    lp->stripe_size,
 				    adjusted_mirror_region_size(
 						vg->extent_size,
 						lv->le_count,
--- LVM2/lib/metadata/merge.c	2010/04/08 00:28:58	1.40
+++ LVM2/lib/metadata/merge.c	2010/04/09 01:00:11	1.41
@@ -30,7 +30,8 @@
 static int _merge(struct lv_segment *first, struct lv_segment *second)
 {
 	if (!first || !second || first->segtype != second->segtype ||
-	    !first->segtype->ops->merge_segments) return 0;
+	    !first->segtype->ops->merge_segments)
+		return 0;
 
 	return first->segtype->ops->merge_segments(first, second);
 }
--- LVM2/lib/metadata/metadata-exported.h	2010/04/08 00:28:58	1.138
+++ LVM2/lib/metadata/metadata-exported.h	2010/04/09 01:00:11	1.139
@@ -665,7 +665,7 @@
 */
 struct lv_segment *find_mirror_seg(struct lv_segment *seg);
 int lv_add_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
-		   uint32_t mirrors, uint32_t stripes,
+		   uint32_t mirrors, uint32_t stripes, uint32_t stripe_size,
 		   uint32_t region_size, uint32_t log_count,
 		   struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags);
 int lv_split_mirror_images(struct logical_volume *lv, const char *split_lv_name,
@@ -688,7 +688,7 @@
 int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
 			 struct dm_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,
+		      uint32_t mirrors, uint32_t stripes, uint32_t stripe_size, uint32_t region_size,
 		      struct dm_list *allocatable_pvs, alloc_policy_t alloc,
 		      uint32_t log_count);
 struct logical_volume *detach_mirror_log(struct lv_segment *seg);
--- LVM2/lib/metadata/mirror.c	2010/04/08 00:28:58	1.111
+++ LVM2/lib/metadata/mirror.c	2010/04/09 01:00:11	1.112
@@ -1174,6 +1174,8 @@
 
 static int _create_mimage_lvs(struct alloc_handle *ah,
 			      uint32_t num_mirrors,
+			      uint32_t stripes,
+			      uint32_t stripe_size,
 			      struct logical_volume *lv,
 			      struct logical_volume **img_lvs,
 			      int log)
@@ -1205,17 +1207,17 @@
 		}
 
 		if (log) {
-			if (!lv_add_log_segment(ah, m + 1, img_lvs[m], 0)) {
+			if (!lv_add_log_segment(ah, m * stripes + 1, img_lvs[m], 0)) {
 				log_error("Aborting. Failed to add mirror image segment "
 					  "to %s. Remove new LV and retry.",
 					  img_lvs[m]->name);
 				return 0;
 			}
 		} else {
-			if (!lv_add_segment(ah, m, 1, img_lvs[m],
+			if (!lv_add_segment(ah, m * stripes, stripes, img_lvs[m],
 					    get_segtype_from_string(lv->vg->cmd,
 								    "striped"),
-					    0, 0, 0)) {
+					    stripe_size, 0, 0)) {
 				log_error("Aborting. Failed to add mirror image segment "
 					  "to %s. Remove new LV and retry.",
 					  img_lvs[m]->name);
@@ -1566,7 +1568,8 @@
  */
 static int _form_mirror(struct cmd_context *cmd, struct alloc_handle *ah,
 			struct logical_volume *lv,
-			uint32_t mirrors, uint32_t region_size, int log)
+			uint32_t mirrors, uint32_t stripes,
+			uint32_t stripe_size, uint32_t region_size, int log)
 {
 	struct logical_volume **img_lvs;
 
@@ -1587,7 +1590,7 @@
 		return 0;
 	}
 
-	if (!_create_mimage_lvs(ah, mirrors, lv, img_lvs, log))
+	if (!_create_mimage_lvs(ah, mirrors, stripes, stripe_size, lv, img_lvs, log))
 		return 0;
 
 	if (!lv_add_mirror_lvs(lv, img_lvs, mirrors,
@@ -1650,7 +1653,7 @@
 	}
 
 	if ((log_count > 1) &&
-	    !_form_mirror(cmd, ah, log_lv, log_count-1, region_size, 1)) {
+	    !_form_mirror(cmd, ah, log_lv, log_count-1, 1, 0, region_size, 1)) {
 		log_error("Failed to form mirrored log.");
 		return NULL;
 	}
@@ -1749,7 +1752,8 @@
  * 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,
+		      uint32_t mirrors, uint32_t stripes,
+		      uint32_t stripe_size, uint32_t region_size,
 		      struct dm_list *allocatable_pvs, alloc_policy_t alloc,
 		      uint32_t log_count)
 {
@@ -1758,11 +1762,6 @@
 	struct dm_list *parallel_areas;
 	struct logical_volume *log_lv = NULL;
 
-	if (stripes > 1) {
-		log_error("stripes > 1 is not supported");
-		return 0;
-	}
-
 	/*
 	 * allocate destination extents
 	 */
@@ -1795,7 +1794,7 @@
 	   So from here on, if failure occurs, the log must be explicitly
 	   removed and the updated vg metadata should be committed. */
 
-	if (!_form_mirror(cmd, ah, lv, mirrors, region_size, 0))
+	if (!_form_mirror(cmd, ah, lv, mirrors, stripes, stripe_size, region_size, 0))
 		goto out_remove_log;
 
 	if (log_count && !attach_mirror_log(first_seg(lv), log_lv))
@@ -1825,7 +1824,7 @@
  * '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 mirrors, uint32_t stripes, uint32_t stripe_size,
 		   uint32_t region_size, uint32_t log_count,
 		   struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags)
 {
@@ -1863,7 +1862,7 @@
 			return add_mirror_log(cmd, lv, log_count,
 					      region_size, pvs, alloc);
 		return add_mirror_images(cmd, lv, mirrors,
-					 stripes, region_size,
+					 stripes, stripe_size, region_size,
 					 pvs, alloc, log_count);
 	}
 
--- LVM2/tools/lvconvert.c	2010/03/31 20:39:51	1.124
+++ LVM2/tools/lvconvert.c	2010/04/09 01:00:11	1.125
@@ -945,21 +945,13 @@
 	if (!(lv->status & MIRRORED)) {
 		/* FIXME Share code with lvcreate */
 
-		/* FIXME Why is this restriction here?  Fix it! */
-		dm_list_iterate_items(seg, &lv->segments) {
-			if (seg_is_striped(seg) && seg->area_count > 1) {
-				log_error("Mirrors of striped volumes are not yet supported.");
-				return 0;
-			}
-		}
-
 		/*
 		 * FIXME should we give not only lp->pvh, but also all PVs
 		 * currently taken by the mirror? Would make more sense from
 		 * user perspective.
 		 */
 		if (!lv_add_mirrors(cmd, lv, new_mimage_count - 1, 1,
-				    region_size, new_log_count, operable_pvs,
+				    0, region_size, new_log_count, operable_pvs,
 				    lp->alloc, MIRROR_BY_LV)) {
 			stack;
 			return failure_code;
@@ -1013,7 +1005,7 @@
 
 		/* FIXME: can't have multiple mlogs. force corelog. */
 		if (!lv_add_mirrors(cmd, lv,
-				    new_mimage_count - old_mimage_count, 1,
+				    new_mimage_count - old_mimage_count, 1, 0,
 				    region_size, 0U, operable_pvs, lp->alloc,
 				    MIRROR_BY_LV)) {
 			layer_lv = seg_lv(first_seg(lv), 0);
--- LVM2/tools/lvcreate.c	2010/03/29 16:09:41	1.218
+++ LVM2/tools/lvcreate.c	2010/04/09 01:00:11	1.219
@@ -457,12 +457,6 @@
 			return 0;
 		}
 
-		if (lp->stripes > 1) {
-			log_error("mirrors and stripes are currently "
-				  "incompatible");
-			return 0;
-		}
-
 		if (!(lp->segtype = get_segtype_from_string(cmd, "striped")))
 			return_0;
 	} else {
--- LVM2/tools/lvresize.c	2010/03/20 03:44:04	1.120
+++ LVM2/tools/lvresize.c	2010/04/09 01:00:11	1.121
@@ -73,10 +73,6 @@
 	} else
 		lp->stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
 
-	if (lp->mirrors) {
-		log_error("Mirrors and striping cannot be combined yet.");
-		return 0;
-	}
 	if (lp->stripe_size & (lp->stripe_size - 1)) {
 		log_error("Stripe size must be power of 2");
 		return 0;
@@ -287,7 +283,7 @@
 	alloc_policy_t alloc;
 	struct logical_volume *lock_lv;
 	struct lv_list *lvl;
-	struct lv_segment *seg;
+	struct lv_segment *seg, *uninitialized_var(mirr_seg);
 	uint32_t seg_extents;
 	uint32_t sz, str;
 	struct dm_list *pvh = NULL;
@@ -429,10 +425,32 @@
 		return EINVALID_CMD_LINE;
 	}
 
+	/* If extending, find mirrors of last segment */
+	if ((lp->extents > lv->le_count)) {
+		dm_list_iterate_back_items(mirr_seg, &lv->segments) {
+			if (seg_is_mirrored(mirr_seg))
+				seg_mirrors = lv_mirror_count(mirr_seg->lv);
+			else
+				seg_mirrors = 0;
+			break;
+		}
+		if (!arg_count(cmd, mirrors_ARG) && seg_mirrors) {
+			log_print("Extending %" PRIu32 " mirror images.",
+				  seg_mirrors);
+			lp->mirrors = seg_mirrors;
+		}
+		if ((arg_count(cmd, mirrors_ARG) || seg_mirrors) &&
+		    (lp->mirrors != seg_mirrors)) {
+			log_error("Cannot vary number of mirrors in LV yet.");
+			return EINVALID_CMD_LINE;
+		}
+	}
+
 	/* If extending, find stripes, stripesize & size of last segment */
 	if ((lp->extents > lv->le_count) &&
 	    !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size))) {
-		dm_list_iterate_items(seg, &lv->segments) {
+		/* FIXME Don't assume mirror seg will always be AREA_LV */
+		dm_list_iterate_items(seg, seg_mirrors ? &seg_lv(mirr_seg, 0)->segments : &lv->segments) {
 			if (!seg_is_striped(seg))
 				continue;
 
@@ -440,7 +458,7 @@
 			str = seg->area_count;
 
 			if ((seg_stripesize && seg_stripesize != sz &&
-			     !lp->stripe_size) ||
+			     sz && !lp->stripe_size) ||
 			    (seg_stripes && seg_stripes != str && !lp->stripes)) {
 				log_error("Please specify number of "
 					  "stripes (-i) and stripesize (-I)");
@@ -470,27 +488,6 @@
 		}
 	}
 
-	/* If extending, find mirrors of last segment */
-	if ((lp->extents > lv->le_count)) {
-		dm_list_iterate_back_items(seg, &lv->segments) {
-			if (seg_is_mirrored(seg))
-				seg_mirrors = lv_mirror_count(seg->lv);
-			else
-				seg_mirrors = 0;
-			break;
-		}
-		if (!arg_count(cmd, mirrors_ARG) && seg_mirrors) {
-			log_print("Extending %" PRIu32 " mirror images.",
-				  seg_mirrors);
-			lp->mirrors = seg_mirrors;
-		}
-		if ((arg_count(cmd, mirrors_ARG) || seg_mirrors) &&
-		    (lp->mirrors != seg_mirrors)) {
-			log_error("Cannot vary number of mirrors in LV yet.");
-			return EINVALID_CMD_LINE;
-		}
-	}
-
 	/* If reducing, find stripes, stripesize & size of last segment */
 	if (lp->extents < lv->le_count) {
 		extents_used = 0;
--- LVM2/tools/pvmove.c	2010/02/05 22:40:50	1.75
+++ LVM2/tools/pvmove.c	2010/04/09 01:00:11	1.76
@@ -254,7 +254,7 @@
 		return NULL;
 	}
 
-	if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, log_count,
+	if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, 0, log_count,
 			    allocatable_pvs, alloc, MIRROR_BY_SEG)) {
 		log_error("Failed to convert pvmove LV to mirrored");
 		return_NULL;


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2010-03-25 21:19 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2010-03-25 21:19 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2010-03-25 21:19:27

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c pv_map.c pv_map.h 

Log message:
	Allow ALLOC_ANYWHERE to split contiguous areas.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1481&r2=1.1482
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.215&r2=1.216
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/pv_map.c.diff?cvsroot=lvm2&r1=1.35&r2=1.36
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/pv_map.h.diff?cvsroot=lvm2&r1=1.12&r2=1.13

--- LVM2/WHATS_NEW	2010/03/25 18:22:39	1.1481
+++ LVM2/WHATS_NEW	2010/03/25 21:19:26	1.1482
@@ -1,5 +1,6 @@
 Version 2.02.63 -  
 ================================
+  Allow ALLOC_ANYWHERE to split contiguous areas.
   Use INTERNAL_ERROR for internal errors throughout tree.
   Add some assertions to allocation code.
   Introduce pv_area_used into allocation algorithm and add debug messages.
--- LVM2/lib/metadata/lv_manip.c	2010/03/25 18:16:55	1.215
+++ LVM2/lib/metadata/lv_manip.c	2010/03/25 21:19:27	1.216
@@ -1018,7 +1018,7 @@
 	struct pv_list *pvl;
 	unsigned already_found_one = 0;
 	unsigned contiguous = 0, cling = 0, preferred_count = 0;
-	unsigned ix;
+	unsigned ix, last_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? */
@@ -1085,99 +1085,125 @@
 		log_needs_allocating = (ah->log_area_count &&
 					dm_list_empty(&ah->alloced_areas[ah->area_count])) ?  1 : 0;
 
-		/*
-		 * Put the smallest area of each PV that is at least the
-		 * size we need into areas array.  If there isn't one
-		 * that fits completely and we're allowed more than one
-		 * LV segment, then take the largest remaining instead.
-		 */
-		dm_list_iterate_items(pvm, pvms) {
-			if (dm_list_empty(&pvm->areas))
-				continue;	/* Next PV */
-
-			if (alloc != ALLOC_ANYWHERE) {
-				/* Don't allocate onto the log 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)
+		do {
+			/*
+			 * Provide for escape from the loop if no progress is made.
+			 * This should not happen: ALLOC_ANYWHERE should be able to use
+			 * all available space. (If there aren't enough extents, the code
+			 * should not reach this point.)
+			 */
+			last_ix = ix;
+
+			/*
+			 * Put the smallest area of each PV that is at least the
+			 * size we need into areas array.  If there isn't one
+			 * that fits completely and we're allowed more than one
+			 * LV segment, then take the largest remaining instead.
+			 */
+			dm_list_iterate_items(pvm, pvms) {
+				if (dm_list_empty(&pvm->areas))
+					continue;	/* Next PV */
+
+				if (alloc != ALLOC_ANYWHERE) {
+					/* Don't allocate onto the log 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)
+						dm_list_iterate_items(pvl, parallel_pvs)
+							if (pvm->pv == pvl->pv)
 								goto next_pv;
+				}
 
-				/* Avoid PVs used by existing parallel areas */
-				if (parallel_pvs)
-					dm_list_iterate_items(pvl, parallel_pvs)
-						if (pvm->pv == pvl->pv)
+				already_found_one = 0;
+				/* First area in each list is the largest */
+				dm_list_iterate_items(pva, &pvm->areas) {
+					/* Skip fully-reserved areas (which are not currently removed from the list). */
+					if (!pva->unreserved)
+						continue;
+					if (contiguous) {
+						if (prev_lvseg &&
+						    _check_contiguous(ah->cmd,
+								      prev_lvseg,
+								      pva, *areas_ptr,
+								      *areas_size_ptr)) {
+							preferred_count++;
 							goto next_pv;
-			}
-
-			already_found_one = 0;
-			/* First area in each list is the largest */
-			dm_list_iterate_items(pva, &pvm->areas) {
-				if (contiguous) {
-					if (prev_lvseg &&
-					    _check_contiguous(ah->cmd,
-							      prev_lvseg,
-							      pva, *areas_ptr,
-							      *areas_size_ptr)) {
-						preferred_count++;
-						goto next_pv;
+						}
+						continue;
 					}
-					continue;
-				}
 
-				if (cling) {
-					if (prev_lvseg &&
-					    _check_cling(ah->cmd,
-							   prev_lvseg,
-							   pva, *areas_ptr,
-							   *areas_size_ptr)) {
-						preferred_count++;
+					if (cling) {
+						if (prev_lvseg &&
+						    _check_cling(ah->cmd,
+								   prev_lvseg,
+								   pva, *areas_ptr,
+								   *areas_size_ptr)) {
+							preferred_count++;
+						}
+						goto next_pv;
 					}
-					goto next_pv;
-				}
-
-				/* Is it big enough on its own? */
-				if (pva->count * ah->area_multiple <
-				    max_parallel - *allocated &&
-				    ((!can_split && !ah->log_area_count) ||
-				     (already_found_one &&
-				      !(alloc == ALLOC_ANYWHERE))))
-					goto next_pv;
-
-				/*
-				 * Except with ALLOC_ANYWHERE, replace first area with this
-				 * one which is smaller but still big enough.
-				 */
-				if (!already_found_one ||
-				    alloc == ALLOC_ANYWHERE) {
-					ix++;
-					already_found_one = 1;
-				}
 
-				if (ix + ix_offset - 1 < ah->area_count)
-					required = (max_parallel - *allocated) / ah->area_multiple;
-				else
-					required = ah->log_len;
+					/* Is it big enough on its own? */
+					if (pva->unreserved * ah->area_multiple <
+					    max_parallel - *allocated &&
+					    ((!can_split && !ah->log_area_count) ||
+					     (already_found_one &&
+					      !(alloc == ALLOC_ANYWHERE))))
+						goto next_pv;
 
-				if (required > pva->count)
-					required = pva->count;
+					/*
+					 * Except with ALLOC_ANYWHERE, replace first area with this
+					 * one which is smaller but still big enough.
+					 */
+					if (!already_found_one ||
+					    alloc == ALLOC_ANYWHERE) {
+						ix++;
+						already_found_one = 1;
+					}
 
-				/* Expand areas array if needed after an area was split. */
-				if (ix + ix_offset > *areas_size_ptr) {
-					*areas_size_ptr *= 2;
-					*areas_ptr = dm_realloc(*areas_ptr, sizeof(**areas_ptr) * (*areas_size_ptr));
+					if (ix + ix_offset - 1 < ah->area_count)
+						required = (max_parallel - *allocated) / ah->area_multiple;
+					else
+						required = ah->log_len;
+
+					if (alloc == ALLOC_ANYWHERE) {
+						/*
+						 * Update amount unreserved - effectively splitting an area 
+						 * into two or more parts.  If the whole stripe doesn't fit,
+						 * reduce amount we're looking for.
+						 */
+						if (required >= pva->unreserved) {
+							required = pva->unreserved;
+							pva->unreserved = 0;
+						} else {
+							pva->unreserved -= required;
+							reinsert_reduced_pv_area(pva);
+						}
+					} else if (required > pva->count)
+						required = pva->count;
+
+					/* Expand areas array if needed after an area was split. */
+					if (ix + ix_offset > *areas_size_ptr) {
+						*areas_size_ptr *= 2;
+						*areas_ptr = dm_realloc(*areas_ptr, sizeof(**areas_ptr) * (*areas_size_ptr));
+					}
+					(*areas_ptr)[ix + ix_offset - 1].pva = pva;
+						(*areas_ptr)[ix + ix_offset - 1].used = required;
+					log_debug("Trying allocation area %" PRIu32 " on %s start PE %" PRIu32
+						  " length %" PRIu32 " leaving %" PRIu32 ".",
+						  ix + ix_offset - 1, dev_name(pva->map->pv->dev), pva->start, required,
+						  (alloc == ALLOC_ANYWHERE) ? pva->unreserved : pva->count - required);
 				}
-				(*areas_ptr)[ix + ix_offset - 1].pva = pva;
-				(*areas_ptr)[ix + ix_offset - 1].used = required;
-				log_debug("Trying allocation area %" PRIu32 " on %s start PE %" PRIu32
-					  " length %" PRIu32 " leaving %" PRIu32 ".",
-					  ix + ix_offset - 1, dev_name(pva->map->pv->dev), pva->start, required,
-					  pva->count - required);
+			next_pv:
+				if (ix + ix_offset >= ah->area_count + (log_needs_allocating ? ah->log_area_count : 0))
+					break;
 			}
-		next_pv:
-			if (ix + ix_offset >= ah->area_count + (log_needs_allocating ? ah->log_area_count : 0))
-				break;
-		}
+		} while (alloc == ALLOC_ANYWHERE && last_ix != ix && ix < ah->area_count + (log_needs_allocating ? ah->log_area_count : 0));
 
 		if ((contiguous || cling) && (preferred_count < ix_offset))
 			break;
@@ -1211,7 +1237,6 @@
 		if (ix + ix_offset < ah->area_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_ptr, allocated,
--- LVM2/lib/metadata/pv_map.c	2010/03/16 14:37:38	1.35
+++ LVM2/lib/metadata/pv_map.c	2010/03/25 21:19:27	1.36
@@ -24,19 +24,25 @@
  *
  * FIXME Cope with overlap.
  */
-static void _insert_area(struct dm_list *head, struct pv_area *a)
+static void _insert_area(struct dm_list *head, struct pv_area *a, unsigned reduced)
 {
 	struct pv_area *pva;
-
-	dm_list_iterate_items(pva, head) {
-		if (a->count > pva->count)
+	uint32_t count = reduced ? a->unreserved : a->count;
+		
+	dm_list_iterate_items(pva, head)
+		if (count > pva->count)
 			break;
-	}
 
 	dm_list_add(&pva->list, &a->list);
 	a->map->pe_count += a->count;
 }
 
+static void _remove_area(struct pv_area *a)
+{
+	dm_list_del(&a->list);
+	a->map->pe_count -= a->count;
+}
+
 static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
 			       uint32_t start, uint32_t length)
 {
@@ -50,7 +56,8 @@
 	pva->map = pvm;
 	pva->start = start;
 	pva->count = length;
-	_insert_area(&pvm->areas, pva);
+	pva->unreserved = pva->count;
+	_insert_area(&pvm->areas, pva, 0);
 
 	return 1;
 }
@@ -184,8 +191,7 @@
 
 void consume_pv_area(struct pv_area *pva, uint32_t to_go)
 {
-	dm_list_del(&pva->list);
-	pva->map->pe_count -= pva->count;
+	_remove_area(pva);
 
 	assert(to_go <= pva->count);
 
@@ -193,10 +199,21 @@
 		/* split the area */
 		pva->start += to_go;
 		pva->count -= to_go;
-		_insert_area(&pva->map->areas, pva);
+		pva->unreserved = pva->count;
+		_insert_area(&pva->map->areas, pva, 0);
 	}
 }
 
+/*
+ * Remove an area from list and reinsert it based on its new smaller size
+ * after a provisional allocation.
+ */
+void reinsert_reduced_pv_area(struct pv_area *pva)
+{
+	_remove_area(pva);
+	_insert_area(&pva->map->areas, pva, 1);
+}
+
 uint32_t pv_maps_size(struct dm_list *pvms)
 {
 	struct pv_map *pvm;
--- LVM2/lib/metadata/pv_map.h	2010/03/25 02:40:09	1.12
+++ LVM2/lib/metadata/pv_map.h	2010/03/25 21:19:27	1.13
@@ -31,6 +31,9 @@
 	uint32_t start;
 	uint32_t count;
 
+	/* Number of extents unreserved during ALLOC_ANYWHERE allocation. */
+	uint32_t unreserved;
+
 	struct dm_list list;		/* pv_map.areas */
 };
 
@@ -66,5 +69,6 @@
 void reinsert_reduced_pv_area(struct pv_area *pva);
 
 uint32_t pv_maps_size(struct dm_list *pvms);
+void reinsert_reduced_pv_area(struct pv_area *pva);
 
 #endif


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2010-03-25  2:31 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2010-03-25  2:31 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2010-03-25 02:31:49

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c pv_map.h 

Log message:
	Introduce pv_area_used into allocation algorithm and add debug messages.
	
	This is the next preparatory step towards better --alloc anywhere
	support and is not intended to break anything that currently works so
	please report any problems - segfaults, bogus data in the new debug
	messages, or if the code now chooses bizarre allocation layouts.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1477&r2=1.1478
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.212&r2=1.213
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/pv_map.h.diff?cvsroot=lvm2&r1=1.10&r2=1.11

--- LVM2/WHATS_NEW	2010/03/24 22:25:11	1.1477
+++ LVM2/WHATS_NEW	2010/03/25 02:31:48	1.1478
@@ -1,7 +1,8 @@
 Version 2.02.63 - 
 ================================
-  Add "monitoring" option to "activation" section of lvm.conf.
-  Add --monitor and --ignoremonitoring support to lvcreate.
+  Introduce pv_area_used into allocation algorithm and add debug messages.
+  Add activation/monitoring to lvm.conf.
+  Add --monitor and --ignoremonitoring to lvcreate.
   Allow dynamic extension of array of areas selected as allocation candidates.
   Export and use only valid cookie value in test suite.
   Remove const modifier for struct volume_group* from process_each_lv_in_vg().
--- LVM2/lib/metadata/lv_manip.c	2010/03/23 22:30:19	1.212
+++ LVM2/lib/metadata/lv_manip.c	2010/03/25 02:31:49	1.213
@@ -735,7 +735,7 @@
  * 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 *allocated,
+				struct pv_area_used *areas, uint32_t *allocated,
 				unsigned log_needs_allocating, uint32_t ix_log_offset)
 {
 	uint32_t area_len, len, remaining;
@@ -749,8 +749,8 @@
 
 	/* Reduce area_len to the smallest of the areas */
 	for (s = 0; s < ah->area_count; s++)
-		if (area_len > areas[s]->count)
-			area_len = areas[s]->count;
+		if (area_len > areas[s].used)
+			area_len = areas[s].used;
 
 	if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) * total_area_count))) {
 		log_error("alloced_area allocation failed");
@@ -769,11 +769,15 @@
 			len = ah->log_len;
 		}
 
-		aa[s].pv = areas[s + ix_log_skip]->map->pv;
-		aa[s].pe = areas[s + ix_log_skip]->start;
+		aa[s].pv = areas[s + ix_log_skip].pva->map->pv;
+		aa[s].pe = areas[s + ix_log_skip].pva->start;
 		aa[s].len = len;
 
-		consume_pv_area(areas[s + ix_log_skip], len);
+		log_debug("Allocating parallel area %" PRIu32
+			  " on %s start PE %" PRIu32 " length %" PRIu32 ".",
+			  s, dev_name(aa[s].pv->dev), aa[s].pe, len);
+
+		consume_pv_area(areas[s + ix_log_skip].pva, len);
 
 		dm_list_add(&ah->alloced_areas[s], &aa[s].list);
 	}
@@ -863,13 +867,13 @@
 
 static int _comp_area(const void *l, const void *r)
 {
-	const struct pv_area *lhs = *((const struct pv_area * const *) l);
-	const struct pv_area *rhs = *((const struct pv_area * const *) r);
+	const struct pv_area_used *lhs = *((const struct pv_area_used * const *) l);
+	const struct pv_area_used *rhs = *((const struct pv_area_used * const *) r);
 
-	if (lhs->count < rhs->count)
+	if (lhs->used < rhs->used)
 		return 1;
 
-	else if (lhs->count > rhs->count)
+	else if (lhs->used > rhs->used)
 		return -1;
 
 	return 0;
@@ -881,7 +885,7 @@
 struct pv_match {
 	int (*condition)(struct pv_segment *pvseg, struct pv_area *pva);
 
-	struct pv_area **areas;
+	struct pv_area_used *areas;
 	struct pv_area *pva;
 	uint32_t areas_size;
 	int s;	/* Area index of match */
@@ -924,7 +928,12 @@
 	if (s >= pvmatch->areas_size)
 		return 1;
 
-	pvmatch->areas[s] = pvmatch->pva;
+	/*
+	 * Only used for cling and contiguous policies so its safe to say all
+	 * the available space is used.
+	 */
+	pvmatch->areas[s].pva = pvmatch->pva;
+	pvmatch->areas[s].used = pvmatch->pva->count;
 
 	return 2;	/* Finished */
 }
@@ -934,7 +943,7 @@
  */
 static int _check_cling(struct cmd_context *cmd,
 			struct lv_segment *prev_lvseg, struct pv_area *pva,
-			struct pv_area **areas, uint32_t areas_size)
+			struct pv_area_used *areas, uint32_t areas_size)
 {
 	struct pv_match pvmatch;
 	int r;
@@ -962,7 +971,7 @@
  */
 static int _check_contiguous(struct cmd_context *cmd,
 			     struct lv_segment *prev_lvseg, struct pv_area *pva,
-			     struct pv_area **areas, uint32_t areas_size)
+			     struct pv_area_used *areas, uint32_t areas_size)
 {
 	struct pv_match pvmatch;
 	int r;
@@ -989,7 +998,7 @@
  * Choose sets of parallel areas to use, respecting any constraints.
  */
 static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
-				struct dm_list *pvms, struct pv_area ***areas_ptr,
+				struct dm_list *pvms, struct pv_area_used **areas_ptr,
 				uint32_t *areas_size_ptr, unsigned can_split,
 				struct lv_segment *prev_lvseg,
 				uint32_t *allocated, uint32_t needed)
@@ -1005,6 +1014,7 @@
 	unsigned too_small_for_log_count; /* How many too small for log? */
 	uint32_t max_parallel;	/* Maximum extents to allocate */
 	uint32_t next_le;
+	uint32_t required;	/* Extents we're trying to obtain from a given area */
 	struct seg_pvs *spvs;
 	struct dm_list *parallel_pvs;
 	uint32_t free_pes;
@@ -1062,6 +1072,9 @@
 			}
 		}
 
+		log_needs_allocating = (ah->log_area_count &&
+					dm_list_empty(&ah->alloced_areas[ah->area_count])) ?  1 : 0;
+
 		/*
 		 * Put the smallest area of each PV that is at least the
 		 * size we need into areas array.  If there isn't one
@@ -1121,30 +1134,44 @@
 				      !(alloc == ALLOC_ANYWHERE))))
 					goto next_pv;
 
+				/*
+				 * Except with ALLOC_ANYWHERE, replace first area with this
+				 * one which is smaller but still big enough.
+				 */
 				if (!already_found_one ||
 				    alloc == ALLOC_ANYWHERE) {
 					ix++;
 					already_found_one = 1;
 				}
 
+				if (ix + ix_offset - 1 < ah->area_count)
+					required = (max_parallel - *allocated) / ah->area_multiple;
+				else
+					required = ah->log_len;
+
+				if (required > pva->count)
+					required = pva->count;
+
 				/* Expand areas array if needed after an area was split. */
 				if (ix + ix_offset > *areas_size_ptr) {
 					*areas_size_ptr *= 2;
 					*areas_ptr = dm_realloc(*areas_ptr, sizeof(**areas_ptr) * (*areas_size_ptr));
 				}
-				(*areas_ptr)[ix + ix_offset - 1] = pva;
+				(*areas_ptr)[ix + ix_offset - 1].pva = pva;
+				(*areas_ptr)[ix + ix_offset - 1].used = required;
+				log_debug("Trying allocation area %" PRIu32 " on %s start PE %" PRIu32
+					  " length %" PRIu32 " leaving %" PRIu32 ".",
+					  ix + ix_offset - 1, dev_name(pva->map->pv->dev), pva->start, required,
+					  pva->count - required);
 			}
 		next_pv:
-			if (ix >= *areas_size_ptr)
+			if (ix + ix_offset >= ah->area_count + (log_needs_allocating ? ah->log_area_count : 0))
 				break;
 		}
 
 		if ((contiguous || cling) && (preferred_count < ix_offset))
 			break;
 
-		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_area_count : 0))
 			break;
@@ -1166,7 +1193,7 @@
 			/* How many areas are too small for the log? */
 			while (too_small_for_log_count < ix_offset + ix &&
 			       (*((*areas_ptr) + ix_offset + ix - 1 -
-				  too_small_for_log_count))->count < ah->log_len)
+				  too_small_for_log_count)).used < ah->log_len)
 				too_small_for_log_count++;
 			ix_log_offset = ix_offset + ix - too_small_for_log_count - ah->log_area_count;
 		}
@@ -1197,7 +1224,7 @@
 		     unsigned can_split,
 		     struct dm_list *allocatable_pvs)
 {
-	struct pv_area **areas;
+	struct pv_area_used *areas;
 	uint32_t allocated = lv ? lv->le_count : 0;
 	uint32_t old_allocated;
 	struct lv_segment *prev_lvseg = NULL;
@@ -1206,12 +1233,16 @@
 	uint32_t areas_size;
 	alloc_policy_t alloc;
 	struct alloced_area *aa;
+	unsigned log_allocated;
 
 	if (allocated >= ah->new_extents && !ah->log_area_count) {
 		log_error("_allocate called with no work to do!");
 		return 1;
 	}
 
+	if (!ah->log_area_count)
+		log_allocated = 1;
+
 	if (ah->alloc == ALLOC_CONTIGUOUS)
 		can_split = 0;
 
@@ -1252,6 +1283,11 @@
 	/* Attempt each defined allocation policy in turn */
 	for (alloc = ALLOC_CONTIGUOUS; alloc < ALLOC_INHERIT; alloc++) {
 		old_allocated = allocated;
+		log_debug("Trying allocation using %s policy.  "
+			  "Need %" PRIu32 " extents for %" PRIu32 " parallel areas and %" PRIu32 " log extents.",
+			  get_alloc_string(alloc),
+			  (ah->new_extents - allocated) / ah->area_multiple,
+			  ah->area_count, log_allocated ? 0 : ah->log_area_count);
 		if (!_find_parallel_space(ah, alloc, pvms, &areas,
 					  &areas_size, can_split,
 					  prev_lvseg, &allocated, ah->new_extents))
@@ -1259,6 +1295,9 @@
 		if ((allocated == ah->new_extents) || (ah->alloc == alloc) ||
 		    (!can_split && (allocated != old_allocated)))
 			break;
+		/* Log is always allocated the first time anything is allocated. */
+		if (old_allocated != allocated)
+			log_allocated = 1;
 	}
 
 	if (allocated != ah->new_extents) {
--- LVM2/lib/metadata/pv_map.h	2008/11/03 22:14:29	1.10
+++ LVM2/lib/metadata/pv_map.h	2010/03/25 02:31:49	1.11
@@ -34,6 +34,18 @@
 	struct dm_list list;		/* pv_map.areas */
 };
 
+/*
+ * When building up a potential group of "parallel" extent ranges during
+ * an allocation attempt, track the maximum number of extents that may
+ * need to be used as a particular parallel area.  Several of these
+ * structs may reference the same pv_area, but 'used' may differ between
+ * them.
+ */
+struct pv_area_used {
+	struct pv_area *pva;
+	uint32_t used;
+};
+
 struct pv_map {
 	struct physical_volume *pv;
 	struct dm_list areas;		/* struct pv_areas */
@@ -49,6 +61,7 @@
 			    struct dm_list *allocatable_pvs);
 
 void consume_pv_area(struct pv_area *area, uint32_t to_go);
+void reinsert_reduced_pv_area(struct pv_area *pva);
 
 uint32_t pv_maps_size(struct dm_list *pvms);
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2010-01-08 22:32 jbrassow
  0 siblings, 0 replies; 36+ messages in thread
From: jbrassow @ 2010-01-08 22:32 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	jbrassow@sourceware.org	2010-01-08 22:32:35

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h mirror.c 
	man            : lvconvert.8.in lvcreate.8.in 
	tools          : commands.h lvconvert.c lvcreate.c 

Log message:
	Add the new mirror log type "redundant".  The options are now:
	--mirrorlog core: in-memory log
	--mirrorlog disk: persistent log
	--mirrorlog redundant: redundant persistent log
	
	Signed-off-by: Jonathan Brassow <jbrassow@redhat.com>

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1376&r2=1.1377
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.191&r2=1.192
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.124&r2=1.125
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.105&r2=1.106
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/man/lvconvert.8.in.diff?cvsroot=lvm2&r1=1.10&r2=1.11
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/man/lvcreate.8.in.diff?cvsroot=lvm2&r1=1.12&r2=1.13
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/commands.h.diff?cvsroot=lvm2&r1=1.137&r2=1.138
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.105&r2=1.106
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.212&r2=1.213

--- LVM2/WHATS_NEW	2010/01/08 22:28:54	1.1376
+++ LVM2/WHATS_NEW	2010/01/08 22:32:35	1.1377
@@ -1,5 +1,6 @@
 Version 2.02.57 -
 ====================================
+  Add redundant mirror log option.
   Add capability to split off and keep mirror legs to lvconvert.
   Change background polldaemon's process name to "(lvm2)".
   Allow vgremove of a VG with PVs missing.
--- LVM2/lib/metadata/lv_manip.c	2010/01/05 21:07:31	1.191
+++ LVM2/lib/metadata/lv_manip.c	2010/01/08 22:32:35	1.192
@@ -515,7 +515,7 @@
 
 	struct dm_list *parallel_areas;	/* PVs to avoid */
 
-	struct alloced_area log_area;	/* Extent used for log */
+	struct dm_list log_areas;	/* Extents used for logs */
 	struct dm_list alloced_areas[0];	/* Lists of areas in each stripe */
 };
 
@@ -582,6 +582,7 @@
 	ah->alloc = alloc;
 	ah->area_multiple = calc_area_multiple(segtype, area_count);
 
+	dm_list_init(&ah->log_areas);
 	for (s = 0; s < ah->area_count; s++)
 		dm_list_init(&ah->alloced_areas[s]);
 
@@ -644,8 +645,7 @@
 				  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;
@@ -685,15 +685,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;
 	}
 
@@ -729,11 +728,11 @@
  */
 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 *ix, struct pv_area **log_areas,
 				uint32_t log_len)
 {
 	uint32_t area_len, remaining;
-	uint32_t s;
+	uint32_t i,s;
 	struct alloced_area *aa;
 
 	remaining = needed - *ix;
@@ -744,8 +743,8 @@
 		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))))) {
+	s = sizeof(*aa) * (ah->area_count + ah->log_count);
+	if (!(aa = dm_pool_alloc(ah->mem, s))) {
 		log_error("alloced_area allocation failed");
 		return 0;
 	}
@@ -762,11 +761,14 @@
 	for (s = 0; s < ah->area_count; s++)
 		consume_pv_area(areas[s], area_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);
+	for (i = 0, s = ah->area_count;
+	     (s < ah->area_count + ah->log_count);
+	     s++, i++) {
+		aa[s].pv = log_areas[i]->map->pv;
+		aa[s].pe = log_areas[i]->start;
+		aa[s].len = log_len;
+		dm_list_add(&ah->log_areas, &aa[s].list);
+		consume_pv_area(log_areas[i], log_len);
 	}
 
 	*ix += area_len * ah->area_multiple;
@@ -983,6 +985,7 @@
 				struct lv_segment *prev_lvseg,
 				uint32_t *allocated, uint32_t needed)
 {
+	int i, j, skip = 0;
 	struct pv_map *pvm;
 	struct pv_area *pva;
 	struct pv_list *pvl;
@@ -997,8 +1000,9 @@
 	struct dm_list *parallel_pvs;
 	uint32_t free_pes;
 	uint32_t log_len;
-	struct pv_area *log_area;
+	struct pv_area **log_areas;
 	unsigned log_needs_allocating;
+	struct alloced_area *aa;
 
 	/* Is there enough total space? */
 	free_pes = pv_maps_size(pvms);
@@ -1061,10 +1065,16 @@
 				continue;	/* Next PV */
 
 			if (alloc != ALLOC_ANYWHERE) {
-				/* Don't allocate onto the log pv */
-				if (ah->log_count &&
-				    pvm->pv == ah->log_area.pv)
-					continue;	/* Next PV */
+				/* Don't allocate onto the log pvs */
+				dm_list_iterate_items(aa, &ah->log_areas)
+					if (pvm->pv == aa->pv) {
+						skip = 1;
+						break;
+					}
+				if (skip) {
+					skip = 0;
+					continue;
+				}
 
 				/* Avoid PVs used by existing parallel areas */
 				if (parallel_pvs)
@@ -1125,11 +1135,17 @@
 		if ((contiguous || cling) && (preferred_count < ix_offset))
 			break;
 
-		log_needs_allocating = (ah->log_count && !ah->log_area.len) ?
-				       1 : 0;
+		log_needs_allocating = 0;
+		if (ah->log_count && dm_list_empty(&ah->log_areas))
+			log_needs_allocating = 1;
 
+		/*
+		 * Note:  If we allow logs on the same devices as mirror
+		 * images, then that shouldn't factor into the equation.
+		 */
 		if (ix + ix_offset < ah->area_count +
-		   (log_needs_allocating ? ah->log_count : 0))
+		    ((log_needs_allocating && (alloc != ALLOC_ANYWHERE)) ?
+		     ah->log_count : 0))
 			break;
 
 		/* sort the areas so we allocate from the biggest */
@@ -1148,8 +1164,12 @@
 
 		if (!log_needs_allocating) {
 			log_len = 0;
-			log_area = NULL;
+			log_areas = NULL;
 		} else {
+			log_areas = dm_pool_alloc(ah->mem,
+						  sizeof(struct pv_area) *
+						  ah->log_count);
+
 			log_len = mirror_log_extents(ah->log_region_size,
 			    pv_pe_size((*areas)->map->pv),
 			    (max_parallel - *allocated) / ah->area_multiple);
@@ -1160,18 +1180,25 @@
 				  too_small_for_log_count))->count < log_len)
 				too_small_for_log_count++;
 
-			log_area = *(areas + ix_offset + ix - 1 -
-				     too_small_for_log_count);
+			i = ah->log_count - 1;
+			j = ix_offset + ix - 1 - too_small_for_log_count;
+			for (; (i >= 0) && (j >= 0); i--) {
+				log_areas[i] = *(areas + j);
+
+				/* Advance to next PV */
+				for (; ((j >= 0) &&
+					(log_areas[i]->map->pv == (*(areas + j))->map->pv)); j--);
+			}
 		}
 
 		if (ix + ix_offset < ah->area_count +
-		    (log_needs_allocating ? ah->log_count +
-					    too_small_for_log_count : 0))
+		    ((log_needs_allocating  && (alloc != ALLOC_ANYWHERE)) ?
+		     ah->log_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_areas, log_len))
 			return_0;
 
 	} while (!contiguous && *allocated != needed && can_split);
@@ -1199,6 +1226,7 @@
 	struct dm_list *pvms;
 	uint32_t areas_size;
 	alloc_policy_t alloc;
+	struct alloced_area *aa;
 
 	if (allocated >= new_extents && !ah->log_count) {
 		log_error("_allocate called with no work to do!");
@@ -1264,11 +1292,14 @@
 		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_count) {
+		dm_list_iterate_items(aa, &ah->log_areas)
+			if (!aa->len) {
+				log_error("Insufficient extents for log "
+					  "allocation for logical volume %s.",
+					  lv ? lv->name : "");
+				goto out;
+			}
 	}
 
 	r = 1;
@@ -1359,6 +1390,18 @@
 		   uint32_t region_size,
 		   struct logical_volume *log_lv)
 {
+	int i;
+	struct dm_list *aa_list;
+
+	/*
+	 * We don't actually use the 'log_lv' parameter for anything more
+	 * than just figuring out that this allocation is for a log device
+	 * It'd be nice to change the arguments type, but the function is
+	 * exported.
+	 */
+	aa_list = (log_lv) ? &ah->log_areas :
+		&ah->alloced_areas[first_area];
+
 	if (!segtype) {
 		log_error("Missing segtype in lv_add_segment().");
 		return 0;
@@ -1369,10 +1412,8 @@
 		return 0;
 	}
 
-	if (!_setup_alloced_segments(lv, &ah->alloced_areas[first_area],
-				     num_areas, status,
-				     stripe_size, segtype,
-				     region_size, log_lv))
+	if (!_setup_alloced_segments(lv, aa_list, num_areas, status,
+				     stripe_size, segtype, region_size))
 		return_0;
 
 	if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) {
@@ -1545,10 +1586,21 @@
 
 /*
  * Turn an empty LV into a mirror log.
+ *
+ * Only for the addition of the first, linear log.
  */
 int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv)
 {
 	struct lv_segment *seg;
+	struct alloced_area *log_area;
+
+	dm_list_iterate_items(log_area, &ah->log_areas)
+		break;
+
+	if (!log_area)
+		return 0;
+
+	dm_list_del(&log_area->list);
 
 	if (dm_list_size(&log_lv->segments)) {
 		log_error("Log segments can only be added to an empty LV");
@@ -1558,19 +1610,21 @@
 	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_lv, 0, log_area->len, MIRROR_LOG,
+				     0, NULL, 1, 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))
+	if (!set_lv_segment_area_pv(seg, 0, log_area->pv, log_area->pe))
 		return_0;
 
 	dm_list_add(&log_lv->segments, &seg->list);
-	log_lv->le_count += ah->log_area.len;
+	log_lv->le_count += log_area->len;
 	log_lv->size += (uint64_t) log_lv->le_count * log_lv->vg->extent_size;
 
+	dm_pool_free(ah->mem, log_area);
+
 	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;
@@ -3055,7 +3109,7 @@
 						vg->extent_size,
 						lv->le_count,
 						lp->region_size),
-				    lp->corelog ? 0U : 1U, lp->pvh, lp->alloc,
+				    lp->log_count, lp->pvh, lp->alloc,
 				    MIRROR_BY_LV |
 				    (lp->nosync ? MIRROR_SKIP_INIT_SYNC : 0))) {
 			stack;
--- LVM2/lib/metadata/metadata-exported.h	2009/11/24 22:55:56	1.124
+++ LVM2/lib/metadata/metadata-exported.h	2010/01/08 22:32:35	1.125
@@ -527,7 +527,7 @@
 	int zero; /* all */
 	int major; /* all */
 	int minor; /* all */
-	int corelog; /* mirror */
+	int log_count; /* mirror */
 	int nosync; /* mirror */
 
 	char *origin; /* snap */
@@ -652,6 +652,8 @@
 		   uint32_t mirrors, uint32_t stripes,
 		   uint32_t region_size, uint32_t log_count,
 		   struct dm_list *pvs, alloc_policy_t alloc, uint32_t flags);
+int lv_split_mirror_images(struct logical_volume *lv, const char *split_lv_name,
+			   uint32_t split_count, struct dm_list *removable_pvs);
 int lv_remove_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
 		      uint32_t mirrors, uint32_t log_count,
 		      struct dm_list *pvs, uint64_t status_mask);
--- LVM2/lib/metadata/mirror.c	2010/01/08 22:00:31	1.105
+++ LVM2/lib/metadata/mirror.c	2010/01/08 22:32:35	1.106
@@ -1171,7 +1171,8 @@
 static int _create_mimage_lvs(struct alloc_handle *ah,
 			      uint32_t num_mirrors,
 			      struct logical_volume *lv,
-			      struct logical_volume **img_lvs)
+			      struct logical_volume **img_lvs,
+			      int for_log)
 {
 	uint32_t m;
 	char *img_name;
@@ -1202,7 +1203,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, for_log ? lv : NULL)) {
 			log_error("Aborting. Failed to add mirror image segment "
 				  "to %s. Remove new LV and retry.",
 				  img_lvs[m]->name);
@@ -1547,11 +1548,51 @@
 	return log_lv;
 }
 
+/*
+ * Returns: 1 on success, 0 on error
+ */
+static int _form_mirror(struct cmd_context *cmd, struct alloc_handle *ah,
+			struct logical_volume *lv,
+			uint32_t mirrors, uint32_t region_size, int for_log)
+{
+	struct logical_volume **img_lvs;
+
+	/*
+	 * insert a mirror layer
+	 */
+	if (dm_list_size(&lv->segments) != 1 ||
+	    seg_type(first_seg(lv), 0) != AREA_LV)
+		if (!insert_layer_for_lv(cmd, lv, 0, "_mimage_%d"))
+			return 0;
+
+	/*
+	 * create mirror image LVs
+	 */
+	if (!(img_lvs = alloca(sizeof(*img_lvs) * mirrors))) {
+		log_error("img_lvs allocation failed. "
+			  "Remove new LV and retry.");
+		return 0;
+	}
+
+	if (!_create_mimage_lvs(ah, mirrors, lv, img_lvs, for_log))
+		return 0;
+
+	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.");
+		return 0;
+	}
+
+	return 1;
+}
+
 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 __attribute((unused)),
+						 uint32_t region_size,
 						 alloc_policy_t alloc,
 						 int in_sync)
 {
@@ -1563,11 +1604,6 @@
 
 	init_mirror_in_sync(in_sync);
 
-	if (log_count != 1) {
-		log_error("log_count != 1 is not supported.");
-		return NULL;
-	}
-
 	/* Mirror log name is lv_name + suffix, determined as the following:
 	 *   1. suffix is:
 	 *        o "_mlog" for the original mirror LV.
@@ -1600,6 +1636,12 @@
 		return NULL;
 	}
 
+	if ((log_count > 1) &&
+	    !_form_mirror(cmd, ah, log_lv, log_count-1, region_size, 1)) {
+		log_error("Failed to form mirrored log.");
+		return NULL;
+	}
+
 	if (!_init_mirror_log(cmd, log_lv, in_sync, &lv->tags, 1)) {
 		log_error("Failed to initialise mirror log.");
 		return NULL;
@@ -1630,12 +1672,6 @@
 	struct lvinfo info;
 	int r = 0;
 
-	/* Unimplemented features */
-	if (log_count > 1) {
-		log_error("log_count > 1 is not supported");
-		return 0;
-	}
-
 	if (dm_list_size(&lv->segments) != 1) {
 		log_error("Multiple-segment mirror is not supported");
 		return 0;
@@ -1707,7 +1743,6 @@
 	struct alloc_handle *ah;
 	const struct segment_type *segtype;
 	struct dm_list *parallel_areas;
-	struct logical_volume **img_lvs;
 	struct logical_volume *log_lv = NULL;
 
 	if (stripes > 1) {
@@ -1747,34 +1782,9 @@
 	   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 (dm_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))
+	if (!_form_mirror(cmd, ah, lv, mirrors, region_size, 0))
 		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_images;
-	}
-
 	if (log_count && !attach_mirror_log(first_seg(lv), log_lv))
 		stack;
 
--- LVM2/man/lvconvert.8.in	2010/01/08 22:00:31	1.10
+++ LVM2/man/lvconvert.8.in	2010/01/08 22:32:35	1.11
@@ -3,7 +3,7 @@
 lvconvert \- convert a logical volume from linear to mirror or snapshot
 .SH SYNOPSIS
 .B lvconvert
-\-m|\-\-mirrors Mirrors [\-\-mirrorlog {disk|core}] [\-\-corelog] [\-R|\-\-regionsize MirrorLogRegionSize]
+\-m|\-\-mirrors Mirrors [\-\-mirrorlog {disk|core|redundant}] [\-\-corelog] [\-R|\-\-regionsize MirrorLogRegionSize]
 [\-A|\-\-alloc AllocationPolicy]
 [\-b|\-\-background] [\-f|\-\-force] [\-i|\-\-interval Seconds]
 [\-h|\-?|\-\-help]
@@ -71,6 +71,7 @@
 Core may be useful for short-lived mirrors: It means the mirror is
 regenerated by copying the data from the first device again every
 time the device is activated - perhaps, for example, after every reboot.
+Using "redundant" will create a persistent log that is itself mirrored.
 .TP
 .I \-\-corelog
 The optional argument "--corelog" is the same as specifying "--mirrorlog core".
--- LVM2/man/lvcreate.8.in	2009/10/26 13:41:13	1.12
+++ LVM2/man/lvcreate.8.in	2010/01/08 22:32:35	1.13
@@ -11,7 +11,7 @@
 {\-l|\-\-extents LogicalExtentsNumber[%{VG|PVS|FREE}] |
  \-L|\-\-size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}
 [\-M|\-\-persistent y|n] [\-\-minor minor]
-[\-m|\-\-mirrors Mirrors [\-\-nosync] [\-\-mirrorlog {disk|core}] [\-\-corelog]
+[\-m|\-\-mirrors Mirrors [\-\-nosync] [\-\-mirrorlog {disk|core|redundant}] [\-\-corelog]
 [\-R|\-\-regionsize MirrorLogRegionSize]]
 [\-n|\-\-name LogicalVolumeName]
 [\-p|\-\-permission r|rw] [\-r|\-\-readahead ReadAheadSectors|auto|none]
@@ -107,9 +107,10 @@
 The optional argument --mirrorlog specifies the type of log to be used.
 The default is disk, which is persistent and requires
 a small amount of storage space, usually on a separate device from the
-data being mirrored. Using core means the mirror is regenerated
+data being mirrored.  Using core means the mirror is regenerated
 by copying the data from the first device again each time the
-device is activated, for example, after every reboot.
+device is activated, for example, after every reboot.  Using "redundant"
+will create a persistent log that is itself mirrored.
 
 The optional argument --corelog is equivalent to --mirrorlog core.
 
--- LVM2/tools/commands.h	2010/01/08 22:00:31	1.137
+++ LVM2/tools/commands.h	2010/01/08 22:32:35	1.138
@@ -96,7 +96,7 @@
    "Change logical volume layout",
    0,
    "lvconvert "
-   "[-m|--mirrors Mirrors [{--mirrorlog {disk|core}|--corelog}]]\n"
+   "[-m|--mirrors Mirrors [{--mirrorlog {disk|core|redundant}|--corelog}]]\n"
    "\t[--repair [--use-policies]]\n"
    "\t[-R|--regionsize MirrorLogRegionSize]\n"
    "\t[--alloc AllocationPolicy]\n"
@@ -145,7 +145,7 @@
    "\t{-l|--extents LogicalExtentsNumber |\n"
    "\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
    "\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
-   "\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core}|--corelog}]]\n"
+   "\t[-m|--mirrors Mirrors [--nosync] [{--mirrorlog {disk|core|redundant}|--corelog}]]\n"
    "\t[-n|--name LogicalVolumeName]\n"
    "\t[--noudevsync]\n"
    "\t[-p|--permission {r|rw}]\n"
--- LVM2/tools/lvconvert.c	2010/01/08 22:00:31	1.105
+++ LVM2/tools/lvconvert.c	2010/01/08 22:32:35	1.106
@@ -550,18 +550,18 @@
 static int _lv_update_log_type(struct cmd_context *cmd,
 			       struct lvconvert_params *lp,
 			       struct logical_volume *lv,
-			       int corelog)
+			       int log_count)
 {
 	struct logical_volume *original_lv = _original_lv(lv);
-	if (_using_corelog(lv) && !corelog) {
-		if (!add_mirror_log(cmd, original_lv, 1,
+	if (_using_corelog(lv) && log_count) {
+		if (!add_mirror_log(cmd, original_lv, log_count,
 				    adjusted_mirror_region_size(
 					lv->vg->extent_size,
 					lv->le_count,
 					lp->region_size),
 				    lp->pvh, lp->alloc))
 			return_0;
-	} else if (!_using_corelog(lv) && corelog) {
+	} else if (!_using_corelog(lv) && !log_count) {
 		if (!remove_mirror_log(cmd, original_lv,
 				       lp->pv_count ? lp->pvh : NULL))
 			return_0;
@@ -613,7 +613,7 @@
 	struct lv_segment *seg;
 	uint32_t existing_mirrors;
 	const char *mirrorlog;
-	unsigned corelog = 0;
+	unsigned log_count = 0;
 	int r = 0;
 	struct logical_volume *log_lv, *layer_lv;
 	int failed_mirrors = 0, failed_log = 0;
@@ -671,7 +671,7 @@
 	if (existing_mirrors && lp->mirrors &&
 	    (lp->mirrors != existing_mirrors) &&
 	    !arg_count(cmd, mirrorlog_ARG) && !arg_count(cmd, corelog_ARG)) {
-		corelog = first_seg(lv)->log_lv ? 0 : 1;
+		log_count = lv_mirror_count(first_seg(lv)->log_lv);
 	}
 
 	if (repair) {
@@ -692,8 +692,10 @@
 			return_0;
 		lp->pvh = lp->failed_pvs = failed_pvs;
 		log_lv=first_seg(lv)->log_lv;
-		if (!log_lv || log_lv->status & PARTIAL_LV)
-			failed_log = corelog = 1;
+		if (!log_lv || log_lv->status & PARTIAL_LV) {
+			failed_log = 1;
+			log_count = 0;
+		}
 	} else {
 		/*
 		 * Did the user try to subtract more legs than available?
@@ -707,20 +709,29 @@
 		/*
 		 * Adjust log type
 		 */
+		/*
+		 * This param used to be 'corelog' and was initialized to '0'.
+		 * We initially set to '1' here so as not to screw the logic.
+		 */
+		log_count = 1;
 		if (arg_count(cmd, corelog_ARG))
-			corelog = 1;
+			log_count = 0;
 
 		mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
-					  corelog ? "core" : DEFAULT_MIRRORLOG);
-		if (!strcmp("disk", mirrorlog)) {
-			if (corelog) {
-				log_error("--mirrorlog disk and --corelog "
-					  "are incompatible");
-				return 0;
-			}
-			corelog = 0;
-		} else if (!strcmp("core", mirrorlog))
-			corelog = 1;
+					  !log_count ? "core" : DEFAULT_MIRRORLOG);
+
+		if (strcmp("core", mirrorlog) && !log_count) {
+			log_error("--mirrorlog disk and --corelog "
+				  "are incompatible");
+			return 0;
+		}
+
+		if (!strcmp("redundant", mirrorlog))
+			log_count = 2;
+		else if (!strcmp("disk", mirrorlog))
+			log_count = 1;
+		else if (!strcmp("core", mirrorlog))
+			log_count = 0;
 		else {
 			log_error("Unknown mirrorlog type: %s", mirrorlog);
 			return 0;
@@ -779,12 +790,12 @@
 						    remove_pvs))
 				return 0;
 		} else if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
-					      (corelog || lp->mirrors == 1) ? 1U : 0U,
+					      (!log_count || lp->mirrors == 1) ? 1U : 0U,
 					      remove_pvs, 0))
 			return_0;
 
 		if (lp->mirrors > 1 &&
-		    !_lv_update_log_type(cmd, lp, lv, corelog))
+		    !_lv_update_log_type(cmd, lp, lv, log_count))
 			return_0;
 	} else if (!(lv->status & MIRRORED)) {
 		/*
@@ -811,7 +822,7 @@
 						lv->vg->extent_size,
 						lv->le_count,
 						lp->region_size),
-				    corelog ? 0U : 1U, lp->pvh, lp->alloc,
+				    log_count, lp->pvh, lp->alloc,
 				    MIRROR_BY_LV)) {
 			stack;
 			return failure_code;
@@ -843,7 +854,7 @@
 		 * insertion to make the end result consistent with
 		 * linear-to-mirror conversion.
 		 */
-		if (!_lv_update_log_type(cmd, lp, lv, corelog)) {
+		if (!_lv_update_log_type(cmd, lp, lv, log_count)) {
 			stack;
 			return failure_code;
 		}
@@ -881,8 +892,8 @@
 	}
 
 	if (lp->mirrors == existing_mirrors) {
-		if (_using_corelog(lv) != corelog) {
-			if (!_lv_update_log_type(cmd, lp, lv, corelog)) {
+		if (_using_corelog(lv) != !log_count) {
+			if (!_lv_update_log_type(cmd, lp, lv, log_count)) {
 				stack;
 				return failure_code;
 			}
@@ -922,8 +933,10 @@
 
 	if (failed_log || failed_mirrors) {
 		lp->pvh = old_pvh;
-		if (failed_log && replace_log)
-			failed_log = corelog = 0;
+		if (failed_log && replace_log) {
+			failed_log = 0;
+			log_count = 1;
+		}
 		if (replace_mirrors)
 			lp->mirrors += failed_mirrors;
 		failed_mirrors = 0;
--- LVM2/tools/lvcreate.c	2009/12/03 01:47:34	1.212
+++ LVM2/tools/lvcreate.c	2010/01/08 22:32:35	1.213
@@ -323,21 +323,29 @@
 	int region_size;
 	const char *mirrorlog;
 
+	/*
+	 * This param used to be 'corelog' and was initialized to '0'.
+	 * We initially set to '1' here so as not to screw the logic.
+	 */
+	lp->log_count = 1;
 	if (arg_count(cmd, corelog_ARG))
-		lp->corelog = 1;
+		lp->log_count = 0;
 
 	mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
-				  lp->corelog ? "core" : DEFAULT_MIRRORLOG);
+				  !lp->log_count ? "core" : DEFAULT_MIRRORLOG);
 
-	if (!strcmp("disk", mirrorlog)) {
-		if (lp->corelog) {
-			log_error("--mirrorlog disk and --corelog "
-				  "are incompatible");
-			return 0;
-		}
-		lp->corelog = 0;
-	} else if (!strcmp("core", mirrorlog))
-		lp->corelog = 1;
+	if (strcmp("core", mirrorlog) && !lp->log_count) {
+		log_error("--mirrorlog disk and --corelog "
+			  "are incompatible");
+		return 0;
+	}
+
+	if (!strcmp("redundant", mirrorlog))
+		lp->log_count = 2;
+	else if (!strcmp("disk", mirrorlog))
+		lp->log_count = 1;
+	else if (!strcmp("core", mirrorlog))
+		lp->log_count = 0;
 	else {
 		log_error("Unknown mirrorlog type: %s", mirrorlog);
 		return 0;


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2009-05-13 21:29 mbroz
  0 siblings, 0 replies; 36+ messages in thread
From: mbroz @ 2009-05-13 21:29 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	mbroz@sourceware.org	2009-05-13 21:29:10

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h metadata.c 
	test           : t-lvcreate-usage.sh test-utils.sh 
	tools          : lvcreate.c 

Log message:
	Check max_lv on only place and force the check only for new volume.
	
	We can temporarily violate max_lv during mirror conversion etc.
	
	(If the operation fails, orphan mirror images are visible to administrator
	for manual remove for example. Not that this should ever happen:-)
	
	Force limit only for lvcreate (and vg merge) command.
	
	Patch also adds simple max_lv tests into testsuite

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1110&r2=1.1111
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.171&r2=1.172
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.72&r2=1.73
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.c.diff?cvsroot=lvm2&r1=1.218&r2=1.219
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/t-lvcreate-usage.sh.diff?cvsroot=lvm2&r1=1.12&r2=1.13
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/test/test-utils.sh.diff?cvsroot=lvm2&r1=1.12&r2=1.13
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.187&r2=1.188

--- LVM2/WHATS_NEW	2009/05/13 21:28:31	1.1110
+++ LVM2/WHATS_NEW	2009/05/13 21:29:10	1.1111
@@ -1,5 +1,6 @@
 Version 2.02.46 - 
 ================================
+  Force max_lv restriction only for newly created LV.
   Remove unneeded import parameter from lv_create_empty.
   Merge lv_is_displayable and lv_is_visible functions.
   Introduce lv_set_visible & lv_set_invisible functions.
--- LVM2/lib/metadata/lv_manip.c	2009/05/13 21:28:31	1.171
+++ LVM2/lib/metadata/lv_manip.c	2009/05/13 21:29:10	1.172
@@ -1804,6 +1804,20 @@
 	return buffer;
 }
 
+int vg_max_lv_reached(struct volume_group *vg)
+{
+	if (!vg->max_lv)
+		return 0;
+
+	if (vg->max_lv > vg_visible_lvs(vg))
+		return 0;
+
+	log_verbose("Maximum number of logical volumes (%u) reached "
+		    "in volume group %s", vg->max_lv, vg->name);
+
+	return 1;
+}
+
 /*
  * Create a new empty LV.
  */
@@ -1817,11 +1831,8 @@
 	struct logical_volume *lv;
 	char dname[NAME_LEN];
 
-	if (vg->max_lv && (vg->max_lv == vg_visible_lvs(vg))) {
-		log_error("Maximum number of logical volumes (%u) reached "
-			  "in volume group %s", vg->max_lv, vg->name);
-		return NULL;
-	}
+	if (vg_max_lv_reached(vg))
+		stack;
 
 	if (strstr(name, "%d") &&
 	    !(name = generate_lv_name(vg, name, dname, sizeof(dname)))) {
@@ -1936,6 +1947,9 @@
 {
 	struct lv_list *lvl;
 
+	if (vg_max_lv_reached(vg))
+		stack;
+
 	if (!(lvl = dm_pool_zalloc(vg->vgmem, sizeof(*lvl))))
 		return_0;
 
--- LVM2/lib/metadata/metadata-exported.h	2009/05/13 21:28:31	1.72
+++ LVM2/lib/metadata/metadata-exported.h	2009/05/13 21:29:10	1.73
@@ -565,6 +565,11 @@
 unsigned vg_visible_lvs(const struct volume_group *vg);
 
 /*
+ * Check if the VG reached maximal LVs count (if set)
+ */
+int vg_max_lv_reached(struct volume_group *vg);
+
+/*
 * Mirroring functions
 */
 struct lv_segment *find_mirror_seg(struct lv_segment *seg);
--- LVM2/lib/metadata/metadata.c	2009/05/13 21:27:43	1.218
+++ LVM2/lib/metadata/metadata.c	2009/05/13 21:29:10	1.219
@@ -1528,12 +1528,8 @@
 		r = 0;
 	}
 
-	if (vg->max_lv && (vg->max_lv < vg_visible_lvs(vg))) {
-		log_error("Internal error: Volume group %s contains %u volumes"
-			  " but the limit is set to %u.",
-			  vg->name, vg_visible_lvs(vg), vg->max_lv);
-		r = 0;
-	}
+	if (vg_max_lv_reached(vg))
+		stack;
 
 	return r;
 }
--- LVM2/test/t-lvcreate-usage.sh	2009/05/08 21:50:20	1.12
+++ LVM2/test/t-lvcreate-usage.sh	2009/05/13 21:29:10	1.13
@@ -55,12 +55,33 @@
 case $(lvdisplay $vg) in "") true ;; *) false ;; esac
 
 # Setting max_lv works. (bz490298)
-vgchange -l 4 $vg
+lvremove -ff $vg
+vgchange -l 3 $vg
 lvcreate -l1 -n $lv1 $vg
 lvcreate -l1 -s -n $lv2 $vg/$lv1
 lvcreate -l1 -n $lv3 $vg
 not lvcreate -l1 -n $lv4 $vg
+
+lvremove -ff $vg/$lv3
+lvcreate -l1 -s -n $lv3 $vg/$lv1
+not lvcreate -l1 -n $lv4 $vg
+not lvcreate -l1 -m1 -n $lv4 $vg
+
+lvremove -ff $vg/$lv3
+lvcreate -l1 -m1 -n $lv3 $vg
+lvs
+vgs -o +max_lv
+not lvcreate -l1 -n $lv4 $vg
+not lvcreate -l1 -m1 -n $lv4 $vg
+
+lvconvert -m0 $vg/$lv3
+lvconvert -m2 -i 1 $vg/$lv3
+lvconvert -m1 $vg/$lv3
+
+not vgchange -l 2
+vgchange -l 4
 vgs $vg
+
 lvremove -ff $vg
 vgchange -l 0 $vg
 
--- LVM2/test/test-utils.sh	2009/05/13 19:18:47	1.12
+++ LVM2/test/test-utils.sh	2009/05/13 21:29:10	1.13
@@ -130,6 +130,7 @@
 	lv1=LV1
 	lv2=LV2
 	lv3=LV3
+	lv4=LV4
 }
 
 disable_dev() {
--- LVM2/tools/lvcreate.c	2009/05/13 21:28:31	1.187
+++ LVM2/tools/lvcreate.c	2009/05/13 21:29:10	1.188
@@ -613,6 +613,12 @@
 		return 0;
 	}
 
+	if (vg_max_lv_reached(vg)) {
+		log_error("Maximum number of logical volumes (%u) reached "
+			  "in volume group %s", vg->max_lv, vg->name);
+		return 0;
+	}
+
 	if (lp->mirrors > 1 && !(vg->fid->fmt->features & FMT_SEGMENTS)) {
 		log_error("Metadata does not support mirroring.");
 		return 0;


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2009-05-13 21:28 mbroz
  0 siblings, 0 replies; 36+ messages in thread
From: mbroz @ 2009-05-13 21:28 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	mbroz@sourceware.org	2009-05-13 21:28:31

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h mirror.c 
	                 snapshot_manip.c 
	tools          : lvcreate.c pvmove.c 

Log message:
	Remove unneeded import parameter from lv_create_empty.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1109&r2=1.1110
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.170&r2=1.171
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.71&r2=1.72
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.86&r2=1.87
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/snapshot_manip.c.diff?cvsroot=lvm2&r1=1.41&r2=1.42
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.186&r2=1.187
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/pvmove.c.diff?cvsroot=lvm2&r1=1.57&r2=1.58

--- LVM2/WHATS_NEW	2009/05/13 21:27:43	1.1109
+++ LVM2/WHATS_NEW	2009/05/13 21:28:31	1.1110
@@ -1,5 +1,6 @@
 Version 2.02.46 - 
 ================================
+  Remove unneeded import parameter from lv_create_empty.
   Merge lv_is_displayable and lv_is_visible functions.
   Introduce lv_set_visible & lv_set_invisible functions.
   Fix lv_is_visible to handle virtual origin.
--- LVM2/lib/metadata/lv_manip.c	2009/05/13 21:27:43	1.170
+++ LVM2/lib/metadata/lv_manip.c	2009/05/13 21:28:31	1.171
@@ -1811,7 +1811,6 @@
 				       union lvid *lvid,
 				       uint32_t status,
 				       alloc_policy_t alloc,
-				       int import,
 				       struct volume_group *vg)
 {
 	struct format_instance *fi = vg->fid;
@@ -1831,8 +1830,7 @@
 		return NULL;
 	}
 
-	if (!import)
-		log_verbose("Creating logical volume %s", name);
+	log_verbose("Creating logical volume %s", name);
 
 	if (!(lv = dm_pool_zalloc(vg->vgmem, sizeof(*lv))))
 		return_NULL;
@@ -2417,7 +2415,7 @@
 	}
 
 	if (!(layer_lv = lv_create_empty(name, NULL, LVM_READ | LVM_WRITE,
-					 ALLOC_INHERIT, 0, lv_where->vg))) {
+					 ALLOC_INHERIT, lv_where->vg))) {
 		log_error("Creation of layer LV failed");
 		return NULL;
 	}
--- LVM2/lib/metadata/metadata-exported.h	2009/05/13 21:27:43	1.71
+++ LVM2/lib/metadata/metadata-exported.h	2009/05/13 21:28:31	1.72
@@ -448,7 +448,6 @@
 				       union lvid *lvid,
 				       uint32_t status,
 				       alloc_policy_t alloc,
-				       int import,
 				       struct volume_group *vg);
 
 /* Write out LV contents */
--- LVM2/lib/metadata/mirror.c	2009/05/13 21:26:45	1.86
+++ LVM2/lib/metadata/mirror.c	2009/05/13 21:28:31	1.87
@@ -932,7 +932,7 @@
 	for (m = 0; m < num_mirrors; m++) {
 		if (!(img_lvs[m] = lv_create_empty(img_name,
 					     NULL, LVM_READ | LVM_WRITE,
-					     ALLOC_INHERIT, 0, lv->vg))) {
+					     ALLOC_INHERIT, lv->vg))) {
 			log_error("Aborting. Failed to create mirror image LV. "
 				  "Remove new LV and retry.");
 			return 0;
@@ -1266,7 +1266,7 @@
 
 	if (!(log_lv = lv_create_empty(log_name, NULL,
 				       VISIBLE_LV | LVM_READ | LVM_WRITE,
-				       alloc, 0, lv->vg)))
+				       alloc, lv->vg)))
 		return_NULL;
 
 	if (!lv_add_log_segment(ah, log_lv))
--- LVM2/lib/metadata/snapshot_manip.c	2009/05/13 21:27:43	1.41
+++ LVM2/lib/metadata/snapshot_manip.c	2009/05/13 21:28:31	1.42
@@ -105,7 +105,7 @@
 
 	if (!(snap = lv_create_empty("snapshot%d",
 				     lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
-				     ALLOC_INHERIT, 1, origin->vg)))
+				     ALLOC_INHERIT, origin->vg)))
 		return_0;
 
 	snap->le_count = extent_count;
--- LVM2/tools/lvcreate.c	2009/05/13 21:21:59	1.186
+++ LVM2/tools/lvcreate.c	2009/05/13 21:28:31	1.187
@@ -577,7 +577,7 @@
 	}
 
 	if (!(lv = lv_create_empty(vorigin_name, NULL, permission,
-				   ALLOC_INHERIT, 0, vg)))
+				   ALLOC_INHERIT, vg)))
 		return_0;
 
 	if (!lv_extend(lv, segtype, 1, 0, 1, voriginextents, NULL, 0u, 0u,
@@ -824,7 +824,7 @@
 	}
 
 	if (!(lv = lv_create_empty(lv_name ? lv_name : "lvol%d", NULL,
-				   status, lp->alloc, 0, vg)))
+				   status, lp->alloc, vg)))
 		return_0;
 
 	if (lp->read_ahead) {
--- LVM2/tools/pvmove.c	2009/04/21 14:31:58	1.57
+++ LVM2/tools/pvmove.c	2009/05/13 21:28:31	1.58
@@ -191,7 +191,7 @@
 	/* FIXME Cope with non-contiguous => splitting existing segments */
 	if (!(lv_mirr = lv_create_empty("pvmove%d", NULL,
 					LVM_READ | LVM_WRITE,
-					ALLOC_CONTIGUOUS, 0, vg))) {
+					ALLOC_CONTIGUOUS, vg))) {
 		log_error("Creation of temporary pvmove LV failed");
 		return NULL;
 	}


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2009-04-21 14:32 mbroz
  0 siblings, 0 replies; 36+ messages in thread
From: mbroz @ 2009-04-21 14:32 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	mbroz@sourceware.org	2009-04-21 14:31:58

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c mirror.c 
	tools          : lvchange.c lvconvert.c lvcreate.c lvresize.c 
	                 pvmove.c 

Log message:
	Move metadata backup call after vg_commit.
	
	The backup() call store metadata from memory.
	
	But in cluster backup() call performs
	remote nodes metadata backup and it reads data from disk.
	
	For metadata backup consistency,
	patch moves all backup() calls after vg_commit.
	
	(Moreover, some tools already do that this way.)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1090&r2=1.1091
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.165&r2=1.166
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.83&r2=1.84
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvchange.c.diff?cvsroot=lvm2&r1=1.96&r2=1.97
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.69&r2=1.70
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.181&r2=1.182
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvresize.c.diff?cvsroot=lvm2&r1=1.106&r2=1.107
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/pvmove.c.diff?cvsroot=lvm2&r1=1.56&r2=1.57

--- LVM2/WHATS_NEW	2009/04/21 13:11:28	1.1090
+++ LVM2/WHATS_NEW	2009/04/21 14:31:57	1.1091
@@ -1,5 +1,6 @@
 Version 2.02.46 - 
 ================================
+  Fix metadata backup to run after vg_commit always.
   Tidy clvmd volume lock cache functions.
   Fix pvs report for orphan PVs when segment attributes are requested.
   Fix pvs -a output to not read volume groups from non-PV devices.
--- LVM2/lib/metadata/lv_manip.c	2009/04/07 10:20:29	1.165
+++ LVM2/lib/metadata/lv_manip.c	2009/04/21 14:31:58	1.166
@@ -1736,6 +1736,7 @@
 {
 	struct volume_group *vg = lv->vg;
 	struct lv_names lv_names;
+	int r = 0;
 
 	/* rename is not allowed on sub LVs */
 	if (!lv_is_displayable(lv)) {
@@ -1773,23 +1774,21 @@
 	if (!vg_write(vg))
 		return 0;
 
-	backup(vg);
-
 	if (!suspend_lv(cmd, lv)) {
-		stack;
 		vg_revert(vg);
-		return 0;
+		goto_out;
 	}
 
 	if (!vg_commit(vg)) {
-		stack;
 		resume_lv(cmd, lv);
-		return 0;
+		goto_out;
 	}
 
 	resume_lv(cmd, lv);
-
-	return 1;
+	r = 1;
+out:
+	backup(vg);
+	return r;
 }
 
 char *generate_lv_name(struct volume_group *vg, const char *format,
@@ -2051,14 +2050,11 @@
 	}
 
 	/* store it on disks */
-	if (!vg_write(vg))
-		return 0;
+	if (!vg_write(vg) || !vg_commit(vg))
+		return_0;
 
 	backup(vg);
 
-	if (!vg_commit(vg))
-		return 0;
-
 	/* If no snapshots left, reload without -real. */
 	if (origin && !lv_is_origin(origin)) {
 		if (!suspend_lv(cmd, origin))
--- LVM2/lib/metadata/mirror.c	2009/04/10 09:53:43	1.83
+++ LVM2/lib/metadata/mirror.c	2009/04/21 14:31:58	1.84
@@ -270,14 +270,11 @@
 		}
 
 	/* store mirror log on disk(s) */
-	if (!vg_write(log_lv->vg))
+	if (!vg_write(log_lv->vg) || !vg_commit(log_lv->vg))
 		goto activate_lv;
 
 	backup(log_lv->vg);
 
-	if (!vg_commit(log_lv->vg))
-		goto activate_lv;
-
 	if (!activate_lv(cmd, log_lv)) {
 		log_error("Aborting. Failed to activate mirror log.");
 		goto revert_new_lv;
@@ -334,10 +331,12 @@
 		return 0;
 	}
 
-	if (!vg_write(log_lv->vg) ||
-	    (backup(log_lv->vg), !vg_commit(log_lv->vg)))
+	if (!vg_write(log_lv->vg) || !vg_commit(log_lv->vg))
 		log_error("Manual intervention may be required to "
 			  "remove/restore abandoned log LV before retrying.");
+	else
+		backup(log_lv->vg);
+
 activate_lv:
 	if (was_active && !remove_on_failure && !activate_lv(cmd, log_lv))
 		return_0;
@@ -1504,11 +1503,15 @@
 	return 1;
 
   out_remove_log:
-	if (log_lv && (!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.");
-
+	if (log_lv) {
+		if (!lv_remove(log_lv) ||
+		    !vg_write(log_lv->vg) ||
+		    !vg_commit(log_lv->vg))
+			log_error("Manual intervention may be required to remove "
+				  "abandoned log LV before retrying.");
+		else
+			backup(log_lv->vg);
+	}
   out_remove_imgs:
 	alloc_destroy(ah);
 	return 0;
--- LVM2/tools/lvchange.c	2008/12/19 14:22:48	1.96
+++ LVM2/tools/lvchange.c	2009/04/21 14:31:58	1.97
@@ -20,6 +20,7 @@
 {
 	uint32_t lv_access;
 	struct lvinfo info;
+	int r = 0;
 
 	lv_access = arg_uint_value(cmd, permission_ARG, 0);
 
@@ -56,26 +57,27 @@
 	if (!vg_write(lv->vg))
 		return_0;
 
-	backup(lv->vg);
-
 	if (!suspend_lv(cmd, lv)) {
 		log_error("Failed to lock %s", lv->name);
 		vg_revert(lv->vg);
-		return 0;
+		goto out;
 	}
 
 	if (!vg_commit(lv->vg)) {
 		resume_lv(cmd, lv);
-		return 0;
+		goto_out;
 	}
 
 	log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
 	if (!resume_lv(cmd, lv)) {
 		log_error("Problem reactivating %s", lv->name);
-		return 0;
+		goto out;
 	}
 
-	return 1;
+	r = 1;	
+out:
+	backup(lv->vg);
+	return r;
 }
 
 static int lvchange_monitoring(struct cmd_context *cmd,
@@ -274,8 +276,6 @@
 			return 0;
 		}
 
-		backup(lv->vg);
-
 		if (!vg_commit(lv->vg)) {
 			log_error("Failed to commit intermediate VG metadata.");
 			if (!attach_mirror_log(first_seg(lv), log_lv))
@@ -285,6 +285,8 @@
 			return 0;
 		}
 
+		backup(lv->vg);
+
 		if (!activate_lv(cmd, log_lv)) {
 			log_error("Unable to activate %s for mirror log resync",
 				  log_lv->name);
@@ -349,15 +351,12 @@
 
 	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
 
-	if (!vg_write(lv->vg))
+	/* No need to suspend LV for this change */
+	if (!vg_write(lv->vg) || !vg_commit(lv->vg))
 		return_0;
 
 	backup(lv->vg);
 
-	/* No need to suspend LV for this change */
-	if (!vg_commit(lv->vg))
-		return_0;
-
 	return 1;
 }
 
@@ -366,6 +365,7 @@
 {
 	unsigned read_ahead = 0;
 	unsigned pagesize = (unsigned) lvm_getpagesize() >> SECTOR_SHIFT;
+	int r = 0;
 
 	read_ahead = arg_uint_value(cmd, readahead_ARG, 0);
 
@@ -401,26 +401,27 @@
 	if (!vg_write(lv->vg))
 		return_0;
 
-	backup(lv->vg);
-
 	if (!suspend_lv(cmd, lv)) {
 		log_error("Failed to lock %s", lv->name);
 		vg_revert(lv->vg);
-		return 0;
+		goto out;
 	}
 
 	if (!vg_commit(lv->vg)) {
 		resume_lv(cmd, lv);
-		return 0;
+		goto_out;
 	}
 
 	log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
 	if (!resume_lv(cmd, lv)) {
 		log_error("Problem reactivating %s", lv->name);
-		return 0;
+		goto out;
 	}
 
-	return 1;
+	r = 1;
+out:
+	backup(lv->vg);
+	return r;
 }
 
 static int lvchange_persistent(struct cmd_context *cmd,
@@ -477,14 +478,11 @@
 	}
 
 	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
-	if (!vg_write(lv->vg))
+	if (!vg_write(lv->vg) || !vg_commit(lv->vg))
 		return_0;
 
 	backup(lv->vg);
 
-	if (!vg_commit(lv->vg))
-		return_0;
-
 	if (active) {
 		log_verbose("Re-activating logical volume \"%s\"", lv->name);
 		if (!activate_lv(cmd, lv)) {
@@ -527,15 +525,13 @@
 	}
 
 	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
-	if (!vg_write(lv->vg))
-		return_0;
-
-	backup(lv->vg);
 
 	/* No need to suspend LV for this change */
-	if (!vg_commit(lv->vg))
+	if (!vg_write(lv->vg) || !vg_commit(lv->vg))
 		return_0;
 
+	backup(lv->vg);
+
 	return 1;
 }
 
--- LVM2/tools/lvconvert.c	2009/04/10 10:01:38	1.69
+++ LVM2/tools/lvconvert.c	2009/04/21 14:31:58	1.70
@@ -269,6 +269,8 @@
 				    struct logical_volume *lv,
 				    struct dm_list *lvs_changed __attribute((unused)))
 {
+	int r = 0;
+
 	if (!collapse_mirrored_lv(lv)) {
 		log_error("Failed to remove temporary sync layer.");
 		return 0;
@@ -281,29 +283,29 @@
 	if (!vg_write(vg))
 		return_0;
 
-	backup(vg);
-
 	if (!suspend_lv(cmd, lv)) {
 		log_error("Failed to lock %s", lv->name);
 		vg_revert(vg);
-		return 0;
+		goto out;
 	}
 
 	if (!vg_commit(vg)) {
 		resume_lv(cmd, lv);
-		return 0;
+		goto_out;
 	}
 
 	log_very_verbose("Updating \"%s\" in kernel", lv->name);
 
 	if (!resume_lv(cmd, lv)) {
 		log_error("Problem reactivating %s", lv->name);
-		return 0;
+		goto out;
 	}
 
+	r = 1;
 	log_print("Logical volume %s converted.", lv->name);
-
-	return 1;
+out:
+	backup(vg);
+	return r;
 }
 
 static struct poll_functions _lvconvert_mirror_fns = {
@@ -383,6 +385,7 @@
 	const char *mirrorlog;
 	unsigned corelog = 0;
 	struct logical_volume *original_lv;
+	int r = 0;
 
 	seg = first_seg(lv);
 	existing_mirrors = lv_mirror_count(lv);
@@ -589,30 +592,31 @@
 	if (!vg_write(lv->vg))
 		return_0;
 
-	backup(lv->vg);
-
 	if (!suspend_lv(cmd, lv)) {
 		log_error("Failed to lock %s", lv->name);
 		vg_revert(lv->vg);
-		return 0;
+		goto out;
 	}
 
 	if (!vg_commit(lv->vg)) {
 		resume_lv(cmd, lv);
-		return 0;
+		goto_out;
 	}
 
 	log_very_verbose("Updating \"%s\" in kernel", lv->name);
 
 	if (!resume_lv(cmd, lv)) {
 		log_error("Problem reactivating %s", lv->name);
-		return 0;
+		goto out;
 	}
 
 	if (!lp->need_polling)
 		log_print("Logical volume %s converted.", lv->name);
 
-	return 1;
+	r = 1;
+out:
+	backup(lv->vg);
+	return r;
 }
 
 static int lvconvert_snapshot(struct cmd_context *cmd,
@@ -620,6 +624,7 @@
 			      struct lvconvert_params *lp)
 {
 	struct logical_volume *org;
+	int r = 0;
 
 	if (!(org = find_lv(lv->vg, lp->origin))) {
 		log_error("Couldn't find origin volume '%s'.", lp->origin);
@@ -664,25 +669,25 @@
 	if (!vg_write(lv->vg))
 		return_0;
 
-	backup(lv->vg);
-
 	if (!suspend_lv(cmd, org)) {
 		log_error("Failed to suspend origin %s", org->name);
 		vg_revert(lv->vg);
-		return 0;
+		goto out;
 	}
 
 	if (!vg_commit(lv->vg))
-		return_0;
+		goto_out;
 
 	if (!resume_lv(cmd, org)) {
 		log_error("Problem reactivating origin %s", org->name);
-		return 0;
+		goto out;
 	}
 
 	log_print("Logical volume %s converted to snapshot.", lv->name);
-
-	return 1;
+	r = 1;
+out:
+	backup(lv->vg);
+	return r;
 }
 
 static int lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
--- LVM2/tools/lvcreate.c	2009/04/10 10:01:38	1.181
+++ LVM2/tools/lvcreate.c	2009/04/21 14:31:58	1.182
@@ -786,14 +786,11 @@
 	}
 
 	/* store vg on disk(s) */
-	if (!vg_write(vg))
+	if (!vg_write(vg) || !vg_commit(vg))
 		return_0;
 
 	backup(vg);
 
-	if (!vg_commit(vg))
-		return_0;
-
 	if (lp->snapshot) {
 		if (!activate_lv_excl(cmd, lv)) {
 			log_error("Aborting. Failed to activate snapshot "
@@ -878,9 +875,12 @@
 
 revert_new_lv:
 	/* FIXME Better to revert to backup of metadata? */
-	if (!lv_remove(lv) || !vg_write(vg) || (backup(vg), !vg_commit(vg)))
+	if (!lv_remove(lv) || !vg_write(vg) || !vg_commit(vg))
 		log_error("Manual intervention may be required to remove "
 			  "abandoned LV(s) before retrying.");
+	else
+		backup(vg);
+
 	return 0;
 }
 
--- LVM2/tools/lvresize.c	2009/04/10 10:01:38	1.106
+++ LVM2/tools/lvresize.c	2009/04/21 14:31:58	1.107
@@ -626,8 +626,6 @@
 		return ECMD_FAILED;
 	}
 
-	backup(vg);
-
 	/* If snapshot, must suspend all associated devices */
 	if (lv_is_cow(lv))
 		lock_lv = origin_from_cow(lv);
@@ -637,20 +635,25 @@
 	if (!suspend_lv(cmd, lock_lv)) {
 		log_error("Failed to suspend %s", lp->lv_name);
 		vg_revert(vg);
+		backup(vg);
 		return ECMD_FAILED;
 	}
 
 	if (!vg_commit(vg)) {
 		stack;
 		resume_lv(cmd, lock_lv);
+		backup(vg);
 		return ECMD_FAILED;
 	}
 
 	if (!resume_lv(cmd, lock_lv)) {
 		log_error("Problem reactivating %s", lp->lv_name);
+		backup(vg);
 		return ECMD_FAILED;
 	}
 
+	backup(vg);
+
 	log_print("Logical volume %s successfully resized", lp->lv_name);
 
 	if (lp->resizefs && (lp->resize == LV_EXTEND) &&
--- LVM2/tools/pvmove.c	2009/04/10 10:01:38	1.56
+++ LVM2/tools/pvmove.c	2009/04/21 14:31:58	1.57
@@ -280,6 +280,7 @@
 {
 	unsigned exclusive = _pvmove_is_exclusive(cmd, vg);
 	unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0;
+	int r = 0;
 
 	log_verbose("Updating volume group metadata");
 	if (!vg_write(vg)) {
@@ -287,19 +288,16 @@
 		return 0;
 	}
 
-	backup(vg);
-
 	/* Suspend lvs_changed */
 	if (!suspend_lvs(cmd, lvs_changed))
-		return_0;
+		goto_out;
 
 	/* Suspend mirrors on subsequent calls */
 	if (!first_time) {
 		if (!suspend_lv(cmd, lv_mirr)) {
-			stack;
 			resume_lvs(cmd, lvs_changed);
 			vg_revert(vg);
-			return 0;
+			goto_out;
 		}
 	}
 
@@ -309,7 +307,7 @@
 		if (!first_time)
 			resume_lv(cmd, lv_mirr);
 		resume_lvs(cmd, lvs_changed);
-		return 0;
+		goto out;
 	}
 
 	/* Activate the temporary mirror LV */
@@ -323,22 +321,25 @@
 					  "Run pvmove --abort.");
 			/* FIXME Resume using *original* metadata here! */
 			resume_lvs(cmd, lvs_changed);
-			return 0;
+			goto out;
 		}
 	} else if (!resume_lv(cmd, lv_mirr)) {
 		log_error("Unable to reactivate logical volume \"%s\"",
 			  lv_mirr->name);
 		resume_lvs(cmd, lvs_changed);
-		return 0;
+		goto out;
 	}
 
 	/* Unsuspend LVs */
 	if (!resume_lvs(cmd, lvs_changed)) {
 		log_error("Unable to resume logical volumes");
-		return 0;
+		goto out;
 	}
 
-	return 1;
+	r = 1;
+out:
+	backup(vg);
+	return r;
 }
 
 static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2009-04-07 10:20 mbroz
  0 siblings, 0 replies; 36+ messages in thread
From: mbroz @ 2009-04-07 10:20 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	mbroz@sourceware.org	2009-04-07 10:20:29

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

Log message:
	Fix memory pool leak.
	
	Call the alloc_destory call always after finishing operation
	with handle otherwise it will leak a memory pool.
	
	Also fix return code in lv_extend.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.1076&r2=1.1077
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.164&r2=1.165
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.81&r2=1.82

--- LVM2/WHATS_NEW	2009/04/02 21:34:41	1.1076
+++ LVM2/WHATS_NEW	2009/04/07 10:20:28	1.1077
@@ -1,5 +1,6 @@
 Version 2.02.46 - 
 ================================
+  Fix memory leak in mirror allocation code.
   Save and restore the previous logging level when log level is changed.
   Fix error message when archive initialization fails.
   Make sure clvmd-corosync releases the lockspace when it exits.
--- LVM2/lib/metadata/lv_manip.c	2009/03/26 09:25:18	1.164
+++ LVM2/lib/metadata/lv_manip.c	2009/04/07 10:20:29	1.165
@@ -1608,16 +1608,12 @@
 				    extents, allocatable_pvs, alloc, NULL)))
 		return_0;
 
-	if (mirrors < 2) {
-		if (!lv_add_segment(ah, 0, ah->area_count, lv, segtype, stripe_size,
-			    status, 0, NULL))
-			goto_out;
-	} else {
-		if (!_lv_extend_mirror(ah, lv, extents, 0))
-			return_0;
-	}
+	if (mirrors < 2)
+		r = lv_add_segment(ah, 0, ah->area_count, lv, segtype,
+				   stripe_size, status, 0, NULL);
+	else
+		r = _lv_extend_mirror(ah, lv, extents, 0);
 
-      out:
 	alloc_destroy(ah);
 	return r;
 }
--- LVM2/lib/metadata/mirror.c	2009/02/28 20:04:24	1.81
+++ LVM2/lib/metadata/mirror.c	2009/04/07 10:20:29	1.82
@@ -1160,6 +1160,7 @@
 	const struct segment_type *segtype;
 	struct dm_list *parallel_areas;
 	uint32_t adjusted_region_size;
+	int r = 1;
 
 	if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
 		return_0;
@@ -1180,10 +1181,11 @@
 
 	if (!lv_add_mirror_areas(ah, lv, 0, adjusted_region_size)) {
 		log_error("Failed to add mirror areas to %s", lv->name);
-		return 0;
+		r = 0;
 	}
 
-	return 1;
+	alloc_destroy(ah);
+	return r;
 }
 
 /*
@@ -1349,6 +1351,7 @@
 	int in_sync;
 	struct logical_volume *log_lv;
 	struct lvinfo info;
+	int r = 0;
 
 	/* Unimplemented features */
 	if (log_count > 1) {
@@ -1404,13 +1407,15 @@
 
 	if (!(log_lv = _set_up_mirror_log(cmd, ah, lv, log_count,
 					  region_size, alloc, in_sync)))
-		return_0;
+		goto_out;
 
 	if (!attach_mirror_log(first_seg(lv), log_lv))
-		return_0;
+		goto_out;
 
+	r = 1;
+out:
 	alloc_destroy(ah);
-	return 1;
+	return r;
 }
 
 /*
@@ -1455,8 +1460,10 @@
 	 */
 	if (log_count &&
 	    !(log_lv = _set_up_mirror_log(cmd, ah, lv, log_count, region_size,
-					  alloc, mirror_in_sync())))
-		return_0;
+					  alloc, mirror_in_sync()))) {
+		stack;
+		goto out_remove_imgs;
+	}
 
 	/* The log initialization involves vg metadata commit.
 	   So from here on, if failure occurs, the log must be explicitly
@@ -1503,6 +1510,7 @@
 			  "abandoned log LV before retrying.");
 
   out_remove_imgs:
+	alloc_destroy(ah);
 	return 0;
 }
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2008-03-28 19:08 wysochanski
  0 siblings, 0 replies; 36+ messages in thread
From: wysochanski @ 2008-03-28 19:08 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	wysochanski@sourceware.org	2008-03-28 19:08:24

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

Log message:
	Add find_lv_in_lv_list() and find_pv_in_pv_list().
	Update _add_pvs() to call find_pv_in_pv_list().

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.811&r2=1.812
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.151&r2=1.152
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.c.diff?cvsroot=lvm2&r1=1.162&r2=1.163
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.178&r2=1.179

--- LVM2/WHATS_NEW	2008/03/28 12:58:08	1.811
+++ LVM2/WHATS_NEW	2008/03/28 19:08:23	1.812
@@ -1,5 +1,6 @@
 Version 2.02.34 -
 ===================================
+  Add find_lv_in_lv_list() and find_pv_in_pv_list().
   Fix uninitialised variable in clvmd that could cause odd hangs.
   Add vgmerge tests.
   Add pvseg_is_allocated() for identifying a PV segment allocated to a LV.
--- LVM2/lib/metadata/lv_manip.c	2008/02/22 13:22:21	1.151
+++ LVM2/lib/metadata/lv_manip.c	2008/03/28 19:08:23	1.152
@@ -1875,8 +1875,7 @@
 	struct pv_list *pvl;
 
 	/* Don't add again if it's already on list. */
-	list_iterate_items(pvl, &spvs->pvs)
-		if (pvl->pv == peg->pv)
+	if (find_pv_in_pv_list(&spvs->pvs, peg->pv))
 			return 1;
 
 	if (!(pvl = dm_pool_alloc(cmd->mem, sizeof(*pvl)))) {
--- LVM2/lib/metadata/metadata.c	2008/03/26 17:26:32	1.162
+++ LVM2/lib/metadata/metadata.c	2008/03/28 19:08:23	1.163
@@ -868,6 +868,17 @@
 	return NULL;
 }
 
+struct pv_list *find_pv_in_pv_list(const struct list *pl,
+				   const struct physical_volume *pv)
+{
+	struct pv_list *pvl;
+
+	list_iterate_items(pvl, pl)
+		if (pvl->pv == pv)
+			return pvl;
+	return NULL;
+}
+
 int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
 {
 	struct pv_list *pvl;
@@ -929,6 +940,17 @@
 	return NULL;
 }
 
+struct lv_list *find_lv_in_lv_list(const struct list *ll,
+				   const struct logical_volume *lv)
+{
+	struct lv_list *lvl;
+
+	list_iterate_items(lvl, ll)
+		if (lvl->lv == lv)
+			return lvl;
+	return NULL;
+}
+
 struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
 				      const union lvid *lvid)
 {
--- LVM2/lib/metadata/metadata.h	2008/03/17 16:51:31	1.178
+++ LVM2/lib/metadata/metadata.h	2008/03/28 19:08:23	1.179
@@ -257,6 +257,9 @@
 struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
 				      const union lvid *lvid);
 
+struct lv_list *find_lv_in_lv_list(const struct list *ll,
+				   const struct logical_volume *lv);
+
 /* Return the VG that contains a given LV (based on path given in lv_name) */
 /* or environment var */
 struct volume_group *find_vg_with_lv(const char *lv_name);
@@ -269,6 +272,9 @@
 /* FIXME Merge these functions with ones above */
 struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
 
+struct pv_list *find_pv_in_pv_list(const struct list *pl,
+				   const struct physical_volume *pv);
+
 /* Find LV segment containing given LE */
 struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le);
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2008-01-26  0:25 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2008-01-26  0:25 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2008-01-26 00:25:04

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h mirror.c 
	tools          : lvchange.c 

Log message:
	Refactor mirror log attachment code.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.777&r2=1.778
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.146&r2=1.147
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.41&r2=1.42
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.65&r2=1.66
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvchange.c.diff?cvsroot=lvm2&r1=1.86&r2=1.87

--- LVM2/WHATS_NEW	2008/01/26 00:13:44	1.777
+++ LVM2/WHATS_NEW	2008/01/26 00:25:04	1.778
@@ -1,5 +1,6 @@
 Version 2.02.32 -
 ===================================
+  Refactor mirror log attachment code.
   Fix internal metadata corruption in lvchange --resync. (2.02.30)
   Fix new parameter validation in vgsplit and test mode. (2.02.30)
   Remove redundant cnxman-socket.h file from clvmd directory.
--- LVM2/lib/metadata/lv_manip.c	2008/01/18 22:00:46	1.146
+++ LVM2/lib/metadata/lv_manip.c	2008/01/26 00:25:04	1.147
@@ -208,11 +208,8 @@
 	seg->log_lv = log_lv;
 	list_init(&seg->tags);
 
-	if (log_lv) {
-		log_lv->status |= MIRROR_LOG;
-		if (!add_seg_to_segs_using_this_lv(log_lv, seg))
-			return_NULL;
-	}
+	if (log_lv && !attach_mirror_log(seg, log_lv))
+		return_NULL;
 
 	return seg;
 }
--- LVM2/lib/metadata/metadata-exported.h	2008/01/18 22:02:37	1.41
+++ LVM2/lib/metadata/metadata-exported.h	2008/01/26 00:25:04	1.42
@@ -495,6 +495,8 @@
 		      uint32_t mirrors, uint32_t stripes, uint32_t region_size,
 		      struct list *allocatable_pvs, alloc_policy_t alloc,
 		      uint32_t log_count);
+struct logical_volume *detach_mirror_log(struct lv_segment *seg);
+int attach_mirror_log(struct lv_segment *seg, struct logical_volume *lv);
 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,
--- LVM2/lib/metadata/mirror.c	2008/01/18 22:02:37	1.65
+++ LVM2/lib/metadata/mirror.c	2008/01/26 00:25:04	1.66
@@ -355,17 +355,20 @@
 }
 
 /* Unlink the relationship between the segment and its log_lv */
-static void _remove_mirror_log(struct lv_segment *mirrored_seg)
+struct logical_volume *detach_mirror_log(struct lv_segment *mirrored_seg)
 {
 	struct logical_volume *log_lv;
 
 	if (!mirrored_seg->log_lv)
-		return;
+		return NULL;
 
 	log_lv = mirrored_seg->log_lv;
 	mirrored_seg->log_lv = NULL;
+	log_lv->status |= VISIBLE_LV;
 	log_lv->status &= ~MIRROR_LOG;
 	remove_seg_from_segs_using_this_lv(log_lv, mirrored_seg);
+
+	return log_lv;
 }
 
 /* Check if mirror image LV is removable with regard to given removable_pvs */
@@ -438,7 +441,7 @@
 	uint32_t m;
 	uint32_t s;
 	struct logical_volume *sub_lv;
-	struct logical_volume *log_lv = NULL;
+	struct logical_volume *detached_log_lv = NULL;
 	struct logical_volume *lv1 = NULL;
 	struct lv_segment *mirrored_seg = first_seg(lv);
 	struct lv_segment_area area;
@@ -495,22 +498,17 @@
 	}
 	mirrored_seg->area_count = new_area_count;
 
-	/* Save log_lv as mirrored_seg may not be available after
-	 * remove_layer_from_lv(), */
-	log_lv = mirrored_seg->log_lv;
-
 	/* If no more mirrors, remove mirror layer */
 	/* As an exceptional case, if the lv is temporary layer,
 	 * leave the LV as mirrored and let the lvconvert completion
 	 * to remove the layer. */
 	if (new_area_count == 1 && !is_temporary_mirror_layer(lv)) {
 		lv1 = seg_lv(mirrored_seg, 0);
-		_remove_mirror_log(mirrored_seg);
+		detached_log_lv = detach_mirror_log(mirrored_seg);
 		if (!remove_layer_from_lv(lv, lv1))
 			return_0;
 		lv->status &= ~MIRRORED;
 		lv->status &= ~MIRROR_NOTSYNCED;
-		remove_log = 1;
 		if (collapse && !_merge_mirror_images(lv, &tmp_orphan_lvs)) {
 			log_error("Failed to add mirror images");
 			return 0;
@@ -520,17 +518,13 @@
 
 		/* All mirror images are gone.
 		 * It can happen for vgreduce --removemissing. */
-		_remove_mirror_log(mirrored_seg);
+		detached_log_lv = detach_mirror_log(mirrored_seg);
 		lv->status &= ~MIRRORED;
 		lv->status &= ~MIRROR_NOTSYNCED;
 		if (!replace_lv_with_error_segment(lv))
 			return_0;
-		remove_log = 1;
 	} else if (remove_log)
-		_remove_mirror_log(mirrored_seg);
-
-	if (remove_log && log_lv)
-		log_lv->status |= VISIBLE_LV;
+		detached_log_lv = detach_mirror_log(mirrored_seg);
 
 	/*
 	 * To successfully remove these unwanted LVs we need to
@@ -565,19 +559,20 @@
 	if (!collapse) {
 		list_iterate_items(lvl, &tmp_orphan_lvs)
 			if (!_delete_lv(lv, lvl->lv))
-				return 0;
+				return_0;
 	}
 
 	if (lv1 && !_delete_lv(lv, lv1))
-		return 0;
+		return_0;
 
-	if (remove_log && log_lv && !_delete_lv(lv, log_lv))
-		return 0;
+	if (detached_log_lv && !_delete_lv(lv, detached_log_lv))
+		return_0;
 
 	/* Mirror with only 1 area is 'in sync'. */
-	if (!remove_log && log_lv &&
-	    new_area_count == 1 && is_temporary_mirror_layer(lv)) {
-		if (!_init_mirror_log(lv->vg->cmd, log_lv, 1, &lv->tags, 0)) {
+	if (new_area_count == 1 && is_temporary_mirror_layer(lv)) {
+		if (first_seg(lv)->log_lv &&
+		    !_init_mirror_log(lv->vg->cmd, first_seg(lv)->log_lv,
+				      1, &lv->tags, 0)) {
 			/* As a result, unnecessary sync may run after
 			 * collapsing. But safe.*/
 			log_error("Failed to initialize log device");
@@ -1245,12 +1240,12 @@
 	return log_lv;
 }
 
-static void _add_mirror_log(struct logical_volume *lv,
-			    struct logical_volume *log_lv)
+int attach_mirror_log(struct lv_segment *seg, struct logical_volume *log_lv)
 {
-	first_seg(lv)->log_lv = log_lv;
+	seg->log_lv = log_lv;
 	log_lv->status |= MIRROR_LOG;
-	add_seg_to_segs_using_this_lv(log_lv, first_seg(lv));
+	log_lv->status &= ~VISIBLE_LV;
+	return add_seg_to_segs_using_this_lv(log_lv, seg);
 }
 
 int add_mirror_log(struct cmd_context *cmd,
@@ -1310,7 +1305,8 @@
 					  region_size, alloc, in_sync)))
 		return_0;
 
-	_add_mirror_log(lv, log_lv);
+	if (!attach_mirror_log(first_seg(lv), log_lv))
+		return_0;
 
 	alloc_destroy(ah);
 	return 1;
@@ -1392,8 +1388,8 @@
 		goto out_remove_imgs;
 	}
 
-	if (log_count)
-		_add_mirror_log(lv, log_lv);
+	if (log_count && !attach_mirror_log(first_seg(lv), log_lv))
+		stack;
 
 	alloc_destroy(ah);
 	return 1;
--- LVM2/tools/lvchange.c	2008/01/26 00:13:45	1.86
+++ LVM2/tools/lvchange.c	2008/01/26 00:25:04	1.87
@@ -271,21 +271,14 @@
 
 	if (log_lv) {
 		/* Separate mirror log so we can clear it */
-		first_seg(lv)->log_lv = NULL;
-		log_lv->status &= ~MIRROR_LOG;
-		log_lv->status |= VISIBLE_LV;
-		remove_seg_from_segs_using_this_lv(log_lv, first_seg(lv));
+		detach_mirror_log(first_seg(lv));
 
 		if (!vg_write(lv->vg)) {
 			log_error("Failed to write intermediate VG metadata.");
-			if (active) {
-				first_seg(lv)->log_lv = log_lv;
-				log_lv->status |= MIRROR_LOG;
-				log_lv->status &= ~VISIBLE_LV;
-				add_seg_to_segs_using_this_lv(log_lv, first_seg(lv));
-				if (!activate_lv(cmd, lv))
-					stack;
-			}
+			if (!attach_mirror_log(first_seg(lv), log_lv))
+				stack;
+			if (active && !activate_lv(cmd, lv))
+				stack;
 			return 0;
 		}
 
@@ -293,14 +286,10 @@
 
 		if (!vg_commit(lv->vg)) {
 			log_error("Failed to commit intermediate VG metadata.");
-			if (active) {
-				first_seg(lv)->log_lv = log_lv;
-				log_lv->status |= MIRROR_LOG;
-				log_lv->status &= ~VISIBLE_LV;
-				add_seg_to_segs_using_this_lv(log_lv, first_seg(lv));
-				if (!activate_lv(cmd, lv))
-					stack;
-			}
+			if (!attach_mirror_log(first_seg(lv), log_lv))
+				stack;
+			if (active && !activate_lv(cmd, lv))
+				stack;
 			return 0;
 		}
 
@@ -326,10 +315,8 @@
 		}
 
 		/* Put mirror log back in place */
-		first_seg(lv)->log_lv = log_lv;
-		log_lv->status |= MIRROR_LOG;
-		log_lv->status &= ~VISIBLE_LV;
-		add_seg_to_segs_using_this_lv(log_lv, first_seg(lv));
+		if (!attach_mirror_log(first_seg(lv), log_lv))
+			stack;
 	}
 
 	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2008-01-18 22:01 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2008-01-18 22:01 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2008-01-18 22:00:51

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

Log message:
	add lvconvert messages

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.768&r2=1.769
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.145&r2=1.146
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.63&r2=1.64

--- LVM2/WHATS_NEW	2008/01/18 21:56:39	1.768
+++ LVM2/WHATS_NEW	2008/01/18 22:00:46	1.769
@@ -1,5 +1,6 @@
 Version 2.02.31 -
 ===================================
+  Add very_verbose lvconvert messages.
   Avoid error message when using default setting of lvcreate -M1. (2.02.30)
 
 Version 2.02.30 - 17th January 2008
--- LVM2/lib/metadata/lv_manip.c	2008/01/17 17:17:09	1.145
+++ LVM2/lib/metadata/lv_manip.c	2008/01/18 22:00:46	1.146
@@ -43,6 +43,9 @@
 		}
 	}
 
+	log_very_verbose("Adding %s:%" PRIu32 " as an user of %s",
+			 seg->lv->name, seg->le, lv->name);
+
 	if (!(sl = dm_pool_zalloc(lv->vg->cmd->mem, sizeof(*sl)))) {
 		log_error("Failed to allocate segment list");
 		return 0;
@@ -65,8 +68,12 @@
 			continue;
 		if (sl->count > 1)
 			sl->count--;
-		else
+		else {
+			log_very_verbose("%s:%" PRIu32 " is no longer a user "
+					 "of %s", seg->lv->name, seg->le,
+					 lv->name);
 			list_del(&sl->list);
+		}
 		return 1;
 	}
 
@@ -255,6 +262,11 @@
 	}
 
 	if (area_reduction == seg->area_len) {
+		log_very_verbose("Remove %s:%" PRIu32 "[%" PRIu32 "] from "
+				 "the top of LV %s:%" PRIu32,
+				 seg->lv->name, seg->le, s,
+				 seg_lv(seg, s)->name, seg_le(seg, s));
+
 		remove_seg_from_segs_using_this_lv(seg_lv(seg, s), seg);
 		seg_lv(seg, s) = NULL;
 		seg_le(seg, s) = 0;
@@ -332,6 +344,9 @@
 			   struct logical_volume *lv, uint32_t le,
 			   uint32_t flags)
 {
+	log_very_verbose("Stack %s:%" PRIu32 "[%" PRIu32 "] on LV %s:%" PRIu32,
+			 seg->lv->name, seg->le, area_num, lv->name, le);
+
 	seg->areas[area_num].type = AREA_LV;
 	seg_lv(seg, area_num) = lv;
 	seg_le(seg, area_num) = le;
@@ -2177,6 +2192,9 @@
 	int lv_changed = 0;
 	struct lv_list *lvl;
 
+	log_very_verbose("Removing layer %s for segments of %s",
+			 layer_lv->name, lv->name);
+
 	/* Find all segments that point at the temporary mirror */
 	list_iterate_items(seg, &lv->segments) {
 		for (s = 0; s < seg->area_count; s++) {
@@ -2313,6 +2331,8 @@
 	struct lv_segment *parent_seg;
 	struct segment_type *segtype;
 
+	log_very_verbose("Removing layer %s for %s", layer_lv->name, lv->name);
+
 	if (!(parent_seg = get_only_segment_using_this_lv(layer_lv))) {
 		log_error("Failed to find layer %s in %s",
 		layer_lv->name, lv->name);
@@ -2569,6 +2589,10 @@
 	int lv_used = 0;
 	uint32_t s;
 
+	log_very_verbose("Inserting layer %s for segments of %s on %s",
+			 layer_lv->name, lv_where->name,
+			 pvl ? pv_dev_name(pvl->pv) : "any");
+
 	if (!_align_segment_boundary_to_pe_range(lv_where, pvl))
 		return_0;
 
--- LVM2/lib/metadata/mirror.c	2008/01/17 17:17:09	1.63
+++ LVM2/lib/metadata/mirror.c	2008/01/18 22:00:46	1.64
@@ -516,6 +516,8 @@
 			return 0;
 		}
 	} else if (new_area_count == 0) {
+		log_very_verbose("All mimages of %s are gone", lv->name);
+
 		/* All mirror images are gone.
 		 * It can happen for vgreduce --removemissing. */
 		_remove_mirror_log(mirrored_seg);
@@ -586,6 +588,9 @@
 	if (removed)
 		*removed = old_area_count - new_area_count;
 
+	log_very_verbose("%" PRIu32 " image(s) removed from %s",
+			 old_area_count - num_removed, lv->name);
+
 	return 1;
 }
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2007-12-20 18:55 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2007-12-20 18:55 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

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

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h metadata.c 
	                 metadata.h mirror.c 
	tools          : lvconvert.c lvresize.c toollib.c 

Log message:
	stacked mirror support (incomplete)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.747&r2=1.748
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.137&r2=1.138
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.26&r2=1.27
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.c.diff?cvsroot=lvm2&r1=1.144&r2=1.145
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.175&r2=1.176
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/mirror.c.diff?cvsroot=lvm2&r1=1.46&r2=1.47
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.48&r2=1.49
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvresize.c.diff?cvsroot=lvm2&r1=1.89&r2=1.90
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/toollib.c.diff?cvsroot=lvm2&r1=1.119&r2=1.120

--- LVM2/WHATS_NEW	2007/12/20 15:42:55	1.747
+++ LVM2/WHATS_NEW	2007/12/20 18:55:46	1.748
@@ -1,5 +1,6 @@
 Version 2.02.30 -
 ===================================
+  Add support for stacked mirrors.
   Major restructuring of pvmove and lvconvert layer manipulation code.
   Replace tools/fsadm with scripts/fsadm.sh.
   Append fields to report/pvsegs_cols_verbose.
--- LVM2/lib/metadata/lv_manip.c	2007/12/20 15:42:55	1.137
+++ LVM2/lib/metadata/lv_manip.c	2007/12/20 18:55:46	1.138
@@ -1407,6 +1407,7 @@
 	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;
+		sub_lvs[m - old_area_count]->status &= ~VISIBLE_LV;
 	}
 
 	return 1;
@@ -1451,6 +1452,39 @@
 	return 1;
 }
 
+static int _lv_extend_mirror(struct alloc_handle *ah,
+			     struct logical_volume *lv,
+			     uint32_t extents, uint32_t first_area)
+{
+	struct lv_segment *seg;
+	uint32_t m, s;
+
+	seg = first_seg(lv);
+	for (m = first_area, s = 0; s < seg->area_count; s++) {
+		if (is_temporary_mirror_layer(seg_lv(seg, s))) {
+			if (!_lv_extend_mirror(ah, seg_lv(seg, s), extents, m))
+				return_0;
+			m += lv_mirror_count(seg_lv(seg, s));
+			continue;
+		}
+
+		if (!lv_add_segment(ah, m++, 1, seg_lv(seg, s),
+				    get_segtype_from_string(lv->vg->cmd,
+							    "striped"),
+				    0, 0, 0, NULL)) {
+			log_error("Aborting. Failed to extend %s.",
+				  seg_lv(seg, s)->name);
+			return 0;
+		}
+	}
+	seg->area_len += extents;
+	seg->len += extents;
+	lv->le_count += extents;
+	lv->size += (uint64_t) extents *lv->vg->extent_size;
+
+	return 1;
+}
+
 /*
  * Entry point for single-step LV allocation + extension.
  */
@@ -1464,9 +1498,7 @@
 	      alloc_policy_t alloc)
 {
 	int r = 1;
-	uint32_t m;
 	struct alloc_handle *ah;
-	struct lv_segment *seg;
 
 	if (segtype_is_virtual(segtype))
 		return lv_add_virtual_segment(lv, status, extents, segtype);
@@ -1482,21 +1514,8 @@
 			goto out;
 		}
 	} else {
-		seg = first_seg(lv);
-		for (m = 0; m < mirrors; m++) {
-			if (!lv_add_segment(ah, m, 1, seg_lv(seg, m),
-					    get_segtype_from_string(lv->vg->cmd,
-								    "striped"),
-					    0, 0, 0, NULL)) {
-				log_error("Aborting. Failed to extend %s.",
-					  seg_lv(seg, m)->name);
-				return 0;
-			}
-		}
-		seg->area_len += extents;
-		seg->len += extents;
-		lv->le_count += extents;
-		lv->size += (uint64_t) extents *lv->vg->extent_size;
+		if (!_lv_extend_mirror(ah, lv, extents, 0))
+			return_0;
 	}
 
       out:
@@ -1599,10 +1618,14 @@
 	list_iterate_items(seg, &lv->segments) {
 		if (seg->log_lv && !func(cmd, seg->log_lv, data))
 			return 0;
-		for (s = 0; s < seg->area_count; s++)
-			if (seg_type(seg, s) == AREA_LV &&
-			    !func(cmd, seg_lv(seg, s), data))
+		for (s = 0; s < seg->area_count; s++) {
+			if (seg_type(seg, s) != AREA_LV)
+				continue;
+			if (!func(cmd, seg_lv(seg, s), data))
 				return 0;
+			if (!_for_each_sub_lv(cmd, seg_lv(seg, s), func, data))
+				return 0;
+		}
 	}
 
 	return 1;
@@ -2180,23 +2203,62 @@
 	lv_from->size = 0;
 }
 
+/*
+ * Find a parent LV for the layer_lv in the lv
+ */
+struct logical_volume *find_parent_for_layer(struct logical_volume *lv,
+                                            struct logical_volume *layer_lv)
+{
+	struct logical_volume *parent;
+	struct lv_segment *seg;
+	uint32_t s;
+
+	list_iterate_items(seg, &lv->segments) {
+		for (s = 0; s < seg->area_count; s++) {
+			if (seg_type(seg, s) != AREA_LV)
+				continue;
+			if (seg_lv(seg, s) == layer_lv)
+				return lv;
+			parent = find_parent_for_layer(seg_lv(seg, s),
+						       layer_lv);
+			if (parent)
+				return parent;
+		}
+	}
+	return NULL;
+}
+
 /* 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)
+int remove_layer_from_lv(struct logical_volume *lv,
+			 struct logical_volume *layer_lv)
 {
-	struct logical_volume *orig_lv;
+	struct logical_volume *parent;
+	struct segment_type *segtype;
+
+	parent = find_parent_for_layer(lv, layer_lv);
+	if (!parent) {
+		log_error("Failed to find layer %s in %s",
+		layer_lv->name, lv->name);
+		return 0;
+	}
 
 	/*
 	 * 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;
+	if (list_size(&parent->segments) != 1 ||
+	    first_seg(parent)->area_count != 1 ||
+	    seg_type(first_seg(parent), 0) != AREA_LV ||
+	    layer_lv != seg_lv(first_seg(parent), 0) ||
+	    parent->le_count != layer_lv->le_count)
+		return_0;
 
-	orig_lv = seg_lv(first_seg(lv), 0);
-	_move_lv_segments(lv, orig_lv, 0, 0);
+	_move_lv_segments(parent, layer_lv, 0, 0);
+
+	/* Replace the empty layer with error segment */
+	segtype = get_segtype_from_string(lv->vg->cmd, "error");
+	if (!lv_add_virtual_segment(layer_lv, 0, parent->le_count, segtype))
+		return_0;
 
 	return 1;
 }
--- LVM2/lib/metadata/metadata-exported.h	2007/12/20 15:42:55	1.26
+++ LVM2/lib/metadata/metadata-exported.h	2007/12/20 18:55:46	1.27
@@ -398,7 +398,10 @@
 				   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 *find_parent_for_layer(struct logical_volume *lv,
+					     struct logical_volume *layer_lv);
+int remove_layer_from_lv(struct logical_volume *lv,
+			 struct logical_volume *layer_lv);
 struct logical_volume *insert_layer_for_lv(struct cmd_context *cmd,
 					   struct logical_volume *lv_where,
 					   uint32_t status,
@@ -417,7 +420,7 @@
 					const char *pv_name);
 
 /* Find LV segment containing given LE */
-struct lv_segment *first_seg(struct logical_volume *lv);
+struct lv_segment *first_seg(const struct logical_volume *lv);
 
 
 /*
@@ -458,8 +461,8 @@
 #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;
+int is_temporary_mirror_layer(const struct logical_volume *lv);
+uint32_t lv_mirror_count(const struct logical_volume *lv);
 uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
                                     uint32_t region_size);
 int remove_mirrors_from_segments(struct logical_volume *lv,
@@ -468,7 +471,7 @@
 			    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,
+int remove_mirror_images(struct logical_volume *lv, 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,
@@ -482,6 +485,7 @@
 
 int reconfigure_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
 			      struct list *removable_pvs, unsigned remove_log);
+int collapse_mirrored_lv(struct logical_volume *lv);
 
 struct logical_volume *find_pvmove_lv(struct volume_group *vg,
 				      struct device *dev, uint32_t lv_type);
--- LVM2/lib/metadata/metadata.c	2007/11/15 02:20:03	1.144
+++ LVM2/lib/metadata/metadata.c	2007/12/20 18:55:46	1.145
@@ -937,7 +937,7 @@
 }
 
 /* Find segment at a given logical extent in an LV */
-struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
+struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le)
 {
 	struct lv_segment *seg;
 
@@ -948,7 +948,7 @@
 	return NULL;
 }
 
-struct lv_segment *first_seg(struct logical_volume *lv)
+struct lv_segment *first_seg(const struct logical_volume *lv)
 {
 	struct lv_segment *seg = NULL;
 
@@ -959,7 +959,7 @@
 }
 
 /* Find segment at a given physical extent in a PV */
-struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe)
+struct pv_segment *find_peg_by_pe(const struct physical_volume *pv, uint32_t pe)
 {
 	struct pv_segment *peg;
 
--- LVM2/lib/metadata/metadata.h	2007/12/20 15:42:55	1.175
+++ LVM2/lib/metadata/metadata.h	2007/12/20 18:55:46	1.176
@@ -264,10 +264,10 @@
 struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
 
 /* Find LV segment containing given LE */
-struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
+struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le);
 
 /* Find PV segment containing given LE */
-struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe);
+struct pv_segment *find_peg_by_pe(const struct physical_volume *pv, uint32_t pe);
 
 /*
  * Remove a dev_dir if present.
--- LVM2/lib/metadata/mirror.c	2007/12/20 15:42:55	1.46
+++ LVM2/lib/metadata/mirror.c	2007/12/20 18:55:46	1.47
@@ -33,11 +33,40 @@
 #define MIRROR_ALLOCATE_ANYWHERE 2
 
 /*
+ * Returns true if the lv is temporary mirror layer for resync
+ */
+int is_temporary_mirror_layer(const struct logical_volume *lv)
+{
+	if (lv->status & MIRROR_IMAGE
+	    && lv->status & MIRRORED
+	    && !(lv->status & LOCKED))
+		return 1;
+
+	return 0;
+}
+
+/*
  * Returns the number of mirrors of the LV
  */
-uint32_t lv_mirror_count(struct logical_volume *lv)
+uint32_t lv_mirror_count(const struct logical_volume *lv)
 {
-	return (lv->status & MIRRORED) ? first_seg(lv)->area_count : 1;
+	struct lv_segment *seg;
+	uint32_t s, mirrors;
+
+	if (!(lv->status & MIRRORED))
+		return 1;
+
+	seg = first_seg(lv);
+	mirrors = seg->area_count;
+
+	for (s = 0; s < seg->area_count; s++) {
+		if (seg_type(seg, s) != AREA_LV)
+			continue;
+		if (is_temporary_mirror_layer(seg_lv(seg, s)))
+			mirrors += lv_mirror_count(seg_lv(seg, s)) - 1;
+	}
+
+	return mirrors;
 }
 
 struct lv_segment *find_mirror_seg(struct lv_segment *seg)
@@ -68,21 +97,21 @@
 /*
  * Delete independent/orphan LV, it must acquire lock.
  */
-static int _delete_lv(struct lv_segment *mirrored_seg, struct logical_volume *lv)
+static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *lv)
 {
-	struct cmd_context *cmd = mirrored_seg->lv->vg->cmd;
+	struct cmd_context *cmd = mirror_lv->vg->cmd;
 	struct str_list *sl;
 
 	/* Inherit tags - maybe needed for activation */
-	if (!str_list_match_list(&mirrored_seg->lv->tags, &lv->tags)) {
-		list_iterate_items(sl, &mirrored_seg->lv->tags)
+	if (!str_list_match_list(&mirror_lv->tags, &lv->tags)) {
+		list_iterate_items(sl, &mirror_lv->tags)
 			if (!str_list_add(cmd->mem, &lv->tags, sl->str)) {
 				log_error("Aborting. Unable to tag.");
 				return 0;
 			}
 
-		if (!vg_write(mirrored_seg->lv->vg) ||
-		    !vg_commit(mirrored_seg->lv->vg)) {
+		if (!vg_write(mirror_lv->vg) ||
+		    !vg_commit(mirror_lv->vg)) {
 			log_error("Intermediate VG commit for orphan volume failed.");
 			return 0;
 		}
@@ -101,29 +130,31 @@
 }
 
 /*
- * Reduce mirrored_seg to num_mirrors images.
+ * Remove num_removed images from mirrored_seg
  */
-int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
-			 struct list *removable_pvs, unsigned remove_log)
+static int _remove_mirror_images(struct logical_volume *lv,
+				 uint32_t num_removed,
+				 struct list *removable_pvs,
+				 unsigned remove_log, struct list *orphan_lvs)
 {
 	uint32_t m;
-	uint32_t extents;
 	uint32_t s, s1;
 	struct logical_volume *sub_lv;
 	struct logical_volume *log_lv = NULL;
 	struct logical_volume *lv1 = NULL;
 	struct physical_volume *pv;
-	struct lv_segment *seg;
+	struct lv_segment *seg, *mirrored_seg = first_seg(lv);
 	struct lv_segment_area area;
 	int all_pvs_removable, pv_found;
 	struct pv_list *pvl;
 	uint32_t old_area_count = mirrored_seg->area_count;
 	uint32_t new_area_count = mirrored_seg->area_count;
-	struct segment_type *segtype;
+	struct lv_list *lvl;
+	struct list tmp_orphan_lvs;
 
 	log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
 			 PRIu32 " image(s)%s.",
-			 old_area_count, num_mirrors,
+			 old_area_count, old_area_count - num_removed,
 			 remove_log ? " and no log volume" : "");
 
 	/* Move removable_pvs to end of array */
@@ -162,39 +193,46 @@
 				mirrored_seg->areas[s] = area;
 			}
 			/* Found enough matches? */
-			if (new_area_count == num_mirrors)
+			if (old_area_count - new_area_count == num_removed)
 				break;
 		}
-		if (new_area_count == mirrored_seg->area_count) {
+		if (old_area_count == new_area_count) {
 			log_error("No mirror images found using specified PVs.");
 			return 0;
 		}
-	}
+	} else
+		new_area_count = old_area_count - num_removed;
 
-	for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
+	/* Remove mimage LVs from the segment */
+	list_init(&tmp_orphan_lvs);
+	for (m = new_area_count; m < mirrored_seg->area_count; m++) {
 		seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE;
 		seg_lv(mirrored_seg, m)->status |= VISIBLE_LV;
+		if (!(lvl = dm_pool_alloc(lv->vg->cmd->mem, sizeof(*lvl)))) {
+			log_error("lv_list alloc failed");
+			return 0;
+		}
+		lvl->lv = seg_lv(mirrored_seg, m);
+		list_add(&tmp_orphan_lvs, &lvl->list);
 	}
+	mirrored_seg->area_count = new_area_count;
 
-	mirrored_seg->area_count = num_mirrors;
+	/* Save log_lv as mirrored_seg may not be available after
+	 * remove_layer_from_lv(), */
+	log_lv = mirrored_seg->log_lv;
 
 	/* If no more mirrors, remove mirror layer */
-	if (num_mirrors == 1) {
+	if (new_area_count == 1) {
 		lv1 = seg_lv(mirrored_seg, 0);
-		extents = lv1->le_count;
-		remove_layer_from_lv(mirrored_seg->lv);
-		mirrored_seg->lv->status &= ~MIRRORED;
-		mirrored_seg->lv->status &= ~MIRROR_NOTSYNCED;
-		remove_log = 1;
-		/* Replace mirror with error segment */
-		segtype = get_segtype_from_string(mirrored_seg->lv->vg->cmd, "error");
-		if (!lv_add_virtual_segment(lv1, 0, extents, segtype))
+		mirrored_seg->log_lv = NULL;
+		if (!remove_layer_from_lv(lv, lv1))
 			return_0;
+		lv->status &= ~MIRRORED;
+		lv->status &= ~MIRROR_NOTSYNCED;
+		remove_log = 1;
 	}
 
-	if (remove_log && mirrored_seg->log_lv) {
-		log_lv = mirrored_seg->log_lv;
-		mirrored_seg->log_lv = NULL;
+	if (remove_log && log_lv) {
 		log_lv->status &= ~MIRROR_LOG;
 		log_lv->status |= VISIBLE_LV;
 	}
@@ -228,16 +266,148 @@
 		return 0;
 	}
 
-	/* Delete the 'orphan' LVs */
-	for (m = num_mirrors; m < old_area_count; m++)
-		if (!_delete_lv(mirrored_seg, seg_lv(mirrored_seg, m)))
-			return 0;
+	/* Save or delete the 'orphan' LVs */
+	if (orphan_lvs) {
+		*orphan_lvs = tmp_orphan_lvs;
+		orphan_lvs->n->p = orphan_lvs;
+		orphan_lvs->p->n = orphan_lvs;
+	} else {
+		list_iterate_items(lvl, &tmp_orphan_lvs)
+			if (!_delete_lv(lv, lvl->lv))
+				return 0;
+	}
 
-	if (lv1 && !_delete_lv(mirrored_seg, lv1))
+	if (lv1 && !_delete_lv(lv, lv1))
 		return 0;
 
-	if (log_lv && !_delete_lv(mirrored_seg, log_lv))
+	if (remove_log && log_lv && !_delete_lv(lv, log_lv))
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Remove the number of mirror images from the LV
+ */
+int remove_mirror_images(struct logical_volume *lv, uint32_t num_mirrors,
+			 struct list *removable_pvs, unsigned remove_log)
+{
+	uint32_t num_removed, removed_once;
+	uint32_t existing_mirrors = lv_mirror_count(lv);
+
+	num_removed = existing_mirrors - num_mirrors;
+
+	while (num_removed) {
+		if (num_removed < first_seg(lv)->area_count)
+			removed_once = num_removed;
+		else
+			removed_once = first_seg(lv)->area_count - 1;
+
+		if (!_remove_mirror_images(lv, removed_once,
+				           removable_pvs, remove_log, NULL))
+			return_0;
+
+		num_removed -= removed_once;
+	}
+
+	return 1;
+}
+
+static int _mirrored_lv_in_sync(struct logical_volume *lv)
+{
+	float sync_percent;
+
+	if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &sync_percent, NULL)) {
+		log_error("Unable to determine mirror sync status of %s/%s.",
+			  lv->vg->name, lv->name);
 		return 0;
+	}
+
+	if (sync_percent >= 100.0)
+		return 1;
+
+	return 0;
+}
+
+static int _merge_mirror_images(struct logical_volume *lv,
+				const struct list *mimages)
+{
+	int addition = list_size(mimages);
+	struct logical_volume **img_lvs;
+	struct lv_list *lvl;
+	int i = 0;
+
+	if (!addition)
+		return 1;
+
+	if (!(img_lvs = alloca(sizeof(*img_lvs) * addition)))
+		return_0;
+
+	list_iterate_items(lvl, mimages)
+		img_lvs[i++] = lvl->lv;
+
+	return lv_add_mirror_lvs(lv, img_lvs, addition,
+				 MIRROR_IMAGE, first_seg(lv)->region_size);
+}
+
+/*
+ * Return a temporary LV for resyncing added mirror image.
+ * Add other mirror legs to lvs list.
+ */
+static struct logical_volume *_find_tmp_mirror(struct logical_volume *lv)
+{
+	struct lv_segment *seg;
+
+	if (!(lv->status & MIRRORED))
+		return NULL;
+
+	seg = first_seg(lv);
+
+	/* Temporary mirror is always area_num == 0 */
+	if (seg_type(seg, 0) == AREA_LV &&
+	    is_temporary_mirror_layer(seg_lv(seg, 0)))
+		return seg_lv(seg, 0);
+
+	return NULL;
+}
+
+/*
+ * Collapsing temporary mirror layers.
+ *
+ * When mirrors are added to already-mirrored LV, a temporary mirror layer
+ * is inserted at the top of the stack to reduce resync work.
+ * The function will remove the intermediate layer and collapse the stack
+ * as far as mirrors are in-sync.
+ *
+ * The function is destructive: to remove intermediate mirror layers,
+ * VG metadata commits and suspend/resume are necessary.
+ */
+int collapse_mirrored_lv(struct logical_volume *lv)
+{
+	struct logical_volume *tmp_lv, *parent_lv;
+	struct list lvlist;
+
+	while ((tmp_lv = _find_tmp_mirror(lv))) {
+		parent_lv = find_parent_for_layer(lv, tmp_lv);
+		if (!_mirrored_lv_in_sync(parent_lv)) {
+			log_verbose("Not collapsing %s: out-of-sync",
+				    parent_lv->name);
+			return 1;
+		}
+
+		list_init(&lvlist);
+		if (!_remove_mirror_images(parent_lv,
+					   first_seg(parent_lv)->area_count - 1,
+					   NULL, 1, &lvlist)) {
+			log_error("Failed to release mirror images");
+			return 0;
+		}
+
+		if (!_merge_mirror_images(parent_lv, &lvlist)) {
+			log_error("Failed to add mirror images");
+			return 0;
+		}
+	}
 
 	return 1;
 }
@@ -338,19 +508,13 @@
 			      struct list *removable_pvs, unsigned remove_log)
 {
 	int r;
-	int in_sync = 0;
+	int in_sync;
 	int log_policy, dev_policy;
 	uint32_t old_num_mirrors = mirrored_seg->area_count;
 	int had_log = (mirrored_seg->log_lv) ? 1 : 0;
-	float sync_percent = 0;
 
 	/* was the mirror in-sync before problems? */
-	if (!lv_mirror_percent(mirrored_seg->lv->vg->cmd,
-			       mirrored_seg->lv, 0, &sync_percent, NULL))
-		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)
-		in_sync = 1;
+	in_sync = _mirrored_lv_in_sync(mirrored_seg->lv);
 
 	/*
 	 * While we are only removing devices, we can have sync set.
@@ -359,7 +523,7 @@
 	 */
 	init_mirror_in_sync(in_sync);
 
-	r = remove_mirror_images(mirrored_seg, num_mirrors,
+	r = remove_mirror_images(mirrored_seg->lv, num_mirrors,
 				 removable_pvs, remove_log);
 	if (!r)
 		/* Unable to remove bad devices */
@@ -721,7 +885,7 @@
 		init_mirror_in_sync(0);
 	}
 
-	if (!remove_mirror_images(first_seg(lv), lv_mirror_count(lv),
+	if (!remove_mirror_images(lv, lv_mirror_count(lv),
 				  removable_pvs, 1U))
 		return_0;
 
@@ -1195,17 +1359,17 @@
 		return 0;
 	}
 
-	if (seg->area_count <= mirrors) {
+	if (lv_mirror_count(lv) <= mirrors) {
 		log_error("Removing more than existing: %d <= %d",
 			  seg->area_count, mirrors);
 		return 0;
 	}
-	new_mirrors = seg->area_count - mirrors - 1;
+	new_mirrors = lv_mirror_count(lv) - 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,
+		return remove_mirror_images(lv, new_mirrors + 1,
 					    pvs, log_count ? 1U : 0);
 	}
 
--- LVM2/tools/lvconvert.c	2007/12/20 15:42:55	1.48
+++ LVM2/tools/lvconvert.c	2007/12/20 18:55:46	1.49
@@ -369,14 +369,20 @@
 			return 1;
 		}
 	} else if (lp->mirrors > existing_mirrors) {
-		/* FIXME Unless anywhere, remove PV of log_lv
-		 * from allocatable_pvs & allocate
-		 * (mirrors - existing_mirrors) new areas
-		 */
-		/* FIXME Create mirror hierarchy to sync */
-		log_error("Adding mirror images is not "
-			  "supported yet.");
-		return 0;
+		/* FIXME: can't have multiple mlogs. force corelog. */
+		corelog = 1;
+		if (!insert_layer_for_lv(cmd, lv, 0, "_resync%d")) {
+			log_error("Failed to insert resync layer");
+			return 0;
+		}
+		if (!lv_add_mirrors(cmd, lv, lp->mirrors - existing_mirrors, 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;
 	} else {
 		/* Reduce number of mirrors */
 		if (!lv_remove_mirrors(cmd, lv, existing_mirrors - lp->mirrors,
--- LVM2/tools/lvresize.c	2007/11/15 02:20:03	1.89
+++ LVM2/tools/lvresize.c	2007/12/20 18:55:46	1.90
@@ -435,7 +435,7 @@
 	if ((lp->extents > lv->le_count)) {
 		list_iterate_back_items(seg, &lv->segments) {
 			if (seg_is_mirrored(seg))
-				seg_mirrors = seg->area_count;
+				seg_mirrors = lv_mirror_count(seg->lv);
 			else
 				seg_mirrors = 0;
 			break;
@@ -469,7 +469,7 @@
 			}
 
 			if (seg_is_mirrored(seg))
-				seg_mirrors = seg->area_count;
+				seg_mirrors = lv_mirror_count(seg->lv);
 			else
 				seg_mirrors = 0;
 
--- LVM2/tools/toollib.c	2007/12/20 15:42:55	1.119
+++ LVM2/tools/toollib.c	2007/12/20 18:55:46	1.120
@@ -1222,6 +1222,12 @@
 		return 0;
 	}
 
+	if (strstr(name, "_resync")) {
+		log_error("Names including \"_resync\" are reserved. "
+			  "Please choose a different LV name.");
+		return 0;
+	}
+
 	return 1;
 }
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2007-08-28 16:14 wysochanski
  0 siblings, 0 replies; 36+ messages in thread
From: wysochanski @ 2007-08-28 16:14 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	wysochanski@sourceware.org	2007-08-28 16:14:49

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata.c 
	man            : vgremove.8 
	tools          : commands.h 

Log message:
	Modify lvremove to prompt for removal if LV active on other cluster nodes.
	Add '-f' to vgremove to force removal of VG even if LVs exist.
	Update vgremove man page for '-f'.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.697&r2=1.698
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.127&r2=1.128
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.c.diff?cvsroot=lvm2&r1=1.134&r2=1.135
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/man/vgremove.8.diff?cvsroot=lvm2&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/commands.h.diff?cvsroot=lvm2&r1=1.101&r2=1.102

--- LVM2/WHATS_NEW	2007/08/24 21:05:15	1.697
+++ LVM2/WHATS_NEW	2007/08/28 16:14:48	1.698
@@ -1,6 +1,8 @@
 Version 2.02.29 -
 ==================================
-
+  Modify lvremove to prompt for removal if LV active on other cluster nodes.
+  Add '-f' to vgremove to force removal of VG even if LVs exist.
+  
 Version 2.02.28 - 24th August 2007
 ==================================
   Fix clvmd logging so you can get lvm-level debugging out of it.
--- LVM2/lib/metadata/lv_manip.c	2007/08/22 14:38:17	1.127
+++ LVM2/lib/metadata/lv_manip.c	2007/08/28 16:14:48	1.128
@@ -1839,37 +1839,49 @@
 
 	/* FIXME Ensure not referred to by another existing LVs */
 
-	if (lv_info(cmd, lv, &info, 1)) {
-		if (info.open_count) {
-			log_error("Can't remove open logical volume \"%s\"",
-				  lv->name);
-			return 0;
-		}
-
-		if (info.exists && (force == PROMPT)) {
-			if (yes_no_prompt("Do you really want to remove active "
-					  "logical volume \"%s\"? [y/n]: ",
-					  lv->name) == 'n') {
-				log_print("Logical volume \"%s\" not removed",
-					  lv->name);
-				return 0;
-			}
-		}
+	/*
+	 * If we can't get information about the LV from the kernel, or
+	 * someone has the LV device open, fail.
+	 */
+	if (!lv_info(cmd, lv, &info, 1)) {
+		log_error("Unable to obtain status for logical volume \"%s\"",
+			  lv->name);
+		return 0;
 	}
-
-	if (!archive(vg))
+	if (info.open_count) {
+		log_error("Can't remove open logical volume \"%s\"",
+			  lv->name);
 		return 0;
+	}
 
-	/* If the VG is clustered then make sure no-one else is using the LV
-	   we are about to remove */
-	if (vg_status(vg) & CLUSTERED) {
-		if (!activate_lv_excl(cmd, lv)) {
-			log_error("Can't get exclusive access to volume \"%s\"",
+	/*
+	 * Check for confirmation prompts in the following cases:
+	 * 1) Clustered VG, and some remote nodes have the LV active
+	 * 2) Non-clustered VG, but LV active locally
+	 */
+	if ((vg_status(vg) & CLUSTERED) && !activate_lv_excl(cmd, lv) &&
+	    (force == PROMPT)) {
+		if (yes_no_prompt("Logical volume \"%s\" is active on other "
+				  "cluster nodes.  Really remove? [y/n]: ",
+				  lv->name) == 'n') {
+			log_print("Logical volume \"%s\" not removed",
 				  lv->name);
 			return 0;
 		}
+	} else if (info.exists && (force == PROMPT)) {
+		 if (yes_no_prompt("Do you really want to remove active "
+				   "logical volume \"%s\"? [y/n]: ",
+				   lv->name) == 'n') {
+			 log_print("Logical volume \"%s\" not removed",
+				  lv->name);
+			 return 0;
+		 }
 	}
 
+
+	if (!archive(vg))
+		return 0;
+
 	/* FIXME Snapshot commit out of sequence if it fails after here? */
 	if (!deactivate_lv(cmd, lv)) {
 		log_error("Unable to deactivate logical volume \"%s\"",
--- LVM2/lib/metadata/metadata.c	2007/08/22 14:38:17	1.134
+++ LVM2/lib/metadata/metadata.c	2007/08/28 16:14:48	1.135
@@ -249,6 +249,20 @@
 	return 1;
 }
 
+static int remove_lvs_in_vg(struct cmd_context *cmd,
+			    struct volume_group *vg,
+			    force_t force)
+{
+	struct lv_list *lvl;
+
+	list_iterate_items(lvl, &vg->lvs)
+		if (!lv_remove_single(cmd, lvl->lv, force))
+			return 0;
+
+	return 1;
+}
+
+/* FIXME: remove redundant vg_name */
 int vg_remove_single(struct cmd_context *cmd, const char *vg_name,
 		     struct volume_group *vg, int consistent,
 		     force_t force __attribute((unused)))
@@ -269,6 +283,19 @@
 		return 0;
 
 	if (vg->lv_count) {
+		if ((force == PROMPT) &&
+		    (yes_no_prompt("Do you really want to remove volume "
+				   "group \"%s\" containing %d "
+				   "logical volumes? [y/n]: ",
+				   vg_name, vg->lv_count) == 'n')) {
+			log_print("Volume group \"%s\" not removed", vg_name);
+			return 0;
+		}
+		if (!remove_lvs_in_vg(cmd, vg, force))
+			return 0;
+	}
+	
+	if (vg->lv_count) {
 		log_error("Volume group \"%s\" still contains %d "
 			  "logical volume(s)", vg_name, vg->lv_count);
 		return 0;
--- LVM2/man/vgremove.8	2004/11/18 19:45:52	1.4
+++ LVM2/man/vgremove.8	2007/08/28 16:14:49	1.5
@@ -3,17 +3,24 @@
 vgremove \- remove a volume group
 .SH SYNOPSIS
 .B vgremove
-[\-d/\-\-debug] [\-h/\-?/\-\-help] [\-t/\-\-test] [\-v/\-\-verbose]
+[\-d/\-\-debug] [\-f/\-\-force] [\-h/\-?/\-\-help]
+[\-t/\-\-test] [\-v/\-\-verbose]
 VolumeGroupName [VolumeGroupName...]
 .SH DESCRIPTION
 vgremove allows you to remove one or more volume groups.
-The volume group(s) must not have any logical volumes allocated:
-Remove them first with \fBlvremove\fP. If one or more physical
-volumes in the volume group are lost, consider 
-\fBvgreduce --removemissing\fP to make the volume group
+If one or more physical volumes in the volume group are lost,
+consider \fBvgreduce --removemissing\fP to make the volume group
 metadata consistent again.
+.sp
+If there are logical volumes that exist in the volume group,
+a prompt will be given to confirm removal.  You can override
+the prompt with \fB-f\fP.
 .SH OPTIONS
 See \fBlvm\fP for common options.
+.TP
+.BR \-f ", " \-\-force
+Force the removal of any logical volumes on the volume group
+without confirmation.
 .SH SEE ALSO
 .BR lvm (8), 
 .BR lvremove (8), 
--- LVM2/tools/commands.h	2007/08/21 19:46:36	1.101
+++ LVM2/tools/commands.h	2007/08/28 16:14:49	1.102
@@ -807,13 +807,14 @@
    "Remove volume group(s)",
    "vgremove\n"
    "\t[-d|--debug]\n"
+   "\t[-f|--force]\n"
    "\t[-h|--help]\n"
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n"
    "\tVolumeGroupName [VolumeGroupName...]\n",
 
-   test_ARG)
+   force_ARG, test_ARG)
 
 xx(vgrename,
    "Rename a volume group",


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2007-08-03 21:22 wysochanski
  0 siblings, 0 replies; 36+ messages in thread
From: wysochanski @ 2007-08-03 21:22 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	wysochanski@sourceware.org	2007-08-03 21:22:10

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata-exported.h 
	tools          : lvrename.c 

Log message:
	Factor out core of lvrename to lv_rename library function.
	Patch by Jun'ichi Nomura <j-nomura@ce.jp.nec.com>

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.676&r2=1.677
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.115&r2=1.116
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvrename.c.diff?cvsroot=lvm2&r1=1.44&r2=1.45

--- LVM2/WHATS_NEW	2007/08/01 21:01:06	1.676
+++ LVM2/WHATS_NEW	2007/08/03 21:22:09	1.677
@@ -1,5 +1,6 @@
 Version 2.02.28 -
 ================================
+  Factor out core of lvrename() to lv_rename lvm library function.
   Add --log argument to specify log type for mirrors.
   Don't try to monitor devices which we failed to create.
   Don't leak a file descriptor in fcntl_lock_file(), when fcntl fails.
--- LVM2/lib/metadata/lv_manip.c	2007/01/05 15:53:40	1.115
+++ LVM2/lib/metadata/lv_manip.c	2007/08/03 21:22:09	1.116
@@ -23,6 +23,7 @@
 #include "pv_alloc.h"
 #include "display.h"
 #include "segtype.h"
+#include "archiver.h"
 
 /*
  * PVs used by a segment of an LV
@@ -1459,6 +1460,66 @@
 	return r;
 }
 
+/*
+ * Core of LV renaming routine.
+ * VG must be locked by caller.
+ * Returns 0 on failure, 1 on success.
+ */
+int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
+	      char *newname)
+{
+	struct volume_group *vg = lv->vg;
+
+	if (find_lv_in_vg(vg, newname)) {
+		log_error("Logical volume \"%s\" already exists in "
+			  "volume group \"%s\"", newname, vg->name);
+		return 0;
+	}
+
+	if (lv->status & LOCKED) {
+		log_error("Cannot rename locked LV %s", lv->name);
+		return 0;
+	}
+
+	if ((lv->status & MIRRORED) ||
+	    (lv->status & MIRROR_LOG) ||
+	    (lv->status & MIRROR_IMAGE)) {
+		log_error("Mirrored LV, \"%s\" cannot be renamed: %s",
+			  lv->name, strerror(ENOSYS));
+		return 0;
+	}
+
+	if (!archive(vg))
+		return_0;
+
+	if (!(lv->name = dm_pool_strdup(cmd->mem, newname))) {
+		log_error("Failed to allocate space for new name");
+		return 0;
+	}
+
+	log_verbose("Writing out updated volume group");
+	if (!vg_write(vg))
+		return_0;
+
+	backup(vg);
+
+	if (!suspend_lv(cmd, lv)) {
+		stack;
+		vg_revert(vg);
+		return 0;
+	}
+
+	if (!vg_commit(vg)) {
+		stack;
+		resume_lv(cmd, lv);
+		return 0;
+	}
+
+	resume_lv(cmd, lv);
+
+	return 1;
+}
+
 char *generate_lv_name(struct volume_group *vg, const char *format,
 		       char *buffer, size_t len)
 {
--- LVM2/lib/metadata/metadata-exported.h	2007/07/23 21:03:42	1.3
+++ LVM2/lib/metadata/metadata-exported.h	2007/08/03 21:22:09	1.4
@@ -356,6 +356,9 @@
 /* lv must be part of lv->vg->lvs */
 int lv_remove(struct logical_volume *lv);
 
+int lv_rename(struct cmd_context *cmd, struct logical_volume *lv,
+	      char *newname);
+
 /* 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);
--- LVM2/tools/lvrename.c	2007/07/23 22:20:42	1.44
+++ LVM2/tools/lvrename.c	2007/08/03 21:22:10	1.45
@@ -16,6 +16,11 @@
 #include "tools.h"
 #include "lvm-types.h"
 
+
+/*
+ * lvrename command implementation.
+ * Check arguments and call lv_rename() to execute the request.
+ */
 int lvrename(struct cmd_context *cmd, int argc, char **argv)
 {
 	size_t maxlen;
@@ -24,7 +29,6 @@
 	char *st;
 
 	struct volume_group *vg;
-	struct logical_volume *lv;
 	struct lv_list *lvl;
 
 	if (argc == 3) {
@@ -103,72 +107,14 @@
 				    CORRECT_INCONSISTENT)))
 		return ECMD_FAILED;
 
-	if (find_lv_in_vg(vg, lv_name_new)) {
-		log_error("Logical volume \"%s\" already exists in "
-			  "volume group \"%s\"", lv_name_new, vg_name);
-		goto error;
-	}
-
 	if (!(lvl = find_lv_in_vg(vg, lv_name_old))) {
 		log_error("Existing logical volume \"%s\" not found in "
 			  "volume group \"%s\"", lv_name_old, vg_name);
 		goto error;
 	}
 
-	lv = lvl->lv;
-
-	if (lv->status & LOCKED) {
-		log_error("Cannot rename locked LV %s", lv->name);
+	if (!lv_rename(cmd, lvl->lv, lv_name_new))
 		goto error;
-	}
-
-	if ((lv->status & MIRRORED) ||
-	    (lv->status & MIRROR_LOG) ||
-	    (lv->status & MIRROR_IMAGE)) {
-		log_error("Mirrored LV, \"%s\" cannot be renamed: %s",
-			  lv->name, strerror(ENOSYS));
-		goto error;
-	}
-
-	if ((lv->status & MIRRORED) ||
-	    (lv->status & MIRROR_LOG) ||
-	    (lv->status & MIRROR_IMAGE)) {
-		log_error("Mirrored LV, \"%s\" cannot be renamed: %s",
-			  lv->name, strerror(ENOSYS));
-		goto error;
-	}
-
-	if (!archive(lv->vg)) {
-		stack;
-		goto error;
-	}
-
-	if (!(lv->name = dm_pool_strdup(cmd->mem, lv_name_new))) {
-		log_error("Failed to allocate space for new name");
-		goto error;
-	}
-
-	log_verbose("Writing out updated volume group");
-	if (!vg_write(vg)) {
-		stack;
-		goto error;
-	}
-
-	backup(lv->vg);
-
-	if (!suspend_lv(cmd, lv)) {
-		stack;
-		vg_revert(vg);
-		goto error;
-	}
-
-	if (!vg_commit(vg)) {
-		stack;
-		resume_lv(cmd, lv);
-		goto error;
-	}
-
-	resume_lv(cmd, lv);
 
 	unlock_vg(cmd, vg_name);
 


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2006-12-13  3:40 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2006-12-13  3:40 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2006-12-13 03:39:59

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata.h 
	tools          : lvconvert.c 

Log message:
	When lvconvert allocates a mirror log, respect parallel area constraints.
	Use loop to iterate through the now-ordered policy list in _allocate().
	Check for failure to allocate just the mirror log.
	Introduce calc_area_multiple().
	Support mirror log allocation when there is only one PV: area_count now 0.
	
	(See lvm-devel list archives for further details.)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.519&r2=1.520
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.113&r2=1.114
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.151&r2=1.152
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvconvert.c.diff?cvsroot=lvm2&r1=1.23&r2=1.24

--- LVM2/WHATS_NEW	2006/12/12 19:30:10	1.519
+++ LVM2/WHATS_NEW	2006/12/13 03:39:57	1.520
@@ -1,5 +1,10 @@
 Version 2.02.17 -
 ===================================
+  When lvconvert allocates a mirror log, respect parallel area constraints.
+  Use loop to iterate through the now-ordered policy list in _allocate().
+  Check for failure to allocate just the mirror log.
+  Introduce calc_area_multiple().
+  Support mirror log allocation when there is only one PV: area_count now 0.
   Fix detection of smallest area in _alloc_parallel_area() for cling policy.
   Add manpage entry for clvmd -T
   Fix gulm operation of clvmd, including a hang when doing lvchange -aey
--- LVM2/lib/metadata/lv_manip.c	2006/12/12 19:30:10	1.113
+++ LVM2/lib/metadata/lv_manip.c	2006/12/13 03:39:58	1.114
@@ -415,6 +415,15 @@
 	struct list alloced_areas[0];	/* Lists of areas in each stripe */
 };
 
+static uint32_t calc_area_multiple(const struct segment_type *segtype,
+				   const uint32_t area_count)
+{
+	if (!segtype_is_striped(segtype) || !area_count)
+		return 1;
+
+	return area_count;
+}
+
 /*
  * Preparation for a specific allocation attempt
  */
@@ -476,7 +485,7 @@
 	ah->area_count = area_count;
 	ah->log_count = log_count;
 	ah->alloc = alloc;
-	ah->area_multiple = segtype_is_striped(segtype) ? ah->area_count : 1;
+	ah->area_multiple = calc_area_multiple(segtype, area_count);
 
 	for (s = 0; s < ah->area_count; s++)
 		list_init(&ah->alloced_areas[s]);
@@ -553,7 +562,7 @@
 	if (mirrored_pv)
 		extra_areas = 1;
 
-	area_multiple = segtype_is_striped(segtype) ? area_count : 1;
+	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,
@@ -707,7 +716,7 @@
 	if (max_seg_len && *max_seg_len > remaining_seg_len)
 		*max_seg_len = remaining_seg_len;
 
-	area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
+	area_multiple = calc_area_multiple(seg->segtype, seg->area_count);
 	area_len = remaining_seg_len / area_multiple ? : 1;
 
 	for (s = first_area;
@@ -1066,6 +1075,7 @@
 	int r = 0;
 	struct list *pvms;
 	uint32_t areas_size;
+	alloc_policy_t alloc;
 
 	if (allocated >= new_extents && !ah->log_count) {
 		log_error("_allocate called with no work to do!");
@@ -1111,50 +1121,18 @@
 		return 0;
 	}
 
-	old_allocated = allocated;
-	if (!_find_parallel_space(ah, ALLOC_CONTIGUOUS, pvms, areas,
-				  areas_size, can_split,
-				  prev_lvseg, &allocated, new_extents)) {
-		stack;
-		goto out;
-	}
-
-	if ((allocated == new_extents) || (ah->alloc == ALLOC_CONTIGUOUS) ||
-	    (!can_split && (allocated != old_allocated)))
-		goto finished;
-
-	old_allocated = allocated;
-	if (!_find_parallel_space(ah, ALLOC_CLING, pvms, areas,
-				  areas_size, can_split,
-				  prev_lvseg, &allocated, new_extents)) {
-		stack;
-		goto out;
-	}
-
-	if ((allocated == new_extents) || (ah->alloc == ALLOC_CLING) ||
-	    (!can_split && (allocated != old_allocated)))
-		goto finished;
-
-	old_allocated = allocated;
-	if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
-				  areas_size, can_split,
-				  prev_lvseg, &allocated, new_extents)) {
-		stack;
-		goto out;
-	}
-
-	if ((allocated == new_extents) || (ah->alloc == ALLOC_NORMAL) ||
-	    (!can_split && (allocated != old_allocated)))
-		goto finished;
-
-	if (!_find_parallel_space(ah, ALLOC_ANYWHERE, pvms, areas,
-				  areas_size, can_split,
-				  prev_lvseg, &allocated, new_extents)) {
-		stack;
-		goto out;
+	/* Attempt each defined allocation policy in turn */
+	for (alloc = ALLOC_CONTIGUOUS; alloc < ALLOC_INHERIT; alloc++) {
+		old_allocated = allocated;
+		if (!_find_parallel_space(ah, alloc, pvms, areas,
+					  areas_size, can_split,
+					  prev_lvseg, &allocated, new_extents))
+			goto_out;
+		if ((allocated == new_extents) || (ah->alloc == alloc) ||
+		    (!can_split && (allocated != old_allocated)))
+			break;
 	}
 
-      finished:
 	if (allocated != new_extents) {
 		log_error("Insufficient suitable %sallocatable extents "
 			  "for logical volume %s: %u more required",
@@ -1165,6 +1143,13 @@
 		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;
+	}
+
 	r = 1;
 
       out:
--- LVM2/lib/metadata/metadata.h	2006/11/03 21:07:14	1.151
+++ LVM2/lib/metadata/metadata.h	2006/12/13 03:39:58	1.152
@@ -78,17 +78,18 @@
 #define FMT_RESIZE_PV		0x00000080U	/* Supports pvresize? */
 #define FMT_UNLIMITED_STRIPESIZE 0x00000100U	/* Unlimited stripe size? */
 
+/* Ordered list - see lv_manip.c */
 typedef enum {
-	ALLOC_INVALID = 0,
-	ALLOC_INHERIT,
+	ALLOC_INVALID,
 	ALLOC_CONTIGUOUS,
 	ALLOC_CLING,
 	ALLOC_NORMAL,
-	ALLOC_ANYWHERE
+	ALLOC_ANYWHERE,
+	ALLOC_INHERIT
 } alloc_policy_t;
 
 typedef enum {
-	AREA_UNASSIGNED = 0,
+	AREA_UNASSIGNED,
 	AREA_PV,
 	AREA_LV
 } area_type_t;
--- LVM2/tools/lvconvert.c	2006/11/02 23:33:20	1.23
+++ LVM2/tools/lvconvert.c	2006/12/13 03:39:58	1.24
@@ -281,15 +281,8 @@
 			if (lp->mirrors == existing_mirrors) {
 				if (!seg->log_lv && !arg_count(cmd, corelog_ARG)) {
 					/* No disk log present, add one. */
-					/* FIXME: Why doesn't this work?  Without
-					   it, we will probably put the log on the
-					   same device as a mirror leg.
-					  if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv))) {
-					  stack;
-					  return 0;
-					  }
-					*/
-					parallel_areas = NULL;
+					if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
+						return_0;
 					if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) {
 						log_error("Unable to determine mirror sync status.");
 						return 0;
@@ -297,7 +290,7 @@
 
 					segtype = get_segtype_from_string(cmd, "striped");
 
-					if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1,
+					if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0,
 								    0, 1, 0,
 								    NULL, 0, 0, lp->pvh,
 								    lp->alloc,


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2006-10-23 15:54 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2006-10-23 15:54 UTC (permalink / raw)
  To: lvm-devel, lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2006-10-23 15:54:51

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c pv_map.c pv_map.h 

Log message:
	Perform high-level free space check before each allocation attempt.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.477&r2=1.478
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.110&r2=1.111
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/pv_map.c.diff?cvsroot=lvm2&r1=1.26&r2=1.27
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/pv_map.h.diff?cvsroot=lvm2&r1=1.7&r2=1.8

--- LVM2/WHATS_NEW	2006/10/23 11:46:15	1.477
+++ LVM2/WHATS_NEW	2006/10/23 15:54:51	1.478
@@ -1,5 +1,6 @@
 Version 2.02.13 -
 ===================================
+  Perform high-level free space check before each allocation attempt.
   Don't allow a node to remove an LV that's exclusively active on anther node.
   Cope if same PV is included more than once in cmdline PE range list.
   Set PV size to current device size if it is found to be zero.
--- LVM2/lib/metadata/lv_manip.c	2006/10/08 12:01:12	1.110
+++ LVM2/lib/metadata/lv_manip.c	2006/10/23 15:54:51	1.111
@@ -890,8 +890,17 @@
 	uint32_t next_le;
 	struct seg_pvs *spvs;
 	struct list *parallel_pvs;
+	uint32_t free_pes;
+
+	/* Is there enough total space? */
+	free_pes = pv_maps_size(pvms);
+	if (needed > free_pes) {
+		log_error("Insufficient free space: %" PRIu32 " extents needed,"
+			  " but only %" PRIu32 " available", needed,
+			  free_pes);
+		return 0;
+	}
 
-	/* FIXME Do calculations on free extent counts before selecting space */
 	/* FIXME Select log PV appropriately if there isn't one yet */
 
 	/* Are there any preceding segments we must follow on from? */
--- LVM2/lib/metadata/pv_map.c	2006/10/21 23:18:43	1.26
+++ LVM2/lib/metadata/pv_map.c	2006/10/23 15:54:51	1.27
@@ -32,6 +32,7 @@
 	}
 
 	list_add(&pva->list, &a->list);
+	a->map->pe_count += a->count;
 }
 
 static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
@@ -191,6 +192,7 @@
 void consume_pv_area(struct pv_area *pva, uint32_t to_go)
 {
 	list_del(&pva->list);
+	pva->map->pe_count -= pva->count;
 
 	assert(to_go <= pva->count);
 
@@ -201,3 +203,14 @@
 		_insert_area(&pva->map->areas, pva);
 	}
 }
+
+uint32_t pv_maps_size(struct list *pvms)
+{
+	struct pv_map *pvm;
+	uint32_t pe_count = 0;
+
+	list_iterate_items(pvm, pvms)
+		pe_count += pvm->pe_count;
+
+	return pe_count;
+}
--- LVM2/lib/metadata/pv_map.h	2005/10/16 23:03:58	1.7
+++ LVM2/lib/metadata/pv_map.h	2006/10/23 15:54:51	1.8
@@ -37,6 +37,7 @@
 struct pv_map {
 	struct physical_volume *pv;
 	struct list areas;		/* struct pv_areas */
+	uint32_t pe_count;		/* Total number of PEs */
 
 	struct list list;
 };
@@ -49,4 +50,6 @@
 
 void consume_pv_area(struct pv_area *area, uint32_t to_go);
 
+uint32_t pv_maps_size(struct list *pvms);
+
 #endif


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2006-10-08 12:01 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2006-10-08 12:01 UTC (permalink / raw)
  To: lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2006-10-08 12:01:13

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata.h 
	man            : lvm.8 
	lib/display    : display.c 
	lib/report     : report.c 

Log message:
	add cling allocation policy

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.462&r2=1.463
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.109&r2=1.110
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.149&r2=1.150
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/man/lvm.8.diff?cvsroot=lvm2&r1=1.8&r2=1.9
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/display/display.c.diff?cvsroot=lvm2&r1=1.67&r2=1.68
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/report/report.c.diff?cvsroot=lvm2&r1=1.49&r2=1.50

--- LVM2/WHATS_NEW	2006/10/07 23:42:03	1.462
+++ LVM2/WHATS_NEW	2006/10/08 12:01:12	1.463
@@ -1,5 +1,6 @@
 Version 2.02.11 - 
 =====================================
+  Add cling allocation policy.
   Change _check_contiguous() to use _for_each_pv().
   Extend _for_each_pv() to allow termination without error.
   Abstract _is_contiguous().
--- LVM2/lib/metadata/lv_manip.c	2006/10/07 23:40:36	1.109
+++ LVM2/lib/metadata/lv_manip.c	2006/10/08 12:01:12	1.110
@@ -773,6 +773,17 @@
 };
 
 /*
+ * Is PV area on the same PV?
+ */
+static int _is_same_pv(struct pv_segment *pvseg, struct pv_area *pva)
+{
+	if (pvseg->pv != pva->map->pv)
+		return 0;
+
+	return 1;
+}
+
+/*
  * Is PV area contiguous to PV segment?
  */
 static int _is_contiguous(struct pv_segment *pvseg, struct pv_area *pva)
@@ -786,9 +797,9 @@
 	return 1;
 }
 
-static int _is_contiguous_condition(struct cmd_context *cmd,
-				    struct pv_segment *pvseg, uint32_t s,
-				    void *data)
+static int _is_condition(struct cmd_context *cmd,
+			 struct pv_segment *pvseg, uint32_t s,
+			 void *data)
 {
 	struct pv_match *pvmatch = data;
 
@@ -804,6 +815,34 @@
 }
 
 /*
+ * Is pva on same PV as any existing areas?
+ */
+static int _check_cling(struct cmd_context *cmd,
+			struct lv_segment *prev_lvseg, struct pv_area *pva,
+			struct pv_area **areas, uint32_t areas_size)
+{
+	struct pv_match pvmatch;
+	int r;
+
+	pvmatch.condition = _is_same_pv;
+	pvmatch.areas = areas;
+	pvmatch.areas_size = areas_size;
+	pvmatch.pva = pva;
+
+	/* FIXME Cope with stacks by flattening */
+	if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
+			       prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
+			       0, 0, -1, 1,
+			       _is_condition, &pvmatch)))
+		stack;
+
+	if (r != 2)
+		return 0;
+
+	return 1;
+}
+
+/*
  * Is pva contiguous to any existing areas or on the same PV?
  */
 static int _check_contiguous(struct cmd_context *cmd,
@@ -822,7 +861,7 @@
 	if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
 			       prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
 			       0, 0, -1, 1,
-			       _is_contiguous_condition, &pvmatch)))
+			       _is_condition, &pvmatch)))
 		stack;
 
 	if (r != 2)
@@ -844,9 +883,9 @@
 	struct pv_area *pva;
 	struct pv_list *pvl;
 	unsigned already_found_one = 0;
-	unsigned contiguous = 0, contiguous_count = 0;
+	unsigned contiguous = 0, cling = 0, preferred_count = 0;
 	unsigned ix;
-	unsigned ix_offset = 0;	/* Offset for non-contiguous allocations */
+	unsigned ix_offset = 0;	/* Offset for non-preferred allocations */
 	uint32_t max_parallel;	/* Maximum extents to allocate */
 	uint32_t next_le;
 	struct seg_pvs *spvs;
@@ -856,9 +895,14 @@
 	/* FIXME Select log PV appropriately if there isn't one yet */
 
 	/* Are there any preceding segments we must follow on from? */
-	if ((alloc == ALLOC_CONTIGUOUS) && prev_lvseg) {
-		contiguous = 1;
+	if (prev_lvseg) {
 		ix_offset = prev_lvseg->area_count;
+		if ((alloc == ALLOC_CONTIGUOUS))
+			contiguous = 1;
+		else if ((alloc == ALLOC_CLING))
+			cling = 1;
+		else
+			ix_offset = 0;
 	}
 
 	/* FIXME This algorithm needs a lot of cleaning up! */
@@ -867,6 +911,7 @@
 	/* ix holds the number of areas found on other PVs */
 	do {
 		ix = 0;
+		preferred_count = 0;
 
 		parallel_pvs = NULL;
 		max_parallel = needed;
@@ -920,12 +965,23 @@
 							      prev_lvseg,
 							      pva, areas,
 							      areas_size)) {
-						contiguous_count++;
+						preferred_count++;
 						goto next_pv;
 					}
 					continue;
 				}
 
+				if (cling) {
+					if (prev_lvseg &&
+					    _check_cling(ah->cmd,
+							   prev_lvseg,
+							   pva, areas,
+							   areas_size)) {
+						preferred_count++;
+					}
+					goto next_pv;
+				}
+
 				/* Is it big enough on its own? */
 				if (pva->count * ah->area_multiple <
 				    max_parallel - *allocated &&
@@ -949,7 +1005,7 @@
 				break;
 		}
 
-		if (contiguous && (contiguous_count < ix_offset))
+		if ((contiguous || cling) && (preferred_count < ix_offset))
 			break;
 
 		/* Only allocate log_area the first time around */
@@ -1059,6 +1115,18 @@
 		goto finished;
 
 	old_allocated = allocated;
+	if (!_find_parallel_space(ah, ALLOC_CLING, pvms, areas,
+				  areas_size, can_split,
+				  prev_lvseg, &allocated, new_extents)) {
+		stack;
+		goto out;
+	}
+
+	if ((allocated == new_extents) || (ah->alloc == ALLOC_CLING) ||
+	    (!can_split && (allocated != old_allocated)))
+		goto finished;
+
+	old_allocated = allocated;
 	if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
 				  areas_size, can_split,
 				  prev_lvseg, &allocated, new_extents)) {
--- LVM2/lib/metadata/metadata.h	2006/09/11 21:14:56	1.149
+++ LVM2/lib/metadata/metadata.h	2006/10/08 12:01:12	1.150
@@ -82,6 +82,7 @@
 	ALLOC_INVALID = 0,
 	ALLOC_INHERIT,
 	ALLOC_CONTIGUOUS,
+	ALLOC_CLING,
 	ALLOC_NORMAL,
 	ALLOC_ANYWHERE
 } alloc_policy_t;
--- LVM2/man/lvm.8	2006/08/18 22:35:59	1.8
+++ LVM2/man/lvm.8	2006/10/08 12:01:12	1.9
@@ -136,7 +136,7 @@
 Delete the tag \fBtag\fP from a PV, VG or LV, if it's present.
 .TP
 \fB--alloc AllocationPolicy\fP
-The allocation policy to use: \fBcontiguous\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
+The allocation policy to use: \fBcontiguous\fP, \fBcling\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
 When a command needs to allocate physical extents from the volume group,
 the allocation policy controls how they are chosen.  
 Each volume group and logical volume has an allocation policy.
@@ -146,15 +146,18 @@
 which applies the same policy as for the volume group.  These policies can
 be changed using \fBlvchange\fP (8) and \fBvgchange\fP (8) or over-ridden
 on the command line of any command that performs allocation.
-The \fBcontiguous\fP policy requires that new extents are adjacent to
-existing extents. If there are sufficient free extents to satisfy
+The \fBcontiguous\fP policy requires that new extents be placed adjacent
+to existing extents. 
+The \fBcling\fP policy places new extents on the same physical
+volume as existing extents in the same stripe of the Logical Volume.
+If there are sufficient free extents to satisfy
 an allocation request but \fBnormal\fP doesn't use them,
 \fBanywhere\fP will - even if that reduces performance by
 placing two stripes on the same physical volume.
 .IP
 N.B. The policies described above are not implemented fully yet.
-In particular, \fBcontiguous\fP does not place new extents adjacent to existing
-extents and \fBanywhere\fP is not implemented at all.
+In particular, contiguous free space cannot be broken up to
+satisfy allocation attempts.
 .SH ENVIRONMENT VARIABLES
 .TP
 \fBLVM_SYSTEM_DIR\fP 
--- LVM2/lib/display/display.c	2006/05/09 21:23:50	1.67
+++ LVM2/lib/display/display.c	2006/10/08 12:01:12	1.68
@@ -30,6 +30,7 @@
 } _policies[] = {
 	{
 	ALLOC_CONTIGUOUS, "contiguous"}, {
+	ALLOC_CLING, "cling"}, {
 	ALLOC_NORMAL, "normal"}, {
 	ALLOC_ANYWHERE, "anywhere"}, {
 	ALLOC_INHERIT, "inherit"}
--- LVM2/lib/report/report.c	2006/10/03 17:55:20	1.49
+++ LVM2/lib/report/report.c	2006/10/08 12:01:13	1.50
@@ -104,6 +104,8 @@
 	switch (alloc) {
 	case ALLOC_CONTIGUOUS:
 		return 'c';
+	case ALLOC_CLING:
+		return 'C';
 	case ALLOC_NORMAL:
 		return 'n';
 	case ALLOC_ANYWHERE:


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2006-09-11 21:14 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2006-09-11 21:14 UTC (permalink / raw)
  To: lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2006-09-11 21:14:56

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

Log message:
	Extend _check_contiguous() to detect single-area LVs.
	Include mirror log (untested) in _for_each_pv() processing.
	Use MIRROR_LOG_SIZE constant.
	Remove struct seg_pvs from _for_each_pv() for generalisation.
	Avoid adding duplicates to list of parallel PVs to avoid.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.437&r2=1.438
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.101&r2=1.102
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.148&r2=1.149

--- LVM2/WHATS_NEW	2006/09/11 14:24:58	1.437
+++ LVM2/WHATS_NEW	2006/09/11 21:14:55	1.438
@@ -1,5 +1,10 @@
 Version 2.02.10 - 
 ==================================
+  Extend _check_contiguous() to detect single-area LVs.
+  Include mirror log (untested) in _for_each_pv() processing.
+  Use MIRROR_LOG_SIZE constant.
+  Remove struct seg_pvs from _for_each_pv() to generalise.
+  Avoid adding duplicates to list of parallel PVs to avoid.
   Fix several incorrect comparisons in parallel area avoidance code.
   Fix segment lengths when flattening existing parallel areas.
   Log existing parallel areas prior to allocation.
--- LVM2/lib/metadata/lv_manip.c	2006/09/11 14:24:58	1.101
+++ LVM2/lib/metadata/lv_manip.c	2006/09/11 21:14:56	1.102
@@ -657,7 +657,7 @@
 	if (log_area) {
 		ah->log_area.pv = log_area->map->pv;
 		ah->log_area.pe = log_area->start;
-		ah->log_area.len = 1;	/* FIXME Calculate & check this */
+		ah->log_area.len = MIRROR_LOG_SIZE;	/* FIXME Calculate & check this */
 		consume_pv_area(log_area, ah->log_area.len);
 	}
 
@@ -685,14 +685,21 @@
  */
 static int _check_contiguous(struct lv_segment *prev_lvseg,
 			     struct physical_volume *pv, struct pv_area *pva,
-			     struct pv_area **areas)
+			     struct pv_area **areas, uint32_t areas_size)
 {
 	struct pv_segment *prev_pvseg;
+	struct lv_segment *lastseg;
 	uint32_t s;
 
-	for (s = 0; s < prev_lvseg->area_count; s++) {
-		if (seg_type(prev_lvseg, s) != AREA_PV)
-			continue;	/* FIXME Broken */
+	for (s = 0; s < prev_lvseg->area_count && s < areas_size; s++) {
+		if (seg_type(prev_lvseg, s) == AREA_LV) {
+			lastseg = list_item(list_last(&seg_lv(prev_lvseg, s)->segments), struct lv_segment);
+			/* FIXME For more areas supply flattened prev_lvseg to ensure consistency */
+			if (lastseg->area_count == 1 &&
+			    _check_contiguous(lastseg, pv, pva, &areas[s], 1))
+				return 1;
+			continue;
+		}
 
 		if (!(prev_pvseg = seg_pvseg(prev_lvseg, s)))
 			continue; /* FIXME Broken */
@@ -796,7 +803,8 @@
 					if (prev_lvseg &&
 					    _check_contiguous(prev_lvseg,
 							      pvm->pv,
-							      pva, areas)) {
+							      pva, areas,
+							      areas_size)) {
 						contiguous_count++;
 						goto next_pv;
 					}
@@ -1374,11 +1382,15 @@
 	return lv;
 }
 
-/* Recursively process each PV used by part of an LV */
+/*
+ * Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len.
+ * If any constituent area contains more than one segment, max_seg_len is
+ * reduced to cover only the first.
+ */
 static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
-			uint32_t le, uint32_t len,
-			int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs),
-			struct seg_pvs *spvs)
+			uint32_t le, uint32_t len, uint32_t *max_seg_len,
+			int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, void *data),
+			void *data)
 {
 	struct lv_segment *seg;
 	uint32_t s;
@@ -1396,36 +1408,41 @@
 	if (remaining_seg_len > len)
 		remaining_seg_len = len;
 
-	if (spvs->len > remaining_seg_len)
-		spvs->len = remaining_seg_len;
+	if (max_seg_len && *max_seg_len > remaining_seg_len)
+		*max_seg_len = remaining_seg_len;
 
 	area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
-	area_len = remaining_seg_len / area_multiple;
+	area_len = remaining_seg_len / area_multiple ? : 1;
 
-	for (s = 0; s < seg->area_count; s++) {
+	for (s = 0; s < seg->area_count; s++)
 		if (seg_type(seg, s) == AREA_LV) {
 			if (!_for_each_pv(cmd, seg_lv(seg, s),
 					  seg_le(seg, s) + (le - seg->le) / area_multiple,
-					  area_len, fn, spvs)) {
-				stack;
-				return 0;
-			}
-		} else if (seg_type(seg, s) == AREA_PV) {
-			if (!fn(cmd, seg_pvseg(seg, s), spvs)) {
-				stack;
-				return 0;
-			}
-		}
-	}
+					  area_len, max_seg_len, fn, data))
+				return_0;
+		} else if ((seg_type(seg, s) == AREA_PV) &&
+			   !fn(cmd, seg_pvseg(seg, s), data))
+			return_0;
+
+	if (seg_is_mirrored(seg) && 
+	    !_for_each_pv(cmd, seg->log_lv, 0, MIRROR_LOG_SIZE,
+			  NULL, fn, data))
+		return_0;
+
+	/* FIXME Add snapshot cow LVs etc. */
 
 	return 1;
 }
 
-static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs)
+static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, void *data)
 {
+	struct seg_pvs *spvs = (struct seg_pvs *) data;
 	struct pv_list *pvl;
 
-	/* FIXME Don't add again if it's already on the list! */
+	/* Don't add again if it's already on list. */
+	list_iterate_items(pvl, &spvs->pvs)
+		if (pvl->pv == peg->pv)
+			return 1;
 
 	if (!(pvl = dm_pool_alloc(cmd->mem, sizeof(*pvl)))) {
 		log_error("pv_list allocation failed");
@@ -1434,11 +1451,8 @@
 
 	pvl->pv = peg->pv;
 
-	/* FIXME Use ordered list to facilitate comparison */
 	list_add(&spvs->pvs, &pvl->list);
 
-	/* FIXME Add mirror logs, snapshot cow LVs etc. */
-
 	return 1;
 }
 
@@ -1474,7 +1488,7 @@
 
 		/* Find next segment end */
 		/* FIXME Unnecessary nesting! */
-		if (!_for_each_pv(cmd, lv, current_le, lv->le_count - current_le, _add_pvs, spvs)) {
+		if (!_for_each_pv(cmd, lv, current_le, spvs->len, &spvs->len, _add_pvs, (void *) spvs)) {
 			stack;
 			return NULL;
 		}
--- LVM2/lib/metadata/metadata.h	2006/08/17 19:30:59	1.148
+++ LVM2/lib/metadata/metadata.h	2006/09/11 21:14:56	1.149
@@ -34,6 +34,7 @@
 #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 */
 
 /* Various flags */
 /* Note that the bits no longer necessarily correspond to LVM1 disk format */


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2005-11-10 14:45 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2005-11-10 14:45 UTC (permalink / raw)
  To: lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2005-11-10 14:45:39

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c 
	lib/mirror     : mirrored.c 

Log message:
	Extend allocation areas to avoid overflow with contiguous with other PVs.
	Another pvmove fix.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.321&r2=1.322
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.88&r2=1.89
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/mirror/mirrored.c.diff?cvsroot=lvm2&r1=1.17&r2=1.18


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2005-10-18 13:43 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2005-10-18 13:43 UTC (permalink / raw)
  To: lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2005-10-18 13:43:40

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata.h 
	lib/striped    : striped.c 

Log message:
	Split lv_segment_area from lv_segment to permit extension.

Patches:
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.306&r2=1.307
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.82&r2=1.83
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.128&r2=1.129
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/lib/striped/striped.c.diff?cvsroot=lvm2&r1=1.9&r2=1.10


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

* LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m ...
@ 2004-05-05 18:49 agk
  0 siblings, 0 replies; 36+ messages in thread
From: agk @ 2004-05-05 18:49 UTC (permalink / raw)
  To: lvm2-cvs

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk@sourceware.org	2004-05-05 18:49:21

Modified files:
	.              : WHATS_NEW 
	lib/metadata   : lv_manip.c metadata.h 
	tools          : lvcreate.c lvresize.c 

Log message:
	Push lv_create & alloc policy up to tool level.

Patches:
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.25&r2=1.26
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/lv_manip.c.diff?cvsroot=lvm2&r1=1.57&r2=1.58
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.101&r2=1.102
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/tools/lvcreate.c.diff?cvsroot=lvm2&r1=1.79&r2=1.80
http://sources.redhat.com/cgi-bin/cvsweb.cgi/LVM2/tools/lvresize.c.diff?cvsroot=lvm2&r1=1.49&r2=1.50


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

end of thread, other threads:[~2012-02-23 17:36 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-15 15:18 LVM2 ./WHATS_NEW lib/metadata/lv_manip.c lib/m zkabelac
  -- strict thread matches above, loose matches on Subject: below --
2012-02-23 17:36 jbrassow
2012-02-23  3:57 jbrassow
2012-02-08 13:05 zkabelac
2012-02-01  2:10 agk
2011-10-22 16:42 zkabelac
2011-09-06 18:49 agk
2011-08-18 19:41 jbrassow
2011-08-11  3:29 jbrassow
2011-06-23 14:01 jbrassow
2011-04-09 19:05 zkabelac
2011-01-24 14:19 agk
2011-01-11 17:05 jbrassow
2010-10-14 20:03 jbrassow
2010-04-23 19:27 snitzer
2010-04-09  1:00 agk
2010-03-25 21:19 agk
2010-03-25  2:31 agk
2010-01-08 22:32 jbrassow
2009-05-13 21:29 mbroz
2009-05-13 21:28 mbroz
2009-04-21 14:32 mbroz
2009-04-07 10:20 mbroz
2008-03-28 19:08 wysochanski
2008-01-26  0:25 agk
2008-01-18 22:01 agk
2007-12-20 18:55 agk
2007-08-28 16:14 wysochanski
2007-08-03 21:22 wysochanski
2006-12-13  3:40 agk
2006-10-23 15:54 agk
2006-10-08 12:01 agk
2006-09-11 21:14 agk
2005-11-10 14:45 agk
2005-10-18 13:43 agk
2004-05-05 18:49 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).