git: 2d1cfa142c00 - stable/14 - snd_dummy: Fix callout(9) races
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 29 Nov 2024 12:28:21 UTC
The branch stable/14 has been updated by christos:
URL: https://cgit.FreeBSD.org/src/commit/?id=2d1cfa142c005949f22e3eefea88dc83a8d4c44b
commit 2d1cfa142c005949f22e3eefea88dc83a8d4c44b
Author: Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2024-11-26 14:48:02 +0000
Commit: Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2024-11-29 12:28:06 +0000
snd_dummy: Fix callout(9) races
Use callout_init_mtx(9) to associate the callback with the driver's
lock. Also make sure the callout is stopped properly during detach.
While here, introduce a dummy_active() function to know when it's
appropriate to stop or not reschedule the callout.
Sponsored by: The FreeBSD Foundation
MFC after: 2 days
Reviewed by: dev_submerge.ch, markj
Differential Revision: https://reviews.freebsd.org/D47459
(cherry picked from commit 5bd08172b4150503c9cf60ffe3c97716c5bf6fa1)
---
sys/dev/sound/dummy.c | 34 ++++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 8 deletions(-)
diff --git a/sys/dev/sound/dummy.c b/sys/dev/sound/dummy.c
index c1cd4dff15f9..1584c489b5af 100644
--- a/sys/dev/sound/dummy.c
+++ b/sys/dev/sound/dummy.c
@@ -67,6 +67,24 @@ struct dummy_softc {
struct mtx *lock;
};
+static bool
+dummy_active(struct dummy_softc *sc)
+{
+ struct dummy_chan *ch;
+ int i;
+
+ snd_mtxassert(sc->lock);
+
+ for (i = 0; i < sc->chnum; i++) {
+ ch = &sc->chans[i];
+ if (ch->run)
+ return (true);
+ }
+
+ /* No channel is running at the moment. */
+ return (false);
+}
+
static void
dummy_chan_io(void *arg)
{
@@ -74,7 +92,9 @@ dummy_chan_io(void *arg)
struct dummy_chan *ch;
int i = 0;
- snd_mtxlock(sc->lock);
+ /* Do not reschedule if no channel is running. */
+ if (!dummy_active(sc))
+ return;
for (i = 0; i < sc->chnum; i++) {
ch = &sc->chans[i];
@@ -89,8 +109,6 @@ dummy_chan_io(void *arg)
snd_mtxlock(sc->lock);
}
callout_schedule(&sc->callout, 1);
-
- snd_mtxunlock(sc->lock);
}
static int
@@ -179,15 +197,15 @@ dummy_chan_trigger(kobj_t obj, void *data, int go)
switch (go) {
case PCMTRIG_START:
- if (!callout_active(&sc->callout))
- callout_reset(&sc->callout, 1, dummy_chan_io, sc);
ch->ptr = 0;
ch->run = 1;
+ callout_reset(&sc->callout, 1, dummy_chan_io, sc);
break;
case PCMTRIG_STOP:
case PCMTRIG_ABORT:
ch->run = 0;
- if (callout_active(&sc->callout))
+ /* If all channels are stopped, stop the callout as well. */
+ if (!dummy_active(sc))
callout_stop(&sc->callout);
default:
break;
@@ -292,6 +310,7 @@ dummy_attach(device_t dev)
sc = device_get_softc(dev);
sc->dev = dev;
sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_dummy softc");
+ callout_init_mtx(&sc->callout, sc->lock, 0);
sc->cap_fmts[0] = SND_FORMAT(AFMT_S32_LE, 2, 0);
sc->cap_fmts[1] = SND_FORMAT(AFMT_S24_LE, 2, 0);
@@ -316,7 +335,6 @@ dummy_attach(device_t dev)
device_get_nameunit(device_get_parent(dev)));
pcm_setstatus(dev, status);
mixer_init(dev, &dummy_mixer_class, sc);
- callout_init(&sc->callout, 1);
return (0);
}
@@ -327,8 +345,8 @@ dummy_detach(device_t dev)
struct dummy_softc *sc = device_get_softc(dev);
int err;
- callout_drain(&sc->callout);
err = pcm_unregister(dev);
+ callout_drain(&sc->callout);
snd_mtxfree(sc->lock);
return (err);