Your message dated Sat, 09 Aug 2014 13:08:20 +0530
with message-id <[email protected]>
and subject line Re: Bug#757508: multipath-tools: multipath segmentation Fault 
(libmultipath: update waiter handling)
has caused the Debian Bug report #757508,
regarding multipath-tools: multipath segmentation Fault (libmultipath: update 
waiter handling)
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
757508: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=757508
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: multipath-tools
Version: 0.4.9-3
Severity: important
Tags: patch
User: [email protected]
Usertags: origin-ubuntu utopic ubuntu-patch

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

In Ubuntu, the attached patch was applied to achieve the following:

[Impact]

 * Multipath can cause segmentation fault due to wrong code and can
   possibly cause user to loose access to multipath devices.

[Test Case]

 * To use multipath and wait for the problem to occur sometime (inevitable).

[Regression Potential]

 * Patch 1/4 tries to fix the issue. Patch 2/4 fixes the 1/4.
 * Patch 3/4 discovers 1/4 was no good. Patch 4/4 fixes 3/4.

 * Fix based on upstream code (96f8146) + subsequent patches.
 * Followed this code development until the issue was addressed.

[Changelog]

  * Added 0001-libmultipath-update-waiter-handling.patch (LP: #1354114)
  * Added 0002-Race-condition-when-calling-stop_waiter_thread.patch (LP: 
#1354114)
  * Added 0003-multipath-clean-up-code-for-stopping-the-waiter-thre.patch (LP: 
#1354114)
  * Added 0004-Fix-race-condition-in-stop_waiter_thread.patch (LP: #1354114)

[Fix]

Fix from upstream: 

The current 'waiter' structure accesses fields which belong
to the main 'mpp' structure, which has a totally different
lifetime.

Thanks for considering the patch.

- -- System Information:
Debian Release: jessie/sid
  APT prefers utopic-updates
  APT policy: (500, 'utopic-updates'), (500, 'utopic')
Architecture: amd64 (x86_64)

Kernel: Linux 3.13.0-32-generic (SMP w/4 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) (ignored: LC_ALL 
set to en_US.UTF-8)
Shell: /bin/sh linked to /bin/dash

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4

iQEcBAEBCgAGBQJT5SnYAAoJEAynk4KHaD/Az18IAK4yUZn8kUq69+53RiohAqoV
T2BNxVqfVGa5nWFKhDmETU3xuJZVHJFUxUdcr+JlByvd5yJdIOThVc5c3vlvaZW2
HOejXtcnqei3JEQZPmvSQ2esMfF+HANtkiMTookAL+uPDkSX9NYSnFyqzztyCGhg
Q8cGJRS3dfsO0siCN1ellc/DFv0ojW+7c+p8hN5J5++qQ7nu+7KY29oUC7ifn7wm
D+njXSZvtj3URskCIEn1eDGIfXEsAgThbVr3djeZJ0ZzMdCLat6mZ6cfwJ6rv4V6
nFE7DoIqu7YrJazOFoP0IFUg9IO0Ve+5eOLAZ8DFdykeoTgEFL8CRLcXbW7jHc0=
=neMH
-----END PGP SIGNATURE-----
diff -Nru multipath-tools-0.4.9/debian/changelog multipath-tools-0.4.9/debian/changelog
diff -Nru multipath-tools-0.4.9/debian/control multipath-tools-0.4.9/debian/control
--- multipath-tools-0.4.9/debian/control	2013-01-29 22:55:25.000000000 -0200
+++ multipath-tools-0.4.9/debian/control	2014-08-08 16:46:38.000000000 -0300
@@ -1,8 +1,7 @@
 Source: multipath-tools
 Section: admin
 Priority: extra
-Maintainer: Ubuntu Developers <[email protected]>
-XSBC-Original-Maintainer: Debian LVM Team <[email protected]>
+Maintainer: Debian LVM Team <[email protected]>
 Uploaders: Guido Günther <[email protected]>, Ritesh Raj Sarraf <[email protected]>
 Build-Depends: debhelper (>= 7.0.17ubuntu2), po-debconf, libdevmapper-dev (>= 2:1.02.20), libreadline-dev, libaio-dev
 Vcs-Git: git://git.debian.org/git/pkg-lvm/multipath-tools.git
diff -Nru multipath-tools-0.4.9/debian/patches/0001-libmultipath-update-waiter-handling.patch multipath-tools-0.4.9/debian/patches/0001-libmultipath-update-waiter-handling.patch
--- multipath-tools-0.4.9/debian/patches/0001-libmultipath-update-waiter-handling.patch	1969-12-31 21:00:00.000000000 -0300
+++ multipath-tools-0.4.9/debian/patches/0001-libmultipath-update-waiter-handling.patch	2014-08-08 16:46:23.000000000 -0300
@@ -0,0 +1,283 @@
+From afc42070233918740201b6401348e0eecfa164ed Mon Sep 17 00:00:00 2001
+From: Hannes Reinecke <[email protected]>
+Date: Mon, 4 May 2009 16:46:58 +0200
+Subject: [PATCH 1/4] libmultipath: update waiter handling
+
+The current 'waiter' structure accesses fields which belong
+to the main 'mpp' structure, which has a totally different
+lifetime. With this patch most of these dependencies are
+removed and the 'waiter' structure can run independently
+of the main 'mpp' structure, reducing the risk of
+use-after-free faults.
+
+Signed-off-by: Hannes Reinecke <[email protected]>
+---
+ libmultipath/structs.c |    7 ----
+ libmultipath/structs.h |    6 ++--
+ libmultipath/waiter.c  |   87 +++++++++++++++++++++++++++---------------------
+ libmultipath/waiter.h  |    5 ++-
+ 4 files changed, 54 insertions(+), 51 deletions(-)
+
+diff --git a/libmultipath/structs.c b/libmultipath/structs.c
+index a4b86d2..58e82e0 100644
+--- a/libmultipath/structs.c
++++ b/libmultipath/structs.c
+@@ -15,7 +15,6 @@
+ #include "debug.h"
+ #include "structs_vec.h"
+ #include "blacklist.h"
+-#include "waiter.h"
+ #include "prio.h"
+ 
+ struct path *
+@@ -175,12 +174,6 @@ free_multipath (struct multipath * mpp, int free_paths)
+ 		mpp->dmi = NULL;
+ 	}
+ 
+-	/*
+-	 * better own vecs->lock here
+-	 */
+-	if (mpp->waiter)
+-		((struct event_thread *)mpp->waiter)->mpp = NULL;
+-
+ 	free_pathvec(mpp->paths, free_paths);
+ 	free_pgvec(mpp->pg, free_paths);
+ 	FREE_PTR(mpp->mpcontext);
+diff --git a/libmultipath/structs.h b/libmultipath/structs.h
+index c559838..e6faff0 100644
+--- a/libmultipath/structs.h
++++ b/libmultipath/structs.h
+@@ -4,9 +4,9 @@
+ #include <sys/types.h>
+ 
+ #define WWID_SIZE		128
+-#define SERIAL_SIZE		64
+-#define NODE_NAME_SIZE		19
+-#define PATH_STR_SIZE  		16
++#define SERIAL_SIZE		65
++#define NODE_NAME_SIZE		65
++#define PATH_STR_SIZE		16
+ #define PARAMS_SIZE		1024
+ #define FILE_NAME_SIZE		256
+ #define CALLOUT_MAX_SIZE	128
+diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
+index 4fb2cff..0be5d21 100644
+--- a/libmultipath/waiter.c
++++ b/libmultipath/waiter.c
+@@ -28,38 +28,24 @@ struct event_thread *alloc_waiter (void)
+ 	struct event_thread *wp;
+ 
+ 	wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
++	memset(wp, 0, sizeof(struct event_thread));
++	pthread_mutex_init(&wp->lock, NULL);
+ 
+ 	return wp;
+ }
+ 
+-void free_waiter (void *data)
++void signal_waiter (void *data)
+ {
+-	sigset_t old;
+ 	struct event_thread *wp = (struct event_thread *)data;
+ 
+-	/*
+-	 * indicate in mpp that the wp is already freed storage
+-	 */
+-	block_signal(SIGHUP, &old);
+-	lock(wp->vecs->lock);
+-
+-	if (wp->mpp)
+-		/*
+-		 * be careful, mpp may already be freed -- null if so
+-		 */
+-		wp->mpp->waiter = NULL;
+-	else
+-		/*
+-		* This is OK condition during shutdown.
+-		*/
+-		condlog(3, "free_waiter, mpp freed before wp=%p (%s).", wp, wp->mapname);
+-
+-	unlock(wp->vecs->lock);
+-	pthread_sigmask(SIG_SETMASK, &old, NULL);
+-
+-	if (wp->dmt)
+-		dm_task_destroy(wp->dmt);
++	pthread_mutex_lock(&wp->lock);
++	memset(wp->mapname, 0, WWID_SIZE);
++	pthread_mutex_unlock(&wp->lock);
++}
+ 
++void free_waiter (struct event_thread *wp)
++{
++	pthread_mutex_destroy(&wp->lock);
+ 	FREE(wp);
+ }
+ 
+@@ -72,9 +58,16 @@ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ 		condlog(3, "%s: no waiter thread", mpp->alias);
+ 		return;
+ 	}
++	if (wp->thread == (pthread_t)0) {
++		condlog(3, "%s: event checker thread already stopped",
++			mpp->alias);
++		return;
++	}
+ 	thread = wp->thread;
+-	condlog(2, "%s: stop event checker thread (%lu)", wp->mapname, thread);
++	wp->thread = (pthread_t)0;
++	mpp->waiter = NULL;
+ 
++	condlog(2, "%s: stop event checker thread (%lu)", wp->mapname, thread);
+ 	pthread_kill(thread, SIGUSR1);
+ }
+ 
+@@ -96,49 +89,61 @@ static sigset_t unblock_signals(void)
+ int waiteventloop (struct event_thread *waiter)
+ {
+ 	sigset_t set;
++	struct dm_task *dmt = NULL;
+ 	int event_nr;
+ 	int r;
+ 
++	pthread_mutex_lock(&waiter->lock);
+ 	if (!waiter->event_nr)
+ 		waiter->event_nr = dm_geteventnr(waiter->mapname);
+ 
+-	if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
++	if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
+ 		condlog(0, "%s: devmap event #%i dm_task_create error",
+ 				waiter->mapname, waiter->event_nr);
++		pthread_mutex_unlock(&waiter->lock);
+ 		return 1;
+ 	}
+ 
+-	if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
++	if (!dm_task_set_name(dmt, waiter->mapname)) {
+ 		condlog(0, "%s: devmap event #%i dm_task_set_name error",
+ 				waiter->mapname, waiter->event_nr);
+-		dm_task_destroy(waiter->dmt);
++		dm_task_destroy(dmt);
++		pthread_mutex_unlock(&waiter->lock);
+ 		return 1;
+ 	}
+ 
+-	if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
++	if (waiter->event_nr && !dm_task_set_event_nr(dmt,
+ 						      waiter->event_nr)) {
+ 		condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
+ 				waiter->mapname, waiter->event_nr);
+-		dm_task_destroy(waiter->dmt);
++		dm_task_destroy(dmt);
++		pthread_mutex_unlock(&waiter->lock);
+ 		return 1;
+ 	}
++	pthread_mutex_unlock(&waiter->lock);
+ 
+-	dm_task_no_open_count(waiter->dmt);
++	dm_task_no_open_count(dmt);
+ 
+ 	/* accept wait interruption */
+ 	set = unblock_signals();
+ 
+ 	/* wait */
+-	r = dm_task_run(waiter->dmt);
++	r = dm_task_run(dmt);
+ 
+ 	/* wait is over : event or interrupt */
+ 	pthread_sigmask(SIG_SETMASK, &set, NULL);
+ 
+-	if (!r) /* wait interrupted by signal */
++	dm_task_destroy(dmt);
++
++	if (!r)	/* wait interrupted by signal */
+ 		return -1;
+ 
+-	dm_task_destroy(waiter->dmt);
+-	waiter->dmt = NULL;
++	pthread_mutex_lock(&waiter->lock);
++	if (!strlen(waiter->mapname)) {
++		/* waiter should exit */
++		pthread_mutex_unlock(&waiter->lock);
++		return -1;
++	}
+ 	waiter->event_nr++;
+ 
+ 	/*
+@@ -167,16 +172,20 @@ int waiteventloop (struct event_thread *waiter)
+ 		if (r) {
+ 			condlog(2, "%s: event checker exit",
+ 				waiter->mapname);
++			pthread_mutex_unlock(&waiter->lock);
+ 			return -1; /* stop the thread */
+ 		}
+ 
+ 		event_nr = dm_geteventnr(waiter->mapname);
+ 
+-		if (waiter->event_nr == event_nr)
++		if (waiter->event_nr == event_nr) {
++			pthread_mutex_unlock(&waiter->lock);
+ 			return 1; /* upon problem reschedule 1s later */
++		}
+ 
+ 		waiter->event_nr = event_nr;
+ 	}
++	pthread_mutex_unlock(&waiter->lock);
+ 	return -1; /* never reach there */
+ }
+ 
+@@ -188,7 +197,7 @@ void *waitevent (void *et)
+ 	mlockall(MCL_CURRENT | MCL_FUTURE);
+ 
+ 	waiter = (struct event_thread *)et;
+-	pthread_cleanup_push(free_waiter, et);
++	pthread_cleanup_push(signal_waiter, et);
+ 
+ 	block_signal(SIGUSR1, NULL);
+ 	block_signal(SIGHUP, NULL);
+@@ -202,6 +211,7 @@ void *waitevent (void *et)
+ 	}
+ 
+ 	pthread_cleanup_pop(1);
++	free_waiter(waiter);
+ 	return NULL;
+ }
+ 
+@@ -217,10 +227,11 @@ int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ 	if (!wp)
+ 		goto out;
+ 
++	pthread_mutex_lock(&wp->lock);
+ 	mpp->waiter = (void *)wp;
+ 	strncpy(wp->mapname, mpp->alias, WWID_SIZE);
+ 	wp->vecs = vecs;
+-	wp->mpp = mpp;
++	pthread_mutex_unlock(&wp->lock);
+ 
+ 	if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
+ 		condlog(0, "%s: cannot create event checker", wp->mapname);
+diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h
+index ab362d1..28a6974 100644
+--- a/libmultipath/waiter.h
++++ b/libmultipath/waiter.h
+@@ -4,16 +4,15 @@
+ extern pthread_attr_t waiter_attr;
+ 
+ struct event_thread {
+-	struct dm_task *dmt;
+ 	pthread_t thread;
++	pthread_mutex_t lock;
+ 	int event_nr;
+ 	char mapname[WWID_SIZE];
+ 	struct vectors *vecs;
+-	struct multipath *mpp;
+ };
+ 
+ struct event_thread * alloc_waiter (void);
+-void free_waiter (void *data);
++void signal_waiter (void *data);
+ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+ int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+ int waiteventloop (struct event_thread *waiter);
+-- 
+1.7.9.5
+
diff -Nru multipath-tools-0.4.9/debian/patches/0002-Race-condition-when-calling-stop_waiter_thread.patch multipath-tools-0.4.9/debian/patches/0002-Race-condition-when-calling-stop_waiter_thread.patch
--- multipath-tools-0.4.9/debian/patches/0002-Race-condition-when-calling-stop_waiter_thread.patch	1969-12-31 21:00:00.000000000 -0300
+++ multipath-tools-0.4.9/debian/patches/0002-Race-condition-when-calling-stop_waiter_thread.patch	2014-08-08 16:46:23.000000000 -0300
@@ -0,0 +1,92 @@
+From 862d728c976a392c156ecbeb38419d1293fe4ecf Mon Sep 17 00:00:00 2001
+From: Hannes Reinecke <[email protected]>
+Date: Wed, 25 May 2011 14:40:19 +0200
+Subject: [PATCH 2/4] Race condition when calling stop_waiter_thread()
+
+We cannot access the waiter structure from other threads as
+the lifetime is totally different and it might be deleted
+at any time.
+So we better store the pthread id in the calling thread and
+just send a signal to the thread.
+
+References: bnc#642846
+
+Signed-off-by: Hannes Reinecke <[email protected]>
+---
+ libmultipath/structs.h |    2 +-
+ libmultipath/waiter.c  |   23 +++++++----------------
+ 2 files changed, 8 insertions(+), 17 deletions(-)
+
+diff --git a/libmultipath/structs.h b/libmultipath/structs.h
+index e6faff0..b44926a 100644
+--- a/libmultipath/structs.h
++++ b/libmultipath/structs.h
+@@ -193,7 +193,7 @@ struct multipath {
+ 	struct hwentry * hwe;
+ 
+ 	/* threads */
+-	void * waiter;
++	pthread_t waiter;
+ 
+ 	/* stats */
+ 	unsigned int stat_switchgroup;
+diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
+index 0be5d21..1a54d93 100644
+--- a/libmultipath/waiter.c
++++ b/libmultipath/waiter.c
+@@ -51,24 +51,15 @@ void free_waiter (struct event_thread *wp)
+ 
+ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ {
+-	struct event_thread *wp = (struct event_thread *)mpp->waiter;
+-	pthread_t thread;
+-
+-	if (!wp) {
+-		condlog(3, "%s: no waiter thread", mpp->alias);
+-		return;
+-	}
+-	if (wp->thread == (pthread_t)0) {
++	if (mpp->waiter == (pthread_t)0) {
+ 		condlog(3, "%s: event checker thread already stopped",
+ 			mpp->alias);
+ 		return;
+ 	}
+-	thread = wp->thread;
+-	wp->thread = (pthread_t)0;
+-	mpp->waiter = NULL;
+-
+-	condlog(2, "%s: stop event checker thread (%lu)", wp->mapname, thread);
+-	pthread_kill(thread, SIGUSR1);
++	condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
++		mpp->waiter);
++	pthread_kill(mpp->waiter, SIGUSR1);
++	mpp->waiter = (pthread_t)0;
+ }
+ 
+ static sigset_t unblock_signals(void)
+@@ -228,7 +219,6 @@ int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ 		goto out;
+ 
+ 	pthread_mutex_lock(&wp->lock);
+-	mpp->waiter = (void *)wp;
+ 	strncpy(wp->mapname, mpp->alias, WWID_SIZE);
+ 	wp->vecs = vecs;
+ 	pthread_mutex_unlock(&wp->lock);
+@@ -237,12 +227,13 @@ int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ 		condlog(0, "%s: cannot create event checker", wp->mapname);
+ 		goto out1;
+ 	}
++	mpp->waiter = wp->thread;
+ 	condlog(2, "%s: event checker started", wp->mapname);
+ 
+ 	return 0;
+ out1:
+ 	free_waiter(wp);
+-	mpp->waiter = NULL;
++	mpp->waiter = (pthread_t)0;
+ out:
+ 	condlog(0, "failed to start waiter thread");
+ 	return 1;
+-- 
+1.7.9.5
+
diff -Nru multipath-tools-0.4.9/debian/patches/0003-multipath-clean-up-code-for-stopping-the-waiter-thre.patch multipath-tools-0.4.9/debian/patches/0003-multipath-clean-up-code-for-stopping-the-waiter-thre.patch
--- multipath-tools-0.4.9/debian/patches/0003-multipath-clean-up-code-for-stopping-the-waiter-thre.patch	1969-12-31 21:00:00.000000000 -0300
+++ multipath-tools-0.4.9/debian/patches/0003-multipath-clean-up-code-for-stopping-the-waiter-thre.patch	2014-08-08 16:46:23.000000000 -0300
@@ -0,0 +1,240 @@
+From d216fee6751ed7b08213e41d8fb960428905f62b Mon Sep 17 00:00:00 2001
+From: Benjamin Marzinski <[email protected]>
+Date: Sat, 19 May 2012 01:37:03 -0500
+Subject: [PATCH 3/4] multipath: clean up code for stopping the waiter threads
+
+The way multipathd currently stops the waiter threads needs some work.
+Right now they are stopped by being sent the SIGUSR1 signal. However their
+cleanup code assumes that they are being cancelled, just like all the other
+threads are.  There's no reason for them to be so unnecessarily
+complicated and different from the other threads
+
+This patch does a couple of things.  First, it removes the mutex from
+the event_thread.  This wasn't doing anything. It was designed to protect
+the wp->mapname variable, which the waiter threads were checking to see
+if they should quit. However, the mutex was only ever being used by the
+thread itself, and it clearly didn't need to serialize with itself.  Also,
+the function to clear the mapname, signal_waiter(), was set with
+pthread_cleanup_push(), which never got called early, since the threads
+weren't being cancelled.  Thus, the mapname never got cleared
+until the pthreads were about to shut down.
+
+The patch also rips out all the signal stopping code, and just uses
+pthread_cancel.  There already are cancellation points in the waiter
+thread code. Between the cancellation points, both explicit and implicit,
+and the fact that the waiter threads will never be killed except when the
+killer is holding the vecs lock, there shouldn't be any place where the
+waiter thread can access freed data.
+
+To make sure the waiter thread cleans itself up properly, the dmt
+has been moved into the event_thread structure, and is destroyed in
+free_waiter() if necessary.
+
+Signed-off-by: Benjamin Marzinski <[email protected]>
+---
+ libmultipath/waiter.c |   74 ++++++++++++-------------------------------------
+ libmultipath/waiter.h |    4 +--
+ 2 files changed, 19 insertions(+), 59 deletions(-)
+
+diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
+index 1a54d93..2323b68 100644
+--- a/libmultipath/waiter.c
++++ b/libmultipath/waiter.c
+@@ -29,23 +29,17 @@ struct event_thread *alloc_waiter (void)
+ 
+ 	wp = (struct event_thread *)MALLOC(sizeof(struct event_thread));
+ 	memset(wp, 0, sizeof(struct event_thread));
+-	pthread_mutex_init(&wp->lock, NULL);
+ 
+ 	return wp;
+ }
+ 
+-void signal_waiter (void *data)
++void free_waiter (void *data)
+ {
+ 	struct event_thread *wp = (struct event_thread *)data;
+ 
+-	pthread_mutex_lock(&wp->lock);
+-	memset(wp->mapname, 0, WWID_SIZE);
+-	pthread_mutex_unlock(&wp->lock);
+-}
++	if (wp->dmt)
++		dm_task_destroy(wp->dmt);
+ 
+-void free_waiter (struct event_thread *wp)
+-{
+-	pthread_mutex_destroy(&wp->lock);
+ 	FREE(wp);
+ }
+ 
+@@ -58,83 +52,56 @@ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ 	}
+ 	condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
+ 		mpp->waiter);
+-	pthread_kill(mpp->waiter, SIGUSR1);
++	pthread_cancel(mpp->waiter);
+ 	mpp->waiter = (pthread_t)0;
+ }
+ 
+-static sigset_t unblock_signals(void)
+-{
+-	sigset_t set, old;
+-
+-	sigemptyset(&set);
+-	sigaddset(&set, SIGHUP);
+-	sigaddset(&set, SIGUSR1);
+-	pthread_sigmask(SIG_UNBLOCK, &set, &old);
+-	return old;
+-}
+-
+ /*
+  * returns the reschedule delay
+  * negative means *stop*
+  */
+ int waiteventloop (struct event_thread *waiter)
+ {
+-	sigset_t set;
+-	struct dm_task *dmt = NULL;
+ 	int event_nr;
+ 	int r;
+ 
+-	pthread_mutex_lock(&waiter->lock);
+ 	if (!waiter->event_nr)
+ 		waiter->event_nr = dm_geteventnr(waiter->mapname);
+ 
+-	if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
++	if (!(waiter->dmt = dm_task_create(DM_DEVICE_WAITEVENT))) {
+ 		condlog(0, "%s: devmap event #%i dm_task_create error",
+ 				waiter->mapname, waiter->event_nr);
+-		pthread_mutex_unlock(&waiter->lock);
+ 		return 1;
+ 	}
+ 
+-	if (!dm_task_set_name(dmt, waiter->mapname)) {
++	if (!dm_task_set_name(waiter->dmt, waiter->mapname)) {
+ 		condlog(0, "%s: devmap event #%i dm_task_set_name error",
+ 				waiter->mapname, waiter->event_nr);
+-		dm_task_destroy(dmt);
+-		pthread_mutex_unlock(&waiter->lock);
++		dm_task_destroy(waiter->dmt);
++		waiter->dmt = NULL;
+ 		return 1;
+ 	}
+ 
+-	if (waiter->event_nr && !dm_task_set_event_nr(dmt,
++	if (waiter->event_nr && !dm_task_set_event_nr(waiter->dmt,
+ 						      waiter->event_nr)) {
+ 		condlog(0, "%s: devmap event #%i dm_task_set_event_nr error",
+ 				waiter->mapname, waiter->event_nr);
+-		dm_task_destroy(dmt);
+-		pthread_mutex_unlock(&waiter->lock);
++		dm_task_destroy(waiter->dmt);
++		waiter->dmt = NULL;
+ 		return 1;
+ 	}
+-	pthread_mutex_unlock(&waiter->lock);
+ 
+-	dm_task_no_open_count(dmt);
+-
+-	/* accept wait interruption */
+-	set = unblock_signals();
++	dm_task_no_open_count(waiter->dmt);
+ 
+ 	/* wait */
+-	r = dm_task_run(dmt);
+-
+-	/* wait is over : event or interrupt */
+-	pthread_sigmask(SIG_SETMASK, &set, NULL);
++	r = dm_task_run(waiter->dmt);
+ 
+-	dm_task_destroy(dmt);
++	dm_task_destroy(waiter->dmt);
++	waiter->dmt = NULL;
+ 
+ 	if (!r)	/* wait interrupted by signal */
+ 		return -1;
+ 
+-	pthread_mutex_lock(&waiter->lock);
+-	if (!strlen(waiter->mapname)) {
+-		/* waiter should exit */
+-		pthread_mutex_unlock(&waiter->lock);
+-		return -1;
+-	}
+ 	waiter->event_nr++;
+ 
+ 	/*
+@@ -163,20 +130,16 @@ int waiteventloop (struct event_thread *waiter)
+ 		if (r) {
+ 			condlog(2, "%s: event checker exit",
+ 				waiter->mapname);
+-			pthread_mutex_unlock(&waiter->lock);
+ 			return -1; /* stop the thread */
+ 		}
+ 
+ 		event_nr = dm_geteventnr(waiter->mapname);
+ 
+-		if (waiter->event_nr == event_nr) {
+-			pthread_mutex_unlock(&waiter->lock);
++		if (waiter->event_nr == event_nr)
+ 			return 1; /* upon problem reschedule 1s later */
+-		}
+ 
+ 		waiter->event_nr = event_nr;
+ 	}
+-	pthread_mutex_unlock(&waiter->lock);
+ 	return -1; /* never reach there */
+ }
+ 
+@@ -188,7 +151,7 @@ void *waitevent (void *et)
+ 	mlockall(MCL_CURRENT | MCL_FUTURE);
+ 
+ 	waiter = (struct event_thread *)et;
+-	pthread_cleanup_push(signal_waiter, et);
++	pthread_cleanup_push(free_waiter, et);
+ 
+ 	block_signal(SIGUSR1, NULL);
+ 	block_signal(SIGHUP, NULL);
+@@ -202,7 +165,6 @@ void *waitevent (void *et)
+ 	}
+ 
+ 	pthread_cleanup_pop(1);
+-	free_waiter(waiter);
+ 	return NULL;
+ }
+ 
+@@ -218,10 +180,8 @@ int start_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ 	if (!wp)
+ 		goto out;
+ 
+-	pthread_mutex_lock(&wp->lock);
+ 	strncpy(wp->mapname, mpp->alias, WWID_SIZE);
+ 	wp->vecs = vecs;
+-	pthread_mutex_unlock(&wp->lock);
+ 
+ 	if (pthread_create(&wp->thread, &waiter_attr, waitevent, wp)) {
+ 		condlog(0, "%s: cannot create event checker", wp->mapname);
+diff --git a/libmultipath/waiter.h b/libmultipath/waiter.h
+index 28a6974..a1f57fb 100644
+--- a/libmultipath/waiter.h
++++ b/libmultipath/waiter.h
+@@ -4,15 +4,15 @@
+ extern pthread_attr_t waiter_attr;
+ 
+ struct event_thread {
++	struct dm_task *dmt;
+ 	pthread_t thread;
+-	pthread_mutex_t lock;
+ 	int event_nr;
+ 	char mapname[WWID_SIZE];
+ 	struct vectors *vecs;
+ };
+ 
+ struct event_thread * alloc_waiter (void);
+-void signal_waiter (void *data);
++void free_waiter (void *data);
+ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+ int start_waiter_thread (struct multipath *mpp, struct vectors *vecs);
+ int waiteventloop (struct event_thread *waiter);
+-- 
+1.7.9.5
+
diff -Nru multipath-tools-0.4.9/debian/patches/0004-Fix-race-condition-in-stop_waiter_thread.patch multipath-tools-0.4.9/debian/patches/0004-Fix-race-condition-in-stop_waiter_thread.patch
--- multipath-tools-0.4.9/debian/patches/0004-Fix-race-condition-in-stop_waiter_thread.patch	1969-12-31 21:00:00.000000000 -0300
+++ multipath-tools-0.4.9/debian/patches/0004-Fix-race-condition-in-stop_waiter_thread.patch	2014-08-08 16:46:23.000000000 -0300
@@ -0,0 +1,40 @@
+From d2fa5b4c00657006169c8c3fb1726fe7b8e7da74 Mon Sep 17 00:00:00 2001
+From: Hannes Reinecke <[email protected]>
+Date: Tue, 8 Jan 2013 14:54:08 +0100
+Subject: [PATCH 4/4] Fix race condition in stop_waiter_thread()
+
+The signal handler might run before we had a chance to
+set the 'waiter' context to '0', so better do it previously.
+
+Signed-off-by: Hannes Reinecke <[email protected]>
+---
+ libmultipath/waiter.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/libmultipath/waiter.c b/libmultipath/waiter.c
+index 2323b68..05050f5 100644
+--- a/libmultipath/waiter.c
++++ b/libmultipath/waiter.c
+@@ -45,6 +45,8 @@ void free_waiter (void *data)
+ 
+ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ {
++	pthread_t thread;
++
+ 	if (mpp->waiter == (pthread_t)0) {
+ 		condlog(3, "%s: event checker thread already stopped",
+ 			mpp->alias);
+@@ -52,8 +54,9 @@ void stop_waiter_thread (struct multipath *mpp, struct vectors *vecs)
+ 	}
+ 	condlog(2, "%s: stop event checker thread (%lu)", mpp->alias,
+ 		mpp->waiter);
+-	pthread_cancel(mpp->waiter);
++	thread = mpp->waiter;
+ 	mpp->waiter = (pthread_t)0;
++	pthread_cancel(thread);
+ }
+ 
+ /*
+-- 
+1.7.9.5
+
diff -Nru multipath-tools-0.4.9/debian/patches/series multipath-tools-0.4.9/debian/patches/series
--- multipath-tools-0.4.9/debian/patches/series	2013-01-29 23:02:49.000000000 -0200
+++ multipath-tools-0.4.9/debian/patches/series	2014-08-08 16:46:23.000000000 -0300
@@ -10,3 +10,7 @@
 1001--fix-linking-command.patch
 0009-fix-delim.patch
 0010-fix-extended-partitions.patch
+0001-libmultipath-update-waiter-handling.patch
+0002-Race-condition-when-calling-stop_waiter_thread.patch
+0003-multipath-clean-up-code-for-stopping-the-waiter-thre.patch
+0004-Fix-race-condition-in-stop_waiter_thread.patch

--- End Message ---
--- Begin Message ---
On 08/09/2014 01:19 AM, Rafael David Tinoco wrote:
> In Ubuntu, the attached patch was applied to achieve the following:

Hello Rafael,

I don't think this bug will apply to Debian. We are currently on 0.5.0.
If you think the bug applies, please re-open this bug report.

-- 
Ritesh Raj Sarraf | http://people.debian.org/~rrs
Debian - The Universal Operating System

Attachment: signature.asc
Description: OpenPGP digital signature


--- End Message ---

Reply via email to