diff mbox

[2/2] multipathd: Avoid that a deadlock is triggered sporadically during shutdown

Message ID 5832949e-aa89-ebf2-11e1-67bbb4d050bf@sandisk.com (mailing list archive)
State Not Applicable, archived
Delegated to: Mike Snitzer
Headers show

Commit Message

Bart Van Assche Oct. 14, 2016, 3:35 p.m. UTC
pthread_cond_wait() is a thread cancellation point. If a thread that
is waiting in pthread_cond_wait() is canceled it is possible that the
mutex is re-acquired before the first cancellation cleanup handler
is called. In this case the cleanup handler is uevq_stop() and that
function locks uevq_lock. Avoid that calling uevq_stop() results in
a deadlock due to an attempt to lock a non-recursive mutex recursively.

Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
---
 libmultipath/uevent.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Xose Vazquez Perez Oct. 20, 2016, 10:28 p.m. UTC | #1
On 10/14/2016 05:35 PM, Bart Van Assche wrote:

> pthread_cond_wait() is a thread cancellation point. If a thread that
> is waiting in pthread_cond_wait() is canceled it is possible that the
> mutex is re-acquired before the first cancellation cleanup handler
> is called. In this case the cleanup handler is uevq_stop() and that
> function locks uevq_lock. Avoid that calling uevq_stop() results in
> a deadlock due to an attempt to lock a non-recursive mutex recursively.
> 
> Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> ---
>  libmultipath/uevent.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
> index 6247898..85fd2fb 100644
> --- a/libmultipath/uevent.c
> +++ b/libmultipath/uevent.c
> @@ -52,7 +52,7 @@ typedef int (uev_trigger)(struct uevent *, void * trigger_data);
>  
>  pthread_t uevq_thr;
>  LIST_HEAD(uevq);
> -pthread_mutex_t uevq_lock = PTHREAD_MUTEX_INITIALIZER;
> +pthread_mutex_t uevq_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
>  pthread_mutex_t *uevq_lockp = &uevq_lock;
>  pthread_cond_t uev_cond = PTHREAD_COND_INITIALIZER;
>  pthread_cond_t *uev_condp = &uev_cond;
> 

PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP is not defined in POSIX.

This is going to be problematic in musl-libc based distributions:
http://wiki.musl-libc.org/wiki/Projects_using_musl#Distributions


~/musl-gcc -O2 -g -pipe -Wall -Wextra -Wformat=2 -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -fPIC -DLIB_STRING=\"lib64\"
-DRUN_DIR=\"run\" -I../libmpathcmd -DUSE_SYSTEMD=229 -DLIBDM_API_FLUSH -D_GNU_SOURCE -DLIBDM_API_COOKIE -DLIBUDEV_API_RECVBUF -DLIBDM_API_DEFERRED -c -o uevent.o uevent.c
uevent.c:55:29: error: ‘PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP’ undeclared here (not in a function)
 pthread_mutex_t uevq_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../Makefile.inc:74: recipe for target 'uevent.o' failed
make[1]: [uevent.o] Error 1 (ignored)

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
Bart Van Assche Oct. 20, 2016, 10:47 p.m. UTC | #2
On 10/20/2016 03:28 PM, Xose Vazquez Perez wrote:
> On 10/14/2016 05:35 PM, Bart Van Assche wrote:
>
>> pthread_cond_wait() is a thread cancellation point. If a thread that
>> is waiting in pthread_cond_wait() is canceled it is possible that the
>> mutex is re-acquired before the first cancellation cleanup handler
>> is called. In this case the cleanup handler is uevq_stop() and that
>> function locks uevq_lock. Avoid that calling uevq_stop() results in
>> a deadlock due to an attempt to lock a non-recursive mutex recursively.
>>
>> Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
>> ---
>>  libmultipath/uevent.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
>> index 6247898..85fd2fb 100644
>> --- a/libmultipath/uevent.c
>> +++ b/libmultipath/uevent.c
>> @@ -52,7 +52,7 @@ typedef int (uev_trigger)(struct uevent *, void * trigger_data);
>>
>>  pthread_t uevq_thr;
>>  LIST_HEAD(uevq);
>> -pthread_mutex_t uevq_lock = PTHREAD_MUTEX_INITIALIZER;
>> +pthread_mutex_t uevq_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
>>  pthread_mutex_t *uevq_lockp = &uevq_lock;
>>  pthread_cond_t uev_cond = PTHREAD_COND_INITIALIZER;
>>  pthread_cond_t *uev_condp = &uev_cond;
>>
>
> PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP is not defined in POSIX.
>
> This is going to be problematic in musl-libc based distributions:
> http://wiki.musl-libc.org/wiki/Projects_using_musl#Distributions
>
>
> ~/musl-gcc -O2 -g -pipe -Wall -Wextra -Wformat=2 -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -fPIC -DLIB_STRING=\"lib64\"
> -DRUN_DIR=\"run\" -I../libmpathcmd -DUSE_SYSTEMD=229 -DLIBDM_API_FLUSH -D_GNU_SOURCE -DLIBDM_API_COOKIE -DLIBUDEV_API_RECVBUF -DLIBDM_API_DEFERRED -c -o uevent.o uevent.c
> uevent.c:55:29: error: ‘PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP’ undeclared here (not in a function)
>  pthread_mutex_t uevq_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
>                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../Makefile.inc:74: recipe for target 'uevent.o' failed
> make[1]: [uevent.o] Error 1 (ignored)

Hello Xose,

Thanks for reporting this. I will rework that patch.

Bart.

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

Patch

diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index 6247898..85fd2fb 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -52,7 +52,7 @@  typedef int (uev_trigger)(struct uevent *, void * trigger_data);
 
 pthread_t uevq_thr;
 LIST_HEAD(uevq);
-pthread_mutex_t uevq_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t uevq_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 pthread_mutex_t *uevq_lockp = &uevq_lock;
 pthread_cond_t uev_cond = PTHREAD_COND_INITIALIZER;
 pthread_cond_t *uev_condp = &uev_cond;