diff mbox

multipath-tools: prevent unexpected swapping of underlying LUNs

Message ID 502E0387.5070808@ce.jp.nec.com (mailing list archive)
State Deferred, archived
Headers show

Commit Message

Junichi Nomura Aug. 17, 2012, 8:40 a.m. UTC
When you want to rename a multipath device
but the new alias is already used by other multipath device,
multipath-tools mistakenly reload a table for the original multipath device
to the other multipath device.
That could lead to very bad result, such as I/O error and data corruption.

This patch checks such a condition and gives up renaming with error log.

For example, suppose you have following 'bindings' file:
   
   # cat /etc/multipath/bindings 
   mpatha 212140084abcd0000
   mpathb 212150084abcd0000

and a logical volume 'VG/LV0' on top of mpathb,
which is on top of /dev/sde(8:64) and /dev/sdk(8:160):

   # dmsetup ls --tree
   mpatha (253:1)
    ?? (8:144)
    ?? (8:48)
   VG-LV0 (253:2)
    ??mpathb (253:0)
       ?? (8:160)
       ?? (8:64)

Then you decide to swap their names and change the 'bindings' as follows:

   # cat /etc/multipath/bindings 
   mpathb 212140084abcd0000
   mpatha 212150084abcd0000

you'll get this after 'service multipathd reload':

   # dmsetup ls --tree
   mpatha (253:1)
    ?? (8:160)
    ?? (8:64)
   VG-LV0 (253:2)
    ??mpathb (253:0)
       ?? (8:144)
       ?? (8:48)

Now you suddenly have 'VG/LV0' on top of /dev/sdd(8:48) and /dev/sdj(8:144),
that is obviously wrong and will corrupt data if you write to 'VG/LV0'.



--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
diff mbox

Patch

diff -urpN multipath-tools.orig/libmultipath/configure.c multipath-tools.new/libmultipath/configure.c
--- multipath-tools.orig/libmultipath/configure.c	2012-07-19 15:17:40.368622358 +0900
+++ multipath-tools.new/libmultipath/configure.c	2012-08-17 17:11:07.691898774 +0900
@@ -150,12 +150,12 @@  static void
 select_action (struct multipath * mpp, vector curmp, int force_reload)
 {
 	struct multipath * cmpp;
+	struct multipath * cmpp_by_name;
 
-	cmpp = find_mp_by_alias(curmp, mpp->alias);
-
-	if (!cmpp) {
-		cmpp = find_mp_by_wwid(curmp, mpp->wwid);
+	cmpp = find_mp_by_wwid(curmp, mpp->wwid);
+	cmpp_by_name = find_mp_by_alias(curmp, mpp->alias);
 
+	if (!cmpp_by_name) {
 		if (cmpp) {
 			condlog(2, "%s: rename %s to %s", mpp->wwid,
 				cmpp->alias, mpp->alias);
@@ -169,17 +169,25 @@  select_action (struct multipath * mpp, v
 		return;
 	}
 
-	if (!find_mp_by_wwid(curmp, mpp->wwid)) {
-		condlog(2, "%s: remove (wwid changed)", cmpp->alias);
+	if (!cmpp) {
+		condlog(2, "%s: remove (wwid changed)", mpp->alias);
 		dm_flush_map(mpp->alias);
-		strncpy(cmpp->wwid, mpp->wwid, WWID_SIZE);
-		drop_multipath(curmp, cmpp->wwid, KEEP_PATHS);
+		strncpy(cmpp_by_name->wwid, mpp->wwid, WWID_SIZE);
+		drop_multipath(curmp, cmpp_by_name->wwid, KEEP_PATHS);
 		mpp->action = ACT_CREATE;
 		condlog(3, "%s: set ACT_CREATE (map wwid change)",
 			mpp->alias);
 		return;
 	}
 
+	if (cmpp != cmpp_by_name) {
+		condlog(2, "%s: unable to rename %s to %s (%s is used by %s)",
+			mpp->wwid, cmpp->alias, mpp->alias,
+			mpp->alias, cmpp_by_name->wwid);
+		mpp->action = ACT_NOTHING;
+		return;
+	}
+
 	if (pathcount(mpp, PATH_UP) == 0) {
 		mpp->action = ACT_NOTHING;
 		condlog(3, "%s: set ACT_NOTHING (no usable path)",