Page MenuHomeFreeBSD

D60554.diff
No OneTemporary

D60554.diff

diff --git a/sys/dev/sound/pcm/buffer.c b/sys/dev/sound/pcm/buffer.c
--- a/sys/dev/sound/pcm/buffer.c
+++ b/sys/dev/sound/pcm/buffer.c
@@ -90,6 +90,24 @@
}
}
+static bool
+sndbuf_busy(struct snd_dbuf *b)
+{
+ CHN_LOCKASSERT(b->channel);
+
+ return (refcount_load(&b->refcount) > 1 ||
+ (b->flags & SNDBUF_F_DETACHED) != 0 ||
+ /*
+ * XXX-MJ CHN_F_MMAP is not reliable, but for software buffers the
+ * refcount accurately reflects whether the buffer is mapped.
+ * Ensure that there is no in-flight DMA transfer by checking
+ * CHN_F_TRIGGERED. This should really be checked at a higher
+ * layer, but this is tricky since chn_resizebuf() and
+ * sndbuf_resize() drop and reacquire the channel lock.
+ */
+ (b->channel->flags & (CHN_F_MMAP | CHN_F_TRIGGERED)) != 0);
+}
+
static void
sndbuf_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
@@ -205,8 +223,7 @@
if (bufsize > b->allocsize ||
bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
- if (refcount_load(&b->refcount) > 1 ||
- (b->flags & SNDBUF_F_DETACHED) != 0) {
+ if (sndbuf_busy(b)) {
CHN_UNLOCK(b->channel);
return (EBUSY);
}
@@ -214,6 +231,11 @@
CHN_UNLOCK(b->channel);
tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
CHN_LOCK(b->channel);
+ if (sndbuf_busy(b)) {
+ CHN_UNLOCK(b->channel);
+ free(tmpbuf, M_DEVBUF);
+ return (EBUSY);
+ }
if (snd_verbose > 3)
printf("%s(): b=%p %p -> %p [%d -> %d : %d]\n",
__func__, b, b->tmpbuf, tmpbuf,
@@ -250,8 +272,7 @@
if (bufsize > b->allocsize ||
bufsize < (b->allocsize >> SNDBUF_CACHE_SHIFT)) {
- if (refcount_load(&b->refcount) > 1 ||
- (b->flags & SNDBUF_F_DETACHED) != 0)
+ if (sndbuf_busy(b))
return (EBUSY);
allocsize = round_page(bufsize);
CHN_UNLOCK(b->channel);
@@ -259,6 +280,12 @@
tmpbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
shadbuf = malloc(allocsize, M_DEVBUF, M_WAITOK);
CHN_LOCK(b->channel);
+ if (sndbuf_busy(b)) {
+ free(buf, M_DEVBUF);
+ free(tmpbuf, M_DEVBUF);
+ free(shadbuf, M_DEVBUF);
+ return (EBUSY);
+ }
free(b->buf, M_DEVBUF);
b->buf = buf;
free(b->tmpbuf, M_DEVBUF);
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -1837,13 +1837,13 @@
{
struct snd_dbuf *b, *bs, *pb;
int sblksz, sblkcnt, hblksz, hblkcnt, limit = 0, nsblksz, nsblkcnt;
- int ret;
u_int32_t maxsize;
CHN_LOCKASSERT(c);
- if ((c->flags & (CHN_F_MMAP | CHN_F_TRIGGERED)) ||
- !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
+ if (!(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC))
+ return EINVAL;
+ if ((c->flags & (CHN_F_MMAP | CHN_F_TRIGGERED)) != 0)
return EINVAL;
if (latency == -1) {
@@ -1901,6 +1901,9 @@
chn_notify(c->parentchannel, CHN_N_BLOCKSIZE);
CHN_UNLOCK(c->parentchannel);
CHN_LOCK(c);
+ /* Revalidate. */
+ if ((c->flags & (CHN_F_MMAP | CHN_F_TRIGGERED)) != 0)
+ return EINVAL;
if (c->direction == PCMDIR_PLAY) {
limit = (pb != NULL) ?
sndbuf_xbytes(pb->bufsize, pb, bs) : 0;
@@ -1909,6 +1912,8 @@
sndbuf_xbytes(pb->blksz, pb, bs) * 2 : 0;
}
} else {
+ int error;
+
/*
* The byte-rate-scaled cap applies to the secondary buffer
* only. It exists to absorb userland scheduling latency,
@@ -1942,12 +1947,31 @@
hblksz -= hblksz % b->align;
CHN_UNLOCK(c);
- if (chn_usefrags == 0 ||
- CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
- hblksz, hblkcnt) != 0)
- b->blksz = CHANNEL_SETBLOCKSIZE(c->methods,
- c->devinfo, hblksz);
+ error = ENOTSUP;
+ if (chn_usefrags) {
+ error = CHANNEL_SETFRAGMENTS(c->methods, c->devinfo,
+ hblksz, hblkcnt);
+ /* The default implementation returns ENOTSUP. */
+ if (error != 0 && error != ENOTSUP) {
+ CHN_LOCK(c);
+ return error;
+ }
+ }
+ if (error == ENOTSUP) {
+ uint32_t blksz;
+
+ blksz = CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo,
+ hblksz);
+ if (blksz == 0) {
+ CHN_LOCK(c);
+ return EINVAL;
+ }
+ b->blksz = blksz;
+ }
CHN_LOCK(c);
+ /* Revalidate. */
+ if ((c->flags & (CHN_F_MMAP | CHN_F_TRIGGERED)) != 0)
+ return EINVAL;
if (!CHN_EMPTY(c, children)) {
nsblksz = round_blksz(
@@ -1985,11 +2009,13 @@
if (bs->blkcnt != sblkcnt || bs->blksz != sblksz ||
bs->bufsize != (sblkcnt * sblksz)) {
- ret = sndbuf_remalloc(bs, sblkcnt, sblksz);
- if (ret != 0) {
+ int error;
+
+ error = sndbuf_remalloc(bs, sblkcnt, sblksz);
+ if (error != 0) {
device_printf(c->dev, "%s(): Failed: %d %d\n",
__func__, sblkcnt, sblksz);
- return ret;
+ return error;
}
}

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 11, 12:15 AM (16 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40571683
Default Alt Text
D60554.diff (4 KB)

Event Timeline