Note: This bug is displayed in read-only format because the product is no longer active in Red Hat Bugzilla.
For bugs related to Red Hat Enterprise Linux 5 product line. The current stable release is 5.10. For Red Hat Enterprise Linux 6 and above, please visit Red Hat JIRA https://issues.redhat.com/secure/CreateIssue!default.jspa?pid=12332745 to report new issues.

Bug 639429

Summary: multipathd segfaults due to shutdown race
Product: Red Hat Enterprise Linux 5 Reporter: Bryn M. Reeves <bmr>
Component: device-mapper-multipathAssignee: Ben Marzinski <bmarzins>
Status: CLOSED ERRATA QA Contact: WANG Chao <chaowang>
Severity: high Docs Contact:
Priority: high    
Version: 5.5CC: agk, bdonahue, bmarzins, bmr, chaowang, christophe.varoqui, coughlan, cww, czhang, dwysocha, fge, heinzm, ichute, junichi.nomura, kdudka, kueda, lmb, marting, mbroz, peterm, prajnoha, prockai, qcai, revers, ruyang, tumeya
Target Milestone: rcKeywords: ZStream
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: device-mapper-multipath-0.4.7-46.el5 Doc Type: Bug Fix
Doc Text:
after acquiring their resource locks, multipathd's threads weren't checking if they had been canceled before accessing their resources. This caused multipathd to occasionally segfault on shutdown, if a thread attempted to access a resource after it was canceled. Now all multipathd threads check if they are canceled before accessing their resources.
Story Points: ---
Clone Of: Environment:
Last Closed: 2011-07-21 08:22:00 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 695055    
Bug Blocks: 590060, 704470, 721245    
Attachments:
Description Flags
check cancellation status in checkerloop before touching vecs->pathvec none

Description Bryn M. Reeves 2010-10-01 18:02:05 UTC
Description of problem:
The patch for bug 459629 seems to introduce a race:

revision 1.69.2.17 date: 2009/04/03 15:09:03; author: bmarzins; state: Exp; lines: +11 -2 Fix for bz #459629. Multipathd needs to wait for the waiter threads to finish before freeing the vecs locks. This bug has already been fixed upstream. 

This was a fix to prevent a hang in multipathd when shutting down (and some related problems):

https://bugzilla.redhat.com/show_bug.cgi?id=459629#c34

The patch adds code to NULL out vecs->pathvec and synchronize with the waiter threads before destroying vecs->lock:

+ vecs->pathvec=NULL; 
[...]
+ ret = 0; 
+ while (num_waiters > 0 && ret == 0)
+         ret = pthread_cond_wait(&waiter_cond, vecs->lock);
+ if (ret) {
+         condlog(0, "error while waiting for event threads: %s", + strerror(errno));
+ exit(1);
+ } 

This gives us:

1679         /*
1680          * exit path
1681          */
1682         block_signal(SIGHUP, NULL);
1683         lock(vecs->lock);
1684         if (conf->queue_without_daemon == QUE_NO_DAEMON_OFF)
1685                 vector_foreach_slot(vecs->mpvec, mpp, i)
1686                         dm_queue_if_no_path(mpp->alias, 0);
1687         remove_maps(vecs, stop_waiter_thread);
1688         free_pathvec(vecs->pathvec, FREE_PATHS);
1689         vecs->pathvec=NULL;
1690 
1691         pthread_cancel(check_thr);
1692         pthread_cancel(uevent_thr);
1693         pthread_cancel(uxlsnr_thr);
1694 
1695         free_keys(keys);
1696         keys = NULL;
1697         free_handlers(handlers);
1698         handlers = NULL;
1699         free_polls();
1700 
1701         ret = 0;
1702         while (num_waiters > 0 && ret == 0)
1703                 ret = pthread_cond_wait(&waiter_cond, vecs->lock);
1704         if (ret) {
1705                 condlog(0, "error while waiting for event threads: %s",
1706                         strerror(errno));
1707                 exit(1);
1708         }
1709         unlock(vecs->lock);
1710         pthread_mutex_destroy(vecs->lock);
1711         FREE(vecs->lock);
1712         vecs->lock = NULL;
1713         FREE(vecs);
1714         vecs = NULL;

But since pthread_cond_wait will automatically unlock vecs->lock when putting the calling thread to sleep this introduces a race condition with the thread running the checkerloop routine:

 964 checkerloop (void *ap)
 965 {
[...]
 985         while (1) {
 986                 block_signal(SIGHUP, &old);
 987                 pthread_cleanup_push(cleanup_lock, vecs->lock);
 988                 lock(vecs->lock);
 989                 condlog(4, "tick");
 990 
 991                 vector_foreach_slot (vecs->pathvec, pp, i) {
 992                         if (!pp->mpp)
[...]
1160         }
1161         return NULL;
1162 }

Although the checker thread has been sent a cancellation request at this point multipathd's pthreads are created with the default deferred cancellation type. This means that the thread will continue to run until it calls a function that is a defined cancellation point.

Since none of the functions called between lock(vecs->lock) and the vector_foreach_slot() is a cancellation point (and the pthread_mutex_lock in lock() is not itself a cancellation point) the checker thread is still running and depending on scheduler timing it is possible for us to acquire the lock and attempt to access vecs->pathvec before the process terminates.

These two behaviours combined with the changes for bug 459629 lead to a situation in which:

- a cancellation request has been sent to check_thr
- the cancellation request has NOT been acted upon
- the main thread has released vecs->lock and is blocked in pthread_cond_wait
- vecs->pathvec has been de-allocated and set to NULL 

Version-Release number of selected component (if applicable):
device-mapper-multipath-0.4.7-34.el5_5.4

How reproducible:
Difficult. The user who provided the core file rebooted the system 1230 times before seeing the problem.

Steps to Reproduce:
1. Repeatedly reboot a system running multipathd
 
Actual results:
Core was generated by `/sbin/multipathd'.
Program terminated with signal 11, Segmentation fault.
#0  0x000000000040628a in checkerloop (ap=0x1b412030) at main.c:953
953			vector_foreach_slot (vecs->pathvec, pp, i) {
(gdb) bt
#0  0x000000000040628a in checkerloop (ap=0x1b412030) at main.c:953
#1  0x0000003b45e06367 in start_thread (arg=<value optimized out>) at pthread_create.c:297
#2  0x0000003b452d30ad in clone () from /lib64/libc.so.6

Expected results:
No segfault during shutdown.

Additional info:
There are a number of ways that we could address this:
- convert threads to use asynchronous cancellation type (causes threads to be cancellable at any time, usually resulting in immediate cancellation but this is not guaranteed)
- insert a call to a function that is required to be a cancellation point between acquisition of the vecs->lock mutex and access to vecs->pathvec
- modify the checker loop to test vecs->pathvec and exit if the field is NULL

I'm leaning toward the 2nd option; the 1st may not close the race completely and the 3rd is a bit blunt.

Comment 1 Bryn M. Reeves 2010-10-01 18:14:11 UTC
Created attachment 451075 [details]
check cancellation status in checkerloop before touching vecs->pathvec

Comment 7 Ben Marzinski 2011-04-07 21:06:59 UTC
I've fixed this crash as well as some others related to similar issues during shutdown.

Comment 8 Ben Marzinski 2011-04-07 21:12:57 UTC
*** Bug 670836 has been marked as a duplicate of this bug. ***

Comment 9 Ben Marzinski 2011-04-08 02:07:36 UTC
    Technical note added. If any revisions are required, please edit the "Technical Notes" field
    accordingly. All revisions will be proofread by the Engineering Content Services team.
    
    New Contents:
after acquiring their resource locks, multipathd's threads weren't checking if they had been canceled before accessing their resources. This caused multipathd to occasionally segfault on shutdown, if a thread attempted to access a resource after it was canceled.  Now all multipathd threads check if they are canceled before accessing their resources.

Comment 11 Ben Marzinski 2011-04-11 16:52:11 UTC
There is a bug in the current version of this patch.

Comment 12 Ben Marzinski 2011-04-11 16:58:33 UTC
*** Bug 695055 has been marked as a duplicate of this bug. ***

Comment 18 WANG Chao 2011-06-21 09:21:44 UTC
confirm patch in device-mapper-multipath-0.4.7-46.el5

Comment 20 errata-xmlrpc 2011-07-21 08:22:00 UTC
An advisory has been issued which should help the problem
described in this bug report. This report is therefore being
closed with a resolution of ERRATA. For more information
on therefore solution and/or where to find the updated files,
please follow the link below. You may reopen this bug report
if the solution does not work for you.

http://rhn.redhat.com/errata/RHBA-2011-1032.html