On 02/27/14 12:15, Laurent Pinchart wrote: > Hi Hans, > > Thank you for the patch. This is a pretty useful debugging tool. Please see > below for two small comments. > > On Tuesday 25 February 2014 13:52:44 Hans Verkuil wrote: >> From: Hans Verkuil <hans.verkuil@xxxxxxxxx> >> >> When a vb2_queue is freed check if all the mem_ops and queue ops were >> balanced. So the number of calls to e.g. buf_finish has to match the number >> of calls to buf_prepare, etc. >> >> This code is only enabled if CONFIG_VIDEO_ADV_DEBUG is set. >> >> Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx> >> Acked-by: Pawel Osciak <pawel@xxxxxxxxxx> >> --- >> drivers/media/v4l2-core/videobuf2-core.c | 233 +++++++++++++++++++++------- >> include/media/videobuf2-core.h | 43 ++++++ >> 2 files changed, 226 insertions(+), 50 deletions(-) >> >> diff --git a/drivers/media/v4l2-core/videobuf2-core.c >> b/drivers/media/v4l2-core/videobuf2-core.c index 909f367..8f1578b 100644 >> --- a/drivers/media/v4l2-core/videobuf2-core.c >> +++ b/drivers/media/v4l2-core/videobuf2-core.c >> @@ -33,12 +33,63 @@ module_param(debug, int, 0644); >> printk(KERN_DEBUG "vb2: " fmt, ## arg); \ >> } while (0) >> >> -#define call_memop(q, op, args...) \ >> - (((q)->mem_ops->op) ? \ >> - ((q)->mem_ops->op(args)) : 0) >> +#ifdef CONFIG_VIDEO_ADV_DEBUG >> + >> +/* >> + * If advanced debugging is on, then count how often each op is called, >> + * which can either be per-buffer or per-queue. >> + * >> + * If the op failed then the 'fail_' variant is called to decrease the >> + * counter. That makes it easy to check that the 'init' and 'cleanup' >> + * (and variations thereof) stay balanced. > > It would have been nice to avoid the fail_ variants by not increasing the > counter when the operation fails, but I suppose that's not possible given that > what return value indicates an error is operation-specific. Yeah, I tried to come up with the least messy solution and this was it. > >> + */ >> + >> +#define call_memop(vb, op, args...) \ >> +({ \ >> + struct vb2_queue *_q = (vb)->vb2_queue; \ >> + dprintk(2, "call_memop(%p, %d, %s)%s\n", \ >> + _q, (vb)->v4l2_buf.index, #op, \ >> + _q->mem_ops->op ? "" : " (nop)"); \ >> + (vb)->cnt_mem_ ## op++; \ >> + _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \ >> +}) >> +#define fail_memop(vb, op) ((vb)->cnt_mem_ ## op--) >> + >> +#define call_qop(q, op, args...) \ >> +({ \ >> + dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \ >> + (q)->ops->op ? "" : " (nop)"); \ >> + (q)->cnt_ ## op++; \ >> + (q)->ops->op ? (q)->ops->op(args) : 0; \ >> +}) >> +#define fail_qop(q, op) ((q)->cnt_ ## op--) >> + >> +#define call_vb_qop(vb, op, args...) \ >> +({ \ >> + struct vb2_queue *_q = (vb)->vb2_queue; \ >> + dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \ >> + _q, (vb)->v4l2_buf.index, #op, \ >> + _q->ops->op ? "" : " (nop)"); \ >> + (vb)->cnt_ ## op++; \ >> + _q->ops->op ? _q->ops->op(args) : 0; \ >> +}) >> +#define fail_vb_qop(vb, op) ((vb)->cnt_ ## op--) >> + >> +#else >> + >> +#define call_memop(vb, op, args...) \ >> + ((vb)->vb2_queue->mem_ops->op ? (vb)->vb2_queue->mem_ops->op(args) : 0) >> +#define fail_memop(vb, op) >> >> #define call_qop(q, op, args...) \ >> - (((q)->ops->op) ? ((q)->ops->op(args)) : 0) >> + ((q)->ops->op ? (q)->ops->op(args) : 0) >> +#define fail_qop(q, op) >> + >> +#define call_vb_qop(vb, op, args...) \ >> + ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0) >> +#define fail_vb_qop(vb, op) >> + >> +#endif >> >> #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | > V4L2_BUF_FLAG_QUEUED >> | \ V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \ >> @@ -61,7 +112,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) >> for (plane = 0; plane < vb->num_planes; ++plane) { >> unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); >> >> - mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], >> + mem_priv = call_memop(vb, alloc, q->alloc_ctx[plane], >> size, q->gfp_flags); >> if (IS_ERR_OR_NULL(mem_priv)) >> goto free; >> @@ -73,9 +124,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) >> >> return 0; >> free: >> + fail_memop(vb, alloc); >> /* Free already allocated memory if one of the allocations failed */ >> for (; plane > 0; --plane) { >> - call_memop(q, put, vb->planes[plane - 1].mem_priv); >> + call_memop(vb, put, vb->planes[plane - 1].mem_priv); >> vb->planes[plane - 1].mem_priv = NULL; >> } >> >> @@ -87,11 +139,10 @@ free: >> */ >> static void __vb2_buf_mem_free(struct vb2_buffer *vb) >> { >> - struct vb2_queue *q = vb->vb2_queue; >> unsigned int plane; >> >> for (plane = 0; plane < vb->num_planes; ++plane) { >> - call_memop(q, put, vb->planes[plane].mem_priv); >> + call_memop(vb, put, vb->planes[plane].mem_priv); >> vb->planes[plane].mem_priv = NULL; >> dprintk(3, "Freed plane %d of buffer %d\n", plane, >> vb->v4l2_buf.index); >> @@ -104,12 +155,11 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb) >> */ >> static void __vb2_buf_userptr_put(struct vb2_buffer *vb) >> { >> - struct vb2_queue *q = vb->vb2_queue; >> unsigned int plane; >> >> for (plane = 0; plane < vb->num_planes; ++plane) { >> if (vb->planes[plane].mem_priv) >> - call_memop(q, put_userptr, vb->planes[plane].mem_priv); >> + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); >> vb->planes[plane].mem_priv = NULL; >> } >> } >> @@ -118,15 +168,15 @@ static void __vb2_buf_userptr_put(struct vb2_buffer >> *vb) * __vb2_plane_dmabuf_put() - release memory associated with >> * a DMABUF shared plane >> */ >> -static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane >> *p) +static void __vb2_plane_dmabuf_put(struct vb2_buffer *vb, struct >> vb2_plane *p) { >> if (!p->mem_priv) >> return; >> >> if (p->dbuf_mapped) >> - call_memop(q, unmap_dmabuf, p->mem_priv); >> + call_memop(vb, unmap_dmabuf, p->mem_priv); >> >> - call_memop(q, detach_dmabuf, p->mem_priv); >> + call_memop(vb, detach_dmabuf, p->mem_priv); >> dma_buf_put(p->dbuf); >> memset(p, 0, sizeof(*p)); >> } >> @@ -137,11 +187,10 @@ static void __vb2_plane_dmabuf_put(struct vb2_queue >> *q, struct vb2_plane *p) */ >> static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) >> { >> - struct vb2_queue *q = vb->vb2_queue; >> unsigned int plane; >> >> for (plane = 0; plane < vb->num_planes; ++plane) >> - __vb2_plane_dmabuf_put(q, &vb->planes[plane]); >> + __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); >> } >> >> /** >> @@ -246,10 +295,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum >> v4l2_memory memory, * callback, if given. An error in initialization >> * results in queue setup failure. >> */ >> - ret = call_qop(q, buf_init, vb); >> + ret = call_vb_qop(vb, buf_init, vb); >> if (ret) { >> dprintk(1, "Buffer %d %p initialization" >> " failed\n", buffer, vb); >> + fail_vb_qop(vb, buf_init); >> __vb2_buf_mem_free(vb); >> kfree(vb); >> break; >> @@ -321,18 +371,77 @@ static int __vb2_queue_free(struct vb2_queue *q, >> unsigned int buffers) } >> >> /* Call driver-provided cleanup function for each buffer, if provided */ >> - if (q->ops->buf_cleanup) { >> - for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; >> - ++buffer) { >> - if (NULL == q->bufs[buffer]) >> - continue; >> - q->ops->buf_cleanup(q->bufs[buffer]); >> - } >> + for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; >> + ++buffer) { >> + if (q->bufs[buffer]) >> + call_vb_qop(q->bufs[buffer], buf_cleanup, q->bufs[buffer]); >> } >> >> /* Release video buffer memory */ >> __vb2_free_mem(q, buffers); >> > > I would have put the code below in a separate function, but that's up to you. Yeah, it was a borderline situation. I prefer to keep it in, but if it needs to be extended in the future then it should probably be split up. Regards, Hans > > Acked-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> > >> +#ifdef CONFIG_VIDEO_ADV_DEBUG >> + /* >> + * Check that all the calls were balances during the life-time of this >> + * queue. If not (or if the debug level is 1 or up), then dump the >> + * counters to the kernel log. >> + */ >> + if (q->num_buffers) { >> + bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming || >> + q->cnt_wait_prepare != q->cnt_wait_finish; >> + >> + if (unbalanced || debug) { >> + pr_info("vb2: counters for queue %p:%s\n", q, >> + unbalanced ? " UNBALANCED!" : ""); >> + pr_info("vb2: setup: %u start_streaming: %u stop_streaming: > %u\n", >> + q->cnt_queue_setup, q->cnt_start_streaming, >> + q->cnt_stop_streaming); >> + pr_info("vb2: wait_prepare: %u wait_finish: %u\n", >> + q->cnt_wait_prepare, q->cnt_wait_finish); >> + } >> + q->cnt_queue_setup = 0; >> + q->cnt_wait_prepare = 0; >> + q->cnt_wait_finish = 0; >> + q->cnt_start_streaming = 0; >> + q->cnt_stop_streaming = 0; >> + } >> + for (buffer = 0; buffer < q->num_buffers; ++buffer) { >> + struct vb2_buffer *vb = q->bufs[buffer]; >> + bool unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put || >> + vb->cnt_mem_prepare != vb->cnt_mem_finish || >> + vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr || >> + vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf || >> + vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf || >> + vb->cnt_buf_queue != vb->cnt_buf_done || >> + vb->cnt_buf_prepare != vb->cnt_buf_finish || >> + vb->cnt_buf_init != vb->cnt_buf_cleanup; >> + >> + if (unbalanced || debug) { >> + pr_info("vb2: counters for queue %p, buffer %d:%s\n", >> + q, buffer, unbalanced ? " UNBALANCED!" : ""); >> + pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u >> buf_finish: %u\n", + vb->cnt_buf_init, vb->cnt_buf_cleanup, >> + vb->cnt_buf_prepare, vb->cnt_buf_finish); >> + pr_info("vb2: buf_queue: %u buf_done: %u\n", >> + vb->cnt_buf_queue, vb->cnt_buf_done); >> + pr_info("vb2: alloc: %u put: %u prepare: %u finish: %u mmap: > %u\n", >> + vb->cnt_mem_alloc, vb->cnt_mem_put, >> + vb->cnt_mem_prepare, vb->cnt_mem_finish, >> + vb->cnt_mem_mmap); >> + pr_info("vb2: get_userptr: %u put_userptr: %u\n", >> + vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr); >> + pr_info("vb2: attach_dmabuf: %u detach_dmabuf: %u map_dmabuf: > %u >> unmap_dmabuf: %u\n", + vb->cnt_mem_attach_dmabuf, >> vb->cnt_mem_detach_dmabuf, >> + vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf); >> + pr_info("vb2: get_dmabuf: %u num_users: %u vaddr: %u cookie: > %u\n", >> + vb->cnt_mem_get_dmabuf, >> + vb->cnt_mem_num_users, >> + vb->cnt_mem_vaddr, >> + vb->cnt_mem_cookie); >> + } >> + } >> +#endif >> + >> /* Free videobuf buffers */ >> for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; >> ++buffer) { >> @@ -424,7 +533,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct >> vb2_buffer *vb) * case anyway. If num_users() returns more than 1, >> * we are not the only user of the plane's memory. >> */ >> - if (mem_priv && call_memop(q, num_users, mem_priv) > 1) >> + if (mem_priv && call_memop(vb, num_users, mem_priv) > 1) >> return true; >> } >> return false; >> @@ -703,8 +812,10 @@ static int __reqbufs(struct vb2_queue *q, struct >> v4l2_requestbuffers *req) */ >> ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, >> q->plane_sizes, q->alloc_ctx); >> - if (ret) >> + if (ret) { >> + fail_qop(q, queue_setup); >> return ret; >> + } >> >> /* Finally, allocate buffers and video memory */ >> ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes); >> @@ -723,6 +834,8 @@ static int __reqbufs(struct vb2_queue *q, struct >> v4l2_requestbuffers *req) >> >> ret = call_qop(q, queue_setup, q, NULL, &num_buffers, >> &num_planes, q->plane_sizes, q->alloc_ctx); >> + if (ret) >> + fail_qop(q, queue_setup); >> >> if (!ret && allocated_buffers < num_buffers) >> ret = -ENOMEM; >> @@ -803,8 +916,10 @@ static int __create_bufs(struct vb2_queue *q, struct >> v4l2_create_buffers *create */ >> ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, >> &num_planes, q->plane_sizes, q->alloc_ctx); >> - if (ret) >> + if (ret) { >> + fail_qop(q, queue_setup); >> return ret; >> + } >> >> /* Finally, allocate buffers and video memory */ >> ret = __vb2_queue_alloc(q, create->memory, num_buffers, >> @@ -828,6 +943,8 @@ static int __create_bufs(struct vb2_queue *q, struct >> v4l2_create_buffers *create */ >> ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, >> &num_planes, q->plane_sizes, q->alloc_ctx); >> + if (ret) >> + fail_qop(q, queue_setup); >> >> if (!ret && allocated_buffers < num_buffers) >> ret = -ENOMEM; >> @@ -882,12 +999,10 @@ EXPORT_SYMBOL_GPL(vb2_create_bufs); >> */ >> void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) >> { >> - struct vb2_queue *q = vb->vb2_queue; >> - >> if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) >> return NULL; >> >> - return call_memop(q, vaddr, vb->planes[plane_no].mem_priv); >> + return call_memop(vb, vaddr, vb->planes[plane_no].mem_priv); >> >> } >> EXPORT_SYMBOL_GPL(vb2_plane_vaddr); >> @@ -905,12 +1020,10 @@ EXPORT_SYMBOL_GPL(vb2_plane_vaddr); >> */ >> void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) >> { >> - struct vb2_queue *q = vb->vb2_queue; >> - >> if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) >> return NULL; >> >> - return call_memop(q, cookie, vb->planes[plane_no].mem_priv); >> + return call_memop(vb, cookie, vb->planes[plane_no].mem_priv); >> } >> EXPORT_SYMBOL_GPL(vb2_plane_cookie); >> >> @@ -938,12 +1051,19 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum >> vb2_buffer_state state) if (state != VB2_BUF_STATE_DONE && state != >> VB2_BUF_STATE_ERROR) return; >> >> +#ifdef CONFIG_VIDEO_ADV_DEBUG >> + /* >> + * Although this is not a callback, it still does have to balance >> + * with the buf_queue op. So update this counter manually. >> + */ >> + vb->cnt_buf_done++; >> +#endif >> dprintk(4, "Done processing on buffer %d, state: %d\n", >> vb->v4l2_buf.index, state); >> >> /* sync buffers */ >> for (plane = 0; plane < vb->num_planes; ++plane) >> - call_memop(q, finish, vb->planes[plane].mem_priv); >> + call_memop(vb, finish, vb->planes[plane].mem_priv); >> >> /* Add the buffer to the done buffers list */ >> spin_lock_irqsave(&q->done_lock, flags); >> @@ -1067,19 +1187,20 @@ static int __qbuf_userptr(struct vb2_buffer *vb, >> const struct v4l2_buffer *b) >> >> /* Release previously acquired memory if present */ >> if (vb->planes[plane].mem_priv) >> - call_memop(q, put_userptr, vb->planes[plane].mem_priv); >> + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); >> >> vb->planes[plane].mem_priv = NULL; >> vb->v4l2_planes[plane].m.userptr = 0; >> vb->v4l2_planes[plane].length = 0; >> >> /* Acquire each plane's memory */ >> - mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane], >> + mem_priv = call_memop(vb, get_userptr, q->alloc_ctx[plane], >> planes[plane].m.userptr, >> planes[plane].length, write); >> if (IS_ERR_OR_NULL(mem_priv)) { >> dprintk(1, "qbuf: failed acquiring userspace " >> "memory for plane %d\n", plane); >> + fail_memop(vb, get_userptr); >> ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL; >> goto err; >> } >> @@ -1090,9 +1211,10 @@ static int __qbuf_userptr(struct vb2_buffer *vb, >> const struct v4l2_buffer *b) * Call driver-specific initialization on the >> newly acquired buffer, * if provided. >> */ >> - ret = call_qop(q, buf_init, vb); >> + ret = call_vb_qop(vb, buf_init, vb); >> if (ret) { >> dprintk(1, "qbuf: buffer initialization failed\n"); >> + fail_vb_qop(vb, buf_init); >> goto err; >> } >> >> @@ -1108,7 +1230,7 @@ err: >> /* In case of errors, release planes that were already acquired */ >> for (plane = 0; plane < vb->num_planes; ++plane) { >> if (vb->planes[plane].mem_priv) >> - call_memop(q, put_userptr, vb->planes[plane].mem_priv); >> + call_memop(vb, put_userptr, vb->planes[plane].mem_priv); >> vb->planes[plane].mem_priv = NULL; >> vb->v4l2_planes[plane].m.userptr = 0; >> vb->v4l2_planes[plane].length = 0; >> @@ -1173,14 +1295,15 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, >> const struct v4l2_buffer *b) dprintk(1, "qbuf: buffer for plane %d >> changed\n", plane); >> >> /* Release previously acquired memory if present */ >> - __vb2_plane_dmabuf_put(q, &vb->planes[plane]); >> + __vb2_plane_dmabuf_put(vb, &vb->planes[plane]); >> memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); >> >> /* Acquire each plane's memory */ >> - mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane], >> + mem_priv = call_memop(vb, attach_dmabuf, q->alloc_ctx[plane], >> dbuf, planes[plane].length, write); >> if (IS_ERR(mem_priv)) { >> dprintk(1, "qbuf: failed to attach dmabuf\n"); >> + fail_memop(vb, attach_dmabuf); >> ret = PTR_ERR(mem_priv); >> dma_buf_put(dbuf); >> goto err; >> @@ -1195,10 +1318,11 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, >> const struct v4l2_buffer *b) * the buffer(s).. >> */ >> for (plane = 0; plane < vb->num_planes; ++plane) { >> - ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv); >> + ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv); >> if (ret) { >> dprintk(1, "qbuf: failed to map dmabuf for plane %d\n", >> plane); >> + fail_memop(vb, map_dmabuf); >> goto err; >> } >> vb->planes[plane].dbuf_mapped = 1; >> @@ -1208,9 +1332,10 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const >> struct v4l2_buffer *b) * Call driver-specific initialization on the newly >> acquired buffer, * if provided. >> */ >> - ret = call_qop(q, buf_init, vb); >> + ret = call_vb_qop(vb, buf_init, vb); >> if (ret) { >> dprintk(1, "qbuf: buffer initialization failed\n"); >> + fail_vb_qop(vb, buf_init); >> goto err; >> } >> >> @@ -1242,9 +1367,9 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) >> >> /* sync buffers */ >> for (plane = 0; plane < vb->num_planes; ++plane) >> - call_memop(q, prepare, vb->planes[plane].mem_priv); >> + call_memop(vb, prepare, vb->planes[plane].mem_priv); >> >> - q->ops->buf_queue(vb); >> + call_vb_qop(vb, buf_queue, vb); >> } >> >> static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer >> *b) @@ -1295,8 +1420,11 @@ static int __buf_prepare(struct vb2_buffer *vb, >> const struct v4l2_buffer *b) ret = -EINVAL; >> } >> >> - if (!ret) >> - ret = call_qop(q, buf_prepare, vb); >> + if (!ret) { >> + ret = call_vb_qop(vb, buf_prepare, vb); >> + if (ret) >> + fail_vb_qop(vb, buf_prepare); >> + } >> if (ret) >> dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); >> vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED; >> @@ -1393,6 +1521,8 @@ static int vb2_start_streaming(struct vb2_queue *q) >> >> /* Tell the driver to start streaming */ >> ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count)); >> + if (ret) >> + fail_qop(q, start_streaming); >> >> /* >> * If there are not enough buffers queued to start streaming, then >> @@ -1635,7 +1765,7 @@ static void __vb2_dqbuf(struct vb2_buffer *vb) >> for (i = 0; i < vb->num_planes; ++i) { >> if (!vb->planes[i].dbuf_mapped) >> continue; >> - call_memop(q, unmap_dmabuf, vb->planes[i].mem_priv); >> + call_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv); >> vb->planes[i].dbuf_mapped = 0; >> } >> } >> @@ -1653,7 +1783,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, >> struct v4l2_buffer *b, bool n if (ret < 0) >> return ret; >> >> - ret = call_qop(q, buf_finish, vb); >> + ret = call_vb_qop(vb, buf_finish, vb); >> if (ret) { >> dprintk(1, "dqbuf: buffer finish failed\n"); >> return ret; >> @@ -1946,10 +2076,11 @@ int vb2_expbuf(struct vb2_queue *q, struct >> v4l2_exportbuffer *eb) >> >> vb_plane = &vb->planes[eb->plane]; >> >> - dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv, eb->flags & >> O_ACCMODE); + dbuf = call_memop(vb, get_dmabuf, vb_plane->mem_priv, >> eb->flags & O_ACCMODE); if (IS_ERR_OR_NULL(dbuf)) { >> dprintk(1, "Failed to export buffer %d, plane %d\n", >> eb->index, eb->plane); >> + fail_memop(vb, get_dmabuf); >> return -EINVAL; >> } >> >> @@ -2041,9 +2172,11 @@ int vb2_mmap(struct vb2_queue *q, struct >> vm_area_struct *vma) return -EINVAL; >> } >> >> - ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma); >> - if (ret) >> + ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma); >> + if (ret) { >> + fail_memop(vb, mmap); >> return ret; >> + } >> >> dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane); >> return 0; >> diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h >> index bef53ce..f04eb28 100644 >> --- a/include/media/videobuf2-core.h >> +++ b/include/media/videobuf2-core.h >> @@ -203,6 +203,37 @@ struct vb2_buffer { >> struct list_head done_entry; >> >> struct vb2_plane planes[VIDEO_MAX_PLANES]; >> + >> +#ifdef CONFIG_VIDEO_ADV_DEBUG >> + /* >> + * Counters for how often these buffer-related ops are >> + * called. Used to check for unbalanced ops. >> + */ >> + u32 cnt_mem_alloc; >> + u32 cnt_mem_put; >> + u32 cnt_mem_get_dmabuf; >> + u32 cnt_mem_get_userptr; >> + u32 cnt_mem_put_userptr; >> + u32 cnt_mem_prepare; >> + u32 cnt_mem_finish; >> + u32 cnt_mem_attach_dmabuf; >> + u32 cnt_mem_detach_dmabuf; >> + u32 cnt_mem_map_dmabuf; >> + u32 cnt_mem_unmap_dmabuf; >> + u32 cnt_mem_vaddr; >> + u32 cnt_mem_cookie; >> + u32 cnt_mem_num_users; >> + u32 cnt_mem_mmap; >> + >> + u32 cnt_buf_init; >> + u32 cnt_buf_prepare; >> + u32 cnt_buf_finish; >> + u32 cnt_buf_cleanup; >> + u32 cnt_buf_queue; >> + >> + /* This counts the number of calls to vb2_buffer_done() */ >> + u32 cnt_buf_done; >> +#endif >> }; >> >> /** >> @@ -364,6 +395,18 @@ struct vb2_queue { >> unsigned int retry_start_streaming:1; >> >> struct vb2_fileio_data *fileio; >> + >> +#ifdef CONFIG_VIDEO_ADV_DEBUG >> + /* >> + * Counters for how often these queue-related ops are >> + * called. Used to check for unbalanced ops. >> + */ >> + u32 cnt_queue_setup; >> + u32 cnt_wait_prepare; >> + u32 cnt_wait_finish; >> + u32 cnt_start_streaming; >> + u32 cnt_stop_streaming; >> +#endif >> }; >> >> void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no); > -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html