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