Subject: Re: kern/32563: audioctl of death
To: None <jmcneill@netbsd.org, gnats-admin@netbsd.org,>
From: Christian Biere <christianbiere@gmx.de>
List: netbsd-bugs
Date: 04/18/2006 16:05:04
The following reply was made to PR kern/32563; it has been noted by GNATS.
From: Christian Biere <christianbiere@gmx.de>
To: "Jared D. McNeill" <jmcneill@invisible.ca>
Cc: gnats-bugs@netbsd.org
Subject: Re: kern/32563: audioctl of death
Date: Tue, 18 Apr 2006 18:03:09 +0200
Jared D. McNeill wrote:
> The following patch isn't perfect (we can't rely on having a giant lock
> for all of MI audio), but it should at least show the concept.
>
> I still need to figure out where to keep this simple_lock on a
> per-instance basis; the audio filters don't have any knowledge of MI audio
> or the hw driver, but they need to be locked to prevent changes to the
> filter list on the fly.
>
> I'll have another look at this tonight.
I updated my sources before trying to apply your patch. After updating
the patch couldn't be applied. I've adapted the patch manually. As
far as I can see, your patch fixes the problem. I cannot trigger the
panic anymore.
Thanks,
Christian
Index: audio.c
===================================================================
RCS file: /cvsroot/src/sys/dev/audio.c,v
retrieving revision 1.202
diff -u -r1.202 audio.c
--- audio.c 28 Mar 2006 17:38:29 -0000 1.202
+++ audio.c 18 Apr 2006 15:48:38 -0000
@@ -81,6 +81,7 @@
#include <sys/conf.h>
#include <sys/audioio.h>
#include <sys/device.h>
+#include <sys/lock.h>
#include <dev/audio_if.h>
#include <dev/audiovar.h>
@@ -103,6 +104,9 @@
int audio_blk_ms = AUDIO_BLK_MS;
+/* XXX: jmcneill */
+struct simplelock audio_filtlock = SIMPLELOCK_INITIALIZER;
+
int audiosetinfo(struct audio_softc *, struct audio_info *);
int audiogetinfo(struct audio_softc *, struct audio_info *);
@@ -656,7 +660,9 @@
audio_stream_t ps[AUDIO_MAX_FILTERS];
const audio_params_t *from_param;
audio_params_t *to_param;
- int i, n;
+ int i, n, error = 0;
+
+ simple_lock(&audio_filtlock);
memset(pf, 0, sizeof(pf));
memset(ps, 0, sizeof(ps));
@@ -681,7 +687,8 @@
pf[i]->dtor(pf[i]);
audio_stream_dtor(&ps[i]);
}
- return EINVAL;
+ error = EINVAL;
+ goto cleanup;
}
audio_destruct_pfilters(sc);
@@ -710,7 +717,10 @@
}
audio_print_params("[HW]", &sc->sc_pr.s.param);
#endif /* AUDIO_DEBUG */
- return 0;
+
+cleanup:
+ simple_unlock(&audio_filtlock);
+ return error;
}
static int
@@ -788,12 +798,16 @@
{
int i;
+ simple_lock(&audio_filtlock);
+
for (i = 0; i < sc->sc_npfilters; i++) {
sc->sc_pfilters[i]->dtor(sc->sc_pfilters[i]);
sc->sc_pfilters[i] = NULL;
audio_stream_dtor(&sc->sc_pstreams[i]);
}
sc->sc_npfilters = 0;
+
+ simple_unlock(&audio_filtlock);
}
static void
@@ -845,6 +859,8 @@
const audio_params_t *param)
{
+ simple_lock(&audio_filtlock);
+
if (list->req_size >= AUDIO_MAX_FILTERS) {
printf("%s: increase AUDIO_MAX_FILTERS in sys/dev/audio_if.h\n",
__func__);
@@ -853,6 +869,8 @@
list->filters[list->req_size].factory = factory;
list->filters[list->req_size].param = *param;
list->req_size++;
+
+ simple_unlock(&audio_filtlock);
}
static void
@@ -860,6 +878,8 @@
stream_filter_factory_t factory,
const audio_params_t *param)
{
+ simple_lock(&audio_filtlock);
+
if (i < 0 || i >= AUDIO_MAX_FILTERS) {
printf("%s: invalid index: %d\n", __func__, i);
return;
@@ -868,6 +888,8 @@
list->filters[i].param = *param;
if (list->req_size <= i)
list->req_size = i + 1;
+
+ simple_unlock(&audio_filtlock);
}
static void
@@ -876,6 +898,8 @@
const audio_params_t *param)
{
+ simple_lock(&audio_filtlock);
+
if (list->req_size >= AUDIO_MAX_FILTERS) {
printf("%s: increase AUDIO_MAX_FILTERS in sys/dev/audio_if.h\n",
__func__);
@@ -886,6 +910,8 @@
list->filters[0].factory = factory;
list->filters[0].param = *param;
list->req_size++;
+
+ simple_unlock(&audio_filtlock);
}
int
@@ -1858,6 +1884,7 @@
* setup filter pipeline
*/
uio_fetcher_ctor(&ufetcher, uio, cb->usedhigh);
+
if (sc->sc_npfilters > 0) {
fetcher = &sc->sc_pfilters[sc->sc_npfilters - 1]->base;
} else {
@@ -1897,12 +1924,22 @@
* work with a temporary audio_stream_t to narrow
* splaudio() enclosure
*/
+
+ simple_lock(&audio_filtlock);
if (sc->sc_npfilters > 0) {
filter = sc->sc_pfilters[0];
filter->set_fetcher(filter, &ufetcher.base);
}
cc = stream.end - stream.start;
+ if (sc->sc_npfilters > 0) {
+ fetcher = &sc->sc_pfilters[sc->sc_npfilters - 1]->base;
+ } else {
+ fetcher = &ufetcher.base;
+ }
+
error = fetcher->fetch_to(fetcher, &stream, cc);
+ simple_unlock(&audio_filtlock);
+
s = splaudio();
if (sc->sc_npfilters > 0) {
cb->fstamp += audio_stream_get_used(sc->sc_pustream)
@@ -1947,6 +1984,7 @@
audio_fill_silence(&cb->s.param, einp, cc);
}
}
+
return error;
}