From 776584319fb4d66cdb1c2f91bed154dfe6a74e5e Mon Sep 17 00:00:00 2001 From: ShengYi Hung Date: Fri, 15 May 2026 16:43:47 +0800 Subject: [PATCH] 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 --- 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 797bfba8102..7bc1decc283 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);