The branch main has been updated by christos:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=47ae0a869c7db693ffb1ac058d63dcb79c4e68a8

commit 47ae0a869c7db693ffb1ac058d63dcb79c4e68a8
Author:     Goran Mekić <[email protected]>
AuthorDate: 2026-06-17 10:34:05 +0000
Commit:     Christos Margiolis <[email protected]>
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);
                }
 

Reply via email to