Convert sndstat_lock from a mutex to an sx lock. sndstat_read()

holds sndstat_lock across a call to uiomove(), which is not legal
to do with a  mutex because of the possibility that the data transfer
could sleep because of a page fault.  It is not possible to just
unlock the mutex for the uiomove() call without introducing another
locking mechanism to prevent the body of sndstat_read() from being
re-entered.  Converting sndstat_lock to an sx lock is the least
complicated change.

This is a candidate for RELENG_5.

LOR:		030
MFC after:	4 days
This commit is contained in:
Don Lewis 2004-09-10 09:37:06 +00:00
parent 8d70d0c0be
commit ca219d048a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=135033

View File

@ -26,6 +26,9 @@
#include <dev/sound/pcm/sound.h> #include <dev/sound/pcm/sound.h>
#include <dev/sound/pcm/vchan.h> #include <dev/sound/pcm/vchan.h>
#ifdef USING_MUTEX
#include <sys/sx.h>
#endif
SND_DECLARE_FILE("$FreeBSD$"); SND_DECLARE_FILE("$FreeBSD$");
@ -59,7 +62,7 @@ struct sndstat_entry {
}; };
#ifdef USING_MUTEX #ifdef USING_MUTEX
static struct mtx sndstat_lock; static struct sx sndstat_lock;
#endif #endif
static struct sbuf sndstat_sbuf; static struct sbuf sndstat_sbuf;
static struct cdev *sndstat_dev = 0; static struct cdev *sndstat_dev = 0;
@ -89,12 +92,12 @@ sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req); error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req);
if (error == 0 && req->newptr != NULL) { if (error == 0 && req->newptr != NULL) {
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
if (verbose < 0 || verbose > 3) if (verbose < 0 || verbose > 3)
error = EINVAL; error = EINVAL;
else else
sndstat_verbose = verbose; sndstat_verbose = verbose;
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
} }
return error; return error;
@ -109,14 +112,14 @@ sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
int error; int error;
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
if (sndstat_isopen) { if (sndstat_isopen) {
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return EBUSY; return EBUSY;
} }
sndstat_isopen = 1; sndstat_isopen = 1;
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) { if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) {
error = ENXIO; error = ENXIO;
@ -127,9 +130,9 @@ sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
out: out:
if (error) { if (error) {
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
sndstat_isopen = 0; sndstat_isopen = 0;
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
} }
return (error); return (error);
@ -141,16 +144,16 @@ sndstat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
intrmask_t s; intrmask_t s;
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
if (!sndstat_isopen) { if (!sndstat_isopen) {
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return EBADF; return EBADF;
} }
sbuf_delete(&sndstat_sbuf); sbuf_delete(&sndstat_sbuf);
sndstat_isopen = 0; sndstat_isopen = 0;
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return 0; return 0;
} }
@ -162,9 +165,9 @@ sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
int l, err; int l, err;
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
if (!sndstat_isopen) { if (!sndstat_isopen) {
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return EBADF; return EBADF;
} }
@ -172,7 +175,7 @@ sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
err = (l > 0)? uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, l, buf) : 0; err = (l > 0)? uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, l, buf) : 0;
sndstat_bufptr += l; sndstat_bufptr += l;
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return err; return err;
} }
@ -227,12 +230,12 @@ sndstat_register(device_t dev, char *str, sndstat_handler handler)
ent->handler = handler; ent->handler = handler;
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
SLIST_INSERT_HEAD(&sndstat_devlist, ent, link); SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
if (type == SS_TYPE_MODULE) if (type == SS_TYPE_MODULE)
sndstat_files++; sndstat_files++;
sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit; sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return 0; return 0;
@ -251,18 +254,18 @@ sndstat_unregister(device_t dev)
struct sndstat_entry *ent; struct sndstat_entry *ent;
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
SLIST_FOREACH(ent, &sndstat_devlist, link) { SLIST_FOREACH(ent, &sndstat_devlist, link) {
if (ent->dev == dev) { if (ent->dev == dev) {
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link); SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
free(ent, M_DEVBUF); free(ent, M_DEVBUF);
return 0; return 0;
} }
} }
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return ENXIO; return ENXIO;
@ -275,19 +278,19 @@ sndstat_unregisterfile(char *str)
struct sndstat_entry *ent; struct sndstat_entry *ent;
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
SLIST_FOREACH(ent, &sndstat_devlist, link) { SLIST_FOREACH(ent, &sndstat_devlist, link) {
if (ent->dev == NULL && ent->str == str) { if (ent->dev == NULL && ent->str == str) {
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link); SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
sndstat_files--; sndstat_files--;
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
free(ent, M_DEVBUF); free(ent, M_DEVBUF);
return 0; return 0;
} }
} }
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return ENXIO; return ENXIO;
@ -342,7 +345,7 @@ sndstat_prepare(struct sbuf *s)
static int static int
sndstat_init(void) sndstat_init(void)
{ {
mtx_init(&sndstat_lock, "sndstat", NULL, MTX_DEF); sx_init(&sndstat_lock, "sndstat");
sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS, UID_ROOT, GID_WHEEL, 0444, "sndstat"); sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS, UID_ROOT, GID_WHEEL, 0444, "sndstat");
return (sndstat_dev != 0)? 0 : ENXIO; return (sndstat_dev != 0)? 0 : ENXIO;
@ -354,9 +357,9 @@ sndstat_uninit(void)
intrmask_t s; intrmask_t s;
s = spltty(); s = spltty();
mtx_lock(&sndstat_lock); sx_xlock(&sndstat_lock);
if (sndstat_isopen) { if (sndstat_isopen) {
mtx_unlock(&sndstat_lock); sx_xunlock(&sndstat_lock);
splx(s); splx(s);
return EBUSY; return EBUSY;
} }
@ -366,7 +369,7 @@ sndstat_uninit(void)
sndstat_dev = 0; sndstat_dev = 0;
splx(s); splx(s);
mtx_destroy(&sndstat_lock); sx_destroy(&sndstat_lock);
return 0; return 0;
} }