All of lore.kernel.org
 help / color / mirror / Atom feed
From: agk@sourceware.org <agk@sourceware.org>
To: lvm-devel@redhat.com
Subject: LVM2 ./WHATS_NEW daemons/clvmd/lvm-functions.c ...
Date: 19 Sep 2008 06:42:05 -0000	[thread overview]
Message-ID: <20080919064205.16217.qmail@sourceware.org> (raw)

CVSROOT:	/cvs/lvm2
Module name:	LVM2
Changes by:	agk at sourceware.org	2008-09-19 06:42:00

Modified files:
	.              : WHATS_NEW 
	daemons/clvmd  : lvm-functions.c 
	doc            : example.conf 
	lib/activate   : activate.c dev_manager.c 
	lib/commands   : toolcontext.c toolcontext.h 
	lib/config     : defaults.h 
	lib/display    : display.c 
	lib/format1    : disk-rep.h format1.c import-export.c 
	lib/format_text: archiver.c flags.c import_vsn1.c 
	lib/locking    : cluster_locking.c locking.h 
	lib/log        : log.c log.h 
	lib/metadata   : metadata-exported.h metadata.c metadata.h 
	lib/report     : report.c 
	man            : lvm.conf.5 vgreduce.8 
	tools          : commands.h lvmcmdline.c lvremove.c pvcreate.c 
	                 vgcfgbackup.c vgreduce.c 

Log message:
	Improve the way VGs with PVs missing are handled so manual intervention
	is required in fewer circumstances.  (mornfall)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/WHATS_NEW.diff?cvsroot=lvm2&r1=1.959&r2=1.960
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/daemons/clvmd/lvm-functions.c.diff?cvsroot=lvm2&r1=1.44&r2=1.45
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/doc/example.conf.diff?cvsroot=lvm2&r1=1.37&r2=1.38
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/activate/activate.c.diff?cvsroot=lvm2&r1=1.137&r2=1.138
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/activate/dev_manager.c.diff?cvsroot=lvm2&r1=1.139&r2=1.140
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/commands/toolcontext.c.diff?cvsroot=lvm2&r1=1.61&r2=1.62
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/commands/toolcontext.h.diff?cvsroot=lvm2&r1=1.24&r2=1.25
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/config/defaults.h.diff?cvsroot=lvm2&r1=1.43&r2=1.44
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/display/display.c.diff?cvsroot=lvm2&r1=1.91&r2=1.92
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format1/disk-rep.h.diff?cvsroot=lvm2&r1=1.51&r2=1.52
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format1/format1.c.diff?cvsroot=lvm2&r1=1.107&r2=1.108
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format1/import-export.c.diff?cvsroot=lvm2&r1=1.98&r2=1.99
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format_text/archiver.c.diff?cvsroot=lvm2&r1=1.13&r2=1.14
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format_text/flags.c.diff?cvsroot=lvm2&r1=1.34&r2=1.35
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/format_text/import_vsn1.c.diff?cvsroot=lvm2&r1=1.53&r2=1.54
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/locking/cluster_locking.c.diff?cvsroot=lvm2&r1=1.29&r2=1.30
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/locking/locking.h.diff?cvsroot=lvm2&r1=1.41&r2=1.42
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/log/log.c.diff?cvsroot=lvm2&r1=1.47&r2=1.48
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/log/log.h.diff?cvsroot=lvm2&r1=1.41&r2=1.42
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata-exported.h.diff?cvsroot=lvm2&r1=1.52&r2=1.53
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.c.diff?cvsroot=lvm2&r1=1.190&r2=1.191
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/metadata/metadata.h.diff?cvsroot=lvm2&r1=1.181&r2=1.182
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/lib/report/report.c.diff?cvsroot=lvm2&r1=1.87&r2=1.88
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/man/lvm.conf.5.diff?cvsroot=lvm2&r1=1.22&r2=1.23
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/man/vgreduce.8.diff?cvsroot=lvm2&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/commands.h.diff?cvsroot=lvm2&r1=1.118&r2=1.119
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvmcmdline.c.diff?cvsroot=lvm2&r1=1.69&r2=1.70
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/lvremove.c.diff?cvsroot=lvm2&r1=1.54&r2=1.55
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/pvcreate.c.diff?cvsroot=lvm2&r1=1.74&r2=1.75
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/vgcfgbackup.c.diff?cvsroot=lvm2&r1=1.25&r2=1.26
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/tools/vgreduce.c.diff?cvsroot=lvm2&r1=1.82&r2=1.83

--- LVM2/WHATS_NEW	2008/09/19 05:33:37	1.959
+++ LVM2/WHATS_NEW	2008/09/19 06:41:57	1.960
@@ -1,5 +1,11 @@
 Version 2.02.40 - 
 ================================
+  In VG with PVs missing, by default allow activation of LVs that are complete.
+  Track PARTIAL_LV and MISSING_PV flags internally.
+  Require --force with --removemissing in vgreduce to remove partial LVs.
+  No longer write out PARTIAL flag into metadata backups.
+  Treat new default activation/missing_stripe_filler "error" as an error target.
+  Remove internal partial_mode.
   Add device/md_chunk_alignment to lvm.conf.
   Pass struct physical_volume to pe_align and adjust for md chunk size.
   Store sysfs location in struct cmd_context.
--- LVM2/daemons/clvmd/lvm-functions.c	2008/06/06 16:37:51	1.44
+++ LVM2/daemons/clvmd/lvm-functions.c	2008/09/19 06:41:57	1.45
@@ -413,9 +413,6 @@
 		}
 	}
 
-	if (lock_flags & LCK_PARTIAL_MODE)
-		init_partial(1);
-
 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
 		init_mirror_in_sync(1);
 
@@ -454,9 +451,6 @@
 		break;
 	}
 
-	if (lock_flags & LCK_PARTIAL_MODE)
-		init_partial(0);
-
 	if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
 		init_mirror_in_sync(0);
 
--- LVM2/doc/example.conf	2008/09/19 05:33:36	1.37
+++ LVM2/doc/example.conf	2008/09/19 06:41:57	1.38
@@ -271,11 +271,13 @@
 }
 
 activation {
-    # Device used in place of missing stripes if activating incomplete volume.
-    # For now, you need to set this up yourself first (e.g. with 'dmsetup')
-    # For example, you could make it return I/O errors using the 'error' 
-    # target or make it return zeros.
-    missing_stripe_filler = "/dev/ioerror"
+    # How to fill in missing stripes if activating an incomplete volume.
+    # Using "error" will make inaccessible parts of the device return
+    # I/O errors on access.  You can instead use a device path, in which 
+    # case, that device will be used to in place of missing stripes.
+    # But note that using anything other than "error" with mirrored 
+    # or snapshotted volumes is likely to result in data corruption.
+    missing_stripe_filler = "error"
 
     # How much stack (in KB) to reserve for use while devices suspended
     reserved_stack = 256
--- LVM2/lib/activate/activate.c	2008/06/08 11:33:15	1.137
+++ LVM2/lib/activate/activate.c	2008/09/19 06:41:57	1.138
@@ -1027,6 +1027,12 @@
 		return 0;
 	}
 
+	if ((!lv->vg->cmd->partial_activate) && (lv->status & PARTIAL_LV)) {
+		log_error("Refusing activation of partial LV %s. Use --partial to override.",
+			  lv->name);
+		return_0;
+	}
+
 	if (test_mode()) {
 		_skip("Activating '%s'.", lv->name);
 		return 1;
--- LVM2/lib/activate/dev_manager.c	2008/07/15 00:25:51	1.139
+++ LVM2/lib/activate/dev_manager.c	2008/09/19 06:41:57	1.140
@@ -47,7 +47,6 @@
 
 	struct cmd_context *cmd;
 
-	const char *stripe_filler;
 	void *target_state;
 	uint32_t pvmove_mirror_count;
 
@@ -59,8 +58,6 @@
 	const char *old_name;
 };
 
-static const char *stripe_filler = NULL;
-
 static char *_build_dlid(struct dm_pool *mem, const char *lvid, const char *layer)
 {
 	char *dlid;
@@ -443,13 +440,6 @@
 	dm->cmd = cmd;
 	dm->mem = mem;
 
-	if (!stripe_filler) {
-		stripe_filler = find_config_tree_str(cmd,
-						"activation/missing_stripe_filler",
-						DEFAULT_STRIPE_FILLER);
-	}
-	dm->stripe_filler = stripe_filler;
-
 	if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name)))
 		goto_bad;
 
@@ -699,6 +689,68 @@
 	return NULL;
 }
 
+static char *_add_error_device(struct dev_manager *dm, struct dm_tree *dtree,
+			       struct lv_segment *seg, int s)
+{
+	char *id, *name;
+	char errid[32];
+	struct dm_tree_node *node;
+	struct lv_segment *seg_i;
+	int segno = -1, i = 0;;
+	uint64_t size = seg->len * seg->lv->vg->extent_size;
+
+	list_iterate_items(seg_i, &seg->lv->segments) {
+		if (seg == seg_i)
+			segno = i;
+		++i;
+	}
+
+	if (segno < 0) {
+		log_error("_add_error_device called with bad segment");
+		return_NULL;
+	}
+
+	sprintf(errid, "missing_%d_%d", segno, s);
+
+	if (!(id = build_dlid(dm, seg->lv->lvid.s, errid))) 
+		return_NULL;
+
+	if (!(name = build_dm_name(dm->mem, seg->lv->vg->name,
+				   seg->lv->name, errid)))
+		return_NULL;
+	if (!(node = dm_tree_add_new_dev(dtree, name, id, 0, 0, 0, 0, 0)))
+		return_NULL;
+	if (!dm_tree_node_add_error_target(node, size))
+		return_NULL;
+
+	return id;
+}
+
+static int _add_error_area(struct dev_manager *dm, struct dm_tree_node *node,
+			   struct lv_segment *seg, int s)
+{
+	char *dlid;
+	uint64_t extent_size = seg->lv->vg->extent_size;
+
+	if (!strcmp(dm->cmd->stripe_filler, "error")) {
+		/*
+		 * FIXME, the tree pointer is first field of dm_tree_node, but
+		 * we don't have the struct definition available.
+		 */
+		struct dm_tree **tree = (struct dm_tree **) node;
+		dlid = _add_error_device(dm, *tree, seg, s);
+		if (!dlid)
+			return_0;
+		dm_tree_node_add_target_area(node, NULL, dlid,
+					     extent_size * seg_le(seg, s));
+	} else {
+		dm_tree_node_add_target_area(node,
+					     dm->cmd->stripe_filler,
+					     NULL, UINT64_C(0));
+	}
+	return 1;
+}
+
 int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
 		   struct dm_tree_node *node, uint32_t start_area,
 		   uint32_t areas)
@@ -712,11 +764,10 @@
 		     (!seg_pvseg(seg, s) ||
 		      !seg_pv(seg, s) ||
 		      !seg_dev(seg, s))) ||
-		    (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s)))
-			dm_tree_node_add_target_area(node,
-							dm->stripe_filler,
-							NULL, UINT64_C(0));
-		else if (seg_type(seg, s) == AREA_PV)
+		    (seg_type(seg, s) == AREA_LV && !seg_lv(seg, s))) {
+			if (!_add_error_area(dm, node, seg, s))
+				return_0;
+		} else if (seg_type(seg, s) == AREA_PV)
 			dm_tree_node_add_target_area(node,
 							dev_name(seg_dev(seg, s)),
 							NULL,
--- LVM2/lib/commands/toolcontext.c	2008/09/19 03:42:37	1.61
+++ LVM2/lib/commands/toolcontext.c	2008/09/19 06:41:58	1.62
@@ -197,6 +197,7 @@
 {
 	mode_t old_umask;
 	const char *read_ahead;
+	struct stat st;
 
 	/* umask */
 	cmd->default_settings.umask = find_config_tree_int(cmd,
@@ -263,6 +264,24 @@
 		return 0;
 	}
 
+	cmd->stripe_filler = find_config_tree_str(cmd,
+						  "activation/missing_stripe_filler",
+						  DEFAULT_STRIPE_FILLER);
+	if (strcmp(cmd->stripe_filler, "error")) {
+		if (stat(cmd->stripe_filler, &st)) {
+			log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
+				 "is invalid,", cmd->stripe_filler);
+			log_warn("         stat failed: %s", strerror(errno));
+			log_warn("Falling back to \"error\" missing_stripe_filler.");
+			cmd->stripe_filler = "error";
+		} else if (!S_ISBLK(st.st_mode)) {
+			log_warn("WARNING: activation/missing_stripe_filler = \"%s\" "
+				 "is not a block device.", cmd->stripe_filler);
+			log_warn("Falling back to \"error\" missing_stripe_filler.");
+			cmd->stripe_filler = "error";
+		}
+	}
+
 	return 1;
 }
 
@@ -981,6 +1000,7 @@
 	cmd->args = the_args;
 	cmd->is_static = is_static;
 	cmd->is_long_lived = is_long_lived;
+	cmd->handles_missing_pvs = 0;
 	cmd->hosttags = 0;
 	list_init(&cmd->formats);
 	list_init(&cmd->segtypes);
--- LVM2/lib/commands/toolcontext.h	2008/09/19 03:42:37	1.24
+++ LVM2/lib/commands/toolcontext.h	2008/09/19 06:41:58	1.25
@@ -66,8 +66,10 @@
 	struct command *command;
 	struct arg *args;
 	char **argv;
-	unsigned is_static;	/* Static binary? */
-	unsigned is_long_lived;	/* Optimises persistent_filter handling */
+	unsigned is_static:1;	/* Static binary? */
+	unsigned is_long_lived:1;	/* Optimises persistent_filter handling */
+	unsigned handles_missing_pvs:1;
+	unsigned partial_activate:1;
 
 	struct dev_filter *filter;
 	int dump_filter;	/* Dump filter when exiting? */
@@ -81,6 +83,7 @@
 
 	struct archive_params *archive_params;
 	struct backup_params *backup_params;
+	const char *stripe_filler;
 
 	/* List of defined tags */
 	struct list tags;
--- LVM2/lib/config/defaults.h	2008/09/19 05:33:37	1.43
+++ LVM2/lib/config/defaults.h	2008/09/19 06:41:58	1.44
@@ -92,7 +92,7 @@
 #  define DEFAULT_ACTIVATION 0
 #endif
 
-#define DEFAULT_STRIPE_FILLER "/dev/ioerror"
+#define DEFAULT_STRIPE_FILLER "error"
 #define DEFAULT_MIRROR_REGION_SIZE 512	/* KB */
 #define DEFAULT_INTERVAL 15
 
--- LVM2/lib/display/display.c	2008/08/07 14:01:17	1.91
+++ LVM2/lib/display/display.c	2008/09/19 06:41:58	1.92
@@ -578,10 +578,7 @@
 	struct lv_list *lvl;
 	char uuid[64] __attribute((aligned(8)));
 
-	if (vg->status & PARTIAL_VG)
-		active_pvs = list_size(&vg->pvs);
-	else
-		active_pvs = vg->pv_count;
+	active_pvs = vg->pv_count - vg_missing_pv_count(vg);
 
 	log_print("--- Volume group ---");
 	log_print("VG Name               %s", vg->name);
@@ -664,10 +661,7 @@
 	const char *access;
 	char uuid[64] __attribute((aligned(8)));
 
-	if (vg->status & PARTIAL_VG)
-		active_pvs = list_size(&vg->pvs);
-	else
-		active_pvs = vg->pv_count;
+	active_pvs = vg->pv_count - vg_missing_pv_count(vg);
 
 	list_iterate_items(lvl, &vg->lvs)
 		if (lv_is_visible(lvl->lv) && !(lvl->lv->status & SNAPSHOT))
--- LVM2/lib/format1/disk-rep.h	2007/08/20 20:55:25	1.51
+++ LVM2/lib/format1/disk-rep.h	2008/09/19 06:41:58	1.52
@@ -212,7 +212,7 @@
 	      struct pv_disk *pvd, struct physical_volume *pv);
 
 int import_vg(struct dm_pool *mem,
-	      struct volume_group *vg, struct disk_list *dl, int partial);
+	      struct volume_group *vg, struct disk_list *dl);
 int export_vg(struct vg_disk *vgd, struct volume_group *vg);
 
 int import_lv(struct dm_pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
--- LVM2/lib/format1/format1.c	2008/03/17 16:51:31	1.107
+++ LVM2/lib/format1/format1.c	2008/09/19 06:41:58	1.108
@@ -23,7 +23,7 @@
 #include "segtype.h"
 
 /* VG consistency checks */
-static int _check_vgs(struct list *pvs, int *partial)
+static int _check_vgs(struct list *pvs)
 {
 	struct list *pvh, *t;
 	struct disk_list *dl = NULL;
@@ -33,8 +33,6 @@
 	uint32_t exported = 0;
 	int first_time = 1;
 
-	*partial = 0;
-
 	/*
 	 * If there are exported and unexported PVs, ignore exported ones.
 	 * This means an active VG won't be affected if disks are inserted
@@ -98,10 +96,6 @@
 				  dl->vgd.pe_total, dl->vgd.pe_allocated,
 				  dl->vgd.pvg_total);
 			list_del(pvh);
-			if (partial_mode()) {
-				*partial = 1;
-				continue;
-			}
 			return 0;
 		}
 		pv_count++;
@@ -111,9 +105,6 @@
 	if (pv_count != first->vgd.pv_cur) {
 		log_error("%d PV(s) found for VG %s: expected %d",
 			  pv_count, first->pvd.vg_name, first->vgd.pv_cur);
-		if (!partial_mode())
-			return 0;
-		*partial = 1;
 	}
 
 	return 1;
@@ -125,7 +116,6 @@
 	struct dm_pool *mem = fid->fmt->cmd->mem;
 	struct volume_group *vg = dm_pool_alloc(mem, sizeof(*vg));
 	struct disk_list *dl;
-	int partial;
 
 	if (!vg)
 		goto_bad;
@@ -142,12 +132,12 @@
 	list_init(&vg->lvs);
 	list_init(&vg->tags);
 
-	if (!_check_vgs(pvs, &partial))
+	if (!_check_vgs(pvs))
 		goto_bad;
 
 	dl = list_item(pvs->n, struct disk_list);
 
-	if (!import_vg(mem, vg, dl, partial))
+	if (!import_vg(mem, vg, dl))
 		goto_bad;
 
 	if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
--- LVM2/lib/format1/import-export.c	2008/09/19 04:27:26	1.98
+++ LVM2/lib/format1/import-export.c	2008/09/19 06:41:58	1.99
@@ -214,7 +214,7 @@
 }
 
 int import_vg(struct dm_pool *mem,
-	      struct volume_group *vg, struct disk_list *dl, int partial)
+	      struct volume_group *vg, struct disk_list *dl)
 {
 	struct vg_disk *vgd = &dl->vgd;
 	memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
@@ -236,10 +236,10 @@
 	if (vgd->vg_status & VG_EXTENDABLE)
 		vg->status |= RESIZEABLE_VG;
 
-	if (partial || (vgd->vg_access & VG_READ))
+	if (vgd->vg_access & VG_READ)
 		vg->status |= LVM_READ;
 
-	if (!partial && (vgd->vg_access & VG_WRITE))
+	if (vgd->vg_access & VG_WRITE)
 		vg->status |= LVM_WRITE;
 
 	if (vgd->vg_access & VG_CLUSTERED)
@@ -255,9 +255,6 @@
 	vg->max_pv = vgd->pv_max;
 	vg->alloc = ALLOC_NORMAL;
 
-	if (partial)
-		vg->status |= PARTIAL_VG;
-
 	return 1;
 }
 
--- LVM2/lib/format_text/archiver.c	2008/01/30 13:59:59	1.13
+++ LVM2/lib/format_text/archiver.c	2008/09/19 06:41:58	1.14
@@ -134,10 +134,8 @@
 {
 	int r1, r2;
 
-	init_partial(1);
 	r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
 	r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
-	init_partial(0);
 
 	return r1 && r2;
 }
@@ -146,9 +144,7 @@
 {
 	int r;
 
-	init_partial(1);
 	r = archive_list_file(cmd, file);
-	init_partial(0);
 
 	return r;
 }
@@ -393,7 +389,7 @@
 	char path[PATH_MAX];
 	struct volume_group *vg_backup;
 
-	if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
+	if (vg->status & EXPORTED_VG)
 		return;
 
 	if (dm_snprintf(path, sizeof(path), "%s/%s",
--- LVM2/lib/format_text/flags.c	2008/07/10 11:30:57	1.34
+++ LVM2/lib/format_text/flags.c	2008/09/19 06:41:58	1.35
@@ -31,12 +31,12 @@
 static struct flag _vg_flags[] = {
 	{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
 	{RESIZEABLE_VG, "RESIZEABLE", STATUS_FLAG},
-	{PARTIAL_VG, "PARTIAL", STATUS_FLAG},
 	{PVMOVE, "PVMOVE", STATUS_FLAG},
 	{LVM_READ, "READ", STATUS_FLAG},
 	{LVM_WRITE, "WRITE", STATUS_FLAG},
 	{CLUSTERED, "CLUSTERED", STATUS_FLAG},
 	{SHARED, "SHARED", STATUS_FLAG},
+	{PARTIAL_VG, NULL, 0},
 	{PRECOMMITTED, NULL, 0},
 	{0, NULL, 0}
 };
@@ -44,6 +44,7 @@
 static struct flag _pv_flags[] = {
 	{ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG},
 	{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
+	{MISSING_PV, "MISSING", COMPATIBLE_FLAG},
 	{0, NULL, 0}
 };
 
@@ -62,6 +63,8 @@
 	{SNAPSHOT, NULL, 0},
 	{ACTIVATE_EXCL, NULL, 0},
 	{CONVERTING, NULL, 0},
+	{PARTIAL_LV, NULL, 0},
+	{POSTORDER_FLAG, NULL, 0},
 	{0, NULL, 0}
 };
 
@@ -155,7 +158,16 @@
 				break;
 			}
 
-		if (!flags[f].description && (type & STATUS_FLAG)) {
+		if (type == VG_FLAGS && !strcmp(cv->v.str, "PARTIAL")) {
+			/*
+			 * Exception: We no longer write this flag out, but it
+			 * might be encountered in old backup files, so restore
+			 * it in that case. It is never part of live metadata
+			 * though, so only vgcfgrestore needs to be concerned
+			 * by this case.
+			 */
+			s |= PARTIAL_VG;
+		} else if (!flags[f].description && (type & STATUS_FLAG)) {
 			log_err("Unknown status flag '%s'.", cv->v.str);
 			return 0;
 		}
--- LVM2/lib/format_text/import_vsn1.c	2008/09/19 04:27:26	1.53
+++ LVM2/lib/format_text/import_vsn1.c	2008/09/19 06:41:58	1.54
@@ -194,11 +194,6 @@
 		else
 			log_error("Couldn't find device with uuid '%s'.",
 				  buffer);
-
-		if (partial_mode())
-			vg->status |= PARTIAL_VG;
-		else
-			return 0;
 	}
 
 	if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
@@ -211,6 +206,9 @@
 		return 0;
 	}
 
+	if (!pv->dev)
+		pv->status |= MISSING_PV;
+
 	/* Late addition */
 	_read_int64(pvn, "dev_size", &pv->size);
 
@@ -800,11 +798,6 @@
 
 	dm_hash_destroy(pv_hash);
 
-	if (vg->status & PARTIAL_VG) {
-		vg->status &= ~LVM_WRITE;
-		vg->status |= LVM_READ;
-	}
-
 	/*
 	 * Finished.
 	 */
--- LVM2/lib/locking/cluster_locking.c	2008/05/09 18:45:15	1.29
+++ LVM2/lib/locking/cluster_locking.c	2008/09/19 06:41:58	1.30
@@ -315,9 +315,6 @@
 	args[0] = flags & 0x7F; /* Maskoff lock flags */
 	args[1] = flags & 0xC0; /* Bitmap flags */
 
-	if (partial_mode())
-		args[1] |= LCK_PARTIAL_MODE;
-
 	if (mirror_in_sync())
 		args[1] |= LCK_MIRROR_NOSYNC_MODE;
 
--- LVM2/lib/locking/locking.h	2008/05/09 19:26:58	1.41
+++ LVM2/lib/locking/locking.h	2008/09/19 06:41:58	1.42
@@ -83,7 +83,6 @@
 /*
  * Additional lock bits for cluster communication
  */
-#define LCK_PARTIAL_MODE	0x00000001U	/* Running in partial mode */
 #define LCK_MIRROR_NOSYNC_MODE	0x00000002U	/* Mirrors don't require sync */
 #define LCK_DMEVENTD_MONITOR_MODE	0x00000004U	/* Register with dmeventd */
 
--- LVM2/lib/log/log.c	2008/06/17 14:14:00	1.47
+++ LVM2/lib/log/log.c	2008/09/19 06:41:59	1.48
@@ -29,7 +29,6 @@
 
 static int _verbose_level = VERBOSE_BASE_LEVEL;
 static int _test = 0;
-static int _partial = 0;
 static int _md_filtering = 0;
 static int _pvmove = 0;
 static int _full_scan_done = 0;	/* Restrict to one full scan during each cmd */
@@ -154,11 +153,6 @@
 	_test = level;
 }
 
-void init_partial(int level)
-{
-	_partial = level;
-}
-
 void init_md_filtering(int level)
 {
 	_md_filtering = level;
@@ -254,11 +248,6 @@
 	return _test;
 }
 
-int partial_mode()
-{
-	return _partial;
-}
-
 int md_filtering()
 {
 	return _md_filtering;
--- LVM2/lib/log/log.h	2008/06/06 19:28:34	1.41
+++ LVM2/lib/log/log.h	2008/09/19 06:41:59	1.42
@@ -64,7 +64,6 @@
 
 void init_verbose(int level);
 void init_test(int level);
-void init_partial(int level);
 void init_md_filtering(int level);
 void init_pvmove(int level);
 void init_full_scan_done(int level);
@@ -84,7 +83,6 @@
 void set_cmd_name(const char *cmd_name);
 
 int test_mode(void);
-int partial_mode(void);
 int md_filtering(void);
 int pvmove_mode(void);
 int full_scan_done(void);
--- LVM2/lib/metadata/metadata-exported.h	2008/09/19 04:27:27	1.52
+++ LVM2/lib/metadata/metadata-exported.h	2008/09/19 06:41:59	1.53
@@ -71,6 +71,13 @@
 //#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 a real flag, reserved for
+//					       temporary use inside vg_read. */
+
 #define LVM_READ              	0x00000100U	/* LV VG */
 #define LVM_WRITE             	0x00000200U	/* LV VG */
 #define CLUSTERED         	0x00000400U	/* VG */
@@ -564,6 +571,7 @@
 uint32_t pv_pe_count(const pv_t *pv);
 uint32_t pv_pe_alloc_count(const pv_t *pv);
 
+int vg_missing_pv_count(const vg_t *vg);
 uint32_t vg_status(const vg_t *vg);
 #define vg_is_clustered(vg) (vg_status((vg)) & CLUSTERED)
 
--- LVM2/lib/metadata/metadata.c	2008/09/19 05:33:36	1.190
+++ LVM2/lib/metadata/metadata.c	2008/09/19 06:41:59	1.191
@@ -334,9 +334,9 @@
 	struct pv_list *pvl;
 	int ret = 1;
 
-	if (!vg || !consistent || (vg_status(vg) & PARTIAL_VG)) {
-		log_error("Volume group \"%s\" not found or inconsistent.",
-			  vg_name);
+	if (!vg || !consistent || vg_missing_pv_count(vg)) {
+		log_error("Volume group \"%s\" not found, is inconsistent "
+			  "or has PVs missing.", vg_name);
 		log_error("Consider vgreduce --removemissing if metadata "
 			  "is inconsistent.");
 		return 0;
@@ -488,19 +488,15 @@
 	struct volume_group *vg;
 	struct dm_pool *mem = cmd->mem;
 	int consistent = 0;
-	int old_partial;
 
 	if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
 		return_NULL;
 
 	/* is this vg name already in use ? */
-	old_partial = partial_mode();
-	init_partial(1);
 	if (vg_read(cmd, vg_name, NULL, &consistent)) {
 		log_err("A volume group called '%s' already exists.", vg_name);
 		goto bad;
 	}
-	init_partial(old_partial);
 
 	if (!id_create(&vg->id)) {
 		log_err("Couldn't create uuid for volume group '%s'.", vg_name);
@@ -1191,6 +1187,157 @@
 	return 1;
 }
 
+struct _lv_postorder_baton {
+	int (*fn)(struct logical_volume *lv, void *data);
+	void *data;
+};
+
+static int _lv_postorder_visit(struct logical_volume *,
+			       int (*fn)(struct logical_volume *lv, void *data),
+			       void *data);
+
+static int _lv_postorder_level(struct logical_volume *lv, void *data)
+{
+	struct _lv_postorder_baton *baton = data;
+	int r =_lv_postorder_visit(lv, baton->fn, baton->data);
+	lv->status |= POSTORDER_FLAG;
+	return r;
+};
+
+static int _lv_each_dependency(struct logical_volume *lv,
+			       int (*fn)(struct logical_volume *lv, void *data),
+			       void *data)
+{
+	int i, s;
+	struct lv_segment *lvseg;
+
+	struct logical_volume *deps[] = {
+		lv->snapshot ? lv->snapshot->origin : 0,
+		lv->snapshot ? lv->snapshot->cow : 0 };
+	for (i = 0; i < sizeof(deps) / sizeof(*deps); ++i) {
+		if (deps[i] && !fn(deps[i], data))
+			return_0;
+	}
+
+	list_iterate_items(lvseg, &lv->segments) {
+		if (lvseg->log_lv && !fn(lvseg->log_lv, data))
+			return_0;
+		for (s = 0; s < lvseg->area_count; ++s) {
+			if (seg_type(lvseg, s) == AREA_LV && !fn(seg_lv(lvseg,s), data))
+				return_0;
+		}
+	}
+	return 1;
+}
+
+static int _lv_postorder_cleanup(struct logical_volume *lv, void *data)
+{
+	if (!(lv->status & POSTORDER_FLAG))
+		return 1;
+	lv->status &= ~POSTORDER_FLAG;
+
+	if (!_lv_each_dependency(lv, _lv_postorder_cleanup, data))
+		return_0;
+	return 1;
+}
+
+static int _lv_postorder_visit(struct logical_volume *lv,
+			       int (*fn)(struct logical_volume *lv, void *data),
+			       void *data)
+{
+	struct _lv_postorder_baton baton;
+	int r;
+
+	if (lv->status & POSTORDER_FLAG)
+		return 1;
+
+	baton.fn = fn;
+	baton.data = data;
+	r = _lv_each_dependency(lv, _lv_postorder_level, &baton);
+	if (r) {
+		r = fn(lv, data);
+		log_verbose("visited %s", lv->name);
+	}
+	return r;
+}
+
+/*
+ * This will walk the LV dependency graph in depth-first order and in the
+ * postorder, call a callback function "fn". The void *data is passed along all
+ * the calls. The callback may return zero to indicate an error and terminate
+ * the depth-first walk. The error is propagated to return value of
+ * _lv_postorder.
+ */
+static int _lv_postorder(struct logical_volume *lv,
+			       int (*fn)(struct logical_volume *lv, void *data),
+			       void *data)
+{
+	int r;
+	r = _lv_postorder_visit(lv, fn, data);
+	_lv_postorder_cleanup(lv, 0);
+	return r;
+}
+
+struct _lv_mark_if_partial_baton {
+	int partial;
+};
+
+static int _lv_mark_if_partial_collect(struct logical_volume *lv, void *data)
+{
+	struct _lv_mark_if_partial_baton *baton = data;
+	if (lv->status & PARTIAL_LV)
+		baton->partial = 1;
+
+	return 1;
+}
+
+static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data)
+{
+	int s;
+	struct _lv_mark_if_partial_baton baton;
+	struct lv_segment *lvseg;
+
+	list_iterate_items(lvseg, &lv->segments) {
+		for (s = 0; s < lvseg->area_count; ++s) {
+			if (seg_type(lvseg, s) == AREA_PV) {
+				if (seg_pv(lvseg, s)->status & MISSING_PV)
+					lv->status |= PARTIAL_LV;
+			}
+		}
+	}
+
+	baton.partial = 0;
+	_lv_each_dependency(lv, _lv_mark_if_partial_collect, &baton);
+
+	if (baton.partial)
+		lv->status |= PARTIAL_LV;
+
+	return 1;
+}
+
+static int _lv_mark_if_partial(struct logical_volume *lv)
+{
+	return _lv_postorder(lv, _lv_mark_if_partial_single, NULL);
+}
+
+/*
+ * Mark LVs with missing PVs using PARTIAL_LV status flag. The flag is
+ * propagated transitively, so LVs referencing other LVs are marked
+ * partial as well, if any of their referenced LVs are marked partial.
+ */
+static int _vg_mark_partial_lvs(struct volume_group *vg)
+{
+	struct logical_volume *lv;
+	struct lv_list *lvl;
+
+	list_iterate_items(lvl, &vg->lvs) {
+		lv = lvl->lv;
+		if (!_lv_mark_if_partial(lv))
+			return_0;
+	}
+	return 1;
+}
+
 int vg_validate(struct volume_group *vg)
 {
 	struct pv_list *pvl, *pvl2;
@@ -1295,8 +1442,13 @@
 		return_0;
 
 	if (vg->status & PARTIAL_VG) {
-		log_error("Cannot change metadata for partial volume group %s",
-			  vg->name);
+		log_error("Cannot update partial volume group %s.", vg->name);
+		return 0;
+	}
+
+	if (vg_missing_pv_count(vg) && !vg->cmd->handles_missing_pvs) {
+		log_error("Cannot update volume group %s while physical "
+			  "volumes are missing.", vg->name);
 		return 0;
 	}
 
@@ -1495,9 +1647,20 @@
 	return 1;
 }
 
+int vg_missing_pv_count(const vg_t *vg)
+{
+	int ret = 0;
+	struct pv_list *pvl;
+	list_iterate_items(pvl, &vg->pvs) {
+		if (pvl->pv->status & MISSING_PV)
+			++ ret;
+	}
+	return ret;
+}
+
 /* Caller sets consistent to 1 if it's safe for vg_read to correct
  * inconsistent metadata on disk (i.e. the VG write lock is held).
- * This guarantees only consistent metadata is returned unless PARTIAL_VG.
+ * This guarantees only consistent metadata is returned.
  * If consistent is 0, caller must check whether consistent == 1 on return
  * and take appropriate action if it isn't (e.g. abort; get write lock
  * and call vg_read again).
@@ -1536,6 +1699,11 @@
 	}
 
 	if ((correct_vg = lvmcache_get_vg(vgid, precommitted))) {
+		if (vg_missing_pv_count(correct_vg)) {
+			log_verbose("There are %d physical volumes missing.",
+				    vg_missing_pv_count(correct_vg));
+			_vg_mark_partial_lvs(correct_vg);
+		}
 		*consistent = 1;
 		return correct_vg;
 	}
@@ -1631,7 +1799,8 @@
 			}
 		}
 
-		if (list_size(&correct_vg->pvs) != list_size(pvids)) {
+		if (list_size(&correct_vg->pvs) != list_size(pvids)
+		    + vg_missing_pv_count(correct_vg)) {
 			log_debug("Cached VG %s had incorrect PV list",
 				  vgname);
 
@@ -1640,6 +1809,8 @@
 			else
 				correct_vg = NULL;
 		} else list_iterate_items(pvl, &correct_vg->pvs) {
+			if (pvl->pv->status & MISSING_PV)
+				continue;
 			if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
 				log_debug("Cached VG %s had incorrect PV list",
 					  vgname);
@@ -1722,15 +1893,6 @@
 		if (!*consistent)
 			return correct_vg;
 
-		/* Don't touch partial volume group metadata */
-		/* Should be fixed manually with vgcfgbackup/restore etc. */
-		if ((correct_vg->status & PARTIAL_VG)) {
-			log_error("Inconsistent metadata copies found for "
-				  "partial volume group %s", vgname);
-			*consistent = 0;
-			return correct_vg;
-		}
-
 		/* Don't touch if vgids didn't match */
 		if (inconsistent_vgid) {
 			log_error("Inconsistent metadata UUIDs found for "
@@ -1769,6 +1931,12 @@
 		}
 	}
 
+	if (vg_missing_pv_count(correct_vg)) {
+		log_verbose("There are %d physical volumes missing.",
+			    vg_missing_pv_count(correct_vg));
+		_vg_mark_partial_lvs(correct_vg);
+	}
+
 	if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
 		log_error("WARNING: Interrupted pvmove detected in "
 			  "volume group %s", correct_vg->name);
@@ -1828,11 +1996,10 @@
 		if ((vg = _vg_read(cmd, NULL, vgid,
 				   &consistent, precommitted)) &&
 		    !strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
+
 			if (!consistent) {
 				log_error("Volume group %s metadata is "
 					  "inconsistent", vg->name);
-				if (!partial_mode())
-					return NULL;
 			}
 			return vg;
 		}
@@ -1860,6 +2027,7 @@
 		if ((vg = _vg_read(cmd, vgname, vgid, &consistent,
 				   precommitted)) &&
 		    !strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
+
 			if (!consistent) {
 				log_error("Volume group %s metadata is "
 					  "inconsistent", vgname);
@@ -1993,7 +2161,6 @@
 	struct list *vgids;
 	struct volume_group *vg;
 	int consistent = 0;
-	int old_partial;
 	int old_pvmove;
 
 	lvmcache_label_scan(cmd, 0);
@@ -2015,9 +2182,7 @@
 
 	/* Read every VG to ensure cache consistency */
 	/* Orphan VG is last on list */
-	old_partial = partial_mode();
 	old_pvmove = pvmove_mode();
-	init_partial(1);
 	init_pvmove(1);
 	list_iterate_items(strl, vgids) {
 		vgid = strl->str;
@@ -2042,7 +2207,6 @@
 				list_add(results, pvh);
 	}
 	init_pvmove(old_pvmove);
-	init_partial(old_partial);
 
 	if (pvslist)
 		*pvslist = results;
--- LVM2/lib/metadata/metadata.h	2008/09/19 04:28:58	1.181
+++ LVM2/lib/metadata/metadata.h	2008/09/19 06:41:59	1.182
@@ -61,6 +61,14 @@
 //#define MIRROR_NOTSYNCED	0x00080000U	/* LV */
 #define ACTIVATE_EXCL		0x00100000U	/* LV - internal use only */
 #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 a real flag, reserved for
+					       temporary use inside vg_read. */
 
 //#define LVM_READ              	0x00000100U	/* LV VG */
 //#define LVM_WRITE             	0x00000200U	/* LV VG */
--- LVM2/lib/report/report.c	2008/06/25 16:52:27	1.87
+++ LVM2/lib/report/report.c	2008/09/19 06:41:59	1.88
@@ -439,7 +439,7 @@
 	else
 		repstr[2] = '-';
 
-	if (vg->status & PARTIAL_VG)
+	if (vg_missing_pv_count(vg))
 		repstr[3] = 'p';
 	else
 		repstr[3] = '-';
--- LVM2/man/lvm.conf.5	2008/04/10 18:50:02	1.22
+++ LVM2/man/lvm.conf.5	2008/09/19 06:41:59	1.23
@@ -300,12 +300,16 @@
 .TP
 \fBactivation\fP \(em Settings affecting device-mapper activation
 .IP
-\fBmissing_stripe_filler\fP \(em When activating an incomplete
-logical volume in partial mode, this missing data is replaced
-with this device.  It could perhaps be a block device that always
-returns an error when it is accessed, or one that always
-returns zeros.  See \fBlvcreate\fP (8) for how to create
-such devices.
+\fBmissing_stripe_filler\fP \(em When activating an incomplete logical
+volume in partial mode, this option dictates how the missing data is
+replaced.  A value of "error" will cause activation to create error
+mappings for the missing data, meaning that read access to missing
+portions of the volume will result in I/O errors. You can instead also
+use a device path, and in that case this device will be used in place of
+missing stripes. However, note that using anything other than
+"error" with mirrored or snapshotted volumes is likely to result in data
+corruption.  For instructions on how to create a device that always
+returns zeros, see \fBlvcreate\fP (8).
 .IP
 \fBmirror_region_size\fP \(em Unit size in KB for copy operations
 when mirroring.
--- LVM2/man/vgreduce.8	2003/01/17 21:04:26	1.3
+++ LVM2/man/vgreduce.8	2008/09/19 06:41:59	1.4
@@ -18,11 +18,13 @@
 Removes all empty physical volumes if none are given on command line.
 .TP
 .I \-\-removemissing
-Removes all missing physical volumes from the volume group and makes 
-the volume group consistent again.  
+Removes all missing physical volumes from the volume group, if there are no
+logical volumes allocated on those. This resumes normal operation of the volume
+group (new logical volumes may again be created, changed and so on).
 
-It's a good idea to run this option with --test first to find out what it 
-would remove before running it for real.  
+If this is not possible (there are logical volumes referencing the missing
+physical volumes) and you cannot or do not want to remove them manually, you
+can run this option with --force to have vgreduce remove any partial LVs.
 
 Any logical volumes and dependent snapshots that were partly on the 
 missing disks get removed completely. This includes those parts 
--- LVM2/tools/commands.h	2008/06/24 22:48:53	1.118
+++ LVM2/tools/commands.h	2008/09/19 06:42:00	1.119
@@ -850,13 +850,15 @@
    "\t[-h|--help]\n"
    "\t[--mirrorsonly]\n"
    "\t[--removemissing]\n"
+   "\t[-f|--force]\n"
    "\t[-t|--test]\n"
    "\t[-v|--verbose]\n"
    "\t[--version]" "\n"
    "\tVolumeGroupName\n"
    "\t[PhysicalVolumePath...]\n",
 
-   all_ARG, autobackup_ARG, mirrorsonly_ARG, removemissing_ARG, test_ARG)
+   all_ARG, autobackup_ARG, mirrorsonly_ARG, removemissing_ARG,
+   force_ARG, test_ARG)
 
 xx(vgremove,
    "Remove volume group(s)",
--- LVM2/tools/lvmcmdline.c	2008/08/01 19:51:27	1.69
+++ LVM2/tools/lvmcmdline.c	2008/09/19 06:42:00	1.70
@@ -710,13 +710,13 @@
 	cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
 	cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
 	cmd->current_settings.cache_vgmetadata = cmd->command->flags & CACHE_VGMETADATA ? 1 : 0;
+	cmd->partial_activate = 0;
 
 	if (arg_count(cmd, partial_ARG)) {
-		init_partial(1);
+		cmd->partial_activate = 1;
 		log_print("Partial mode. Incomplete volume groups will "
 			  "be activated read-only.");
-	} else
-		init_partial(0);
+	}
 
 	if (arg_count(cmd, ignorelockingfailure_ARG))
 		init_ignorelockingfailure(1);
@@ -826,6 +826,7 @@
 
 	cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG,
 				 cmd->current_settings.fmt);
+	cmd->handles_missing_pvs = 0;
 }
 
 static char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
--- LVM2/tools/lvremove.c	2008/01/30 14:00:02	1.54
+++ LVM2/tools/lvremove.c	2008/09/19 06:42:00	1.55
@@ -31,6 +31,8 @@
 		return EINVALID_CMD_LINE;
 	}
 
+	cmd->handles_missing_pvs = 1;
+
 	return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL,
 			       &lvremove_single);
 }
--- LVM2/tools/pvcreate.c	2008/07/29 21:05:20	1.74
+++ LVM2/tools/pvcreate.c	2008/09/19 06:42:00	1.75
@@ -49,7 +49,6 @@
 	/* FIXME Check partition type is LVM unless --force is given */
 
 	/* Is there a pv here already? */
-	/* FIXME Use partial mode here? */
 	pv = pv_read(cmd, name, NULL, NULL, 0);
 
 	/*
@@ -272,13 +271,11 @@
 	if (arg_count(cmd, restorefile_ARG)) {
 		pp->restorefile = arg_str_value(cmd, restorefile_ARG, "");
 		/* The uuid won't already exist */
-		init_partial(1);
 		if (!(vg = backup_read_vg(cmd, NULL, pp->restorefile))) {
 			log_error("Unable to read volume group from %s",
 				  pp->restorefile);
 			return 0;
 		}
-		init_partial(0);
 		if (!(existing_pv = find_pv_in_vg_by_uuid(vg, pp->idp))) {
 			log_error("Can't find uuid %s in backup file %s",
 				  uuid, pp->restorefile);
--- LVM2/tools/vgcfgbackup.c	2008/08/13 12:44:24	1.25
+++ LVM2/tools/vgcfgbackup.c	2008/09/19 06:42:00	1.26
@@ -96,8 +96,7 @@
 	int ret;
 	char *last_filename = NULL;
 
-	if (partial_mode())
-		init_pvmove(1);
+	init_pvmove(1);
 
 	ret = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, &last_filename,
 			      &vg_backup_single);
--- LVM2/tools/vgreduce.c	2008/09/19 03:45:34	1.82
+++ LVM2/tools/vgreduce.c	2008/09/19 06:42:00	1.83
@@ -16,7 +16,7 @@
 #include "tools.h"
 #include "lv_alloc.h"
 
-static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
+static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
 {
 	char uuid[64] __attribute((aligned(8)));
 
@@ -31,8 +31,9 @@
 	log_verbose("Removing PV with UUID %s from VG %s", uuid, vg->name);
 
 	if (pvl->pv->pe_alloc_count) {
-		log_error("LVs still present on PV with UUID %s: Can't remove "
-			  "from VG %s", uuid, vg->name);
+		if (!silent)
+			log_error("LVs still present on PV with UUID %s: "
+				  "Can't remove from VG %s", uuid, vg->name);
 		return 0;
 	}
 
@@ -130,11 +131,39 @@
 	return 1;
 }
 
+static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
+{
+	struct pv_list *pvl;
+	struct lv_list *lvl;
+	int r = 1;
+
+	list_iterate_items(lvl, &vg->lvs)
+		if (lvl->lv->status & PARTIAL_LV) {
+			log_warn("WARNING: Partial LV %s needs to be repaired "
+				 "or removed. ", lvl->lv->name);
+			r = 0;
+		}
+
+	if (!r) {
+		cmd->handles_missing_pvs = 1;
+		log_warn("WARNING: There are still partial LVs in VG %s.", vg->name);
+		log_warn("To remove them unconditionally use: vgreduce --removemissing --force.");
+		log_warn("Proceeding to remove empty missing PVs.");
+	}
+
+	list_iterate_items(pvl, &vg->pvs) {
+		if (pvl->pv->dev && !(pvl->pv->status & MISSING_PV))
+			continue;
+		if (r && !_remove_pv(vg, pvl, 0))
+			return_0;
+	}
+
+	return r;
+}
+
 static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
 {
-	struct list *pvh, *pvht;
 	struct list *lvh, *lvht;
-	struct pv_list *pvl;
 	struct lv_list *lvl, *lvl2, *lvlt;
 	struct logical_volume *lv;
 	struct physical_volume *pv;
@@ -182,20 +211,8 @@
 		return 0;
 	}
 
-	/* Remove missing PVs */
-	list_iterate_safe(pvh, pvht, &vg->pvs) {
-		pvl = list_item(pvh, struct pv_list);
-		if (pvl->pv->dev)
-			continue;
-		if (!_remove_pv(vg, pvl))
-			return_0;
-	}
-
-	/* VG is now consistent */
-	vg->status &= ~PARTIAL_VG;
-	vg->status |= LVM_WRITE;
-
-	init_partial(0);
+	if (!_consolidate_vg(cmd, vg))
+		return_0;
 
 	/* FIXME Recovery.  For now people must clean up by hand. */
 
@@ -208,14 +225,11 @@
 
 		if (!test_mode()) {
 			/* Suspend lvs_changed */
-			init_partial(1);
 			if (!suspend_lvs(cmd, &lvs_changed)) {
 				stack;
-				init_partial(0);
 				vg_revert(vg);
 				return 0;
 			}
-			init_partial(0);
 		}
 
 		if (!vg_commit(vg)) {
@@ -439,26 +453,26 @@
 	char *vg_name;
 	int ret = 1;
 	int consistent = 1;
+	int fixed = 1;
+	int repairing = arg_count(cmd, removemissing_ARG);
 
-	if (!argc && !arg_count(cmd, removemissing_ARG)) {
+	if (!argc && !repairing) {
 		log_error("Please give volume group name and "
 			  "physical volume paths");
 		return EINVALID_CMD_LINE;
 	}
-
-	if (!argc && arg_count(cmd, removemissing_ARG)) {
+	
+	if (!argc && repairing) {
 		log_error("Please give volume group name");
 		return EINVALID_CMD_LINE;
 	}
 
-	if (arg_count(cmd, mirrorsonly_ARG) &&
-	    !arg_count(cmd, removemissing_ARG)) {
+	if (arg_count(cmd, mirrorsonly_ARG) && !repairing) {
 		log_error("--mirrorsonly requires --removemissing");
 		return EINVALID_CMD_LINE;
 	}
 
-	if (argc == 1 && !arg_count(cmd, all_ARG)
-	    && !arg_count(cmd, removemissing_ARG)) {
+	if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) {
 		log_error("Please enter physical volume paths or option -a");
 		return EINVALID_CMD_LINE;
 	}
@@ -469,7 +483,7 @@
 		return EINVALID_CMD_LINE;
 	}
 
-	if (argc > 1 && arg_count(cmd, removemissing_ARG)) {
+	if (argc > 1 && repairing) {
 		log_error("Please only specify the volume group");
 		return EINVALID_CMD_LINE;
 	}
@@ -490,8 +504,8 @@
 		return ECMD_FAILED;
 	}
 
-	if ((!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent) &&
-	    !arg_count(cmd, removemissing_ARG)) {
+	if ((!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent)
+	    && !repairing) {
 		log_error("Volume group \"%s\" doesn't exist", vg_name);
 		unlock_vg(cmd, vg_name);
 		return ECMD_FAILED;
@@ -502,16 +516,15 @@
 		return ECMD_FAILED;
 	}
 
-	if (arg_count(cmd, removemissing_ARG)) {
-		if (vg && consistent) {
+	if (repairing) {
+		if (vg && consistent && !vg_missing_pv_count(vg)) {
 			log_error("Volume group \"%s\" is already consistent",
 				  vg_name);
 			unlock_vg(cmd, vg_name);
 			return ECMD_PROCESSED;
 		}
 
-		init_partial(1);
-		consistent = 0;
+		consistent = !arg_count(cmd, force_ARG);
 		if (!(vg = vg_read(cmd, vg_name, NULL, &consistent))) {
 			log_error("Volume group \"%s\" not found", vg_name);
 			unlock_vg(cmd, vg_name);
@@ -522,16 +535,17 @@
 			return ECMD_FAILED;
 		}
 		if (!archive(vg)) {
-			init_partial(0);
 			unlock_vg(cmd, vg_name);
 			return ECMD_FAILED;
 		}
 
-		if (!_make_vg_consistent(cmd, vg)) {
-			init_partial(0);
-			unlock_vg(cmd, vg_name);
-			return ECMD_FAILED;
-		}
+		if (arg_count(cmd, force_ARG)) {
+			if (!_make_vg_consistent(cmd, vg)) {
+				unlock_vg(cmd, vg_name);
+				return ECMD_FAILED;
+			}
+		} else
+			fixed = _consolidate_vg(cmd, vg);
 
 		if (!vg_write(vg) || !vg_commit(vg)) {
 			log_error("Failed to write out a consistent VG for %s",
@@ -542,7 +556,9 @@
 
 		backup(vg);
 
-		log_print("Wrote out consistent volume group %s", vg_name);
+		if (fixed)
+			log_print("Wrote out consistent volume group %s",
+				  vg_name);
 
 	} else {
 		if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG)) {



             reply	other threads:[~2008-09-19  6:42 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-09-19  6:42 agk [this message]
  -- strict thread matches above, loose matches on Subject: below --
2012-01-20  0:27 LVM2 ./WHATS_NEW daemons/clvmd/lvm-functions.c jbrassow
2011-12-08 21:24 agk
2011-09-27 22:43 agk
2011-08-10 20:25 zkabelac
2011-02-18 14:16 zkabelac
2011-02-18  0:36 jbrassow
2011-02-04 20:30 jbrassow
2011-02-03 16:03 zkabelac
2011-02-03  1:58 zkabelac
2010-12-08 20:51 agk
2010-11-23  1:56 agk
2010-03-26 15:40 snitzer
2010-03-23 22:30 snitzer
2010-01-19 13:25 mbroz
2010-01-05 16:09 mbroz
2010-01-05 16:06 mbroz
2010-01-05 16:03 mbroz
2009-11-23 10:44 mbroz
2009-07-24 18:15 agk
2009-07-16  0:37 agk
2009-07-15 23:57 agk
2009-07-13 19:49 agk
2009-06-12  8:30 mbroz
2009-02-22 21:14 agk
2009-01-26 19:01 agk
2007-08-07  9:06 meyering
2007-01-25 14:37 agk
2007-01-23 15:58 agk
2007-01-19 22:21 agk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080919064205.16217.qmail@sourceware.org \
    --to=agk@sourceware.org \
    --cc=lvm-devel@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.