DF-5434 / fix.diff
--- sys/bus/u4b/uvc/uvc_buf.c.orig +++ sys/bus/u4b/uvc/uvc_buf.c @@ -82,6 +82,8 @@ #define UVC_LOCK(lkp) lockmgr(lkp, LK_EXCLUSIVE) #define UVC_UNLOCK(lkp) lockmgr(lkp, LK_RELEASE) +static void uvc_buf_queue_init_qbuf(struct uvc_buf *buf, int ind); + #define FRAME_DUMP 0 #if FRAME_DUMP static void uvc_writefile(char *path, void *data, int len); @@ -517,11 +519,26 @@ static void uvc_buf_queue_free_bufs_locked(struct uvc_buf_queue *bq) { + int i; + if (bq->mem) { kfree(bq->mem, M_UVC); bq->mem = NULL; bq->buf_count = 0; + bq->buf_size = 0; } + + /* + * The queues and per-buffer descriptors must not outlive the + * backing buffer: a completion callback (uvc_buf_sell_buf / + * uvc_bulkbuf_sell_buf) or a still-open mmap must never see a + * stale buf->mem or a stale vbuf.bytesused. Drain both STAILQs + * and reset every descriptor. + */ + STAILQ_INIT(&bq->consumer); + STAILQ_INIT(&bq->product); + for (i = 0; i < UVC_BUF_MAX_BUFFERS; i++) + uvc_buf_queue_init_qbuf(bq->buf + i, i); } void @@ -537,7 +554,7 @@ int uvc_buf_queue_req_bufs(struct uvc_buf_queue *bq, uint32_t *count, uint32_t len) { - void *mem; + void *mem = NULL; struct uvc_buf *buf; int i, num, ret = 0; unsigned long rl; @@ -546,9 +563,8 @@ rl = round_page(len); DPRINTF("page align size:%lu-real size:%u\n", rl, len); - num = *count; - if (num > UVC_BUF_MAX_BUFFERS) - num = UVC_BUF_MAX_BUFFERS; + /* unsigned clamp: counts >= 2^31 must clamp, not go negative */ + num = (*count > UVC_BUF_MAX_BUFFERS) ? UVC_BUF_MAX_BUFFERS : *count; UVC_LOCK(&bq->mtx); uvc_buf_queue_free_bufs_locked(bq); @@ -568,6 +584,7 @@ for (i = 0; i < num; i++) { buf = bq->buf + i; + uvc_buf_queue_init_qbuf(buf, i); buf->index = i; buf->mem = mem; buf->offset = i * rl; |