git: 47ae0a869c7d - main - sound: Start each channel individually
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 17 Jun 2026 10:52:49 UTC
The branch main has been updated by christos:
URL: https://cgit.FreeBSD.org/src/commit/?id=47ae0a869c7db693ffb1ac058d63dcb79c4e68a8
commit 47ae0a869c7db693ffb1ac058d63dcb79c4e68a8
Author: Goran Mekić <meka@tilda.center>
AuthorDate: 2026-06-17 10:34:05 +0000
Commit: Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2026-06-17 10:34:45 +0000
sound: Start each channel individually
Unlock all members before starting any of them. Holding multiple channel
locks while calling chn_start() on a virtual channel can trigger the
parent, which acquires PCM_LOCK() while other virtual channels are still
locked -- a lock order reversal.
Reviewed by: christos
Differential Revision: https://reviews.freebsd.org/D57399
---
sys/dev/sound/pcm/dsp.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index 05fdc18e31f8..1fa665b6b6cf 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -2742,16 +2742,29 @@ dsp_oss_syncstart(int sg_id)
/* Proceed only if no errors encountered. */
if (ret == 0) {
- /* Launch channels */
- while ((sm = SLIST_FIRST(&sg->members)) != NULL) {
- SLIST_REMOVE_HEAD(&sg->members, link);
+ /*
+ * Unlock all members before starting any of them.
+ * Holding multiple channel locks while calling chn_start()
+ * on a virtual channel can trigger the parent, which
+ * acquires PCM_LOCK() while other virtual channels are
+ * still locked -- a lock order reversal.
+ */
+ SLIST_FOREACH(sm, &sg->members, link) {
+ sm->ch->sm = NULL;
+ sm->ch->flags &= ~CHN_F_NOTRIGGER;
+ CHN_UNLOCK(sm->ch);
+ }
+ /*
+ * Start each channel individually, then remove it from
+ * the sync group and free its member structure.
+ */
+ while ((sm = SLIST_FIRST(&sg->members)) != NULL) {
c = sm->ch;
- c->sm = NULL;
+ CHN_LOCK(c);
chn_start(c, 1);
- c->flags &= ~CHN_F_NOTRIGGER;
CHN_UNLOCK(c);
-
+ SLIST_REMOVE_HEAD(&sg->members, link);
free(sm, M_DEVBUF);
}