diff options
author | attilio <attilio@FreeBSD.org> | 2007-11-22 12:15:54 +0000 |
---|---|---|
committer | attilio <attilio@FreeBSD.org> | 2007-11-22 12:15:54 +0000 |
commit | 5ed5cf01be214f92f0fee018e2db163981968114 (patch) | |
tree | 1318aa3673acfead31e946794628252ef5f39846 /sys/kern/kern_timeout.c | |
parent | 2b0672aa28222167908103b3d0e38cc09db3043f (diff) | |
download | FreeBSD-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
Diffstat (limited to 'sys/kern/kern_timeout.c')
-rw-r--r-- | sys/kern/kern_timeout.c | 12 |
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; |