All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hans Verkuil <hverkuil@xs4all.nl>
To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: linux-media@vger.kernel.org, pawel@osciak.com,
	s.nawrocki@samsung.com, m.szyprowski@samsung.com,
	Hans Verkuil <hans.verkuil@cisco.com>
Subject: Re: [REVIEWv2 PATCH 04/15] vb2: add debugging code to check for unbalanced ops
Date: Thu, 27 Feb 2014 12:23:22 +0100	[thread overview]
Message-ID: <530F202A.70406@xs4all.nl> (raw)
In-Reply-To: <10248266.i30TtiCt0v@avalon>

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@cisco.com>
>>
>> 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@cisco.com>
>> Acked-by: Pawel Osciak <pawel@osciak.com>
>> ---
>>  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@ideasonboard.com>
> 
>> +#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);
> 


  reply	other threads:[~2014-02-27 11:23 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-25 12:52 [REVIEWv2 PATCH 00/15] vb2: fixes, balancing callbacks (PART 1) Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 01/15] vb2: Check if there are buffers before streamon Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 02/15] vb2: fix read/write regression Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 03/15] vb2: fix PREPARE_BUF regression Hans Verkuil
2014-02-27 10:52   ` Laurent Pinchart
2014-02-25 12:52 ` [REVIEWv2 PATCH 04/15] vb2: add debugging code to check for unbalanced ops Hans Verkuil
2014-02-27 11:15   ` Laurent Pinchart
2014-02-27 11:23     ` Hans Verkuil [this message]
2014-02-25 12:52 ` [REVIEWv2 PATCH 05/15] vb2: change result code of buf_finish to void Hans Verkuil
2014-02-27 11:23   ` Laurent Pinchart
2014-02-27 11:27     ` Laurent Pinchart
2014-02-27 11:28   ` Laurent Pinchart
2014-02-25 12:52 ` [REVIEWv2 PATCH 06/15] vb2: add note that buf_finish can be called with !vb2_is_streaming() Hans Verkuil
2014-02-27 11:39   ` Laurent Pinchart
2014-02-25 12:52 ` [REVIEWv2 PATCH 07/15] vb2: call buf_finish from __dqbuf Hans Verkuil
2014-02-27 11:51   ` Laurent Pinchart
2014-02-27 12:13     ` Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 08/15] vb2: fix buf_init/buf_cleanup call sequences Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 09/15] vb2: rename queued_count to owned_by_drv_count Hans Verkuil
2014-02-27 12:08   ` Laurent Pinchart
2014-02-25 12:52 ` [REVIEWv2 PATCH 10/15] vb2: don't init the list if there are still buffers Hans Verkuil
2014-02-27 12:08   ` Laurent Pinchart
2014-02-25 12:52 ` [REVIEWv2 PATCH 11/15] vb2: only call start_streaming if sufficient buffers are queued Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 12/15] vb2: properly clean up PREPARED and QUEUED buffers Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 13/15] vb2: replace BUG by WARN_ON Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 14/15] vb2: fix streamoff handling if streamon wasn't called Hans Verkuil
2014-02-25 12:52 ` [REVIEWv2 PATCH 15/15] vivi: correctly cleanup after a start_streaming failure Hans Verkuil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=530F202A.70406@xs4all.nl \
    --to=hverkuil@xs4all.nl \
    --cc=hans.verkuil@cisco.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-media@vger.kernel.org \
    --cc=m.szyprowski@samsung.com \
    --cc=pawel@osciak.com \
    --cc=s.nawrocki@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.