git: b5c1ab6c8f28 - main - snd_hdsp*: malloc(9) with M_WAITOK

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Sat, 22 Aug 2026 12:49:16 UTC
The branch main has been updated by christos:

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

commit b5c1ab6c8f2811278b801084713a6618f3b783d3
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2026-08-22 12:48:50 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2026-08-22 12:48:50 +0000

    snd_hdsp*: malloc(9) with M_WAITOK
    
    Perform the allocations outside the lock section so that we can use
    M_WAITOK. Holding the lock here is actually not really necessary and we
    could just as well remove it, but keep it for consistency.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 month
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D59079
---
 sys/dev/sound/pci/hdsp-pcm.c  | 17 +++++++++++++++--
 sys/dev/sound/pci/hdspe-pcm.c | 17 +++++++++++++++--
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/sys/dev/sound/pci/hdsp-pcm.c b/sys/dev/sound/pci/hdsp-pcm.c
index b4df8ca90555..7f4f7dc76557 100644
--- a/sys/dev/sound/pci/hdsp-pcm.c
+++ b/sys/dev/sound/pci/hdsp-pcm.c
@@ -676,10 +676,13 @@ hdspchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
 	struct sc_pcminfo *scp;
 	struct sc_chinfo *ch;
 	struct sc_info *sc;
+	struct pcmchan_caps *caps;
+	uint32_t *data;
 	int num;
 
 	scp = devinfo;
 	sc = scp->sc;
+	caps = malloc(sizeof(struct pcmchan_caps), M_HDSP, M_WAITOK);
 
 	mtx_lock(&sc->lock);
 	num = scp->chnum;
@@ -704,7 +707,7 @@ hdspchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
 	    SND_FORMAT(AFMT_S32_LE, hdsp_port_slot_count(ch->ports, 192000), 0);
 	ch->cap_fmts[3] = 0;
 
-	ch->caps = malloc(sizeof(struct pcmchan_caps), M_HDSP, M_NOWAIT);
+	ch->caps = caps;
 	*(ch->caps) = (struct pcmchan_caps) {32000, 192000, ch->cap_fmts, 0};
 
 	/* HDSP 9652 does not support quad speed sample rates. */
@@ -715,7 +718,6 @@ hdspchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
 
 	/* Allocate maximum buffer size. */
 	ch->size = HDSP_CHANBUF_SIZE * hdsp_port_slot_count_max(ch->ports);
-	ch->data = malloc(ch->size, M_HDSP, M_NOWAIT);
 	ch->position = 0;
 
 	ch->buffer = b;
@@ -726,6 +728,17 @@ hdspchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
 
 	mtx_unlock(&sc->lock);
 
+	/*
+	 * It is safe to access ch->size here without holding the lock, because
+	 * 1) as of now, ch->size is written only once, here, and 2) ch's
+	 * lifetime is equal to scp's lifetime so it cannot go away yet.
+	 */
+	data = malloc(ch->size, M_HDSP, M_WAITOK);
+
+	mtx_lock(&sc->lock);
+	ch->data = data;
+	mtx_unlock(&sc->lock);
+
 	if (sndbuf_setup(ch->buffer, ch->data, ch->size) != 0) {
 		device_printf(scp->dev, "Can't setup sndbuf.\n");
 		hdspchan_free(obj, ch);
diff --git a/sys/dev/sound/pci/hdspe-pcm.c b/sys/dev/sound/pci/hdspe-pcm.c
index e0b6168efcba..a814c80127b1 100644
--- a/sys/dev/sound/pci/hdspe-pcm.c
+++ b/sys/dev/sound/pci/hdspe-pcm.c
@@ -670,10 +670,13 @@ hdspechan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
 	struct sc_pcminfo *scp;
 	struct sc_chinfo *ch;
 	struct sc_info *sc;
+	struct pcmchan_caps *caps;
+	uint32_t *data;
 	int num;
 
 	scp = devinfo;
 	sc = scp->sc;
+	caps = malloc(sizeof(struct pcmchan_caps), M_HDSPE, M_WAITOK);
 
 	mtx_lock(&sc->lock);
 	num = scp->chnum;
@@ -697,12 +700,11 @@ hdspechan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
 	ch->cap_fmts[2] =
 	    SND_FORMAT(AFMT_S32_LE, hdspe_channel_count(ch->ports, 8), 0);
 	ch->cap_fmts[3] = 0;
-	ch->caps = malloc(sizeof(struct pcmchan_caps), M_HDSPE, M_NOWAIT);
+	ch->caps = caps;
 	*(ch->caps) = (struct pcmchan_caps) {32000, 192000, ch->cap_fmts, 0};
 
 	/* Allocate maximum buffer size. */
 	ch->size = HDSPE_CHANBUF_SIZE * hdspe_channel_count(ch->ports, 8);
-	ch->data = malloc(ch->size, M_HDSPE, M_NOWAIT);
 	ch->position = 0;
 
 	ch->buffer = b;
@@ -713,6 +715,17 @@ hdspechan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
 
 	mtx_unlock(&sc->lock);
 
+	/*
+	 * It is safe to access ch->size here without holding the lock, because
+	 * 1) as of now, ch->size is written only once, here, and 2) ch's
+	 * lifetime is equal to scp's lifetime so it cannot go away yet.
+	 */
+	data = malloc(ch->size, M_HDSPE, M_WAITOK);
+
+	mtx_lock(&sc->lock);
+	ch->data = data;
+	mtx_unlock(&sc->lock);
+
 	if (sndbuf_setup(ch->buffer, ch->data, ch->size) != 0) {
 		device_printf(scp->dev, "Can't setup sndbuf.\n");
 		hdspechan_free(obj, ch);