git: 5760c22a0522 - main - sound: Let pcm_unregister() tear down a partially initialized device
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 27 Oct 2026 11:28:09 UTC
The branch main has been updated by christos:
URL: https://cgit.FreeBSD.org/src/commit/?id=5760c22a05220cfb6b6cbf623f2cda5047b28706
commit 5760c22a05220cfb6b6cbf623f2cda5047b28706
Author: Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2026-10-27 11:26:29 +0000
Commit: Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2026-10-27 11:26:29 +0000
sound: Let pcm_unregister() tear down a partially initialized device
Since 3107b952f534 ("sound: Merge PCM_ALIVE() with PCM_REGISTERED()"),
pcm_unregister() is gated on PCM_REGISTERED(), so it cannot run unless
pcm_register() has already succeeded, which means drivers will leak
resources if a failure happened prior to this.
Reintroduce PCM_ALIVE(), but test dev rather than the lock. pcm_init()
assigns dev before anything else, so it can tell us whether pcm_init()
has run or not. Make sure to clear it in pcm_unregister() so that a
second call to pcm_unregister() cannot double-free.
While here, publish to sndstat(4) only once pcm_register() has
succeeded.
Reported by: jah
Fixes: 3107b952f534 ("sound: Merge PCM_ALIVE() with PCM_REGISTERED()")
MFC after: 1 week
Sponsored by: The FreeBSD Foundation
Reviewed by: jah, markj
Differential Revision: https://reviews.freebsd.org/D60801
---
sys/dev/sound/pcm/dsp.c | 9 ++++++++-
sys/dev/sound/pcm/sound.c | 10 ++++++----
sys/dev/sound/pcm/sound.h | 4 ++--
3 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index e1242ec4deb4..9277a1f337ff 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -160,7 +160,14 @@ dsp_destroy_dev(device_t dev)
struct snddev_info *d;
d = device_get_softc(dev);
- destroy_dev(d->dsp_dev);
+ /*
+ * The cdev may not exist if the driver failed before or during
+ * pcm_register().
+ */
+ if (d->dsp_dev != NULL) {
+ destroy_dev(d->dsp_dev);
+ d->dsp_dev = NULL;
+ }
}
static int
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 92aedb552d27..f0db8554c950 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -428,8 +428,6 @@ pcm_register(device_t dev, char *str)
vchan_initsys(dev);
feeder_eq_initsys(dev);
- sndstat_register(dev, SNDST_TYPE_PCM, d->status);
-
err = dsp_make_dev(dev);
if (err)
return (err);
@@ -441,6 +439,9 @@ pcm_register(device_t dev, char *str)
}
}
+ /* Publish only once registration really has finished properly. */
+ sndstat_register(dev, SNDST_TYPE_PCM, d->status);
+
bus_topo_lock();
if (snd_unit_auto < 0)
snd_unit_auto = (snd_unit < 0) ? 1 : 0;
@@ -463,8 +464,8 @@ pcm_unregister(device_t dev)
d = device_get_softc(dev);
- if (!PCM_REGISTERED(d)) {
- device_printf(dev, "unregister: device not configured\n");
+ if (!PCM_ALIVE(d)) {
+ device_printf(dev, "unregister: device not initialized\n");
return (0);
}
@@ -496,6 +497,7 @@ pcm_unregister(device_t dev)
cv_destroy(&d->cv);
mtx_destroy(&d->lock);
+ d->dev = NULL;
bus_topo_lock();
if (snd_unit == device_get_unit(dev)) {
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index ecd4dec5a170..16110e46a152 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -122,8 +122,8 @@ struct snd_mixer;
"\015PVCHANS" \
"\016RVCHANS"
-#define PCM_REGISTERED(x) \
- ((x) != NULL && ((x)->flags & SD_F_REGISTERED))
+#define PCM_ALIVE(x) ((x) != NULL && (x)->dev != NULL)
+#define PCM_REGISTERED(x) (PCM_ALIVE(x) && ((x)->flags & SD_F_REGISTERED))
#define PCM_MAXCHANS 10000
#define PCM_CHANCOUNT(d) \