summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorattilio <attilio@FreeBSD.org>2007-11-22 12:15:54 +0000
committerattilio <attilio@FreeBSD.org>2007-11-22 12:15:54 +0000
commit5ed5cf01be214f92f0fee018e2db163981968114 (patch)
tree1318aa3673acfead31e946794628252ef5f39846
parent2b0672aa28222167908103b3d0e38cc09db3043f (diff)
downloadFreeBSD-src-5ed5cf01be214f92f0fee018e2db163981968114.zip
FreeBSD-src-5ed5cf01be214f92f0fee018e2db163981968114.tar.gz
Cache the value of c_lock as it can change, in the struct,
while the global callout spinlock is not held, and can lead to PF#. Reported by: dougb, Mark Atkinson <atkin901 at yahoo dot com> Tested by: dougb Diagnosed by: jhb
-rw-r--r--sys/kern/kern_timeout.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index b6b70f0..143e38c 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -216,6 +216,7 @@ softclock(void *dummy)
void (*c_func)(void *);
void *c_arg;
struct lock_class *class;
+ struct lock_object *c_lock;
int c_flags, sharedlock;
nextsoftcheck = TAILQ_NEXT(c, c_links.tqe);
@@ -224,6 +225,7 @@ softclock(void *dummy)
LOCK_CLASS(c->c_lock) : NULL;
sharedlock = (c->c_flags & CALLOUT_SHAREDLOCK) ?
0 : 1;
+ c_lock = c->c_lock;
c_func = c->c_func;
c_arg = c->c_arg;
c_flags = c->c_flags;
@@ -240,20 +242,20 @@ softclock(void *dummy)
}
curr_cancelled = 0;
mtx_unlock_spin(&callout_lock);
- if (class != NULL) {
- class->lc_lock(c->c_lock, sharedlock);
+ if (c_lock != NULL) {
+ class->lc_lock(c_lock, sharedlock);
/*
* The callout may have been cancelled
* while we switched locks.
*/
if (curr_cancelled) {
- class->lc_unlock(c->c_lock);
+ class->lc_unlock(c_lock);
goto skip;
}
/* The callout cannot be stopped now. */
curr_cancelled = 1;
- if (c->c_lock == &Giant.lock_object) {
+ if (c_lock == &Giant.lock_object) {
gcalls++;
CTR3(KTR_CALLOUT,
"callout %p func %p arg %p",
@@ -294,7 +296,7 @@ softclock(void *dummy)
}
#endif
if ((c_flags & CALLOUT_RETURNUNLOCKED) == 0)
- class->lc_unlock(c->c_lock);
+ class->lc_unlock(c_lock);
skip:
mtx_lock_spin(&callout_lock);
curr_callout = NULL;
OpenPOWER on IntegriCloud