summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgreen <green@FreeBSD.org>2002-07-25 04:49:45 +0000
committergreen <green@FreeBSD.org>2002-07-25 04:49:45 +0000
commitde2cfb0a7a345b657b83e8a56d35a723fc436192 (patch)
tree5c72f4c9c3de7b3c307d1b3e261f39f93e56ad6a
parent891c9fcb896ad87afa576f252cb60c125f96ac38 (diff)
downloadFreeBSD-src-de2cfb0a7a345b657b83e8a56d35a723fc436192.zip
FreeBSD-src-de2cfb0a7a345b657b83e8a56d35a723fc436192.tar.gz
Fix some of the places where sound(4) can sleep with a lock held. (Help
courtesy of fenner).
-rw-r--r--sys/dev/sound/pcm/mixer.c2
-rw-r--r--sys/dev/sound/pcm/sndstat.c25
-rw-r--r--sys/dev/sound/pcm/sound.c15
3 files changed, 30 insertions, 12 deletions
diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c
index 34dbcbd..7c1bd04 100644
--- a/sys/dev/sound/pcm/mixer.c
+++ b/sys/dev/sound/pcm/mixer.c
@@ -300,7 +300,9 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
m = oidp->oid_arg1;
snd_mtxlock(m->lock);
strncpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
+ snd_mtxunlock(m->lock);
error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
+ snd_mtxlock(m->lock);
if (error == 0 && req->newptr != NULL) {
dev = mixer_lookup(devname);
if (dev == -1) {
diff --git a/sys/dev/sound/pcm/sndstat.c b/sys/dev/sound/pcm/sndstat.c
index 5ff2080..bd9cb32 100644
--- a/sys/dev/sound/pcm/sndstat.c
+++ b/sys/dev/sound/pcm/sndstat.c
@@ -112,7 +112,7 @@ static int
sndstat_open(dev_t i_dev, int flags, int mode, struct thread *td)
{
intrmask_t s;
- int err;
+ int error;
s = spltty();
mtx_lock(&sndstat_lock);
@@ -121,19 +121,24 @@ sndstat_open(dev_t i_dev, int flags, int mode, struct thread *td)
splx(s);
return EBUSY;
}
+ sndstat_isopen = 1;
+ mtx_unlock(&sndstat_lock);
+ splx(s);
if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) {
+ error = ENXIO;
+ goto out;
+ }
+ sndstat_bufptr = 0;
+ error = (sndstat_prepare(&sndstat_sbuf) > 0) ? 0 : ENOMEM;
+out:
+ if (error) {
+ s = spltty();
+ mtx_lock(&sndstat_lock);
+ sndstat_isopen = 0;
mtx_unlock(&sndstat_lock);
splx(s);
- return ENXIO;
}
- sndstat_bufptr = 0;
- err = (sndstat_prepare(&sndstat_sbuf) > 0)? 0 : ENOMEM;
- if (!err)
- sndstat_isopen = 1;
-
- mtx_unlock(&sndstat_lock);
- splx(s);
- return err;
+ return (error);
}
static int
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 3f346f3..8fe48a2 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -798,7 +798,7 @@ sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
struct snddev_info *d;
struct snddev_channel *sce;
struct pcm_channel *c;
- int err, oldcnt, newcnt, cnt;
+ int err, newcnt, cnt;
d = oidp->oid_arg1;
@@ -809,10 +809,21 @@ sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL))
cnt++;
}
- oldcnt = cnt;
newcnt = cnt;
+ pcm_unlock(d);
err = sysctl_handle_int(oidp, &newcnt, sizeof(newcnt), req);
+ pcm_lock(d);
+ /*
+ * Since we dropped the pcm_lock, reload cnt now as it may
+ * have changed.
+ */
+ cnt = 0;
+ SLIST_FOREACH(sce, &d->channels, link) {
+ c = sce->channel;
+ if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL))
+ cnt++;
+ }
if (err == 0 && req->newptr != NULL) {
if (newcnt < 0 || newcnt > SND_MAXVCHANS) {
pcm_unlock(d);
OpenPOWER on IntegriCloud