mrc0mmand / rpms / lvm2

Forked from rpms/lvm2 2 years ago
Clone

Blame SOURCES/lvm2-2_02_106-additional-lvmetad-fixes.patch

4c7ee1
commit 923b95504e189fb3b9353a66a3c3a9e147a46e39
4c7ee1
Author: Peter Rajnoha <prajnoha@redhat.com>
4c7ee1
Date:   Wed Mar 5 16:48:17 2014 +0100
4c7ee1
4c7ee1
    lvmetad_fixes
4c7ee1
---
4c7ee1
 WHATS_NEW                       |  3 +++
4c7ee1
 daemons/lvmetad/lvmetad-core.c  | 20 +++++++++++++++++---
4c7ee1
 test/shell/lvmetad-ambiguous.sh | 34 ++++++++++++++++++++++++++++++++++
4c7ee1
 3 files changed, 54 insertions(+), 3 deletions(-)
4c7ee1
4c7ee1
diff --git a/WHATS_NEW b/WHATS_NEW
4c7ee1
index 224e351..3ee9585 100644
4c7ee1
--- a/WHATS_NEW
4c7ee1
+++ b/WHATS_NEW
4c7ee1
@@ -1,5 +1,8 @@
4c7ee1
 Version 2.02.106 - 
4c7ee1
 ====================================
4c7ee1
+  Fix cache consistency in lvmetad when PV moves around.
4c7ee1
+  Fix memleak when lvmetad discovers PV to appear on another device.
4c7ee1
+  Fix invalid memory read in lvmetad that could cause a deadlock.
4c7ee1
   Fix calculation of maximum size of COW device for snapshot (2.02.99).
4c7ee1
   Do not allow stripe size to be bigger then extent size for lvresize.
4c7ee1
   Zero snapshot COW header when creating read-only snapshot.
4c7ee1
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
4c7ee1
index e6e222f..f35db89 100644
4c7ee1
--- a/daemons/lvmetad/lvmetad-core.c
4c7ee1
+++ b/daemons/lvmetad/lvmetad-core.c
4c7ee1
@@ -861,7 +861,7 @@ static response pv_found(lvmetad_state *s, request r)
4c7ee1
 	const char *vgid = daemon_request_str(r, "metadata/id", NULL);
4c7ee1
 	const char *vgid_old = NULL;
4c7ee1
 	struct dm_config_node *pvmeta = dm_config_find_node(r.cft->root, "pvmeta");
4c7ee1
-	uint64_t device;
4c7ee1
+	uint64_t device, device_old_pvid = 0;
4c7ee1
 	struct dm_config_tree *cft, *pvmeta_old_dev = NULL, *pvmeta_old_pvid = NULL;
4c7ee1
 	char *old;
4c7ee1
 	char *pvid_dup;
4c7ee1
@@ -883,9 +883,12 @@ static response pv_found(lvmetad_state *s, request r)
4c7ee1
 		dm_hash_remove(s->pvid_to_pvmeta, old);
4c7ee1
 		vgid_old = dm_hash_lookup(s->pvid_to_vgid, old);
4c7ee1
 	}
4c7ee1
-	pvmeta_old_pvid = dm_hash_lookup(s->pvid_to_pvmeta, pvid);
4c7ee1
 
4c7ee1
-	DEBUGLOG(s, "pv_found %s, vgid = %s, device = %" PRIu64 ", old = %s", pvid, vgid, device, old);
4c7ee1
+	if ((pvmeta_old_pvid = dm_hash_lookup(s->pvid_to_pvmeta, pvid)))
4c7ee1
+		dm_config_get_uint64(pvmeta_old_pvid->root, "pvmeta/device", &device_old_pvid);
4c7ee1
+
4c7ee1
+	DEBUGLOG(s, "pv_found %s, vgid = %s, device = %" PRIu64 " (previously %" PRIu64 "), old = %s",
4c7ee1
+		 pvid, vgid, device, device_old_pvid, old);
4c7ee1
 
4c7ee1
 	dm_free(old);
4c7ee1
 
4c7ee1
@@ -903,6 +906,12 @@ static response pv_found(lvmetad_state *s, request r)
4c7ee1
 		return reply_fail("out of memory");
4c7ee1
 	}
4c7ee1
 
4c7ee1
+	if (pvmeta_old_pvid && device != device_old_pvid) {
4c7ee1
+		DEBUGLOG(s, "pv %s no longer on device %" PRIu64, pvid, device_old_pvid);
4c7ee1
+		dm_free(dm_hash_lookup_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid)));
4c7ee1
+		dm_hash_remove_binary(s->device_to_pvid, &device_old_pvid, sizeof(device_old_pvid));
4c7ee1
+	}
4c7ee1
+
4c7ee1
 	if (!dm_hash_insert(s->pvid_to_pvmeta, pvid, cft) ||
4c7ee1
 	    !dm_hash_insert_binary(s->device_to_pvid, &device, sizeof(device), (void*)pvid_dup)) {
4c7ee1
 		dm_hash_remove(s->pvid_to_pvmeta, pvid);
4c7ee1
@@ -911,6 +920,7 @@ static response pv_found(lvmetad_state *s, request r)
4c7ee1
 		dm_free(pvid_dup);
4c7ee1
 		return reply_fail("out of memory");
4c7ee1
 	}
4c7ee1
+
4c7ee1
 	if (pvmeta_old_pvid)
4c7ee1
 		dm_config_destroy(pvmeta_old_pvid);
4c7ee1
 	if (pvmeta_old_dev && pvmeta_old_dev != pvmeta_old_pvid)
4c7ee1
@@ -949,9 +959,13 @@ static response pv_found(lvmetad_state *s, request r)
4c7ee1
 	}
4c7ee1
 
4c7ee1
 	if (vgid_old && (!vgid || strcmp(vgid, vgid_old))) {
4c7ee1
+		/* make a copy, because vg_remove_if_missing will deallocate the
4c7ee1
+		 * storage behind vgid_old */
4c7ee1
+		vgid_old = dm_strdup(vgid_old);
4c7ee1
 		lock_vg(s, vgid_old);
4c7ee1
 		vg_remove_if_missing(s, vgid_old, 1);
4c7ee1
 		unlock_vg(s, vgid_old);
4c7ee1
+		dm_free((char*)vgid_old);
4c7ee1
 	}
4c7ee1
 
4c7ee1
 	return daemon_reply_simple("OK",
4c7ee1
diff --git a/test/shell/lvmetad-ambiguous.sh b/test/shell/lvmetad-ambiguous.sh
4c7ee1
new file mode 100644
4c7ee1
index 0000000..455aa5d
4c7ee1
--- /dev/null
4c7ee1
+++ b/test/shell/lvmetad-ambiguous.sh
4c7ee1
@@ -0,0 +1,34 @@
4c7ee1
+#!/bin/sh
4c7ee1
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
4c7ee1
+#
4c7ee1
+# This copyrighted material is made available to anyone wishing to use,
4c7ee1
+# modify, copy, or redistribute it subject to the terms and conditions
4c7ee1
+# of the GNU General Public License v.2.
4c7ee1
+#
4c7ee1
+# You should have received a copy of the GNU General Public License
4c7ee1
+# along with this program; if not, write to the Free Software Foundation,
4c7ee1
+# Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
4c7ee1
+
4c7ee1
+. lib/test
4c7ee1
+
4c7ee1
+test -e LOCAL_LVMETAD || skip
4c7ee1
+
4c7ee1
+aux prepare_pvs 2
4c7ee1
+
4c7ee1
+# flip the devices around
4c7ee1
+aux init_udev_transaction
4c7ee1
+dmsetup remove -f "$dev1"
4c7ee1
+dmsetup remove -f "$dev2"
4c7ee1
+dmsetup create -u TEST-${PREFIX}pv2 ${PREFIX}pv2 ${PREFIX}pv2.table
4c7ee1
+dmsetup create -u TEST-${PREFIX}pv1 ${PREFIX}pv1 ${PREFIX}pv1.table
4c7ee1
+aux finish_udev_transaction
4c7ee1
+
4c7ee1
+# re-scan them
4c7ee1
+pvscan --cache $dev1
4c7ee1
+pvscan --cache $dev2
4c7ee1
+
4c7ee1
+# expect both to be there
4c7ee1
+pvs | tee pvs.txt
4c7ee1
+grep $dev1 pvs.txt
4c7ee1
+grep $dev2 pvs.txt
4c7ee1
+