--- 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 ---