Race in kevent
Harti Brandt
brandt at fokus.fraunhofer.de
Wed Jul 9 06:28:42 PDT 2003
Hi,
I just had a crash while typing ^C to a program that has a kevent timer
running. The crash was:
callout_stop
callout_reset
filt_timerexpire
softclock
and callout_stop was accessing freed memory (0xdeadc0e2). After looking
some time at the filt_timerdetach, callout_stop and softclock I think the
following happened:
Proc 1 Proc 2
------ ------
filt_timerdetach softclock called
call with Giant locked
lock_spin(callout_lock)
...
call callout_stop which hangs on
lock_spin(callout_lock)
sofclock finds the callout,
removes it from its queue and
clears PENDING
unlock_spin(callout_lock)
lock(&Giant) blocks
callout_stop finds the callout to
be not pending and returns
filt_timerdetach frees the callout
...
unlock(&Giant)
softclock continues and calls
the (stopped) callout
KABOOM because the pointer used
by filt_timerexpire is gone
The problem seems to be that there is a small window where the callout is
already taken off from the callout queue, but not yet called and where all
locks are unlocked. callout_stop may just slip into this window and
invalidate the callout softclock() is about to call as soon as it gets
Giant (event with an non-MPSAFE callout the same problem exists although
the window is much smaller).
What to do?
callout_stop already detects this situation and returns 0. As far as I
understand the way to handle this is not to free the callout memory in
filt_timerdetach() when callout_stop() returns 0, but let the callout be
called. filt_timerexpire() should detect this situation and simply free
the memory and return. Is this a possible solution? (Actually this
requires some work, because the knote pointer that the filt_timerexpire()
gets is probably also gone).
harti
--
harti brandt,
http://www.fokus.fraunhofer.de/research/cc/cats/employees/hartmut.brandt/private
brandt at fokus.fraunhofer.de, harti at freebsd.org
More information about the freebsd-hackers
mailing list