Fix a panic due to holding a lock over calls to uiomove.

Pointed out by:	Artur Poplawski
Explained by:	Don Lewis (truckman)
Approved by:	tanimura (mentor)
Approved by:	scottl	(re)
This commit is contained in:
Mathew Kanner 2003-11-27 19:51:44 +00:00
parent a0598a8716
commit 8e2d74a486
3 changed files with 39 additions and 30 deletions

View file

@ -499,33 +499,6 @@ sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count)
return 0;
}
int
sndbuf_uiomove(struct snd_dbuf *b, struct uio *uio, unsigned int count)
{
int x, c, p, rd, err;
err = 0;
rd = (uio->uio_rw == UIO_READ)? 1 : 0;
if (count > uio->uio_resid)
return EINVAL;
if (count > (rd? sndbuf_getready(b) : sndbuf_getfree(b))) {
return EINVAL;
}
while (err == 0 && count > 0) {
p = rd? sndbuf_getreadyptr(b) : sndbuf_getfreeptr(b);
c = MIN(count, sndbuf_getsize(b) - p);
x = uio->uio_resid;
err = uiomove(sndbuf_getbufofs(b, p), c, uio);
x -= uio->uio_resid;
count -= x;
x = rd? sndbuf_dispose(b, NULL, x) : sndbuf_acquire(b, NULL, x);
}
return 0;
}
/* count is number of bytes we want added to destination buffer */
int
sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count)

View file

@ -106,7 +106,6 @@ void sndbuf_updateprevtotal(struct snd_dbuf *b);
int sndbuf_acquire(struct snd_dbuf *b, u_int8_t *from, unsigned int count);
int sndbuf_dispose(struct snd_dbuf *b, u_int8_t *to, unsigned int count);
int sndbuf_uiomove(struct snd_dbuf *b, struct uio *uio, unsigned int count);
int sndbuf_feed(struct snd_dbuf *from, struct snd_dbuf *to, struct pcm_channel *channel, struct pcm_feeder *feeder, unsigned int count);
u_int32_t sndbuf_getflags(struct snd_dbuf *b);

View file

@ -250,6 +250,8 @@ chn_write(struct pcm_channel *c, struct uio *buf)
{
int ret, timeout, newsize, count, sz;
struct snd_dbuf *bs = c->bufsoft;
void *off;
int t, x,togo,p;
CHN_LOCKASSERT(c);
/*
@ -291,7 +293,24 @@ chn_write(struct pcm_channel *c, struct uio *buf)
sz = MIN(sz, buf->uio_resid);
KASSERT(sz > 0, ("confusion in chn_write"));
/* printf("sz: %d\n", sz); */
ret = sndbuf_uiomove(bs, buf, sz);
/*
* The following assumes that the free space in
* the buffer can never be less around the
* unlock-uiomove-lock sequence.
*/
togo = sz;
while (ret == 0 && togo> 0) {
p = sndbuf_getfreeptr(bs);
t = MIN(togo, sndbuf_getsize(bs) - p);
off = sndbuf_getbufofs(bs, p);
CHN_UNLOCK(c);
ret = uiomove(off, t, buf);
CHN_LOCK(c);
togo -= t;
x = sndbuf_acquire(bs, NULL, t);
}
ret = 0;
if (ret == 0 && !(c->flags & CHN_F_TRIGGERED))
chn_start(c, 0);
}
@ -395,6 +414,8 @@ chn_read(struct pcm_channel *c, struct uio *buf)
{
int ret, timeout, sz, count;
struct snd_dbuf *bs = c->bufsoft;
void *off;
int t, x,togo,p;
CHN_LOCKASSERT(c);
if (!(c->flags & CHN_F_TRIGGERED))
@ -406,7 +427,23 @@ chn_read(struct pcm_channel *c, struct uio *buf)
sz = MIN(buf->uio_resid, sndbuf_getready(bs));
if (sz > 0) {
ret = sndbuf_uiomove(bs, buf, sz);
/*
* The following assumes that the free space in
* the buffer can never be less around the
* unlock-uiomove-lock sequence.
*/
togo = sz;
while (ret == 0 && togo> 0) {
p = sndbuf_getreadyptr(bs);
t = MIN(togo, sndbuf_getsize(bs) - p);
off = sndbuf_getbufofs(bs, p);
CHN_UNLOCK(c);
ret = uiomove(off, t, buf);
CHN_LOCK(c);
togo -= t;
x = sndbuf_dispose(bs, NULL, t);
}
ret = 0;
} else {
if (c->flags & CHN_F_NBIO) {
ret = EWOULDBLOCK;