git: 83cddc84693a - stable/15 - sound: Fix lock order reversal in dsp_poll()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 29 May 2026 15:20:40 UTC
The branch stable/15 has been updated by aokblast:
URL: https://cgit.FreeBSD.org/src/commit/?id=83cddc84693af1fb7f1ba6ee1213f2b9694eee3c
commit 83cddc84693af1fb7f1ba6ee1213f2b9694eee3c
Author: ShengYi Hung <aokblast@FreeBSD.org>
AuthorDate: 2026-05-15 08:43:47 +0000
Commit: ShengYi Hung <aokblast@FreeBSD.org>
CommitDate: 2026-05-29 15:19:49 +0000
sound: Fix lock order reversal in dsp_poll()
chn_poll() may hold both rdch and wrch channel locks while calling
chn_trigger(rdch). chn_trigger() switches the lock order from
"channel -> dsp dev" to "dsp dev -> channel" by temporarily dropping
the channel lock before acquiring the dsp lock.
However, only rdch was unlocked during the transition while wrch
remained locked. Since wrch is also a channel lock and witness had
already established the lock order requirement:
dsp dev -> channel
witness reports a lock order reversal when pcm_lock() is acquired while
wrch is still held.
Avoid holding rdch and wrch simultaneously during chn_trigger()
lock-order switching by only keeping the channel locks when needed.
The issue can be reliably reproduced by starting pipewire,
pipewire-pulse, and pavucontrol.
Reviewed by: christos
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D57009
(cherry picked from commit 776584319fb4d66cdb1c2f91bed154dfe6a74e5e)
---
sys/dev/sound/pcm/dsp.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index 6d76877e90ba..82c960fc3b40 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -1877,24 +1877,25 @@ dsp_poll(struct cdev *i_dev, int events, struct thread *td)
ret = 0;
- dsp_lock_chans(priv, FREAD | FWRITE);
wrch = priv->wrch;
rdch = priv->rdch;
if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) {
+ CHN_LOCK(wrch);
e = (events & (POLLOUT | POLLWRNORM));
if (e)
ret |= chn_poll(wrch, e, td);
+ CHN_UNLOCK(wrch);
}
if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) {
+ CHN_LOCK(rdch);
e = (events & (POLLIN | POLLRDNORM));
if (e)
ret |= chn_poll(rdch, e, td);
+ CHN_UNLOCK(rdch);
}
- dsp_unlock_chans(priv, FREAD | FWRITE);
-
PCM_GIANT_LEAVE(d);
return (ret);