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

Re: [lvm-devel][PATCH] Fix segfault when using vgsplit in stacked environment



Hi,

Alasdair G Kergon <agk redhat com> writes:
> I don't think the code should be getting as far as it does in that
> situation.

(explanation for the list) After an IRC discussion, we have agreed that a
different approach would work here, specifically, that we should not allow
tools to try tinkering with VGs that have PVs missing, unless they specifically
know what they are doing. There's probably half dozen other places where we
assume that `pv->dev` is valid. The attached patch changes the meaning of
`cmd->handles_missing_pvs` somewhat: If a tool now opens a VG *for writing* but
it does not set handles_missing_pvs, vg_read will fail.

This check was previously done only in vg_write, which led to situations like
the above bug, where a little less vigorous code path trips a NULL
pointer. This behaviour change of handles_missing_pvs affects these situations:

- lvchange -a, vgchange -a take a write lock, so they need to set, for the -a
  case, handles_missing_pvs. This is safe.
- vgreduce needs to set handles_missing_pvs, since it is supposed to work in
  that situation... it previously did not need the flag in general, since it
  most of the time writes out a VG that has no PVs missing in it; however,
  since it's now needed also for opening the VG for writing, this needs to be
  always set for --removemissing; there's a small risk of bugs associated, but
  it can be mitigated by adding appropriate check to the code...

Please note that this patch depends on the "vg_read" patchset found elsewhere
on this list.

Yours,
   Petr.

Mon Feb 16 23:09:02 CET 2009  Petr Rockai <me mornfall net>
  * Refuse to open VG with MISSING_PVs for update unless handles_missing_pvs is set.
diff -rN -u -p old-lvmlib/lib/metadata/metadata.c new-lvmlib/lib/metadata/metadata.c
--- old-lvmlib/lib/metadata/metadata.c	2009-02-16 23:09:25.741274395 +0100
+++ new-lvmlib/lib/metadata/metadata.c	2009-02-16 23:09:25.797274040 +0100
@@ -2546,6 +2546,14 @@ static vg_t *_vg_lock_and_read(struct cm
 		}
 	}
 
+	if (!cmd->handles_missing_pvs && vg_missing_pv_count(vg) &&
+	    (lock_flags & LCK_WRITE)) {
+		log_error("Cannot change VG %s while PVs are missing!",
+			  vg->name);
+		failure |= FAILED_INCONSISTENT; // FIXME
+		goto_bad;
+	}
+
 	failure |= _vg_check_status(vg, status_flags & ~CLUSTERED);
 	if (failure)
 		goto_bad;
diff -rN -u -p old-lvmlib/test/t-partial-activate.sh new-lvmlib/test/t-partial-activate.sh
--- old-lvmlib/test/t-partial-activate.sh	2009-02-16 23:09:25.741274395 +0100
+++ new-lvmlib/test/t-partial-activate.sh	2009-02-16 23:09:25.833271562 +0100
@@ -10,3 +10,7 @@ disable_dev $dev1
 vgreduce --removemissing $vg
 not lvchange -v -a y $vg/mirror
 lvchange -v --partial -a y $vg/mirror
+
+# also check that vgchange works
+vgchange -a n --partial $vg
+vgchange -a y --partial $vg
diff -rN -u -p old-lvmlib/test/t-vgsplit-stacked.sh new-lvmlib/test/t-vgsplit-stacked.sh
--- old-lvmlib/test/t-vgsplit-stacked.sh	1970-01-01 01:00:00.000000000 +0100
+++ new-lvmlib/test/t-vgsplit-stacked.sh	2009-02-16 23:09:25.837272211 +0100
@@ -0,0 +1,17 @@
+. ./test-utils.sh
+
+aux prepare_devs 3
+
+pvcreate $devs
+vgcreate $vg1 $dev1 $dev2
+lvcreate -n $lv1 -l 100%FREE $vg1
+
+#top VG
+pvcreate $G_dev_/$vg1/$lv1
+vgcreate $vg $G_dev_/$vg1/$lv1 $dev3
+
+vgchange -a n $vg
+vgchange -a n $vg1
+
+# this should fail but not segfault
+not vgsplit $vg $vg1 $dev3
diff -rN -u -p old-lvmlib/tools/lvchange.c new-lvmlib/tools/lvchange.c
--- old-lvmlib/tools/lvchange.c	2009-02-16 23:09:25.741274395 +0100
+++ new-lvmlib/tools/lvchange.c	2009-02-16 23:09:25.837272211 +0100
@@ -692,15 +692,20 @@ int lvchange(struct cmd_context *cmd, in
 		return EINVALID_CMD_LINE;
 	}
 
-	if (arg_count(cmd, ignorelockingfailure_ARG) &&
-	    (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
+	int avail_only =
+	    !(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
 	     arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
 	     arg_count(cmd, addtag_ARG) || arg_count(cmd, deltag_ARG) ||
-	     arg_count(cmd, refresh_ARG) || arg_count(cmd, alloc_ARG))) {
+	     arg_count(cmd, refresh_ARG) || arg_count(cmd, alloc_ARG));
+
+	if (arg_count(cmd, ignorelockingfailure_ARG) && !avail_only) {
 		log_error("Only -a permitted with --ignorelockingfailure");
 		return EINVALID_CMD_LINE;
 	}
 
+	if (avail_only)
+		cmd->handles_missing_pvs = 1;
+
 	if (!argc) {
 		log_error("Please give logical volume path(s)");
 		return EINVALID_CMD_LINE;
diff -rN -u -p old-lvmlib/tools/vgchange.c new-lvmlib/tools/vgchange.c
--- old-lvmlib/tools/vgchange.c	2009-02-16 23:09:25.741274395 +0100
+++ new-lvmlib/tools/vgchange.c	2009-02-16 23:09:25.841274186 +0100
@@ -126,6 +126,12 @@ static int _vgchange_available(struct cm
 	int available;
 	int activate = 1;
 
+	/*
+	 * Safe, since we never write out new metadata here. Required for
+	 * partial activation to work.
+	 */
+	cmd->handles_missing_pvs = 1;
+
 	available = arg_uint_value(cmd, available_ARG, 0);
 
 	if ((available == CHANGE_AN) || (available == CHANGE_ALN))
diff -rN -u -p old-lvmlib/tools/vgreduce.c new-lvmlib/tools/vgreduce.c
--- old-lvmlib/tools/vgreduce.c	2009-02-16 23:09:25.741274395 +0100
+++ new-lvmlib/tools/vgreduce.c	2009-02-16 23:09:25.845274135 +0100
@@ -506,6 +506,9 @@ int vgreduce(struct cmd_context *cmd, in
 
 	log_verbose("Finding volume group \"%s\"", vg_name);
 
+	if (repairing)
+		cmd->handles_missing_pvs = 1;
+
 	vg = vg_read_for_update(cmd, vg_name, NULL, ALLOW_EXPORTED);
 	if (vg_read_error(vg) == FAILED_ALLOCATION ||
 	    vg_read_error(vg) == FAILED_NOTFOUND)
PS: The patch passes the testsuite and also makes Milan's testcase pass (it is
included with the patch).

-- 
Peter Rockai | me()mornfall!net | prockai()redhat!com
 http://blog.mornfall.net | http://web.mornfall.net

"In My Egotistical Opinion, most people's C programs should be
 indented six feet downward and covered with dirt."
     -- Blair P. Houghton on the subject of C program indentation

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