diff options
author | attilio <attilio@FreeBSD.org> | 2011-08-21 10:52:50 +0000 |
---|---|---|
committer | attilio <attilio@FreeBSD.org> | 2011-08-21 10:52:50 +0000 |
commit | a5ccee99f762eeb025ed186ef72c8cf32515896c (patch) | |
tree | e75230ec49c93d136417ab1e1dcb7cffed2bcc8a /sys/kern/kern_timeout.c | |
parent | 7b624f0be1a93c6b631464d3f96c4277a78781af (diff) | |
download | FreeBSD-src-a5ccee99f762eeb025ed186ef72c8cf32515896c.zip FreeBSD-src-a5ccee99f762eeb025ed186ef72c8cf32515896c.tar.gz |
callout_cpu_switch() allows preemption when dropping the outcoming
callout cpu lock (and after having dropped it).
If the newly scheduled thread wants to acquire the old queue it will
just spin forever.
Fix this by disabling preemption and interrupts entirely (because fast
interrupt handlers may incur in the same problem too) while switching
locks.
Reported by: hrs, Mike Tancsa <mike AT sentex DOT net>,
Chip Camden <sterling AT camdensoftware DOT com>
Tested by: hrs, Mike Tancsa <mike AT sentex DOT net>,
Chip Camden <sterling AT camdensoftware DOT com>,
Nicholas Esborn <nick AT desert DOT net>
Approved by: re (kib)
MFC after: 10 days
Diffstat (limited to 'sys/kern/kern_timeout.c')
-rw-r--r-- | sys/kern/kern_timeout.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 6a6f46b..b820bd9 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -269,10 +269,17 @@ callout_cpu_switch(struct callout *c, struct callout_cpu *cc, int new_cpu) MPASS(c != NULL && cc != NULL); CC_LOCK_ASSERT(cc); + /* + * Avoid interrupts and preemption firing after the callout cpu + * is blocked in order to avoid deadlocks as the new thread + * may be willing to acquire the callout cpu lock. + */ c->c_cpu = CPUBLOCK; + spinlock_enter(); CC_UNLOCK(cc); new_cc = CC_CPU(new_cpu); CC_LOCK(new_cc); + spinlock_exit(); c->c_cpu = new_cpu; return (new_cc); } |