diff -Nru multipath-tools-0.4.9/debian/changelog multipath-tools-0.4.9/debian/changelog --- multipath-tools-0.4.9/debian/changelog 2013-01-29 23:10:55.000000000 -0200 +++ multipath-tools-0.4.9/debian/changelog 2014-08-07 17:26:24.000000000 -0300 @@ -1,3 +1,12 @@ +multipath-tools (0.4.9-3ubuntu8) trusty; urgency=medium + + * 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) + + -- Rafael David Tinoco Thu, 07 Aug 2014 16:15:25 -0300 + multipath-tools (0.4.9-3ubuntu7) raring; urgency=low * Add 0010-fix-extended-partitions.patch: Only expose the 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 17:18:37.000000000 -0300 @@ -0,0 +1,285 @@ +Description: [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 + +Origin: upstream, commit: 96f8146 +Author: Hannes Reinecke +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1354114 +Last-Update: 2014-08-08 +--- + 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 + + #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 17:19:10.000000000 -0300 @@ -0,0 +1,95 @@ +Description: [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 + +Origin: upstream, commit: c301a3f +Author: Hannes Reinecke +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1354114 +Last-Update: 2014-08-08 + +--- + 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 17:20:26.000000000 -0300 @@ -0,0 +1,243 @@ +Description: [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 + +Origin: upstream, commit: e1fcc59 +Author: Benjamin Marzinski +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1354114 +Last-Update: 2014-08-08 + +--- + 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 17:21:13.000000000 -0300 @@ -0,0 +1,43 @@ +Description: [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 + +Origin: upstream, commit: af4fd6d +Author: Hannes Reinecke +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1354114 +Last-Update: 2014-08-08 + +--- + 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-07 17:25:24.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