diff options
| author | riastradh <riastradh@NetBSD.org> | 2022-06-29 22:27:01 +0000 |
|---|---|---|
| committer | riastradh <riastradh@NetBSD.org> | 2022-06-29 22:27:01 +0000 |
| commit | 1d15b657dfc539a24f6ceeb6894184bf3bc42d64 (patch) | |
| tree | cc8e254dc68f71cd42c57f80f290b2f7b0362558 /sys/kern/kern_timeout.c | |
| parent | 4f46ee441c5fd0e1667f385005b453dca450871b (diff) | |
sleepq(9): Pass syncobj through to sleepq_block.
Previously the usage pattern was:
sleepq_enter(sq, l, lock); // locks l
...
sleepq_enqueue(sq, ..., sobj, ...); // assumes l locked, sets l_syncobj
... (*)
sleepq_block(...); // unlocks l
As long as l remains locked from sleepq_enter to sleepq_block,
l_syncobj is stable, and sleepq_block uses it via ktrcsw to determine
whether the sleep is on a mutex in order to avoid creating ktrace
context-switch records (which involves allocation which is forbidden
in softint context, while taking and even sleeping for a mutex is
allowed).
However, in turnstile_block, the logic at (*) also involves
turnstile_lendpri, which sometimes unlocks and relocks l. At that
point, another thread can swoop in and sleepq_remove l, which sets
l_syncobj to sched_syncobj. If that happens, ktrcsw does what is
forbidden -- tries to allocate a ktrace record for the context
switch.
As an optimization, sleepq_block or turnstile_block could stop early
if it detects that l_syncobj doesn't match -- we've already been
requested to wake up at this point so there's no need to mi_switch.
(And then it would be unnecessary to pass the syncobj through
sleepq_block, because l_syncobj would remain stable.) But I'll leave
that to another change.
Reported-by: syzbot+8b9d7b066c32dbcdc63b@syzkaller.appspotmail.com
Diffstat (limited to 'sys/kern/kern_timeout.c')
| -rw-r--r-- | sys/kern/kern_timeout.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 1f78dabfd6e..3d710613b6f 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_timeout.c,v 1.69 2022/03/30 17:02:02 riastradh Exp $ */ +/* $NetBSD: kern_timeout.c,v 1.70 2022/06/29 22:27:01 riastradh Exp $ */ /*- * Copyright (c) 2003, 2006, 2007, 2008, 2009, 2019 The NetBSD Foundation, Inc. @@ -59,7 +59,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_timeout.c,v 1.69 2022/03/30 17:02:02 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_timeout.c,v 1.70 2022/06/29 22:27:01 riastradh Exp $"); /* * Timeouts are kept in a hierarchical timing wheel. The c_time is the @@ -543,7 +543,7 @@ callout_wait(callout_impl_t *c, void *interlock, kmutex_t *lock) sleepq_enter(&cc->cc_sleepq, l, cc->cc_lock); sleepq_enqueue(&cc->cc_sleepq, cc, "callout", &sleep_syncobj, false); - sleepq_block(0, false); + sleepq_block(0, false, &sleep_syncobj); } /* |
