mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 00:32:25 -04:00
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:
parent
a0598a8716
commit
8e2d74a486
3 changed files with 39 additions and 30 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue