Skip to content

Commit 0d3df81

Browse files
arun-kvaviksildc
authored andcommitted
Fixed a race condition in 'spl_cv_wait' that could potentially
cause a thread to miss a broadcast event. (cherry picked from commit 47fd9bd)
1 parent bc0c9d2 commit 0d3df81

File tree

2 files changed

+9
-2
lines changed

2 files changed

+9
-2
lines changed

ZFSin/spl/include/osx/condvar.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ enum {
1919
struct cv {
2020
KEVENT kevent[CV_MAX_EVENTS]; // signal event, broadcast event
2121
KSPIN_LOCK waiters_count_lock;
22-
uint32_t waiters_count;
22+
volatile uint32_t waiters_count;
2323
uint32_t initialised; // Just used as sanity
2424
};
2525

ZFSin/spl/module/spl/spl-condvar.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ spl_cv_wait(kcondvar_t *cvp, kmutex_t *mp, int flags, const char *msg)
121121
void *locks[CV_MAX_EVENTS] = { &cvp->kevent[CV_SIGNAL], &cvp->kevent[CV_BROADCAST] };
122122
result = KeWaitForMultipleObjects(2, locks, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
123123

124+
/*
125+
* Moved this above waiters_count == 1 check to avoid the
126+
* possibility of this thread wrongly detecting this is the
127+
* only thread waiting for the event while there could be another
128+
* thread that aquired the mutex and is about to increment the
129+
* 'waiters_count' a few lines above in this function.
130+
*/
131+
mutex_enter(mp);
124132
// KeAcquireSpinLock(&cvp->waiters_count_lock, &oldIrq);
125133
// If last listener, clear BROADCAST event. (Even if it was SIGNAL
126134
// overclearing will not hurt?)
@@ -137,7 +145,6 @@ spl_cv_wait(kcondvar_t *cvp, kmutex_t *mp, int flags, const char *msg)
137145
//if (last_waiter)
138146
// KeClearEvent(&cvp->kevent[CV_BROADCAST]);
139147

140-
mutex_enter(mp);
141148

142149
#ifdef SPL_DEBUG_MUTEX
143150
spl_wdlist_settime(mp->leak, gethrestime_sec());

0 commit comments

Comments
 (0)