Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 17 Jun 2026 10:52:49 +0000
From:      Christos Margiolis <christos@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Cc:        Goran=?utf-8?Q? Meki=C4=87?= <meka@tilda.center>
Subject:   git: 47ae0a869c7d - main - sound: Start each channel individually
Message-ID:  <6a327c81.1bbd0.3aad8c2b@gitrepo.freebsd.org>

index | next in thread | raw e-mail

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);
 		}
 


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a327c81.1bbd0.3aad8c2b>