linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/10] Add DELETE_BUF ioctl
@ 2023-08-24  9:21 Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 01/10] media: videobuf2: Rework offset 'cookie' encoding pattern Benjamin Gaignard
                   ` (9 more replies)
  0 siblings, 10 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Unlike when resolution change on keyframes, dynamic resolution change
on inter frames doesn't allow to do a stream off/on sequence because
it is need to keep all previous references alive to decode inter frames.
This constraint have two main problems:
- more memory consumption.
- more buffers in use.
To solve these issue this series introduce DELETE_BUFS ioctl and remove
the 32 buffers limit per queue.

VP9 conformance tests using fluster give a score of 210/305.
The 24 resize inter tests (vp90-2-21-resize_inter_* files) are ok
but require to use postprocessor.

Kernel branch is available here:
https://gitlab.collabora.com/benjamin.gaignard/for-upstream/-/commits/remove_vb2_queue_limit_v5

GStreamer branch to use DELETE_BUF ioctl and testing dynamic resolution
change is here:
https://gitlab.freedesktop.org/benjamin.gaignard1/gstreamer/-/commits/VP9_drc

changes in version 5
- Rework offset cookie encoding pattern is n ow the first patch of the
  serie.
- Use static array instead of allocated one for postprocessor buffers.

changes in version 4:
- Stop using Xarray, instead let queues decide about their own maximum
  number of buffer and allocate bufs array given that value.
- Rework offset cookie encoding pattern.
- Change DELETE_BUF to DELETE_BUFS because it now usable for
  range of buffer to be symetrical of CREATE_BUFS.
- Add fixes tags on couple of Verisilicon related patches.
- Be smarter in Verisilicon postprocessor buffers management.
- Rebase on top of v6.4

changes in version 3:
- Use Xarray API to store allocated video buffers.
- No module parameter to limit the number of buffer per queue.
- Use Xarray inside Verisilicon driver to store postprocessor buffers
  and remove VB2_MAX_FRAME limit.
- Allow Versilicon driver to change of resolution while streaming
- Various fixes the Verisilicon VP9 code to improve fluster score.
 
changes in version 2:
- Use a dynamic array and not a list to keep trace of allocated buffers.
  Not use IDR interface because it is marked as deprecated in kernel
  documentation.
- Add a module parameter to limit the number of buffer per queue.
- Add DELETE_BUF ioctl and m2m helpers.

Regards,
Benjamin
 
Benjamin Gaignard (10):
  media: videobuf2: Rework offset 'cookie' encoding pattern
  media: videobuf2: Access vb2_queue bufs array through helper functions
  media: videobuf2: Be more flexible on the number of queue stored
    buffers
  media: verisilicon: Refactor postprocessor to store more buffers
  media: verisilicon: Store chroma and motion vectors offset
  media: verisilicon: vp9: Use destination buffer height to compute
    chroma offset
  media: verisilicon: postproc: Fix down scale test
  media: verisilicon: vp9: Allow to change resolution while streaming
  media: v4l2: Add DELETE_BUFS ioctl
  media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl

 .../userspace-api/media/v4l/user-func.rst     |   1 +
 .../media/v4l/vidioc-delete-bufs.rst          |  73 +++++
 .../media/common/videobuf2/videobuf2-core.c   | 304 +++++++++++++-----
 .../media/common/videobuf2/videobuf2-v4l2.c   |  44 ++-
 drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
 .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
 drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
 drivers/media/platform/verisilicon/hantro.h   |   9 +-
 .../media/platform/verisilicon/hantro_drv.c   |   4 +-
 .../platform/verisilicon/hantro_g2_vp9_dec.c  |  10 +-
 .../media/platform/verisilicon/hantro_hw.h    |   4 +-
 .../platform/verisilicon/hantro_postproc.c    |  95 ++++--
 .../media/platform/verisilicon/hantro_v4l2.c  |  27 +-
 drivers/media/test-drivers/vim2m.c            |   1 +
 drivers/media/test-drivers/visl/visl-dec.c    |  28 +-
 drivers/media/v4l2-core/v4l2-dev.c            |   1 +
 drivers/media/v4l2-core/v4l2-ioctl.c          |  17 +
 drivers/media/v4l2-core/v4l2-mem2mem.c        |  20 ++
 .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
 include/media/v4l2-ioctl.h                    |   4 +
 include/media/v4l2-mem2mem.h                  |  12 +
 include/media/videobuf2-core.h                |  13 +-
 include/media/videobuf2-v4l2.h                |  11 +
 include/uapi/linux/videodev2.h                |  17 +
 25 files changed, 584 insertions(+), 147 deletions(-)
 create mode 100644 Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst

-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v5 01/10] media: videobuf2: Rework offset 'cookie' encoding pattern
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-30 12:25   ` Hans Verkuil
  2023-08-24  9:21 ` [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions Benjamin Gaignard
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Change how offset 'cookie' field value is computed to make possible
to use more buffers (up to 0xffff).
With this encoding pattern we know the maximum number that a queue
could store so we can check ing at queue init time.
It also make easier and faster to find buffer and plane from using
the offset field.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
---
v5:
- I haven't change DST_QUEUE_OFF_BASE definition because it used in
  v4l2-mem2mem and s5p_mfc driver with a shift.

 .../media/common/videobuf2/videobuf2-core.c   | 48 +++++++++----------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index cf6727d9c81f..e06905533ef4 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -31,6 +31,10 @@
 
 #include <trace/events/vb2.h>
 
+#define PLANE_INDEX_SHIFT	3
+#define PLANE_INDEX_MASK	0x7
+#define MAX_BUFFERS		0xffff
+
 static int debug;
 module_param(debug, int, 0644);
 
@@ -358,21 +362,23 @@ static void __setup_offsets(struct vb2_buffer *vb)
 	unsigned int plane;
 	unsigned long off = 0;
 
-	if (vb->index) {
-		struct vb2_buffer *prev = q->bufs[vb->index - 1];
-		struct vb2_plane *p = &prev->planes[prev->num_planes - 1];
-
-		off = PAGE_ALIGN(p->m.offset + p->length);
-	}
+	/*
+	 * Offsets cookies value have the following constraints:
+	 * - a buffer could have up to 8 planes.
+	 * - v4l2 mem2mem use bit 30 to distinguish between source and destination buffers.
+	 * - must be page aligned
+	 * That led to this bit mapping:
+	 * |30                |29        15|14       12|11 0|
+	 * |DST_QUEUE_OFF_BASE|buffer index|plane index| 0  |
+	 * where there is 16 bits to store buffer index.
+	 */
+	off = vb->index << (PLANE_INDEX_SHIFT + PAGE_SHIFT);
 
 	for (plane = 0; plane < vb->num_planes; ++plane) {
-		vb->planes[plane].m.offset = off;
+		vb->planes[plane].m.offset = off + (plane << PAGE_SHIFT);
 
 		dprintk(q, 3, "buffer %d, plane %d offset 0x%08lx\n",
 				vb->index, plane, off);
-
-		off += vb->planes[plane].length;
-		off = PAGE_ALIGN(off);
 	}
 }
 
@@ -2209,21 +2215,15 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
 		return -EBUSY;
 	}
 
-	/*
-	 * Go over all buffers and their planes, comparing the given offset
-	 * with an offset assigned to each plane. If a match is found,
-	 * return its buffer and plane numbers.
-	 */
-	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
-		vb = q->bufs[buffer];
+	/* Get buffer and plane from the offset */
+	buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
+	plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
 
-		for (plane = 0; plane < vb->num_planes; ++plane) {
-			if (vb->planes[plane].m.offset == off) {
-				*_buffer = buffer;
-				*_plane = plane;
-				return 0;
-			}
-		}
+	vb = q->bufs[buffer];
+	if (vb->planes[plane].m.offset == off) {
+		*_buffer = buffer;
+		*_plane = plane;
+		return 0;
 	}
 
 	return -EINVAL;
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 01/10] media: videobuf2: Rework offset 'cookie' encoding pattern Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-30 13:23   ` Hans Verkuil
  2023-08-24  9:21 ` [PATCH v5 03/10] media: videobuf2: Be more flexible on the number of queue stored buffers Benjamin Gaignard
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

The first step before changing how vb2 buffers are stored into queue
is to avoid direct access to bufs arrays.

This patch adds 2 helpers functions to add and remove vb2 buffers
from a queue. With these 2 and vb2_get_buffer(), bufs field of
struct vb2_queue becomes like a private member of the structure.

After each call to vb2_get_buffer() we need to be sure that we get
a valid pointer so check the return value of all of them.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>

# Conflicts:
#	drivers/media/common/videobuf2/videobuf2-core.c
---
 .../media/common/videobuf2/videobuf2-core.c   | 203 ++++++++++++++----
 .../media/common/videobuf2/videobuf2-v4l2.c   |  28 ++-
 drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
 .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
 .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
 drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
 drivers/media/test-drivers/visl/visl-dec.c    |  28 ++-
 .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
 8 files changed, 230 insertions(+), 65 deletions(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index e06905533ef4..8aa13591b782 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -403,6 +403,37 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
 		vb->skip_cache_sync_on_finish = 1;
 }
 
+/**
+ * vb2_queue_add_buffer() - add a buffer to a queue
+ * @q:	pointer to &struct vb2_queue with videobuf2 queue.
+ * @vb:	pointer to &struct vb2_buffer to be added to the queue.
+ * @index: index where add vb2_buffer in the queue
+ */
+static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
+{
+	if (index < VB2_MAX_FRAME && !q->bufs[index]) {
+		q->bufs[index] = vb;
+		vb->index = index;
+		vb->vb2_queue = q;
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * vb2_queue_remove_buffer() - remove a buffer from a queue
+ * @q:	pointer to &struct vb2_queue with videobuf2 queue.
+ * @vb:	pointer to &struct vb2_buffer to be removed from the queue.
+ */
+static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
+{
+	if (vb->index < VB2_MAX_FRAME) {
+		q->bufs[vb->index] = NULL;
+		vb->vb2_queue = NULL;
+	}
+}
+
 /*
  * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
  * video buffer memory for all buffers/planes on the queue and initializes the
@@ -431,9 +462,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
 		}
 
 		vb->state = VB2_BUF_STATE_DEQUEUED;
-		vb->vb2_queue = q;
 		vb->num_planes = num_planes;
-		vb->index = q->num_buffers + buffer;
 		vb->type = q->type;
 		vb->memory = memory;
 		init_buffer_cache_hints(q, vb);
@@ -443,7 +472,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
 		}
 		call_void_bufop(q, init_buffer, vb);
 
-		q->bufs[vb->index] = vb;
+		if (!vb2_queue_add_buffer(q, vb, q->num_buffers + buffer)) {
+			dprintk(q, 1, "failed adding buffer %d to queue\n", buffer);
+			kfree(vb);
+			break;
+		}
 
 		/* Allocate video buffer memory for the MMAP type */
 		if (memory == VB2_MEMORY_MMAP) {
@@ -451,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
 			if (ret) {
 				dprintk(q, 1, "failed allocating memory for buffer %d\n",
 					buffer);
-				q->bufs[vb->index] = NULL;
+				vb2_queue_remove_buffer(q, vb);
 				kfree(vb);
 				break;
 			}
@@ -466,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
 				dprintk(q, 1, "buffer %d %p initialization failed\n",
 					buffer, vb);
 				__vb2_buf_mem_free(vb);
-				q->bufs[vb->index] = NULL;
+				vb2_queue_remove_buffer(q, vb);
 				kfree(vb);
 				break;
 			}
@@ -489,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
 
 	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
 	     ++buffer) {
-		vb = q->bufs[buffer];
+		vb = vb2_get_buffer(q, buffer);
 		if (!vb)
 			continue;
 
@@ -517,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
 	/* Call driver-provided cleanup function for each buffer, if provided */
 	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
 	     ++buffer) {
-		struct vb2_buffer *vb = q->bufs[buffer];
+		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
 
 		if (vb && vb->planes[0].mem_priv)
 			call_void_vb_qop(vb, buf_cleanup, vb);
@@ -557,15 +590,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
 		q->cnt_unprepare_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;
+		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
+		bool unbalanced;
+
+		if (!vb)
+			continue;
+
+		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("   counters for queue %p, buffer %d:%s\n",
@@ -597,8 +635,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
 	/* Free vb2 buffers */
 	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
 	     ++buffer) {
-		kfree(q->bufs[buffer]);
-		q->bufs[buffer] = NULL;
+		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
+
+		if (!vb)
+			continue;
+
+		vb2_queue_remove_buffer(q, vb);
+		kfree(vb);
 	}
 
 	q->num_buffers -= buffers;
@@ -634,7 +677,12 @@ static bool __buffers_in_use(struct vb2_queue *q)
 {
 	unsigned int buffer;
 	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
-		if (vb2_buffer_in_use(q, q->bufs[buffer]))
+		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
+
+		if (!vb)
+			continue;
+
+		if (vb2_buffer_in_use(q, vb))
 			return true;
 	}
 	return false;
@@ -642,7 +690,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
 
 void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
 {
-	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
+	struct vb2_buffer *vb = vb2_get_buffer(q, index);
+
+	if (vb)
+		call_void_bufop(q, fill_user_buffer, vb, pb);
 }
 EXPORT_SYMBOL_GPL(vb2_core_querybuf);
 
@@ -1553,7 +1604,13 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
 	struct vb2_buffer *vb;
 	int ret;
 
-	vb = q->bufs[index];
+	vb = vb2_get_buffer(q, index);
+
+	if (!vb) {
+		dprintk(q, 1, "can't find the requested buffer\n");
+		return -EINVAL;
+	}
+
 	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
 		dprintk(q, 1, "invalid buffer state %s\n",
 			vb2_state_name(vb->state));
@@ -1624,7 +1681,11 @@ static int vb2_start_streaming(struct vb2_queue *q)
 		 * correctly return them to vb2.
 		 */
 		for (i = 0; i < q->num_buffers; ++i) {
-			vb = q->bufs[i];
+			vb = vb2_get_buffer(q, i);
+
+			if (!vb)
+				continue;
+
 			if (vb->state == VB2_BUF_STATE_ACTIVE)
 				vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
 		}
@@ -1652,7 +1713,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
 		return -EIO;
 	}
 
-	vb = q->bufs[index];
+	vb = vb2_get_buffer(q, index);
+
+	if (!vb) {
+		dprintk(q, 1, "can't find the requested buffer\n");
+		return -EINVAL;
+	}
 
 	if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
 	    q->requires_requests) {
@@ -2028,12 +2094,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
 	 * to vb2 in stop_streaming().
 	 */
 	if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
-		for (i = 0; i < q->num_buffers; ++i)
-			if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
+		for (i = 0; i < q->num_buffers; ++i) {
+			struct vb2_buffer *vb = vb2_get_buffer(q, i);
+
+			if (!vb)
+				continue;
+
+			if (vb->state == VB2_BUF_STATE_ACTIVE) {
 				pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
-					q->bufs[i]);
-				vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
+					vb);
+				vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
 			}
+		}
 		/* Must be zero now */
 		WARN_ON(atomic_read(&q->owned_by_drv_count));
 	}
@@ -2067,9 +2139,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
 	 * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
 	 */
 	for (i = 0; i < q->num_buffers; ++i) {
-		struct vb2_buffer *vb = q->bufs[i];
-		struct media_request *req = vb->req_obj.req;
+		struct vb2_buffer *vb;
+		struct media_request *req;
+
+		vb = vb2_get_buffer(q, i);
+		if (!vb)
+			continue;
 
+		req = vb->req_obj.req;
 		/*
 		 * If a request is associated with this buffer, then
 		 * call buf_request_cancel() to give the driver to complete()
@@ -2219,7 +2296,10 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
 	buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
 	plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
 
-	vb = q->bufs[buffer];
+	vb = vb2_get_buffer(q, buffer);
+	if (!vb)
+		return -EINVAL;
+
 	if (vb->planes[plane].m.offset == off) {
 		*_buffer = buffer;
 		*_plane = plane;
@@ -2262,7 +2342,12 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
 		return -EINVAL;
 	}
 
-	vb = q->bufs[index];
+	vb = vb2_get_buffer(q, index);
+
+	if (!vb) {
+		dprintk(q, 1, "can't find the requested buffer\n");
+		return -EINVAL;
+	}
 
 	if (plane >= vb->num_planes) {
 		dprintk(q, 1, "buffer plane out of range\n");
@@ -2339,7 +2424,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
 	if (ret)
 		goto unlock;
 
-	vb = q->bufs[buffer];
+	vb = vb2_get_buffer(q, buffer);
+
+	if (!vb) {
+		dprintk(q, 1, "can't find the requested buffer\n");
+		ret = -EINVAL;
+		goto unlock;
+	}
 
 	/*
 	 * MMAP requires page_aligned buffers.
@@ -2396,7 +2487,12 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
 	if (ret)
 		goto unlock;
 
-	vb = q->bufs[buffer];
+	vb = vb2_get_buffer(q, buffer);
+	if (!vb) {
+		dprintk(q, 1, "can't find the requested buffer\n");
+		ret = -EINVAL;
+		goto unlock;
+	}
 
 	vaddr = vb2_plane_vaddr(vb, plane);
 	mutex_unlock(&q->mmap_lock);
@@ -2625,6 +2721,7 @@ struct vb2_fileio_data {
 static int __vb2_init_fileio(struct vb2_queue *q, int read)
 {
 	struct vb2_fileio_data *fileio;
+	struct vb2_buffer *vb;
 	int i, ret;
 	unsigned int count = 0;
 
@@ -2679,7 +2776,13 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
 	 * Check if plane_count is correct
 	 * (multiplane buffers are not supported).
 	 */
-	if (q->bufs[0]->num_planes != 1) {
+	vb = vb2_get_buffer(q, 0);
+	if (!vb) {
+		ret = -EBUSY;
+		goto err_reqbufs;
+	}
+
+	if (vb->num_planes != 1) {
 		ret = -EBUSY;
 		goto err_reqbufs;
 	}
@@ -2688,12 +2791,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
 	 * Get kernel address of each buffer.
 	 */
 	for (i = 0; i < q->num_buffers; i++) {
-		fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
+		vb = vb2_get_buffer(q, i);
+
+		if (!vb)
+			continue;
+
+		fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
 		if (fileio->bufs[i].vaddr == NULL) {
 			ret = -EINVAL;
 			goto err_reqbufs;
 		}
-		fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
+		fileio->bufs[i].size = vb2_plane_size(vb, 0);
 	}
 
 	/*
@@ -2821,15 +2929,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
 
 		fileio->cur_index = index;
 		buf = &fileio->bufs[index];
-		b = q->bufs[index];
+		b = vb2_get_buffer(q, index);
+
+		if (!b)
+			return -EINVAL;
 
 		/*
 		 * Get number of bytes filled by the driver
 		 */
 		buf->pos = 0;
 		buf->queued = 0;
-		buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
-				 : vb2_plane_size(q->bufs[index], 0);
+		buf->size = read ? vb2_get_plane_payload(b, 0)
+				 : vb2_plane_size(b, 0);
 		/* Compensate for data_offset on read in the multiplanar case. */
 		if (is_multiplanar && read &&
 				b->planes[0].data_offset < buf->size) {
@@ -2872,8 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
 	 * Queue next buffer if required.
 	 */
 	if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
-		struct vb2_buffer *b = q->bufs[index];
+		struct vb2_buffer *b = vb2_get_buffer(q, index);
 
+		if (!b) {
+			dprintk(q, 1, "can't find the requested buffer\n");
+			return -EINVAL;
+		}
 		/*
 		 * Check if this is the last buffer to read.
 		 */
@@ -2899,7 +3014,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
 		 */
 		buf->pos = 0;
 		buf->queued = 1;
-		buf->size = vb2_plane_size(q->bufs[index], 0);
+		buf->size = vb2_plane_size(b, 0);
 		fileio->q_count += 1;
 		/*
 		 * If we are queuing up buffers for the first time, then
@@ -2970,7 +3085,9 @@ static int vb2_thread(void *data)
 		 * Call vb2_dqbuf to get buffer back.
 		 */
 		if (prequeue) {
-			vb = q->bufs[index++];
+			vb = vb2_get_buffer(q, index++);
+			if (!vb)
+				continue;
 			prequeue--;
 		} else {
 			call_void_qop(q, wait_finish, q);
@@ -2979,7 +3096,7 @@ static int vb2_thread(void *data)
 			call_void_qop(q, wait_prepare, q);
 			dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
 			if (!ret)
-				vb = q->bufs[index];
+				vb = vb2_get_buffer(q, index);
 		}
 		if (ret || threadio->stop)
 			break;
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index c7a54d82a55e..724135d41f7f 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -383,8 +383,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
 		return -EINVAL;
 	}
 
-	if (q->bufs[b->index] == NULL) {
-		/* Should never happen */
+	if (!vb2_get_buffer(q, b->index)) {
 		dprintk(q, 1, "%s: buffer is NULL\n", opname);
 		return -EINVAL;
 	}
@@ -394,7 +393,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
 		return -EINVAL;
 	}
 
-	vb = q->bufs[b->index];
+	vb = vb2_get_buffer(q, b->index);
 	vbuf = to_vb2_v4l2_buffer(vb);
 	ret = __verify_planes_array(vb, b);
 	if (ret)
@@ -628,11 +627,18 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
 struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
 {
 	unsigned int i;
+	struct vb2_buffer *vb2;
 
-	for (i = 0; i < q->num_buffers; i++)
-		if (q->bufs[i]->copied_timestamp &&
-		    q->bufs[i]->timestamp == timestamp)
-			return vb2_get_buffer(q, i);
+	for (i = 0; i < q->num_buffers; i++) {
+		vb2 = vb2_get_buffer(q, i);
+
+		if (!vb2)
+			continue;
+
+		if (vb2->copied_timestamp &&
+		    vb2->timestamp == timestamp)
+			return vb2;
+	}
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(vb2_find_buffer);
@@ -664,7 +670,13 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
 		dprintk(q, 1, "buffer index out of range\n");
 		return -EINVAL;
 	}
-	vb = q->bufs[b->index];
+	vb = vb2_get_buffer(q, b->index);
+
+	if (!vb) {
+		dprintk(q, 1, "can't find the requested buffer\n");
+		return -EINVAL;
+	}
+
 	ret = __verify_planes_array(vb, b);
 	if (!ret)
 		vb2_core_querybuf(q, b->index, b);
diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
index 982c2c777484..a462d6fe4ea9 100644
--- a/drivers/media/platform/amphion/vpu_dbg.c
+++ b/drivers/media/platform/amphion/vpu_dbg.c
@@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
 
 	vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
 	for (i = 0; i < vq->num_buffers; i++) {
-		struct vb2_buffer *vb = vq->bufs[i];
-		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+		struct vb2_buffer *vb;
+		struct vb2_v4l2_buffer *vbuf;
+
+		vb = vb2_get_buffer(vq, i);
+		if (!vb)
+			continue;
 
 		if (vb->state == VB2_BUF_STATE_DEQUEUED)
 			continue;
+
+		vbuf = to_vb2_v4l2_buffer(vb);
+
 		num = scnprintf(str, sizeof(str),
 				"output [%2d] state = %10s, %8s\n",
 				i, vb2_stat_name[vb->state],
@@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
 
 	vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
 	for (i = 0; i < vq->num_buffers; i++) {
-		struct vb2_buffer *vb = vq->bufs[i];
-		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+		struct vb2_buffer *vb;
+		struct vb2_v4l2_buffer *vbuf;
+
+		vb = vb2_get_buffer(vq, i);
+		if (!vb)
+			continue;
 
 		if (vb->state == VB2_BUF_STATE_DEQUEUED)
 			continue;
+
+		vbuf = to_vb2_v4l2_buffer(vb);
+
 		num = scnprintf(str, sizeof(str),
 				"capture[%2d] state = %10s, %8s\n",
 				i, vb2_stat_name[vb->state],
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 621038aab116..62910a1b8a98 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -603,7 +603,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 		return -EINVAL;
 	}
 
-	vb = vq->bufs[buf->index];
+	vb = vb2_get_buffer(vq, buf->index);
+	if (!vb) {
+		dev_err(ctx->jpeg->dev, "buffer not found\n");
+		return -EINVAL;
+	}
 	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
 	jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
 
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
index e393e3e668f8..3d2ae0e1b5b6 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
@@ -1696,7 +1696,7 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
 
 	/* update internal buffer's width/height */
 	for (i = 0; i < vq->num_buffers; i++) {
-		if (vb == vq->bufs[i]) {
+		if (vb == vb2_get_buffer(vq, i)) {
 			instance->dpb[i].width = w;
 			instance->dpb[i].height = h;
 			break;
diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
index 3a848ca32a0e..326be09bdb55 100644
--- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
+++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
@@ -577,6 +577,10 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
 		}
 
 		vb2_buf = vb2_get_buffer(vq, buf->index);
+		if (!vb2_buf) {
+			dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
+			return -EINVAL;
+		}
 		stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
 		stream->bytesused = buf->bytesused;
 	}
diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
index 318d675e5668..ba20ea998d19 100644
--- a/drivers/media/test-drivers/visl/visl-dec.c
+++ b/drivers/media/test-drivers/visl/visl-dec.c
@@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
 	for (i = 0; i < out_q->num_buffers; i++) {
 		char entry[] = "index: %u, state: %s, request_fd: %d, ";
 		u32 old_len = len;
-		char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
+		struct vb2_buffer *vb2;
+		char *q_status;
+
+		vb2 = vb2_get_buffer(out_q, i);
+		if (!vb2)
+			continue;
+
+		q_status = visl_get_vb2_state(vb2->state);
 
 		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
 				 entry, i, q_status,
-				 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
+				 to_vb2_v4l2_buffer(vb2)->request_fd);
 
-		len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
+		len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
 					   &buf[len],
 					   TPG_STR_BUF_SZ - len);
 
@@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
 	len = 0;
 	for (i = 0; i < cap_q->num_buffers; i++) {
 		u32 old_len = len;
-		char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
+		struct vb2_buffer *vb2;
+		char *q_status;
+
+		vb2 = vb2_get_buffer(cap_q, i);
+		if (!vb2)
+			continue;
+
+		q_status = visl_get_vb2_state(vb2->state);
 
 		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
 				 "index: %u, status: %s, timestamp: %llu, is_held: %d",
-				 cap_q->bufs[i]->index, q_status,
-				 cap_q->bufs[i]->timestamp,
-				 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
+				 vb2->index, q_status,
+				 vb2->timestamp,
+				 to_vb2_v4l2_buffer(vb2)->is_held);
 
 		tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
 		frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index d2174156573a..4b65c69fa60d 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -1061,7 +1061,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
 	if (ret)
 		return ret;
 
-	vb = pipe->vb_queue.bufs[buf->index];
+	vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
 	frame = vb_to_frame(vb);
 
 	buf->reserved = asd->frame_status[buf->index];
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 03/10] media: videobuf2: Be more flexible on the number of queue stored buffers
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 01/10] media: videobuf2: Rework offset 'cookie' encoding pattern Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-30 13:27   ` Hans Verkuil
  2023-08-24  9:21 ` [PATCH v5 04/10] media: verisilicon: Refactor postprocessor to store more buffers Benjamin Gaignard
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Add 'max_allowed_buffers' field in vb2_queue struct to let drivers decide
how many buffers could be stored in a queue.
This request 'bufs' array to be allocated at queue init time and freed
when releasing the queue.
By default VB2_MAX_FRAME remains the limit.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
---
 .../media/common/videobuf2/videobuf2-core.c   | 25 +++++++++++++------
 include/media/videobuf2-core.h                |  4 ++-
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 8aa13591b782..70e36389b704 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -411,7 +411,7 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
  */
 static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
 {
-	if (index < VB2_MAX_FRAME && !q->bufs[index]) {
+	if (index < q->max_allowed_buffers && !q->bufs[index]) {
 		q->bufs[index] = vb;
 		vb->index = index;
 		vb->vb2_queue = q;
@@ -428,7 +428,7 @@ static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int
  */
 static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
 {
-	if (vb->index < VB2_MAX_FRAME) {
+	if (vb->index < q->max_allowed_buffers) {
 		q->bufs[vb->index] = NULL;
 		vb->vb2_queue = NULL;
 	}
@@ -449,9 +449,9 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
 	struct vb2_buffer *vb;
 	int ret;
 
-	/* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */
+	/* Ensure that q->num_buffers+num_buffers is below q->max_allowed_buffers */
 	num_buffers = min_t(unsigned int, num_buffers,
-			    VB2_MAX_FRAME - q->num_buffers);
+			    q->max_allowed_buffers - q->num_buffers);
 
 	for (buffer = 0; buffer < num_buffers; ++buffer) {
 		/* Allocate vb2 buffer structures */
@@ -852,9 +852,9 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
 	/*
 	 * Make sure the requested values and current defaults are sane.
 	 */
-	WARN_ON(q->min_buffers_needed > VB2_MAX_FRAME);
+	WARN_ON(q->min_buffers_needed > q->max_allowed_buffers);
 	num_buffers = max_t(unsigned int, *count, q->min_buffers_needed);
-	num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME);
+	num_buffers = min_t(unsigned int, num_buffers, q->max_allowed_buffers);
 	memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
 	/*
 	 * Set this now to ensure that drivers see the correct q->memory value
@@ -970,7 +970,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
 	bool no_previous_buffers = !q->num_buffers;
 	int ret;
 
-	if (q->num_buffers == VB2_MAX_FRAME) {
+	if (q->num_buffers == q->max_allowed_buffers) {
 		dprintk(q, 1, "maximum number of buffers already allocated\n");
 		return -ENOBUFS;
 	}
@@ -999,7 +999,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
 			return -EINVAL;
 	}
 
-	num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
+	num_buffers = min(*count, q->max_allowed_buffers - q->num_buffers);
 
 	if (requested_planes && requested_sizes) {
 		num_planes = requested_planes;
@@ -2541,6 +2541,14 @@ int vb2_core_queue_init(struct vb2_queue *q)
 
 	q->memory = VB2_MEMORY_UNKNOWN;
 
+	if (!q->max_allowed_buffers)
+		q->max_allowed_buffers = VB2_MAX_FRAME;
+
+	/* The maximum is limited by offset cookie encoding pattern */
+	q->max_allowed_buffers = min_t(unsigned int, q->max_allowed_buffers, MAX_BUFFERS);
+
+	q->bufs = kcalloc(q->max_allowed_buffers, sizeof(*q->bufs), GFP_KERNEL);
+
 	if (q->buf_struct_size == 0)
 		q->buf_struct_size = sizeof(struct vb2_buffer);
 
@@ -2565,6 +2573,7 @@ void vb2_core_queue_release(struct vb2_queue *q)
 	__vb2_queue_cancel(q);
 	mutex_lock(&q->mmap_lock);
 	__vb2_queue_free(q, q->num_buffers);
+	kfree(q->bufs);
 	mutex_unlock(&q->mmap_lock);
 }
 EXPORT_SYMBOL_GPL(vb2_core_queue_release);
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 4b6a9d2ea372..ee9161b9fd64 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -558,6 +558,7 @@ struct vb2_buf_ops {
  * @dma_dir:	DMA mapping direction.
  * @bufs:	videobuf2 buffer structures
  * @num_buffers: number of allocated/used buffers
+ * @max_allowed_buffers: upper limit of number of allocated/used buffers
  * @queued_list: list of buffers currently queued from userspace
  * @queued_count: number of buffers queued and ready for streaming.
  * @owned_by_drv_count: number of buffers owned by the driver
@@ -619,8 +620,9 @@ struct vb2_queue {
 	struct mutex			mmap_lock;
 	unsigned int			memory;
 	enum dma_data_direction		dma_dir;
-	struct vb2_buffer		*bufs[VB2_MAX_FRAME];
+	struct vb2_buffer		**bufs;
 	unsigned int			num_buffers;
+	unsigned int			max_allowed_buffers;
 
 	struct list_head		queued_list;
 	unsigned int			queued_count;
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 04/10] media: verisilicon: Refactor postprocessor to store more buffers
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
                   ` (2 preceding siblings ...)
  2023-08-24  9:21 ` [PATCH v5 03/10] media: videobuf2: Be more flexible on the number of queue stored buffers Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 05/10] media: verisilicon: Store chroma and motion vectors offset Benjamin Gaignard
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Since vb2 queue can store than VB2_MAX_FRAME buffers postprocessor
buffer storage must be capable to store more buffers too.
Change static dec_q array to allocated array to be capable to store
up to queue 'max_allowed_buffers'.
Keep allocating queue 'num_buffers' at queue setup time but also allows
to allocate postprocessors buffers on the fly.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
---
v5:
- Use a static buffer array instead of an allocated one.

 drivers/media/platform/verisilicon/hantro.h   |  7 +-
 .../media/platform/verisilicon/hantro_drv.c   |  4 +-
 .../media/platform/verisilicon/hantro_hw.h    |  4 +-
 .../platform/verisilicon/hantro_postproc.c    | 93 +++++++++++++++----
 .../media/platform/verisilicon/hantro_v4l2.c  |  2 +-
 5 files changed, 85 insertions(+), 25 deletions(-)

diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index 77aee9489516..0948b04a9f8d 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -469,11 +469,14 @@ hantro_get_dst_buf(struct hantro_ctx *ctx)
 bool hantro_needs_postproc(const struct hantro_ctx *ctx,
 			   const struct hantro_fmt *fmt);
 
+dma_addr_t
+hantro_postproc_get_dec_buf_addr(struct hantro_ctx *ctx, int index);
+
 static inline dma_addr_t
 hantro_get_dec_buf_addr(struct hantro_ctx *ctx, struct vb2_buffer *vb)
 {
 	if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt))
-		return ctx->postproc.dec_q[vb->index].dma;
+		return hantro_postproc_get_dec_buf_addr(ctx, vb->index);
 	return vb2_dma_contig_plane_dma_addr(vb, 0);
 }
 
@@ -485,8 +488,8 @@ vb2_to_hantro_decoded_buf(struct vb2_buffer *buf)
 
 void hantro_postproc_disable(struct hantro_ctx *ctx);
 void hantro_postproc_enable(struct hantro_ctx *ctx);
+int hantro_postproc_init(struct hantro_ctx *ctx);
 void hantro_postproc_free(struct hantro_ctx *ctx);
-int hantro_postproc_alloc(struct hantro_ctx *ctx);
 int hanto_postproc_enum_framesizes(struct hantro_ctx *ctx,
 				   struct v4l2_frmsizeenum *fsize);
 
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 423fc85d79ee..18f56edee3fc 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -234,8 +234,10 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 	 * The Kernel needs access to the JPEG destination buffer for the
 	 * JPEG encoder to fill in the JPEG headers.
 	 */
-	if (!ctx->is_encoder)
+	if (!ctx->is_encoder) {
 		dst_vq->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
+		dst_vq->max_allowed_buffers = MAX_POSTPROC_BUFFERS;
+	}
 
 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
diff --git a/drivers/media/platform/verisilicon/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h
index 7f33f7b07ce4..292a76ef643e 100644
--- a/drivers/media/platform/verisilicon/hantro_hw.h
+++ b/drivers/media/platform/verisilicon/hantro_hw.h
@@ -40,6 +40,8 @@
 
 #define AV1_MAX_FRAME_BUF_COUNT	(V4L2_AV1_TOTAL_REFS_PER_FRAME + 1)
 
+#define MAX_POSTPROC_BUFFERS	64
+
 struct hantro_dev;
 struct hantro_ctx;
 struct hantro_buf;
@@ -336,7 +338,7 @@ struct hantro_av1_dec_hw_ctx {
  * @dec_q:		References buffers, in decoder format.
  */
 struct hantro_postproc_ctx {
-	struct hantro_aux_buf dec_q[VB2_MAX_FRAME];
+	struct hantro_aux_buf dec_q[MAX_POSTPROC_BUFFERS];
 };
 
 /**
diff --git a/drivers/media/platform/verisilicon/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c
index 0224ff68ab3f..e624cd98f41b 100644
--- a/drivers/media/platform/verisilicon/hantro_postproc.c
+++ b/drivers/media/platform/verisilicon/hantro_postproc.c
@@ -177,9 +177,11 @@ static int hantro_postproc_g2_enum_framesizes(struct hantro_ctx *ctx,
 void hantro_postproc_free(struct hantro_ctx *ctx)
 {
 	struct hantro_dev *vpu = ctx->dev;
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	struct vb2_queue *queue = &m2m_ctx->cap_q_ctx.q;
 	unsigned int i;
 
-	for (i = 0; i < VB2_MAX_FRAME; ++i) {
+	for (i = 0; i < queue->max_allowed_buffers; ++i) {
 		struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i];
 
 		if (priv->cpu) {
@@ -190,20 +192,17 @@ void hantro_postproc_free(struct hantro_ctx *ctx)
 	}
 }
 
-int hantro_postproc_alloc(struct hantro_ctx *ctx)
+static unsigned int hantro_postproc_buffer_size(struct hantro_ctx *ctx)
 {
-	struct hantro_dev *vpu = ctx->dev;
-	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
-	struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q;
-	unsigned int num_buffers = cap_queue->num_buffers;
 	struct v4l2_pix_format_mplane pix_mp;
 	const struct hantro_fmt *fmt;
-	unsigned int i, buf_size;
+	unsigned int buf_size;
 
 	/* this should always pick native format */
 	fmt = hantro_get_default_fmt(ctx, false, ctx->bit_depth, HANTRO_AUTO_POSTPROC);
 	if (!fmt)
-		return -EINVAL;
+		return 0;
+
 	v4l2_fill_pixfmt_mp(&pix_mp, fmt->fourcc, ctx->src_fmt.width,
 			    ctx->src_fmt.height);
 
@@ -221,23 +220,77 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx)
 		buf_size += hantro_av1_mv_size(pix_mp.width,
 					       pix_mp.height);
 
-	for (i = 0; i < num_buffers; ++i) {
-		struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i];
+	return buf_size;
+}
+
+static int hantro_postproc_alloc(struct hantro_ctx *ctx, int index)
+{
+	struct hantro_dev *vpu = ctx->dev;
+	struct hantro_aux_buf *priv = &ctx->postproc.dec_q[index];
+	unsigned int buf_size = hantro_postproc_buffer_size(ctx);
+
+	if (!buf_size)
+		return -EINVAL;
+
+	/*
+	 * The buffers on this queue are meant as intermediate
+	 * buffers for the decoder, so no mapping is needed.
+	 */
+	priv->attrs = DMA_ATTR_NO_KERNEL_MAPPING;
+	priv->cpu = dma_alloc_attrs(vpu->dev, buf_size, &priv->dma,
+				    GFP_KERNEL, priv->attrs);
+	if (!priv->cpu)
+		return -ENOMEM;
+	priv->size = buf_size;
+
+	return 0;
+}
 
-		/*
-		 * The buffers on this queue are meant as intermediate
-		 * buffers for the decoder, so no mapping is needed.
-		 */
-		priv->attrs = DMA_ATTR_NO_KERNEL_MAPPING;
-		priv->cpu = dma_alloc_attrs(vpu->dev, buf_size, &priv->dma,
-					    GFP_KERNEL, priv->attrs);
-		if (!priv->cpu)
-			return -ENOMEM;
-		priv->size = buf_size;
+int hantro_postproc_init(struct hantro_ctx *ctx)
+{
+	struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+	struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q;
+	unsigned int num_buffers = cap_queue->num_buffers;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < num_buffers; i++) {
+		ret = hantro_postproc_alloc(ctx, i);
+		if (ret)
+			return ret;
 	}
+
 	return 0;
 }
 
+dma_addr_t
+hantro_postproc_get_dec_buf_addr(struct hantro_ctx *ctx, int index)
+{
+	struct hantro_aux_buf *priv = &ctx->postproc.dec_q[index];
+	unsigned int buf_size = hantro_postproc_buffer_size(ctx);
+	struct hantro_dev *vpu = ctx->dev;
+	int ret;
+
+	if (priv->size < buf_size && priv->cpu) {
+		/* buffer is too small, release it */
+		dma_free_attrs(vpu->dev, priv->size, priv->cpu,
+			       priv->dma, priv->attrs);
+		priv->cpu = NULL;
+	}
+
+	if (!priv->cpu) {
+		/* buffer not already allocated, try getting a new one */
+		ret = hantro_postproc_alloc(ctx, index);
+		if (ret)
+			return 0;
+	}
+
+	if (!priv->cpu)
+		return 0;
+
+	return priv->dma;
+}
+
 static void hantro_postproc_g1_disable(struct hantro_ctx *ctx)
 {
 	struct hantro_dev *vpu = ctx->dev;
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index b3ae037a50f6..f0d8b165abcd 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -933,7 +933,7 @@ static int hantro_start_streaming(struct vb2_queue *q, unsigned int count)
 		}
 
 		if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) {
-			ret = hantro_postproc_alloc(ctx);
+			ret = hantro_postproc_init(ctx);
 			if (ret)
 				goto err_codec_exit;
 		}
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 05/10] media: verisilicon: Store chroma and motion vectors offset
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
                   ` (3 preceding siblings ...)
  2023-08-24  9:21 ` [PATCH v5 04/10] media: verisilicon: Refactor postprocessor to store more buffers Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 06/10] media: verisilicon: vp9: Use destination buffer height to compute chroma offset Benjamin Gaignard
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Store computed values of chroma and motion vectors offset because
they depends on width and height values which change if the resolution
change.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
---
 drivers/media/platform/verisilicon/hantro.h            | 2 ++
 drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c | 6 ++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index 0948b04a9f8d..6f5eb975d0e3 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -328,6 +328,8 @@ struct hantro_vp9_decoded_buffer_info {
 	/* Info needed when the decoded frame serves as a reference frame. */
 	unsigned short width;
 	unsigned short height;
+	size_t chroma_offset;
+	size_t mv_offset;
 	u32 bit_depth : 4;
 };
 
diff --git a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
index 6fc4b555517f..6db1c32fce4d 100644
--- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
+++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
@@ -158,9 +158,11 @@ static void config_output(struct hantro_ctx *ctx,
 
 	chroma_addr = luma_addr + chroma_offset(ctx, dec_params);
 	hantro_write_addr(ctx->dev, G2_OUT_CHROMA_ADDR, chroma_addr);
+	dst->vp9.chroma_offset = chroma_offset(ctx, dec_params);
 
 	mv_addr = luma_addr + mv_offset(ctx, dec_params);
 	hantro_write_addr(ctx->dev, G2_OUT_MV_ADDR, mv_addr);
+	dst->vp9.mv_offset = mv_offset(ctx, dec_params);
 }
 
 struct hantro_vp9_ref_reg {
@@ -195,7 +197,7 @@ static void config_ref(struct hantro_ctx *ctx,
 	luma_addr = hantro_get_dec_buf_addr(ctx, &buf->base.vb.vb2_buf);
 	hantro_write_addr(ctx->dev, ref_reg->y_base, luma_addr);
 
-	chroma_addr = luma_addr + chroma_offset(ctx, dec_params);
+	chroma_addr = luma_addr + buf->vp9.chroma_offset;
 	hantro_write_addr(ctx->dev, ref_reg->c_base, chroma_addr);
 }
 
@@ -238,7 +240,7 @@ static void config_ref_registers(struct hantro_ctx *ctx,
 	config_ref(ctx, dst, &ref_regs[2], dec_params, dec_params->alt_frame_ts);
 
 	mv_addr = hantro_get_dec_buf_addr(ctx, &mv_ref->base.vb.vb2_buf) +
-		  mv_offset(ctx, dec_params);
+		  mv_ref->vp9.mv_offset;
 	hantro_write_addr(ctx->dev, G2_REF_MV_ADDR(0), mv_addr);
 
 	hantro_reg_write(ctx->dev, &vp9_last_sign_bias,
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 06/10] media: verisilicon: vp9: Use destination buffer height to compute chroma offset
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
                   ` (4 preceding siblings ...)
  2023-08-24  9:21 ` [PATCH v5 05/10] media: verisilicon: Store chroma and motion vectors offset Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 07/10] media: verisilicon: postproc: Fix down scale test Benjamin Gaignard
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Source and destination buffer height may not be the same because
alignment constraint are different.
Use destination height to compute chroma offset because we target
this buffer as hardware output.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Fixes: e2da465455ce ("media: hantro: Support VP9 on the G2 core")
---
 drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
index 6db1c32fce4d..1f3f5e7ce978 100644
--- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
+++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
@@ -93,9 +93,7 @@ static int start_prepare_run(struct hantro_ctx *ctx, const struct v4l2_ctrl_vp9_
 static size_t chroma_offset(const struct hantro_ctx *ctx,
 			    const struct v4l2_ctrl_vp9_frame *dec_params)
 {
-	int bytes_per_pixel = dec_params->bit_depth == 8 ? 1 : 2;
-
-	return ctx->src_fmt.width * ctx->src_fmt.height * bytes_per_pixel;
+	return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8;
 }
 
 static size_t mv_offset(const struct hantro_ctx *ctx,
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 07/10] media: verisilicon: postproc: Fix down scale test
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
                   ` (5 preceding siblings ...)
  2023-08-24  9:21 ` [PATCH v5 06/10] media: verisilicon: vp9: Use destination buffer height to compute chroma offset Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 08/10] media: verisilicon: vp9: Allow to change resolution while streaming Benjamin Gaignard
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Do not allow down scaling if the source buffer resolution is
smaller  than destination one.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Fixes: fbb6c848dd89 ("media: destage Hantro VPU driver")
---
Note: Marek has propose exactly the same fix in this patch:
[PATCH] media: verisilicon: Do not enable G2 postproc downscale if source is narrower than destination

 drivers/media/platform/verisilicon/hantro_postproc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/verisilicon/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c
index e624cd98f41b..77d8ecfbe12f 100644
--- a/drivers/media/platform/verisilicon/hantro_postproc.c
+++ b/drivers/media/platform/verisilicon/hantro_postproc.c
@@ -107,7 +107,7 @@ static void hantro_postproc_g1_enable(struct hantro_ctx *ctx)
 
 static int down_scale_factor(struct hantro_ctx *ctx)
 {
-	if (ctx->src_fmt.width == ctx->dst_fmt.width)
+	if (ctx->src_fmt.width <= ctx->dst_fmt.width)
 		return 0;
 
 	return DIV_ROUND_CLOSEST(ctx->src_fmt.width, ctx->dst_fmt.width);
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 08/10] media: verisilicon: vp9: Allow to change resolution while streaming
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
                   ` (6 preceding siblings ...)
  2023-08-24  9:21 ` [PATCH v5 07/10] media: verisilicon: postproc: Fix down scale test Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 09/10] media: v4l2: Add DELETE_BUFS ioctl Benjamin Gaignard
  2023-08-24  9:21 ` [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for " Benjamin Gaignard
  9 siblings, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Remove all checks that prohibit to set a new format while streaming.
This allow to change dynamically the resolution if the pixel format
remains the same.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
---
 .../media/platform/verisilicon/hantro_v4l2.c  | 24 +++----------------
 1 file changed, 3 insertions(+), 21 deletions(-)

diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index f0d8b165abcd..27a1e77cca38 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -514,25 +514,14 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx,
 		return ret;
 
 	if (!ctx->is_encoder) {
-		struct vb2_queue *peer_vq;
-
 		/*
 		 * In order to support dynamic resolution change,
 		 * the decoder admits a resolution change, as long
-		 * as the pixelformat remains. Can't be done if streaming.
-		 */
-		if (vb2_is_streaming(vq) || (vb2_is_busy(vq) &&
-		    pix_mp->pixelformat != ctx->src_fmt.pixelformat))
-			return -EBUSY;
-		/*
-		 * Since format change on the OUTPUT queue will reset
-		 * the CAPTURE queue, we can't allow doing so
-		 * when the CAPTURE queue has buffers allocated.
+		 * as the pixelformat remains.
 		 */
-		peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
-					  V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-		if (vb2_is_busy(peer_vq))
+		if (vb2_is_streaming(vq) && pix_mp->pixelformat != ctx->src_fmt.pixelformat) {
 			return -EBUSY;
+		}
 	} else {
 		/*
 		 * The encoder doesn't admit a format change if
@@ -577,15 +566,8 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx,
 static int hantro_set_fmt_cap(struct hantro_ctx *ctx,
 			      struct v4l2_pix_format_mplane *pix_mp)
 {
-	struct vb2_queue *vq;
 	int ret;
 
-	/* Change not allowed if queue is busy. */
-	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
-			     V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-	if (vb2_is_busy(vq))
-		return -EBUSY;
-
 	if (ctx->is_encoder) {
 		struct vb2_queue *peer_vq;
 
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 09/10] media: v4l2: Add DELETE_BUFS ioctl
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
                   ` (7 preceding siblings ...)
  2023-08-24  9:21 ` [PATCH v5 08/10] media: verisilicon: vp9: Allow to change resolution while streaming Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-30 13:45   ` Hans Verkuil
  2023-08-30 13:51   ` Hans Verkuil
  2023-08-24  9:21 ` [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for " Benjamin Gaignard
  9 siblings, 2 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

VIDIOC_DELETE_BUFS ioctl allows to delete buffers from a queue.
The number of buffers to delete in given by count field of
struct v4l2_delete_buffers and the range start at the index
specified in the same structure.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
---
 .../userspace-api/media/v4l/user-func.rst     |  1 +
 .../media/v4l/vidioc-delete-bufs.rst          | 73 +++++++++++++++++++
 .../media/common/videobuf2/videobuf2-core.c   | 34 +++++++++
 .../media/common/videobuf2/videobuf2-v4l2.c   | 16 ++++
 drivers/media/v4l2-core/v4l2-dev.c            |  1 +
 drivers/media/v4l2-core/v4l2-ioctl.c          | 17 +++++
 include/media/v4l2-ioctl.h                    |  4 +
 include/media/videobuf2-core.h                |  9 +++
 include/media/videobuf2-v4l2.h                | 11 +++
 include/uapi/linux/videodev2.h                | 17 +++++
 10 files changed, 183 insertions(+)
 create mode 100644 Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst

diff --git a/Documentation/userspace-api/media/v4l/user-func.rst b/Documentation/userspace-api/media/v4l/user-func.rst
index 15ff0bf7bbe6..3fd567695477 100644
--- a/Documentation/userspace-api/media/v4l/user-func.rst
+++ b/Documentation/userspace-api/media/v4l/user-func.rst
@@ -17,6 +17,7 @@ Function Reference
     vidioc-dbg-g-chip-info
     vidioc-dbg-g-register
     vidioc-decoder-cmd
+    vidioc-delete-bufs
     vidioc-dqevent
     vidioc-dv-timings-cap
     vidioc-encoder-cmd
diff --git a/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst
new file mode 100644
index 000000000000..a55fe6331fc8
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst
@@ -0,0 +1,73 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+.. c:namespace:: V4L
+
+.. _VIDIOC_DELETE_BUFS:
+
+************************
+ioctl VIDIOC_DELETE_BUFS
+************************
+
+Name
+====
+
+VIDIOC_DELETE_BUFS - Deletes buffers from a queue
+
+Synopsis
+========
+
+.. c:macro:: VIDIOC_DELETE_BUFs
+
+``int ioctl(int fd, VIDIOC_DELETE_BUFs, struct v4l2_delete_buffers *argp)``
+
+Arguments
+=========
+
+``fd``
+    File descriptor returned by :c:func:`open()`.
+
+``argp``
+    Pointer to struct :c:type:`v4l2_delete_buffers`.
+
+Description
+===========
+
+Applications can optionally call the :ref:`VIDIOC_DELETE_BUFS` ioctl to
+delete buffers from a queue.
+
+.. c:type:: v4l2_delete_buffers
+
+.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.5cm}|
+
+.. flat-table:: struct v4l2_delete_buffers
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u32
+      - ``index``
+      - The starting buffer index to delete.
+    * - __u32
+      - ``count``
+      - The number of buffers to be deleted.
+    * - __u32
+      - ``type``
+      - Type of the stream or buffers, this is the same as the struct
+	:c:type:`v4l2_format` ``type`` field. See
+	:c:type:`v4l2_buf_type` for valid values.
+    * - __u32
+      - ``reserved``\ [13]
+      - A place holder for future extensions. Drivers and applications
+	must set the array to zero.
+
+Return Value
+============
+
+On success 0 is returned, on error -1 and the ``errno`` variable is set
+appropriately. The generic error codes are described at the
+:ref:`Generic Error Codes <gen-errors>` chapter.
+
+EBUSY
+    File I/O is in progress.
+
+EINVAL
+    The buffer ``index`` doesn't exist in the queue.
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 70e36389b704..3d915b4c33b2 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -1634,6 +1634,40 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
 }
 EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
 
+int vb2_core_delete_buf(struct vb2_queue *q, unsigned int index)
+{
+	struct vb2_buffer *vb;
+
+	vb = vb2_get_buffer(q, index);
+	if (!vb) {
+		dprintk(q, 1, "invalid buffer index %d\n", index);
+		return -EINVAL;
+	}
+
+	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+		dprintk(q, 1, "can't delete non dequeued buffer index %d\n", index);
+		return -EINVAL;
+	}
+
+	if (vb->planes[0].mem_priv)
+		call_void_vb_qop(vb, buf_cleanup, vb);
+
+	/* Free MMAP buffers or release USERPTR buffers */
+	if (q->memory == VB2_MEMORY_MMAP)
+		__vb2_buf_mem_free(vb);
+	else if (q->memory == VB2_MEMORY_DMABUF)
+		__vb2_buf_dmabuf_put(vb);
+	else
+		__vb2_buf_userptr_put(vb);
+
+	vb2_queue_remove_buffer(q, vb);
+	kfree(vb);
+
+	dprintk(q, 2, "buffer %d deleted\n", index);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_core_delete_buf);
+
 /*
  * vb2_start_streaming() - Attempt to start streaming.
  * @q:		videobuf2 queue
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 724135d41f7f..ffe6b66a27f1 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -751,6 +751,22 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
 }
 EXPORT_SYMBOL_GPL(vb2_prepare_buf);
 
+int vb2_delete_bufs(struct vb2_queue *q, struct v4l2_delete_buffers *d)
+{
+	unsigned int index;
+	int ret = 0;
+
+	for (index = d->index; index < d->index + d->count; index++) {
+		ret = vb2_core_delete_buf(q, index);
+		if (ret)
+			break;
+	}
+
+	d->index = index;
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_delete_bufs);
+
 int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 {
 	unsigned requested_planes = 1;
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index f81279492682..215654fd6581 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -720,6 +720,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
 		SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
 		SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
 		SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
+		SET_VALID_IOCTL(ops, VIDIOC_DELETE_BUFS, vidioc_delete_bufs);
 	}
 
 	if (is_vid || is_vbi || is_meta) {
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index f4d9d6279094..32336b9bb7e4 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -489,6 +489,13 @@ static void v4l_print_create_buffers(const void *arg, bool write_only)
 	v4l_print_format(&p->format, write_only);
 }
 
+static void v4l_print_delete_buffers(const void *arg, bool write_only)
+{
+	const struct v4l2_delete_buffers *p = arg;
+
+	pr_cont("index=%d, count=%d\n", p->index, p->count);
+}
+
 static void v4l_print_streamparm(const void *arg, bool write_only)
 {
 	const struct v4l2_streamparm *p = arg;
@@ -2160,6 +2167,15 @@ static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops,
 	return ret ? ret : ops->vidioc_prepare_buf(file, fh, b);
 }
 
+static int v4l_delete_bufs(const struct v4l2_ioctl_ops *ops,
+			   struct file *file, void *fh, void *arg)
+{
+	struct v4l2_delete_buffers *delete = arg;
+	int ret = check_fmt(file, delete->type);
+
+	return ret ? ret : ops->vidioc_delete_bufs(file, fh, delete);
+}
+
 static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
@@ -2909,6 +2925,7 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = {
 	IOCTL_INFO(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
 	IOCTL_INFO(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
 	IOCTL_INFO(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
+	IOCTL_INFO(VIDIOC_DELETE_BUFS, v4l_delete_bufs, v4l_print_delete_buffers, INFO_FL_QUEUE),
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index edb733f21604..55afbde54211 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -163,6 +163,8 @@ struct v4l2_fh;
  *	:ref:`VIDIOC_CREATE_BUFS <vidioc_create_bufs>` ioctl
  * @vidioc_prepare_buf: pointer to the function that implements
  *	:ref:`VIDIOC_PREPARE_BUF <vidioc_prepare_buf>` ioctl
+ * @vidioc_delete_bufs: pointer to the function that implements
+ *	:ref:`VIDIOC_DELETE_BUFS <vidioc_delete_bufs>` ioctl
  * @vidioc_overlay: pointer to the function that implements
  *	:ref:`VIDIOC_OVERLAY <vidioc_overlay>` ioctl
  * @vidioc_g_fbuf: pointer to the function that implements
@@ -422,6 +424,8 @@ struct v4l2_ioctl_ops {
 				  struct v4l2_create_buffers *b);
 	int (*vidioc_prepare_buf)(struct file *file, void *fh,
 				  struct v4l2_buffer *b);
+	int (*vidioc_delete_bufs)(struct file *file, void *fh,
+				  struct v4l2_delete_buffers *d);
 
 	int (*vidioc_overlay)(struct file *file, void *fh, unsigned int i);
 	int (*vidioc_g_fbuf)(struct file *file, void *fh,
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index ee9161b9fd64..c9ecc4214982 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -843,6 +843,15 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
  */
 int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb);
 
+/**
+ * vb2_core_delete_buf() -
+ * @q: pointer to &struct vb2_queue with videobuf2 queue.
+ * @index:	id number of the buffer.
+ *
+ *  Return: returns zero on success; an error code otherwise.
+ */
+int vb2_core_delete_buf(struct vb2_queue *q, unsigned int index);
+
 /**
  * vb2_core_qbuf() - Queue a buffer from userspace
  *
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 5a845887850b..2ef68fdf388f 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -118,6 +118,17 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create);
  */
 int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
 		    struct v4l2_buffer *b);
+/**
+ * vb2_delete_bufs() - Delete buffers from the queue
+ *
+ * @q:		pointer to &struct vb2_queue with videobuf2 queue.
+ * @d:		delete parameter, passed from userspace to
+ *		&v4l2_ioctl_ops->vidioc_delete_bufs handler in driver
+ *
+ * The return values from this function are intended to be directly returned
+ * from &v4l2_ioctl_ops->vidioc_delete_bufs handler in driver.
+ */
+int vb2_delete_bufs(struct vb2_queue *q, struct v4l2_delete_buffers *d);
 
 /**
  * vb2_qbuf() - Queue a buffer from userspace
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 78260e5d9985..4807b38e2a6f 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -2616,6 +2616,21 @@ struct v4l2_create_buffers {
 	__u32			reserved[6];
 };
 
+/**
+ * struct v4l2_delete_buffers - VIDIOC_DELETE_BUFS argument
+ * @index:	the first buffer to be deleted
+ * @count:	number of buffers to delete
+ * @type:	enum v4l2_buf_type; buffer type (type == *_MPLANE for
+ *		multiplanar buffers);
+ * @reserved:	futur extensions
+ */
+struct v4l2_delete_buffers {
+	__u32			index;
+	__u32			count;
+	__u32			type;
+	__u32			reserved[13];
+};
+
 /*
  *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
  *
@@ -2715,6 +2730,8 @@ struct v4l2_create_buffers {
 #define VIDIOC_DBG_G_CHIP_INFO  _IOWR('V', 102, struct v4l2_dbg_chip_info)
 
 #define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
+#define VIDIOC_DELETE_BUFS	_IOWR('V', 104, struct v4l2_delete_buffers)
+
 
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl
  2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
                   ` (8 preceding siblings ...)
  2023-08-24  9:21 ` [PATCH v5 09/10] media: v4l2: Add DELETE_BUFS ioctl Benjamin Gaignard
@ 2023-08-24  9:21 ` Benjamin Gaignard
  2023-08-25 10:29   ` kernel test robot
                     ` (2 more replies)
  9 siblings, 3 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-24  9:21 UTC (permalink / raw)
  To: mchehab, tfiga, m.szyprowski, ming.qian, ezequiel, p.zabel,
	gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel,
	Benjamin Gaignard

Create v4l2-mem2mem helpers for VIDIOC_DELETE_BUFS ioctl.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
---
 .../media/platform/verisilicon/hantro_v4l2.c  |  1 +
 drivers/media/test-drivers/vim2m.c            |  1 +
 drivers/media/v4l2-core/v4l2-mem2mem.c        | 20 +++++++++++++++++++
 include/media/v4l2-mem2mem.h                  | 12 +++++++++++
 4 files changed, 34 insertions(+)

diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index 27a1e77cca38..0fd1c2fc78c8 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -756,6 +756,7 @@ const struct v4l2_ioctl_ops hantro_ioctl_ops = {
 	.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
 	.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
 	.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+	.vidioc_delete_bufs = v4l2_m2m_ioctl_delete_bufs,
 	.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
 
 	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c
index 3e3b424b4860..3014b8ee13d0 100644
--- a/drivers/media/test-drivers/vim2m.c
+++ b/drivers/media/test-drivers/vim2m.c
@@ -960,6 +960,7 @@ static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
 	.vidioc_dqbuf		= v4l2_m2m_ioctl_dqbuf,
 	.vidioc_prepare_buf	= v4l2_m2m_ioctl_prepare_buf,
 	.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
+	.vidioc_delete_buf	= v4l2_m2m_ioctl_delete_buf,
 	.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
 
 	.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index 0cc30397fbad..d1d59943680f 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -831,6 +831,17 @@ int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf);
 
+int v4l2_m2m_delete_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+			 struct v4l2_delete_buffers *d)
+{
+	struct vb2_queue *vq;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, d->type);
+
+	return vb2_delete_bufs(vq, d);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_delete_bufs);
+
 int v4l2_m2m_create_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 			 struct v4l2_create_buffers *create)
 {
@@ -1377,6 +1388,15 @@ int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv,
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs);
 
+int v4l2_m2m_ioctl_delete_bufs(struct file *file, void *priv,
+			       struct v4l2_delete_buffers *d)
+{
+	struct v4l2_fh *fh = file->private_data;
+
+	return v4l2_m2m_delete_bufs(file, fh->m2m_ctx, d);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_delete_bufs);
+
 int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv,
 				struct v4l2_buffer *buf)
 {
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index d6c8eb2b5201..161f85c42dc8 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -381,6 +381,16 @@ int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 			 struct v4l2_buffer *buf);
 
+/**
+ * v4l2_m2m_delete_bufs() - delete buffers from the queue
+ *
+ * @file: pointer to struct &file
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ * @d: pointer to struct &v4l2_delete_buffers
+ */
+int v4l2_m2m_delete_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+			 struct v4l2_delete_buffers *d);
+
 /**
  * v4l2_m2m_create_bufs() - create a source or destination buffer, depending
  * on the type
@@ -860,6 +870,8 @@ int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv,
 				struct v4l2_requestbuffers *rb);
 int v4l2_m2m_ioctl_create_bufs(struct file *file, void *fh,
 				struct v4l2_create_buffers *create);
+int v4l2_m2m_ioctl_delete_bufs(struct file *file, void *priv,
+			       struct v4l2_delete_buffers *d);
 int v4l2_m2m_ioctl_querybuf(struct file *file, void *fh,
 				struct v4l2_buffer *buf);
 int v4l2_m2m_ioctl_expbuf(struct file *file, void *fh,
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl
  2023-08-24  9:21 ` [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for " Benjamin Gaignard
@ 2023-08-25 10:29   ` kernel test robot
  2023-08-25 15:34     ` Benjamin Gaignard
  2023-08-25 12:26   ` kernel test robot
  2023-08-30 13:53   ` Hans Verkuil
  2 siblings, 1 reply; 27+ messages in thread
From: kernel test robot @ 2023-08-25 10:29 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: oe-kbuild-all, linux-media, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-arm-msm, linux-rockchip, linux-staging,
	kernel, Benjamin Gaignard

Hi Benjamin,

kernel test robot noticed the following build errors:

[auto build test ERROR on next-20230824]
[also build test ERROR on v6.5-rc7]
[cannot apply to linus/master v6.5-rc7 v6.5-rc6 v6.5-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Benjamin-Gaignard/media-videobuf2-Rework-offset-cookie-encoding-pattern/20230824-172416
base:   next-20230824
patch link:    https://lore.kernel.org/r/20230824092133.39510-11-benjamin.gaignard%40collabora.com
patch subject: [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl
config: alpha-randconfig-r005-20230825 (https://download.01.org/0day-ci/archive/20230825/202308251828.fSyIXACx-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20230825/202308251828.fSyIXACx-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202308251828.fSyIXACx-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/media/test-drivers/vim2m.c:963:10: error: 'const struct v4l2_ioctl_ops' has no member named 'vidioc_delete_buf'; did you mean 'vidioc_delete_bufs'?
     963 |         .vidioc_delete_buf      = v4l2_m2m_ioctl_delete_buf,
         |          ^~~~~~~~~~~~~~~~~
         |          vidioc_delete_bufs
>> drivers/media/test-drivers/vim2m.c:963:35: error: 'v4l2_m2m_ioctl_delete_buf' undeclared here (not in a function); did you mean 'v4l2_m2m_ioctl_delete_bufs'?
     963 |         .vidioc_delete_buf      = v4l2_m2m_ioctl_delete_buf,
         |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~
         |                                   v4l2_m2m_ioctl_delete_bufs


vim +963 drivers/media/test-drivers/vim2m.c

   942	
   943	static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
   944		.vidioc_querycap	= vidioc_querycap,
   945	
   946		.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
   947		.vidioc_enum_framesizes = vidioc_enum_framesizes,
   948		.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
   949		.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
   950		.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
   951	
   952		.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
   953		.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
   954		.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
   955		.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
   956	
   957		.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
   958		.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
   959		.vidioc_qbuf		= v4l2_m2m_ioctl_qbuf,
   960		.vidioc_dqbuf		= v4l2_m2m_ioctl_dqbuf,
   961		.vidioc_prepare_buf	= v4l2_m2m_ioctl_prepare_buf,
   962		.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
 > 963		.vidioc_delete_buf	= v4l2_m2m_ioctl_delete_buf,
   964		.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
   965	
   966		.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
   967		.vidioc_streamoff	= v4l2_m2m_ioctl_streamoff,
   968	
   969		.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
   970		.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
   971	};
   972	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl
  2023-08-24  9:21 ` [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for " Benjamin Gaignard
  2023-08-25 10:29   ` kernel test robot
@ 2023-08-25 12:26   ` kernel test robot
  2023-08-30 13:53   ` Hans Verkuil
  2 siblings, 0 replies; 27+ messages in thread
From: kernel test robot @ 2023-08-25 12:26 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: llvm, oe-kbuild-all, linux-media, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-arm-msm, linux-rockchip, linux-staging,
	kernel, Benjamin Gaignard

Hi Benjamin,

kernel test robot noticed the following build errors:

[auto build test ERROR on next-20230824]
[also build test ERROR on v6.5-rc7]
[cannot apply to linus/master v6.5-rc7 v6.5-rc6 v6.5-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Benjamin-Gaignard/media-videobuf2-Rework-offset-cookie-encoding-pattern/20230824-172416
base:   next-20230824
patch link:    https://lore.kernel.org/r/20230824092133.39510-11-benjamin.gaignard%40collabora.com
patch subject: [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl
config: i386-randconfig-r033-20230825 (https://download.01.org/0day-ci/archive/20230825/202308252057.jcyaKKOJ-lkp@intel.com/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce: (https://download.01.org/0day-ci/archive/20230825/202308252057.jcyaKKOJ-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202308252057.jcyaKKOJ-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/media/test-drivers/vim2m.c:963:23: error: use of undeclared identifier 'v4l2_m2m_ioctl_delete_buf'; did you mean 'v4l2_m2m_ioctl_delete_bufs'?
           .vidioc_delete_buf      = v4l2_m2m_ioctl_delete_buf,
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~
                                     v4l2_m2m_ioctl_delete_bufs
   include/media/v4l2-mem2mem.h:873:5: note: 'v4l2_m2m_ioctl_delete_bufs' declared here
   int v4l2_m2m_ioctl_delete_bufs(struct file *file, void *priv,
       ^
>> drivers/media/test-drivers/vim2m.c:963:3: error: field designator 'vidioc_delete_buf' does not refer to any field in type 'const struct v4l2_ioctl_ops'; did you mean 'vidioc_delete_bufs'?
           .vidioc_delete_buf      = v4l2_m2m_ioctl_delete_buf,
            ^~~~~~~~~~~~~~~~~
            vidioc_delete_bufs
   include/media/v4l2-ioctl.h:427:8: note: 'vidioc_delete_bufs' declared here
           int (*vidioc_delete_bufs)(struct file *file, void *fh,
                 ^
   2 errors generated.


vim +963 drivers/media/test-drivers/vim2m.c

   942	
   943	static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
   944		.vidioc_querycap	= vidioc_querycap,
   945	
   946		.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
   947		.vidioc_enum_framesizes = vidioc_enum_framesizes,
   948		.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
   949		.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
   950		.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
   951	
   952		.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
   953		.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
   954		.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
   955		.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
   956	
   957		.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
   958		.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
   959		.vidioc_qbuf		= v4l2_m2m_ioctl_qbuf,
   960		.vidioc_dqbuf		= v4l2_m2m_ioctl_dqbuf,
   961		.vidioc_prepare_buf	= v4l2_m2m_ioctl_prepare_buf,
   962		.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
 > 963		.vidioc_delete_buf	= v4l2_m2m_ioctl_delete_buf,
   964		.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
   965	
   966		.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
   967		.vidioc_streamoff	= v4l2_m2m_ioctl_streamoff,
   968	
   969		.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
   970		.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
   971	};
   972	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl
  2023-08-25 10:29   ` kernel test robot
@ 2023-08-25 15:34     ` Benjamin Gaignard
  0 siblings, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-25 15:34 UTC (permalink / raw)
  To: kernel test robot, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, hverkuil-cisco, nicolas.dufresne
  Cc: oe-kbuild-all, linux-media, linux-kernel, linux-arm-kernel,
	linux-mediatek, linux-arm-msm, linux-rockchip, linux-staging,
	kernel


Le 25/08/2023 à 12:29, kernel test robot a écrit :
> Hi Benjamin,

Damned I have forgot this configuration flag when rebasing my code after 
holidays...

It will be fixed for v6 but I will wait for more comments before send it.

Regards,

Benjamin

>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on next-20230824]
> [also build test ERROR on v6.5-rc7]
> [cannot apply to linus/master v6.5-rc7 v6.5-rc6 v6.5-rc5]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Benjamin-Gaignard/media-videobuf2-Rework-offset-cookie-encoding-pattern/20230824-172416
> base:   next-20230824
> patch link:    https://lore.kernel.org/r/20230824092133.39510-11-benjamin.gaignard%40collabora.com
> patch subject: [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl
> config: alpha-randconfig-r005-20230825 (https://download.01.org/0day-ci/archive/20230825/202308251828.fSyIXACx-lkp@intel.com/config)
> compiler: alpha-linux-gcc (GCC) 13.2.0
> reproduce: (https://download.01.org/0day-ci/archive/20230825/202308251828.fSyIXACx-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202308251828.fSyIXACx-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
>>> drivers/media/test-drivers/vim2m.c:963:10: error: 'const struct v4l2_ioctl_ops' has no member named 'vidioc_delete_buf'; did you mean 'vidioc_delete_bufs'?
>       963 |         .vidioc_delete_buf      = v4l2_m2m_ioctl_delete_buf,
>           |          ^~~~~~~~~~~~~~~~~
>           |          vidioc_delete_bufs
>>> drivers/media/test-drivers/vim2m.c:963:35: error: 'v4l2_m2m_ioctl_delete_buf' undeclared here (not in a function); did you mean 'v4l2_m2m_ioctl_delete_bufs'?
>       963 |         .vidioc_delete_buf      = v4l2_m2m_ioctl_delete_buf,
>           |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~
>           |                                   v4l2_m2m_ioctl_delete_bufs
>
>
> vim +963 drivers/media/test-drivers/vim2m.c
>
>     942	
>     943	static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
>     944		.vidioc_querycap	= vidioc_querycap,
>     945	
>     946		.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
>     947		.vidioc_enum_framesizes = vidioc_enum_framesizes,
>     948		.vidioc_g_fmt_vid_cap	= vidioc_g_fmt_vid_cap,
>     949		.vidioc_try_fmt_vid_cap	= vidioc_try_fmt_vid_cap,
>     950		.vidioc_s_fmt_vid_cap	= vidioc_s_fmt_vid_cap,
>     951	
>     952		.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
>     953		.vidioc_g_fmt_vid_out	= vidioc_g_fmt_vid_out,
>     954		.vidioc_try_fmt_vid_out	= vidioc_try_fmt_vid_out,
>     955		.vidioc_s_fmt_vid_out	= vidioc_s_fmt_vid_out,
>     956	
>     957		.vidioc_reqbufs		= v4l2_m2m_ioctl_reqbufs,
>     958		.vidioc_querybuf	= v4l2_m2m_ioctl_querybuf,
>     959		.vidioc_qbuf		= v4l2_m2m_ioctl_qbuf,
>     960		.vidioc_dqbuf		= v4l2_m2m_ioctl_dqbuf,
>     961		.vidioc_prepare_buf	= v4l2_m2m_ioctl_prepare_buf,
>     962		.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
>   > 963		.vidioc_delete_buf	= v4l2_m2m_ioctl_delete_buf,
>     964		.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
>     965	
>     966		.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
>     967		.vidioc_streamoff	= v4l2_m2m_ioctl_streamoff,
>     968	
>     969		.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
>     970		.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
>     971	};
>     972	
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 01/10] media: videobuf2: Rework offset 'cookie' encoding pattern
  2023-08-24  9:21 ` [PATCH v5 01/10] media: videobuf2: Rework offset 'cookie' encoding pattern Benjamin Gaignard
@ 2023-08-30 12:25   ` Hans Verkuil
  2023-08-30 12:51     ` Benjamin Gaignard
  0 siblings, 1 reply; 27+ messages in thread
From: Hans Verkuil @ 2023-08-30 12:25 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel

On 24/08/2023 11:21, Benjamin Gaignard wrote:
> Change how offset 'cookie' field value is computed to make possible
> to use more buffers (up to 0xffff).
> With this encoding pattern we know the maximum number that a queue
> could store so we can check ing at queue init time.
> It also make easier and faster to find buffer and plane from using
> the offset field.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
> ---
> v5:
> - I haven't change DST_QUEUE_OFF_BASE definition because it used in
>   v4l2-mem2mem and s5p_mfc driver with a shift.
> 
>  .../media/common/videobuf2/videobuf2-core.c   | 48 +++++++++----------
>  1 file changed, 24 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> index cf6727d9c81f..e06905533ef4 100644
> --- a/drivers/media/common/videobuf2/videobuf2-core.c
> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> @@ -31,6 +31,10 @@
>  
>  #include <trace/events/vb2.h>
>  
> +#define PLANE_INDEX_SHIFT	3
> +#define PLANE_INDEX_MASK	0x7
> +#define MAX_BUFFERS		0xffff

Very poor name, see below.

> +
>  static int debug;
>  module_param(debug, int, 0644);
>  
> @@ -358,21 +362,23 @@ static void __setup_offsets(struct vb2_buffer *vb)
>  	unsigned int plane;
>  	unsigned long off = 0;
>  
> -	if (vb->index) {
> -		struct vb2_buffer *prev = q->bufs[vb->index - 1];
> -		struct vb2_plane *p = &prev->planes[prev->num_planes - 1];
> -
> -		off = PAGE_ALIGN(p->m.offset + p->length);
> -	}
> +	/*
> +	 * Offsets cookies value have the following constraints:
> +	 * - a buffer could have up to 8 planes.
> +	 * - v4l2 mem2mem use bit 30 to distinguish between source and destination buffers.
> +	 * - must be page aligned
> +	 * That led to this bit mapping:
> +	 * |30                |29        15|14       12|11 0|
> +	 * |DST_QUEUE_OFF_BASE|buffer index|plane index| 0  |
> +	 * where there is 16 bits to store buffer index.

16 -> 15: there are 15 (not 16!) bits available for buffer indices. So the maximum
number of buffers is 32768, given that the indices start at 0.

> +	 */
> +	off = vb->index << (PLANE_INDEX_SHIFT + PAGE_SHIFT);
>  
>  	for (plane = 0; plane < vb->num_planes; ++plane) {
> -		vb->planes[plane].m.offset = off;
> +		vb->planes[plane].m.offset = off + (plane << PAGE_SHIFT);
>  
>  		dprintk(q, 3, "buffer %d, plane %d offset 0x%08lx\n",
>  				vb->index, plane, off);
> -
> -		off += vb->planes[plane].length;
> -		off = PAGE_ALIGN(off);
>  	}
>  }
>  
> @@ -2209,21 +2215,15 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>  		return -EBUSY;
>  	}
>  
> -	/*
> -	 * Go over all buffers and their planes, comparing the given offset
> -	 * with an offset assigned to each plane. If a match is found,
> -	 * return its buffer and plane numbers.
> -	 */
> -	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
> -		vb = q->bufs[buffer];
> +	/* Get buffer and plane from the offset */
> +	buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;

Hmm, you use it as a mask. The name MAX_BUFFERS is really confusing.
How about BUFFER_INDEX_MASK? That is consistent with PLANE_INDEX_MASK.

> +	plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>  
> -		for (plane = 0; plane < vb->num_planes; ++plane) {
> -			if (vb->planes[plane].m.offset == off) {
> -				*_buffer = buffer;
> -				*_plane = plane;
> -				return 0;
> -			}
> -		}
> +	vb = q->bufs[buffer];
> +	if (vb->planes[plane].m.offset == off) {
> +		*_buffer = buffer;
> +		*_plane = plane;
> +		return 0;
>  	}
>  
>  	return -EINVAL;

Regards,

	Hans

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 01/10] media: videobuf2: Rework offset 'cookie' encoding pattern
  2023-08-30 12:25   ` Hans Verkuil
@ 2023-08-30 12:51     ` Benjamin Gaignard
  0 siblings, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-30 12:51 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, tfiga, m.szyprowski, ming.qian, ezequiel,
	p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel


Le 30/08/2023 à 14:25, Hans Verkuil a écrit :
> On 24/08/2023 11:21, Benjamin Gaignard wrote:
>> Change how offset 'cookie' field value is computed to make possible
>> to use more buffers (up to 0xffff).
>> With this encoding pattern we know the maximum number that a queue
>> could store so we can check ing at queue init time.
>> It also make easier and faster to find buffer and plane from using
>> the offset field.
>>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
>> ---
>> v5:
>> - I haven't change DST_QUEUE_OFF_BASE definition because it used in
>>    v4l2-mem2mem and s5p_mfc driver with a shift.
>>
>>   .../media/common/videobuf2/videobuf2-core.c   | 48 +++++++++----------
>>   1 file changed, 24 insertions(+), 24 deletions(-)
>>
>> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
>> index cf6727d9c81f..e06905533ef4 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-core.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
>> @@ -31,6 +31,10 @@
>>   
>>   #include <trace/events/vb2.h>
>>   
>> +#define PLANE_INDEX_SHIFT	3
>> +#define PLANE_INDEX_MASK	0x7
>> +#define MAX_BUFFERS		0xffff
> Very poor name, see below.
>
>> +
>>   static int debug;
>>   module_param(debug, int, 0644);
>>   
>> @@ -358,21 +362,23 @@ static void __setup_offsets(struct vb2_buffer *vb)
>>   	unsigned int plane;
>>   	unsigned long off = 0;
>>   
>> -	if (vb->index) {
>> -		struct vb2_buffer *prev = q->bufs[vb->index - 1];
>> -		struct vb2_plane *p = &prev->planes[prev->num_planes - 1];
>> -
>> -		off = PAGE_ALIGN(p->m.offset + p->length);
>> -	}
>> +	/*
>> +	 * Offsets cookies value have the following constraints:
>> +	 * - a buffer could have up to 8 planes.
>> +	 * - v4l2 mem2mem use bit 30 to distinguish between source and destination buffers.
>> +	 * - must be page aligned
>> +	 * That led to this bit mapping:
>> +	 * |30                |29        15|14       12|11 0|
>> +	 * |DST_QUEUE_OFF_BASE|buffer index|plane index| 0  |
>> +	 * where there is 16 bits to store buffer index.
> 16 -> 15: there are 15 (not 16!) bits available for buffer indices. So the maximum
> number of buffers is 32768, given that the indices start at 0.
>
>> +	 */
>> +	off = vb->index << (PLANE_INDEX_SHIFT + PAGE_SHIFT);
>>   
>>   	for (plane = 0; plane < vb->num_planes; ++plane) {
>> -		vb->planes[plane].m.offset = off;
>> +		vb->planes[plane].m.offset = off + (plane << PAGE_SHIFT);
>>   
>>   		dprintk(q, 3, "buffer %d, plane %d offset 0x%08lx\n",
>>   				vb->index, plane, off);
>> -
>> -		off += vb->planes[plane].length;
>> -		off = PAGE_ALIGN(off);
>>   	}
>>   }
>>   
>> @@ -2209,21 +2215,15 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>>   		return -EBUSY;
>>   	}
>>   
>> -	/*
>> -	 * Go over all buffers and their planes, comparing the given offset
>> -	 * with an offset assigned to each plane. If a match is found,
>> -	 * return its buffer and plane numbers.
>> -	 */
>> -	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
>> -		vb = q->bufs[buffer];
>> +	/* Get buffer and plane from the offset */
>> +	buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
> Hmm, you use it as a mask. The name MAX_BUFFERS is really confusing.
> How about BUFFER_INDEX_MASK? That is consistent with PLANE_INDEX_MASK.

I will follow your advice and fix that in next version.
I will until you have finish your review in this series before send it.

Regards,
Benjamin

>
>> +	plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>>   
>> -		for (plane = 0; plane < vb->num_planes; ++plane) {
>> -			if (vb->planes[plane].m.offset == off) {
>> -				*_buffer = buffer;
>> -				*_plane = plane;
>> -				return 0;
>> -			}
>> -		}
>> +	vb = q->bufs[buffer];
>> +	if (vb->planes[plane].m.offset == off) {
>> +		*_buffer = buffer;
>> +		*_plane = plane;
>> +		return 0;
>>   	}
>>   
>>   	return -EINVAL;
> Regards,
>
> 	Hans
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions
  2023-08-24  9:21 ` [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions Benjamin Gaignard
@ 2023-08-30 13:23   ` Hans Verkuil
  2023-08-30 16:24     ` Benjamin Gaignard
  2023-09-01 12:29     ` Benjamin Gaignard
  0 siblings, 2 replies; 27+ messages in thread
From: Hans Verkuil @ 2023-08-30 13:23 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel

On 24/08/2023 11:21, Benjamin Gaignard wrote:
> The first step before changing how vb2 buffers are stored into queue
> is to avoid direct access to bufs arrays.
> 
> This patch adds 2 helpers functions to add and remove vb2 buffers
> from a queue. With these 2 and vb2_get_buffer(), bufs field of
> struct vb2_queue becomes like a private member of the structure.
> 
> After each call to vb2_get_buffer() we need to be sure that we get
> a valid pointer so check the return value of all of them.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
> 
> # Conflicts:
> #	drivers/media/common/videobuf2/videobuf2-core.c
> ---
>  .../media/common/videobuf2/videobuf2-core.c   | 203 ++++++++++++++----
>  .../media/common/videobuf2/videobuf2-v4l2.c   |  28 ++-
>  drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
>  .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
>  .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
>  drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
>  drivers/media/test-drivers/visl/visl-dec.c    |  28 ++-
>  .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
>  8 files changed, 230 insertions(+), 65 deletions(-)
> 
> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> index e06905533ef4..8aa13591b782 100644
> --- a/drivers/media/common/videobuf2/videobuf2-core.c
> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> @@ -403,6 +403,37 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
>  		vb->skip_cache_sync_on_finish = 1;
>  }
>  
> +/**
> + * vb2_queue_add_buffer() - add a buffer to a queue
> + * @q:	pointer to &struct vb2_queue with videobuf2 queue.
> + * @vb:	pointer to &struct vb2_buffer to be added to the queue.
> + * @index: index where add vb2_buffer in the queue
> + */
> +static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
> +{
> +	if (index < VB2_MAX_FRAME && !q->bufs[index]) {
> +		q->bufs[index] = vb;
> +		vb->index = index;
> +		vb->vb2_queue = q;
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +/**
> + * vb2_queue_remove_buffer() - remove a buffer from a queue
> + * @q:	pointer to &struct vb2_queue with videobuf2 queue.
> + * @vb:	pointer to &struct vb2_buffer to be removed from the queue.
> + */
> +static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
> +{
> +	if (vb->index < VB2_MAX_FRAME) {
> +		q->bufs[vb->index] = NULL;
> +		vb->vb2_queue = NULL;
> +	}
> +}
> +
>  /*
>   * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
>   * video buffer memory for all buffers/planes on the queue and initializes the
> @@ -431,9 +462,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>  		}
>  
>  		vb->state = VB2_BUF_STATE_DEQUEUED;
> -		vb->vb2_queue = q;
>  		vb->num_planes = num_planes;
> -		vb->index = q->num_buffers + buffer;
>  		vb->type = q->type;
>  		vb->memory = memory;
>  		init_buffer_cache_hints(q, vb);
> @@ -443,7 +472,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>  		}
>  		call_void_bufop(q, init_buffer, vb);
>  
> -		q->bufs[vb->index] = vb;
> +		if (!vb2_queue_add_buffer(q, vb, q->num_buffers + buffer)) {
> +			dprintk(q, 1, "failed adding buffer %d to queue\n", buffer);
> +			kfree(vb);
> +			break;
> +		}
>  
>  		/* Allocate video buffer memory for the MMAP type */
>  		if (memory == VB2_MEMORY_MMAP) {
> @@ -451,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>  			if (ret) {
>  				dprintk(q, 1, "failed allocating memory for buffer %d\n",
>  					buffer);
> -				q->bufs[vb->index] = NULL;
> +				vb2_queue_remove_buffer(q, vb);
>  				kfree(vb);
>  				break;
>  			}
> @@ -466,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>  				dprintk(q, 1, "buffer %d %p initialization failed\n",
>  					buffer, vb);
>  				__vb2_buf_mem_free(vb);
> -				q->bufs[vb->index] = NULL;
> +				vb2_queue_remove_buffer(q, vb);
>  				kfree(vb);
>  				break;
>  			}
> @@ -489,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
>  
>  	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>  	     ++buffer) {
> -		vb = q->bufs[buffer];
> +		vb = vb2_get_buffer(q, buffer);
>  		if (!vb)
>  			continue;
>  
> @@ -517,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>  	/* Call driver-provided cleanup function for each buffer, if provided */
>  	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>  	     ++buffer) {
> -		struct vb2_buffer *vb = q->bufs[buffer];
> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>  
>  		if (vb && vb->planes[0].mem_priv)
>  			call_void_vb_qop(vb, buf_cleanup, vb);
> @@ -557,15 +590,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>  		q->cnt_unprepare_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;
> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
> +		bool unbalanced;
> +
> +		if (!vb)
> +			continue;
> +
> +		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) {

I think we should drop the '|| debug' part. It is already annoying today to see these
messages when the debug parameter is > 0, and now the number of buffers is still
fairly small. But if we allow a lot more buffers, then this will really spam the
kernel log.

I think this should be dropped, and we only report unbalanced buffers.

And another optimization is to only report the unbalanced counters. Right now
it reports all counters, but it is again too much spamming of the kernel log.

I think this change can be done as a separate patch before this patch.
That way it can be picked up separately from the other changes in this series.

>  			pr_info("   counters for queue %p, buffer %d:%s\n",
> @@ -597,8 +635,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>  	/* Free vb2 buffers */
>  	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>  	     ++buffer) {
> -		kfree(q->bufs[buffer]);
> -		q->bufs[buffer] = NULL;
> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
> +
> +		if (!vb)
> +			continue;
> +
> +		vb2_queue_remove_buffer(q, vb);
> +		kfree(vb);
>  	}
>  
>  	q->num_buffers -= buffers;
> @@ -634,7 +677,12 @@ static bool __buffers_in_use(struct vb2_queue *q)
>  {
>  	unsigned int buffer;
>  	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
> -		if (vb2_buffer_in_use(q, q->bufs[buffer]))
> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
> +
> +		if (!vb)
> +			continue;
> +
> +		if (vb2_buffer_in_use(q, vb))
>  			return true;
>  	}
>  	return false;
> @@ -642,7 +690,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
>  
>  void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>  {
> -	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
> +	struct vb2_buffer *vb = vb2_get_buffer(q, index);
> +
> +	if (vb)
> +		call_void_bufop(q, fill_user_buffer, vb, pb);

I think that rather than passing the index (that then has to be verified)
it is better to pass the vb2_buffer pointer directly and leave it up to
the caller to do the index verification.

Another option is to drop this function altogether and let the called
call the fill_user_buffer function. Either works for me.

>  }
>  EXPORT_SYMBOL_GPL(vb2_core_querybuf);
>  
> @@ -1553,7 +1604,13 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)

Here too it is better to pass the vb2_buffer pointer instead of an index.

This function assumes that the index is valid, so the called actually does the
validation. Passing the vb pointer instead of the index makes more sense
in this new situation.

This is also true for two other core functions: vb2_core_qbuf and vb2_core_expbuf.

>  	struct vb2_buffer *vb;
>  	int ret;
>  
> -	vb = q->bufs[index];
> +	vb = vb2_get_buffer(q, index);
> +
> +	if (!vb) {
> +		dprintk(q, 1, "can't find the requested buffer\n");
> +		return -EINVAL;
> +	}

Changing that avoids having to add this check, so it simplifies the code.

I think that this change can be done in a separate patch before this one.

It makes sense to apply that regardless of the remainder of this series.

> +
>  	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
>  		dprintk(q, 1, "invalid buffer state %s\n",
>  			vb2_state_name(vb->state));
> @@ -1624,7 +1681,11 @@ static int vb2_start_streaming(struct vb2_queue *q)
>  		 * correctly return them to vb2.
>  		 */
>  		for (i = 0; i < q->num_buffers; ++i) {
> -			vb = q->bufs[i];
> +			vb = vb2_get_buffer(q, i);
> +
> +			if (!vb)
> +				continue;
> +
>  			if (vb->state == VB2_BUF_STATE_ACTIVE)
>  				vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
>  		}
> @@ -1652,7 +1713,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
>  		return -EIO;
>  	}
>  
> -	vb = q->bufs[index];
> +	vb = vb2_get_buffer(q, index);
> +
> +	if (!vb) {
> +		dprintk(q, 1, "can't find the requested buffer\n");
> +		return -EINVAL;
> +	}
>  
>  	if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
>  	    q->requires_requests) {
> @@ -2028,12 +2094,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>  	 * to vb2 in stop_streaming().
>  	 */
>  	if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
> -		for (i = 0; i < q->num_buffers; ++i)
> -			if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
> +		for (i = 0; i < q->num_buffers; ++i) {
> +			struct vb2_buffer *vb = vb2_get_buffer(q, i);
> +
> +			if (!vb)
> +				continue;
> +
> +			if (vb->state == VB2_BUF_STATE_ACTIVE) {
>  				pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
> -					q->bufs[i]);
> -				vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
> +					vb);
> +				vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
>  			}
> +		}
>  		/* Must be zero now */
>  		WARN_ON(atomic_read(&q->owned_by_drv_count));
>  	}
> @@ -2067,9 +2139,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>  	 * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
>  	 */
>  	for (i = 0; i < q->num_buffers; ++i) {
> -		struct vb2_buffer *vb = q->bufs[i];
> -		struct media_request *req = vb->req_obj.req;
> +		struct vb2_buffer *vb;
> +		struct media_request *req;
> +
> +		vb = vb2_get_buffer(q, i);
> +		if (!vb)
> +			continue;
>  
> +		req = vb->req_obj.req;
>  		/*
>  		 * If a request is associated with this buffer, then
>  		 * call buf_request_cancel() to give the driver to complete()
> @@ -2219,7 +2296,10 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>  	buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
>  	plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>  
> -	vb = q->bufs[buffer];
> +	vb = vb2_get_buffer(q, buffer);
> +	if (!vb)
> +		return -EINVAL;
> +
>  	if (vb->planes[plane].m.offset == off) {
>  		*_buffer = buffer;
>  		*_plane = plane;
> @@ -2262,7 +2342,12 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
>  		return -EINVAL;
>  	}
>  
> -	vb = q->bufs[index];
> +	vb = vb2_get_buffer(q, index);
> +
> +	if (!vb) {
> +		dprintk(q, 1, "can't find the requested buffer\n");
> +		return -EINVAL;
> +	}
>  
>  	if (plane >= vb->num_planes) {
>  		dprintk(q, 1, "buffer plane out of range\n");
> @@ -2339,7 +2424,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
>  	if (ret)
>  		goto unlock;
>  
> -	vb = q->bufs[buffer];
> +	vb = vb2_get_buffer(q, buffer);
> +
> +	if (!vb) {
> +		dprintk(q, 1, "can't find the requested buffer\n");
> +		ret = -EINVAL;
> +		goto unlock;
> +	}
>  
>  	/*
>  	 * MMAP requires page_aligned buffers.
> @@ -2396,7 +2487,12 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
>  	if (ret)
>  		goto unlock;
>  
> -	vb = q->bufs[buffer];
> +	vb = vb2_get_buffer(q, buffer);
> +	if (!vb) {
> +		dprintk(q, 1, "can't find the requested buffer\n");
> +		ret = -EINVAL;
> +		goto unlock;
> +	}
>  
>  	vaddr = vb2_plane_vaddr(vb, plane);
>  	mutex_unlock(&q->mmap_lock);
> @@ -2625,6 +2721,7 @@ struct vb2_fileio_data {
>  static int __vb2_init_fileio(struct vb2_queue *q, int read)
>  {
>  	struct vb2_fileio_data *fileio;
> +	struct vb2_buffer *vb;
>  	int i, ret;
>  	unsigned int count = 0;
>  
> @@ -2679,7 +2776,13 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>  	 * Check if plane_count is correct
>  	 * (multiplane buffers are not supported).
>  	 */
> -	if (q->bufs[0]->num_planes != 1) {
> +	vb = vb2_get_buffer(q, 0);
> +	if (!vb) {
> +		ret = -EBUSY;
> +		goto err_reqbufs;
> +	}

This cannot happen. These fileio helper functions implement the read() support
and all the buffer allocation happens here. Userspace can never add or delete
buffers later, so there will never be holes. It is safe to assume that
vb2_get_buffer(q, i) will always return a valid vb pointer for i in the range
of 0 - q->num_buffers-1.

Perhaps add a comment to that effect, but otherwise you can drop the checks.

> +
> +	if (vb->num_planes != 1) {
>  		ret = -EBUSY;
>  		goto err_reqbufs;
>  	}
> @@ -2688,12 +2791,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>  	 * Get kernel address of each buffer.
>  	 */
>  	for (i = 0; i < q->num_buffers; i++) {
> -		fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
> +		vb = vb2_get_buffer(q, i);
> +
> +		if (!vb)
> +			continue;
> +
> +		fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
>  		if (fileio->bufs[i].vaddr == NULL) {
>  			ret = -EINVAL;
>  			goto err_reqbufs;
>  		}
> -		fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
> +		fileio->bufs[i].size = vb2_plane_size(vb, 0);
>  	}
>  
>  	/*
> @@ -2821,15 +2929,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>  
>  		fileio->cur_index = index;
>  		buf = &fileio->bufs[index];
> -		b = q->bufs[index];
> +		b = vb2_get_buffer(q, index);
> +
> +		if (!b)
> +			return -EINVAL;
>  
>  		/*
>  		 * Get number of bytes filled by the driver
>  		 */
>  		buf->pos = 0;
>  		buf->queued = 0;
> -		buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
> -				 : vb2_plane_size(q->bufs[index], 0);
> +		buf->size = read ? vb2_get_plane_payload(b, 0)
> +				 : vb2_plane_size(b, 0);
>  		/* Compensate for data_offset on read in the multiplanar case. */
>  		if (is_multiplanar && read &&
>  				b->planes[0].data_offset < buf->size) {
> @@ -2872,8 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>  	 * Queue next buffer if required.
>  	 */
>  	if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
> -		struct vb2_buffer *b = q->bufs[index];
> +		struct vb2_buffer *b = vb2_get_buffer(q, index);
>  
> +		if (!b) {
> +			dprintk(q, 1, "can't find the requested buffer\n");
> +			return -EINVAL;
> +		}
>  		/*
>  		 * Check if this is the last buffer to read.
>  		 */
> @@ -2899,7 +3014,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>  		 */
>  		buf->pos = 0;
>  		buf->queued = 1;
> -		buf->size = vb2_plane_size(q->bufs[index], 0);
> +		buf->size = vb2_plane_size(b, 0);
>  		fileio->q_count += 1;
>  		/*
>  		 * If we are queuing up buffers for the first time, then
> @@ -2970,7 +3085,9 @@ static int vb2_thread(void *data)
>  		 * Call vb2_dqbuf to get buffer back.
>  		 */
>  		if (prequeue) {
> -			vb = q->bufs[index++];
> +			vb = vb2_get_buffer(q, index++);
> +			if (!vb)
> +				continue;
>  			prequeue--;
>  		} else {
>  			call_void_qop(q, wait_finish, q);
> @@ -2979,7 +3096,7 @@ static int vb2_thread(void *data)
>  			call_void_qop(q, wait_prepare, q);
>  			dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
>  			if (!ret)
> -				vb = q->bufs[index];
> +				vb = vb2_get_buffer(q, index);
>  		}
>  		if (ret || threadio->stop)
>  			break;
> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> index c7a54d82a55e..724135d41f7f 100644
> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> @@ -383,8 +383,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>  		return -EINVAL;
>  	}
>  
> -	if (q->bufs[b->index] == NULL) {
> -		/* Should never happen */
> +	if (!vb2_get_buffer(q, b->index)) {
>  		dprintk(q, 1, "%s: buffer is NULL\n", opname);

How about:

  		dprintk(q, 1, "%s: buffer %u was deleted\n", opname, b->index);

although perhaps that change is more appropriate in patch 09/10?

Regardless, once it is possible to delete buffers, then this message should be
adjusted accordingly.

>  		return -EINVAL;
>  	}
> @@ -394,7 +393,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>  		return -EINVAL;
>  	}
>  
> -	vb = q->bufs[b->index];
> +	vb = vb2_get_buffer(q, b->index);

This can be moved up to the 'if (!vb2_get_buffer(q, b->index)) {' check above.
That avoids calling vb2_get_buffer twice.

>  	vbuf = to_vb2_v4l2_buffer(vb);
>  	ret = __verify_planes_array(vb, b);
>  	if (ret)
> @@ -628,11 +627,18 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
>  struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
>  {
>  	unsigned int i;
> +	struct vb2_buffer *vb2;
>  
> -	for (i = 0; i < q->num_buffers; i++)
> -		if (q->bufs[i]->copied_timestamp &&
> -		    q->bufs[i]->timestamp == timestamp)
> -			return vb2_get_buffer(q, i);

Perhaps add a comment here that this loop doesn't scale if there
is a really large number of buffers and something more efficient
will have to be found in that case.

> +	for (i = 0; i < q->num_buffers; i++) {
> +		vb2 = vb2_get_buffer(q, i);
> +
> +		if (!vb2)
> +			continue;
> +
> +		if (vb2->copied_timestamp &&
> +		    vb2->timestamp == timestamp)
> +			return vb2;
> +	}
>  	return NULL;
>  }
>  EXPORT_SYMBOL_GPL(vb2_find_buffer);
> @@ -664,7 +670,13 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
>  		dprintk(q, 1, "buffer index out of range\n");
>  		return -EINVAL;
>  	}
> -	vb = q->bufs[b->index];
> +	vb = vb2_get_buffer(q, b->index);
> +
> +	if (!vb) {
> +		dprintk(q, 1, "can't find the requested buffer\n");
> +		return -EINVAL;
> +	}
> +
>  	ret = __verify_planes_array(vb, b);
>  	if (!ret)
>  		vb2_core_querybuf(q, b->index, b);
> diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
> index 982c2c777484..a462d6fe4ea9 100644
> --- a/drivers/media/platform/amphion/vpu_dbg.c
> +++ b/drivers/media/platform/amphion/vpu_dbg.c
> @@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>  
>  	vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
>  	for (i = 0; i < vq->num_buffers; i++) {
> -		struct vb2_buffer *vb = vq->bufs[i];
> -		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> +		struct vb2_buffer *vb;
> +		struct vb2_v4l2_buffer *vbuf;
> +
> +		vb = vb2_get_buffer(vq, i);
> +		if (!vb)
> +			continue;
>  
>  		if (vb->state == VB2_BUF_STATE_DEQUEUED)
>  			continue;
> +
> +		vbuf = to_vb2_v4l2_buffer(vb);
> +
>  		num = scnprintf(str, sizeof(str),
>  				"output [%2d] state = %10s, %8s\n",
>  				i, vb2_stat_name[vb->state],
> @@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>  
>  	vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
>  	for (i = 0; i < vq->num_buffers; i++) {
> -		struct vb2_buffer *vb = vq->bufs[i];
> -		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> +		struct vb2_buffer *vb;
> +		struct vb2_v4l2_buffer *vbuf;
> +
> +		vb = vb2_get_buffer(vq, i);
> +		if (!vb)
> +			continue;
>  
>  		if (vb->state == VB2_BUF_STATE_DEQUEUED)
>  			continue;
> +
> +		vbuf = to_vb2_v4l2_buffer(vb);
> +
>  		num = scnprintf(str, sizeof(str),
>  				"capture[%2d] state = %10s, %8s\n",
>  				i, vb2_stat_name[vb->state],

This can be a separate patch, right? It doesn't depend on any core changes.

And this can also be applied before this patch.

> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> index 621038aab116..62910a1b8a98 100644
> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
> @@ -603,7 +603,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>  		return -EINVAL;
>  	}
>  
> -	vb = vq->bufs[buf->index];
> +	vb = vb2_get_buffer(vq, buf->index);
> +	if (!vb) {
> +		dev_err(ctx->jpeg->dev, "buffer not found\n");
> +		return -EINVAL;
> +	}
>  	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
>  	jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
>  

Ditto.

> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> index e393e3e668f8..3d2ae0e1b5b6 100644
> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
> @@ -1696,7 +1696,7 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
>  
>  	/* update internal buffer's width/height */
>  	for (i = 0; i < vq->num_buffers; i++) {
> -		if (vb == vq->bufs[i]) {
> +		if (vb == vb2_get_buffer(vq, i)) {
>  			instance->dpb[i].width = w;
>  			instance->dpb[i].height = h;
>  			break;

Ditto.

> diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
> index 3a848ca32a0e..326be09bdb55 100644
> --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
> +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
> @@ -577,6 +577,10 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>  		}
>  
>  		vb2_buf = vb2_get_buffer(vq, buf->index);
> +		if (!vb2_buf) {
> +			dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
> +			return -EINVAL;
> +		}
>  		stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
>  		stream->bytesused = buf->bytesused;
>  	}

Ditto.

> diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
> index 318d675e5668..ba20ea998d19 100644
> --- a/drivers/media/test-drivers/visl/visl-dec.c
> +++ b/drivers/media/test-drivers/visl/visl-dec.c
> @@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>  	for (i = 0; i < out_q->num_buffers; i++) {
>  		char entry[] = "index: %u, state: %s, request_fd: %d, ";
>  		u32 old_len = len;
> -		char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
> +		struct vb2_buffer *vb2;
> +		char *q_status;
> +
> +		vb2 = vb2_get_buffer(out_q, i);
> +		if (!vb2)
> +			continue;
> +
> +		q_status = visl_get_vb2_state(vb2->state);
>  
>  		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>  				 entry, i, q_status,
> -				 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
> +				 to_vb2_v4l2_buffer(vb2)->request_fd);
>  
> -		len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
> +		len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
>  					   &buf[len],
>  					   TPG_STR_BUF_SZ - len);
>  
> @@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>  	len = 0;
>  	for (i = 0; i < cap_q->num_buffers; i++) {
>  		u32 old_len = len;
> -		char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
> +		struct vb2_buffer *vb2;
> +		char *q_status;
> +
> +		vb2 = vb2_get_buffer(cap_q, i);
> +		if (!vb2)
> +			continue;
> +
> +		q_status = visl_get_vb2_state(vb2->state);
>  
>  		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>  				 "index: %u, status: %s, timestamp: %llu, is_held: %d",
> -				 cap_q->bufs[i]->index, q_status,
> -				 cap_q->bufs[i]->timestamp,
> -				 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
> +				 vb2->index, q_status,
> +				 vb2->timestamp,
> +				 to_vb2_v4l2_buffer(vb2)->is_held);
>  
>  		tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
>  		frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);

Ditto.

> diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
> index d2174156573a..4b65c69fa60d 100644
> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
> @@ -1061,7 +1061,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
>  	if (ret)
>  		return ret;
>  
> -	vb = pipe->vb_queue.bufs[buf->index];
> +	vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
>  	frame = vb_to_frame(vb);
>  
>  	buf->reserved = asd->frame_status[buf->index];

Ditto.

Background: I think it is really useful to merge a lot of the groundwork early
on, where possible. It simplifies the remainder of the patch series.

Regards,

	Hans

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 03/10] media: videobuf2: Be more flexible on the number of queue stored buffers
  2023-08-24  9:21 ` [PATCH v5 03/10] media: videobuf2: Be more flexible on the number of queue stored buffers Benjamin Gaignard
@ 2023-08-30 13:27   ` Hans Verkuil
  0 siblings, 0 replies; 27+ messages in thread
From: Hans Verkuil @ 2023-08-30 13:27 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel

On 24/08/2023 11:21, Benjamin Gaignard wrote:
> Add 'max_allowed_buffers' field in vb2_queue struct to let drivers decide
> how many buffers could be stored in a queue.
> This request 'bufs' array to be allocated at queue init time and freed
> when releasing the queue.
> By default VB2_MAX_FRAME remains the limit.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
> ---
>  .../media/common/videobuf2/videobuf2-core.c   | 25 +++++++++++++------
>  include/media/videobuf2-core.h                |  4 ++-
>  2 files changed, 20 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> index 8aa13591b782..70e36389b704 100644
> --- a/drivers/media/common/videobuf2/videobuf2-core.c
> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> @@ -411,7 +411,7 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
>   */
>  static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)

Let's use 'unsigned int index' to avoid signedness issues.

>  {
> -	if (index < VB2_MAX_FRAME && !q->bufs[index]) {
> +	if (index < q->max_allowed_buffers && !q->bufs[index]) {
>  		q->bufs[index] = vb;
>  		vb->index = index;
>  		vb->vb2_queue = q;
> @@ -428,7 +428,7 @@ static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int
>   */
>  static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
>  {
> -	if (vb->index < VB2_MAX_FRAME) {
> +	if (vb->index < q->max_allowed_buffers) {
>  		q->bufs[vb->index] = NULL;
>  		vb->vb2_queue = NULL;
>  	}
> @@ -449,9 +449,9 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>  	struct vb2_buffer *vb;
>  	int ret;
>  
> -	/* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */
> +	/* Ensure that q->num_buffers+num_buffers is below q->max_allowed_buffers */
>  	num_buffers = min_t(unsigned int, num_buffers,
> -			    VB2_MAX_FRAME - q->num_buffers);
> +			    q->max_allowed_buffers - q->num_buffers);
>  
>  	for (buffer = 0; buffer < num_buffers; ++buffer) {
>  		/* Allocate vb2 buffer structures */
> @@ -852,9 +852,9 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
>  	/*
>  	 * Make sure the requested values and current defaults are sane.
>  	 */
> -	WARN_ON(q->min_buffers_needed > VB2_MAX_FRAME);
> +	WARN_ON(q->min_buffers_needed > q->max_allowed_buffers);
>  	num_buffers = max_t(unsigned int, *count, q->min_buffers_needed);
> -	num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME);
> +	num_buffers = min_t(unsigned int, num_buffers, q->max_allowed_buffers);
>  	memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
>  	/*
>  	 * Set this now to ensure that drivers see the correct q->memory value
> @@ -970,7 +970,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
>  	bool no_previous_buffers = !q->num_buffers;
>  	int ret;
>  
> -	if (q->num_buffers == VB2_MAX_FRAME) {
> +	if (q->num_buffers == q->max_allowed_buffers) {
>  		dprintk(q, 1, "maximum number of buffers already allocated\n");
>  		return -ENOBUFS;
>  	}
> @@ -999,7 +999,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
>  			return -EINVAL;
>  	}
>  
> -	num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
> +	num_buffers = min(*count, q->max_allowed_buffers - q->num_buffers);
>  
>  	if (requested_planes && requested_sizes) {
>  		num_planes = requested_planes;
> @@ -2541,6 +2541,14 @@ int vb2_core_queue_init(struct vb2_queue *q)
>  
>  	q->memory = VB2_MEMORY_UNKNOWN;
>  
> +	if (!q->max_allowed_buffers)
> +		q->max_allowed_buffers = VB2_MAX_FRAME;
> +
> +	/* The maximum is limited by offset cookie encoding pattern */
> +	q->max_allowed_buffers = min_t(unsigned int, q->max_allowed_buffers, MAX_BUFFERS);

With the new MAX_BUFFERS define this probably will need to be adjusted.

> +
> +	q->bufs = kcalloc(q->max_allowed_buffers, sizeof(*q->bufs), GFP_KERNEL);
> +
>  	if (q->buf_struct_size == 0)
>  		q->buf_struct_size = sizeof(struct vb2_buffer);
>  
> @@ -2565,6 +2573,7 @@ void vb2_core_queue_release(struct vb2_queue *q)
>  	__vb2_queue_cancel(q);
>  	mutex_lock(&q->mmap_lock);
>  	__vb2_queue_free(q, q->num_buffers);
> +	kfree(q->bufs);
>  	mutex_unlock(&q->mmap_lock);
>  }
>  EXPORT_SYMBOL_GPL(vb2_core_queue_release);
> diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
> index 4b6a9d2ea372..ee9161b9fd64 100644
> --- a/include/media/videobuf2-core.h
> +++ b/include/media/videobuf2-core.h
> @@ -558,6 +558,7 @@ struct vb2_buf_ops {
>   * @dma_dir:	DMA mapping direction.
>   * @bufs:	videobuf2 buffer structures
>   * @num_buffers: number of allocated/used buffers
> + * @max_allowed_buffers: upper limit of number of allocated/used buffers
>   * @queued_list: list of buffers currently queued from userspace
>   * @queued_count: number of buffers queued and ready for streaming.
>   * @owned_by_drv_count: number of buffers owned by the driver
> @@ -619,8 +620,9 @@ struct vb2_queue {
>  	struct mutex			mmap_lock;
>  	unsigned int			memory;
>  	enum dma_data_direction		dma_dir;
> -	struct vb2_buffer		*bufs[VB2_MAX_FRAME];
> +	struct vb2_buffer		**bufs;
>  	unsigned int			num_buffers;
> +	unsigned int			max_allowed_buffers;
>  
>  	struct list_head		queued_list;
>  	unsigned int			queued_count;

Regards,

	Hans

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 09/10] media: v4l2: Add DELETE_BUFS ioctl
  2023-08-24  9:21 ` [PATCH v5 09/10] media: v4l2: Add DELETE_BUFS ioctl Benjamin Gaignard
@ 2023-08-30 13:45   ` Hans Verkuil
  2023-08-30 13:51   ` Hans Verkuil
  1 sibling, 0 replies; 27+ messages in thread
From: Hans Verkuil @ 2023-08-30 13:45 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel

On 24/08/2023 11:21, Benjamin Gaignard wrote:
> VIDIOC_DELETE_BUFS ioctl allows to delete buffers from a queue.
> The number of buffers to delete in given by count field of
> struct v4l2_delete_buffers and the range start at the index
> specified in the same structure.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
> ---
>  .../userspace-api/media/v4l/user-func.rst     |  1 +
>  .../media/v4l/vidioc-delete-bufs.rst          | 73 +++++++++++++++++++
>  .../media/common/videobuf2/videobuf2-core.c   | 34 +++++++++
>  .../media/common/videobuf2/videobuf2-v4l2.c   | 16 ++++
>  drivers/media/v4l2-core/v4l2-dev.c            |  1 +
>  drivers/media/v4l2-core/v4l2-ioctl.c          | 17 +++++
>  include/media/v4l2-ioctl.h                    |  4 +
>  include/media/videobuf2-core.h                |  9 +++
>  include/media/videobuf2-v4l2.h                | 11 +++
>  include/uapi/linux/videodev2.h                | 17 +++++
>  10 files changed, 183 insertions(+)
>  create mode 100644 Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst
> 
> diff --git a/Documentation/userspace-api/media/v4l/user-func.rst b/Documentation/userspace-api/media/v4l/user-func.rst
> index 15ff0bf7bbe6..3fd567695477 100644
> --- a/Documentation/userspace-api/media/v4l/user-func.rst
> +++ b/Documentation/userspace-api/media/v4l/user-func.rst
> @@ -17,6 +17,7 @@ Function Reference
>      vidioc-dbg-g-chip-info
>      vidioc-dbg-g-register
>      vidioc-decoder-cmd
> +    vidioc-delete-bufs
>      vidioc-dqevent
>      vidioc-dv-timings-cap
>      vidioc-encoder-cmd
> diff --git a/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst
> new file mode 100644
> index 000000000000..a55fe6331fc8
> --- /dev/null
> +++ b/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst
> @@ -0,0 +1,73 @@
> +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
> +.. c:namespace:: V4L
> +
> +.. _VIDIOC_DELETE_BUFS:
> +
> +************************
> +ioctl VIDIOC_DELETE_BUFS
> +************************
> +
> +Name
> +====
> +
> +VIDIOC_DELETE_BUFS - Deletes buffers from a queue
> +
> +Synopsis
> +========
> +
> +.. c:macro:: VIDIOC_DELETE_BUFs
> +
> +``int ioctl(int fd, VIDIOC_DELETE_BUFs, struct v4l2_delete_buffers *argp)``
> +
> +Arguments
> +=========
> +
> +``fd``
> +    File descriptor returned by :c:func:`open()`.
> +
> +``argp``
> +    Pointer to struct :c:type:`v4l2_delete_buffers`.
> +
> +Description
> +===========
> +
> +Applications can optionally call the :ref:`VIDIOC_DELETE_BUFS` ioctl to
> +delete buffers from a queue.
> +
> +.. c:type:: v4l2_delete_buffers
> +
> +.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.5cm}|
> +
> +.. flat-table:: struct v4l2_delete_buffers
> +    :header-rows:  0
> +    :stub-columns: 0
> +    :widths:       1 1 2
> +
> +    * - __u32
> +      - ``index``
> +      - The starting buffer index to delete.
> +    * - __u32
> +      - ``count``
> +      - The number of buffers to be deleted.
> +    * - __u32
> +      - ``type``
> +      - Type of the stream or buffers, this is the same as the struct
> +	:c:type:`v4l2_format` ``type`` field. See
> +	:c:type:`v4l2_buf_type` for valid values.
> +    * - __u32
> +      - ``reserved``\ [13]
> +      - A place holder for future extensions. Drivers and applications
> +	must set the array to zero.
> +
> +Return Value
> +============
> +
> +On success 0 is returned, on error -1 and the ``errno`` variable is set
> +appropriately. The generic error codes are described at the
> +:ref:`Generic Error Codes <gen-errors>` chapter.
> +
> +EBUSY
> +    File I/O is in progress.
> +
> +EINVAL
> +    The buffer ``index`` doesn't exist in the queue.
> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> index 70e36389b704..3d915b4c33b2 100644
> --- a/drivers/media/common/videobuf2/videobuf2-core.c
> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> @@ -1634,6 +1634,40 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
>  }
>  EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
>  
> +int vb2_core_delete_buf(struct vb2_queue *q, unsigned int index)

Same as the other core functions: rather than an index, pass a valid
vb2_buffer pointer. Let the caller do the validation.

My rule of thumb is that the core code should only need to call
vb2_get_buffer() if it is walking over all buffers (i.e. in a
for-loop). For functions like this it should get the vb pointer
directly rather than having to look it up, since the caller
should have done that already.

> +{
> +	struct vb2_buffer *vb;
> +
> +	vb = vb2_get_buffer(q, index);
> +	if (!vb) {
> +		dprintk(q, 1, "invalid buffer index %d\n", index);
> +		return -EINVAL;
> +	}
> +
> +	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
> +		dprintk(q, 1, "can't delete non dequeued buffer index %d\n", index);
> +		return -EINVAL;
> +	}
> +
> +	if (vb->planes[0].mem_priv)
> +		call_void_vb_qop(vb, buf_cleanup, vb);
> +
> +	/* Free MMAP buffers or release USERPTR buffers */
> +	if (q->memory == VB2_MEMORY_MMAP)
> +		__vb2_buf_mem_free(vb);
> +	else if (q->memory == VB2_MEMORY_DMABUF)
> +		__vb2_buf_dmabuf_put(vb);
> +	else
> +		__vb2_buf_userptr_put(vb);
> +
> +	vb2_queue_remove_buffer(q, vb);

When freeing all buffers (REQBUFS with count=0) the q->mmap_lock is taken.
I wonder if the same has to happen here. You don't want userspace to call mmap
while deleting a buffer.

I also think this should be refactored since __vb2_queue_free/__vb2_free_mem
need to do the same thing.

> +	kfree(vb);
> +
> +	dprintk(q, 2, "buffer %d deleted\n", index);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(vb2_core_delete_buf);
> +
>  /*
>   * vb2_start_streaming() - Attempt to start streaming.
>   * @q:		videobuf2 queue
> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> index 724135d41f7f..ffe6b66a27f1 100644
> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> @@ -751,6 +751,22 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
>  }
>  EXPORT_SYMBOL_GPL(vb2_prepare_buf);
>  
> +int vb2_delete_bufs(struct vb2_queue *q, struct v4l2_delete_buffers *d)
> +{
> +	unsigned int index;
> +	int ret = 0;
> +

Add a check if index < q->num_buffers, count < q->num_buffers and that
the sum of the two <= q->num_buffers. I.e., basic sanity checks.

Return -EINVAL if that's the case.

> +	for (index = d->index; index < d->index + d->count; index++) {
> +		ret = vb2_core_delete_buf(q, index);
> +		if (ret)
> +			break;
> +	}
> +
> +	d->index = index;

Hmm. I wonder if vb2_core_delete_buf shouldn't be void, and instead
verify here first that all buffers your want to delete 1) exist, and
2) are in state DEQUEUED.

> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(vb2_delete_bufs);
> +
>  int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
>  {
>  	unsigned requested_planes = 1;
> diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
> index f81279492682..215654fd6581 100644
> --- a/drivers/media/v4l2-core/v4l2-dev.c
> +++ b/drivers/media/v4l2-core/v4l2-dev.c
> @@ -720,6 +720,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
>  		SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
>  		SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
>  		SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
> +		SET_VALID_IOCTL(ops, VIDIOC_DELETE_BUFS, vidioc_delete_bufs);
>  	}
>  
>  	if (is_vid || is_vbi || is_meta) {
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index f4d9d6279094..32336b9bb7e4 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -489,6 +489,13 @@ static void v4l_print_create_buffers(const void *arg, bool write_only)
>  	v4l_print_format(&p->format, write_only);
>  }
>  
> +static void v4l_print_delete_buffers(const void *arg, bool write_only)
> +{
> +	const struct v4l2_delete_buffers *p = arg;
> +
> +	pr_cont("index=%d, count=%d\n", p->index, p->count);
> +}
> +
>  static void v4l_print_streamparm(const void *arg, bool write_only)
>  {
>  	const struct v4l2_streamparm *p = arg;
> @@ -2160,6 +2167,15 @@ static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops,
>  	return ret ? ret : ops->vidioc_prepare_buf(file, fh, b);
>  }
>  
> +static int v4l_delete_bufs(const struct v4l2_ioctl_ops *ops,
> +			   struct file *file, void *fh, void *arg)
> +{
> +	struct v4l2_delete_buffers *delete = arg;
> +	int ret = check_fmt(file, delete->type);
> +
> +	return ret ? ret : ops->vidioc_delete_bufs(file, fh, delete);
> +}
> +
>  static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
>  				struct file *file, void *fh, void *arg)
>  {
> @@ -2909,6 +2925,7 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = {
>  	IOCTL_INFO(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
>  	IOCTL_INFO(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
>  	IOCTL_INFO(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
> +	IOCTL_INFO(VIDIOC_DELETE_BUFS, v4l_delete_bufs, v4l_print_delete_buffers, INFO_FL_QUEUE),

You can add INFO_FL_CLEAR here to automatically zero the reserved field. It also needs INFO_FL_PRIO.

>  };
>  #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
>  
> diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
> index edb733f21604..55afbde54211 100644
> --- a/include/media/v4l2-ioctl.h
> +++ b/include/media/v4l2-ioctl.h
> @@ -163,6 +163,8 @@ struct v4l2_fh;
>   *	:ref:`VIDIOC_CREATE_BUFS <vidioc_create_bufs>` ioctl
>   * @vidioc_prepare_buf: pointer to the function that implements
>   *	:ref:`VIDIOC_PREPARE_BUF <vidioc_prepare_buf>` ioctl
> + * @vidioc_delete_bufs: pointer to the function that implements
> + *	:ref:`VIDIOC_DELETE_BUFS <vidioc_delete_bufs>` ioctl
>   * @vidioc_overlay: pointer to the function that implements
>   *	:ref:`VIDIOC_OVERLAY <vidioc_overlay>` ioctl
>   * @vidioc_g_fbuf: pointer to the function that implements
> @@ -422,6 +424,8 @@ struct v4l2_ioctl_ops {
>  				  struct v4l2_create_buffers *b);
>  	int (*vidioc_prepare_buf)(struct file *file, void *fh,
>  				  struct v4l2_buffer *b);
> +	int (*vidioc_delete_bufs)(struct file *file, void *fh,
> +				  struct v4l2_delete_buffers *d);
>  
>  	int (*vidioc_overlay)(struct file *file, void *fh, unsigned int i);
>  	int (*vidioc_g_fbuf)(struct file *file, void *fh,
> diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
> index ee9161b9fd64..c9ecc4214982 100644
> --- a/include/media/videobuf2-core.h
> +++ b/include/media/videobuf2-core.h
> @@ -843,6 +843,15 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
>   */
>  int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb);
>  
> +/**
> + * vb2_core_delete_buf() -
> + * @q: pointer to &struct vb2_queue with videobuf2 queue.
> + * @index:	id number of the buffer.
> + *
> + *  Return: returns zero on success; an error code otherwise.
> + */
> +int vb2_core_delete_buf(struct vb2_queue *q, unsigned int index);
> +
>  /**
>   * vb2_core_qbuf() - Queue a buffer from userspace
>   *
> diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
> index 5a845887850b..2ef68fdf388f 100644
> --- a/include/media/videobuf2-v4l2.h
> +++ b/include/media/videobuf2-v4l2.h
> @@ -118,6 +118,17 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create);
>   */
>  int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
>  		    struct v4l2_buffer *b);
> +/**
> + * vb2_delete_bufs() - Delete buffers from the queue
> + *
> + * @q:		pointer to &struct vb2_queue with videobuf2 queue.
> + * @d:		delete parameter, passed from userspace to
> + *		&v4l2_ioctl_ops->vidioc_delete_bufs handler in driver
> + *
> + * The return values from this function are intended to be directly returned
> + * from &v4l2_ioctl_ops->vidioc_delete_bufs handler in driver.
> + */
> +int vb2_delete_bufs(struct vb2_queue *q, struct v4l2_delete_buffers *d);
>  
>  /**
>   * vb2_qbuf() - Queue a buffer from userspace
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 78260e5d9985..4807b38e2a6f 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -2616,6 +2616,21 @@ struct v4l2_create_buffers {
>  	__u32			reserved[6];
>  };
>  
> +/**
> + * struct v4l2_delete_buffers - VIDIOC_DELETE_BUFS argument
> + * @index:	the first buffer to be deleted
> + * @count:	number of buffers to delete
> + * @type:	enum v4l2_buf_type; buffer type (type == *_MPLANE for
> + *		multiplanar buffers);

I would drop the bit between (). That seems overkill to me.

> + * @reserved:	futur extensions

futur -> future

> + */
> +struct v4l2_delete_buffers {
> +	__u32			index;
> +	__u32			count;
> +	__u32			type;
> +	__u32			reserved[13];
> +};
> +
>  /*
>   *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
>   *
> @@ -2715,6 +2730,8 @@ struct v4l2_create_buffers {
>  #define VIDIOC_DBG_G_CHIP_INFO  _IOWR('V', 102, struct v4l2_dbg_chip_info)
>  
>  #define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
> +#define VIDIOC_DELETE_BUFS	_IOWR('V', 104, struct v4l2_delete_buffers)
> +
>  
>  /* Reminder: when adding new ioctls please add support for them to
>     drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */

Regards,

	Hans

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 09/10] media: v4l2: Add DELETE_BUFS ioctl
  2023-08-24  9:21 ` [PATCH v5 09/10] media: v4l2: Add DELETE_BUFS ioctl Benjamin Gaignard
  2023-08-30 13:45   ` Hans Verkuil
@ 2023-08-30 13:51   ` Hans Verkuil
  1 sibling, 0 replies; 27+ messages in thread
From: Hans Verkuil @ 2023-08-30 13:51 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel

On 24/08/2023 11:21, Benjamin Gaignard wrote:
> VIDIOC_DELETE_BUFS ioctl allows to delete buffers from a queue.
> The number of buffers to delete in given by count field of
> struct v4l2_delete_buffers and the range start at the index
> specified in the same structure.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
> ---
>  .../userspace-api/media/v4l/user-func.rst     |  1 +
>  .../media/v4l/vidioc-delete-bufs.rst          | 73 +++++++++++++++++++
>  .../media/common/videobuf2/videobuf2-core.c   | 34 +++++++++
>  .../media/common/videobuf2/videobuf2-v4l2.c   | 16 ++++
>  drivers/media/v4l2-core/v4l2-dev.c            |  1 +
>  drivers/media/v4l2-core/v4l2-ioctl.c          | 17 +++++
>  include/media/v4l2-ioctl.h                    |  4 +
>  include/media/videobuf2-core.h                |  9 +++
>  include/media/videobuf2-v4l2.h                | 11 +++
>  include/uapi/linux/videodev2.h                | 17 +++++
>  10 files changed, 183 insertions(+)
>  create mode 100644 Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst
> 
> diff --git a/Documentation/userspace-api/media/v4l/user-func.rst b/Documentation/userspace-api/media/v4l/user-func.rst
> index 15ff0bf7bbe6..3fd567695477 100644
> --- a/Documentation/userspace-api/media/v4l/user-func.rst
> +++ b/Documentation/userspace-api/media/v4l/user-func.rst
> @@ -17,6 +17,7 @@ Function Reference
>      vidioc-dbg-g-chip-info
>      vidioc-dbg-g-register
>      vidioc-decoder-cmd
> +    vidioc-delete-bufs
>      vidioc-dqevent
>      vidioc-dv-timings-cap
>      vidioc-encoder-cmd
> diff --git a/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst
> new file mode 100644
> index 000000000000..a55fe6331fc8
> --- /dev/null
> +++ b/Documentation/userspace-api/media/v4l/vidioc-delete-bufs.rst
> @@ -0,0 +1,73 @@
> +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
> +.. c:namespace:: V4L
> +
> +.. _VIDIOC_DELETE_BUFS:
> +
> +************************
> +ioctl VIDIOC_DELETE_BUFS
> +************************
> +
> +Name
> +====
> +
> +VIDIOC_DELETE_BUFS - Deletes buffers from a queue
> +
> +Synopsis
> +========
> +
> +.. c:macro:: VIDIOC_DELETE_BUFs
> +
> +``int ioctl(int fd, VIDIOC_DELETE_BUFs, struct v4l2_delete_buffers *argp)``
> +
> +Arguments
> +=========
> +
> +``fd``
> +    File descriptor returned by :c:func:`open()`.
> +
> +``argp``
> +    Pointer to struct :c:type:`v4l2_delete_buffers`.
> +
> +Description
> +===========
> +
> +Applications can optionally call the :ref:`VIDIOC_DELETE_BUFS` ioctl to
> +delete buffers from a queue.
> +
> +.. c:type:: v4l2_delete_buffers
> +
> +.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.5cm}|
> +
> +.. flat-table:: struct v4l2_delete_buffers
> +    :header-rows:  0
> +    :stub-columns: 0
> +    :widths:       1 1 2
> +
> +    * - __u32
> +      - ``index``
> +      - The starting buffer index to delete.
> +    * - __u32
> +      - ``count``
> +      - The number of buffers to be deleted.
> +    * - __u32
> +      - ``type``
> +      - Type of the stream or buffers, this is the same as the struct
> +	:c:type:`v4l2_format` ``type`` field. See
> +	:c:type:`v4l2_buf_type` for valid values.
> +    * - __u32
> +      - ``reserved``\ [13]
> +      - A place holder for future extensions. Drivers and applications
> +	must set the array to zero.
> +
> +Return Value
> +============
> +
> +On success 0 is returned, on error -1 and the ``errno`` variable is set
> +appropriately. The generic error codes are described at the
> +:ref:`Generic Error Codes <gen-errors>` chapter.
> +
> +EBUSY
> +    File I/O is in progress.
> +
> +EINVAL
> +    The buffer ``index`` doesn't exist in the queue.
> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> index 70e36389b704..3d915b4c33b2 100644
> --- a/drivers/media/common/videobuf2/videobuf2-core.c
> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> @@ -1634,6 +1634,40 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
>  }
>  EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
>  
> +int vb2_core_delete_buf(struct vb2_queue *q, unsigned int index)

I didn't realize this the first time I reviewed this, but I would
suggest that you change this to

vb2_core_delete_bufs(struct vb2_queue *q, unsigned int index, unsigned int count)

This is consistent with vb2_core_create_bufs, and I strongly suspect it will
help with locking (mmap_lock), since you don't need to lock for every buffer you
delete, you can do it up front.

And you can move the index/count validation to the core as well, that will help
if e.g. dvb would want to use this ioctl in the future.

Regards,

	Hans

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for DELETE_BUFS ioctl
  2023-08-24  9:21 ` [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for " Benjamin Gaignard
  2023-08-25 10:29   ` kernel test robot
  2023-08-25 12:26   ` kernel test robot
@ 2023-08-30 13:53   ` Hans Verkuil
  2 siblings, 0 replies; 27+ messages in thread
From: Hans Verkuil @ 2023-08-30 13:53 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel

On 24/08/2023 11:21, Benjamin Gaignard wrote:
> Create v4l2-mem2mem helpers for VIDIOC_DELETE_BUFS ioctl.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
> ---
>  .../media/platform/verisilicon/hantro_v4l2.c  |  1 +
>  drivers/media/test-drivers/vim2m.c            |  1 +
>  drivers/media/v4l2-core/v4l2-mem2mem.c        | 20 +++++++++++++++++++
>  include/media/v4l2-mem2mem.h                  | 12 +++++++++++
>  4 files changed, 34 insertions(+)
> 
> diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
> index 27a1e77cca38..0fd1c2fc78c8 100644
> --- a/drivers/media/platform/verisilicon/hantro_v4l2.c
> +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
> @@ -756,6 +756,7 @@ const struct v4l2_ioctl_ops hantro_ioctl_ops = {
>  	.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
>  	.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
>  	.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
> +	.vidioc_delete_bufs = v4l2_m2m_ioctl_delete_bufs,
>  	.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
>  
>  	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
> diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c
> index 3e3b424b4860..3014b8ee13d0 100644
> --- a/drivers/media/test-drivers/vim2m.c
> +++ b/drivers/media/test-drivers/vim2m.c
> @@ -960,6 +960,7 @@ static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
>  	.vidioc_dqbuf		= v4l2_m2m_ioctl_dqbuf,
>  	.vidioc_prepare_buf	= v4l2_m2m_ioctl_prepare_buf,
>  	.vidioc_create_bufs	= v4l2_m2m_ioctl_create_bufs,
> +	.vidioc_delete_buf	= v4l2_m2m_ioctl_delete_buf,

I suspect you didn't enable vim2m in your kernel config, since this
should be:

	.vidioc_delete_bufs = v4l2_m2m_ioctl_delete_bufs,

>  	.vidioc_expbuf		= v4l2_m2m_ioctl_expbuf,
>  
>  	.vidioc_streamon	= v4l2_m2m_ioctl_streamon,
> diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
> index 0cc30397fbad..d1d59943680f 100644
> --- a/drivers/media/v4l2-core/v4l2-mem2mem.c
> +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
> @@ -831,6 +831,17 @@ int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
>  }
>  EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf);
>  
> +int v4l2_m2m_delete_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
> +			 struct v4l2_delete_buffers *d)
> +{
> +	struct vb2_queue *vq;
> +
> +	vq = v4l2_m2m_get_vq(m2m_ctx, d->type);
> +
> +	return vb2_delete_bufs(vq, d);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_m2m_delete_bufs);
> +
>  int v4l2_m2m_create_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
>  			 struct v4l2_create_buffers *create)
>  {
> @@ -1377,6 +1388,15 @@ int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv,
>  }
>  EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs);
>  
> +int v4l2_m2m_ioctl_delete_bufs(struct file *file, void *priv,
> +			       struct v4l2_delete_buffers *d)
> +{
> +	struct v4l2_fh *fh = file->private_data;
> +
> +	return v4l2_m2m_delete_bufs(file, fh->m2m_ctx, d);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_delete_bufs);
> +
>  int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv,
>  				struct v4l2_buffer *buf)
>  {
> diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
> index d6c8eb2b5201..161f85c42dc8 100644
> --- a/include/media/v4l2-mem2mem.h
> +++ b/include/media/v4l2-mem2mem.h
> @@ -381,6 +381,16 @@ int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
>  int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
>  			 struct v4l2_buffer *buf);
>  
> +/**
> + * v4l2_m2m_delete_bufs() - delete buffers from the queue
> + *
> + * @file: pointer to struct &file
> + * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
> + * @d: pointer to struct &v4l2_delete_buffers
> + */
> +int v4l2_m2m_delete_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
> +			 struct v4l2_delete_buffers *d);
> +
>  /**
>   * v4l2_m2m_create_bufs() - create a source or destination buffer, depending
>   * on the type
> @@ -860,6 +870,8 @@ int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv,
>  				struct v4l2_requestbuffers *rb);
>  int v4l2_m2m_ioctl_create_bufs(struct file *file, void *fh,
>  				struct v4l2_create_buffers *create);
> +int v4l2_m2m_ioctl_delete_bufs(struct file *file, void *priv,
> +			       struct v4l2_delete_buffers *d);
>  int v4l2_m2m_ioctl_querybuf(struct file *file, void *fh,
>  				struct v4l2_buffer *buf);
>  int v4l2_m2m_ioctl_expbuf(struct file *file, void *fh,

Regards,

	Hans

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions
  2023-08-30 13:23   ` Hans Verkuil
@ 2023-08-30 16:24     ` Benjamin Gaignard
  2023-08-30 16:36       ` Hans Verkuil
  2023-09-01 12:29     ` Benjamin Gaignard
  1 sibling, 1 reply; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-30 16:24 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, tfiga, m.szyprowski, ming.qian, ezequiel,
	p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel


Le 30/08/2023 à 15:23, Hans Verkuil a écrit :
> On 24/08/2023 11:21, Benjamin Gaignard wrote:
>> The first step before changing how vb2 buffers are stored into queue
>> is to avoid direct access to bufs arrays.
>>
>> This patch adds 2 helpers functions to add and remove vb2 buffers
>> from a queue. With these 2 and vb2_get_buffer(), bufs field of
>> struct vb2_queue becomes like a private member of the structure.
>>
>> After each call to vb2_get_buffer() we need to be sure that we get
>> a valid pointer so check the return value of all of them.
>>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
>>
>> # Conflicts:
>> #	drivers/media/common/videobuf2/videobuf2-core.c
>> ---
>>   .../media/common/videobuf2/videobuf2-core.c   | 203 ++++++++++++++----
>>   .../media/common/videobuf2/videobuf2-v4l2.c   |  28 ++-
>>   drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
>>   .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
>>   .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
>>   drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
>>   drivers/media/test-drivers/visl/visl-dec.c    |  28 ++-
>>   .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
>>   8 files changed, 230 insertions(+), 65 deletions(-)
>>
>> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
>> index e06905533ef4..8aa13591b782 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-core.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
>> @@ -403,6 +403,37 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
>>   		vb->skip_cache_sync_on_finish = 1;
>>   }
>>   
>> +/**
>> + * vb2_queue_add_buffer() - add a buffer to a queue
>> + * @q:	pointer to &struct vb2_queue with videobuf2 queue.
>> + * @vb:	pointer to &struct vb2_buffer to be added to the queue.
>> + * @index: index where add vb2_buffer in the queue
>> + */
>> +static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
>> +{
>> +	if (index < VB2_MAX_FRAME && !q->bufs[index]) {
>> +		q->bufs[index] = vb;
>> +		vb->index = index;
>> +		vb->vb2_queue = q;
>> +		return true;
>> +	}
>> +
>> +	return false;
>> +}
>> +
>> +/**
>> + * vb2_queue_remove_buffer() - remove a buffer from a queue
>> + * @q:	pointer to &struct vb2_queue with videobuf2 queue.
>> + * @vb:	pointer to &struct vb2_buffer to be removed from the queue.
>> + */
>> +static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
>> +{
>> +	if (vb->index < VB2_MAX_FRAME) {
>> +		q->bufs[vb->index] = NULL;
>> +		vb->vb2_queue = NULL;
>> +	}
>> +}
>> +
>>   /*
>>    * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
>>    * video buffer memory for all buffers/planes on the queue and initializes the
>> @@ -431,9 +462,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>   		}
>>   
>>   		vb->state = VB2_BUF_STATE_DEQUEUED;
>> -		vb->vb2_queue = q;
>>   		vb->num_planes = num_planes;
>> -		vb->index = q->num_buffers + buffer;
>>   		vb->type = q->type;
>>   		vb->memory = memory;
>>   		init_buffer_cache_hints(q, vb);
>> @@ -443,7 +472,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>   		}
>>   		call_void_bufop(q, init_buffer, vb);
>>   
>> -		q->bufs[vb->index] = vb;
>> +		if (!vb2_queue_add_buffer(q, vb, q->num_buffers + buffer)) {
>> +			dprintk(q, 1, "failed adding buffer %d to queue\n", buffer);
>> +			kfree(vb);
>> +			break;
>> +		}
>>   
>>   		/* Allocate video buffer memory for the MMAP type */
>>   		if (memory == VB2_MEMORY_MMAP) {
>> @@ -451,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>   			if (ret) {
>>   				dprintk(q, 1, "failed allocating memory for buffer %d\n",
>>   					buffer);
>> -				q->bufs[vb->index] = NULL;
>> +				vb2_queue_remove_buffer(q, vb);
>>   				kfree(vb);
>>   				break;
>>   			}
>> @@ -466,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>   				dprintk(q, 1, "buffer %d %p initialization failed\n",
>>   					buffer, vb);
>>   				__vb2_buf_mem_free(vb);
>> -				q->bufs[vb->index] = NULL;
>> +				vb2_queue_remove_buffer(q, vb);
>>   				kfree(vb);
>>   				break;
>>   			}
>> @@ -489,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
>>   
>>   	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>   	     ++buffer) {
>> -		vb = q->bufs[buffer];
>> +		vb = vb2_get_buffer(q, buffer);
>>   		if (!vb)
>>   			continue;
>>   
>> @@ -517,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>   	/* Call driver-provided cleanup function for each buffer, if provided */
>>   	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>   	     ++buffer) {
>> -		struct vb2_buffer *vb = q->bufs[buffer];
>> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>   
>>   		if (vb && vb->planes[0].mem_priv)
>>   			call_void_vb_qop(vb, buf_cleanup, vb);
>> @@ -557,15 +590,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>   		q->cnt_unprepare_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;
>> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>> +		bool unbalanced;
>> +
>> +		if (!vb)
>> +			continue;
>> +
>> +		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) {
> I think we should drop the '|| debug' part. It is already annoying today to see these
> messages when the debug parameter is > 0, and now the number of buffers is still
> fairly small. But if we allow a lot more buffers, then this will really spam the
> kernel log.
>
> I think this should be dropped, and we only report unbalanced buffers.
>
> And another optimization is to only report the unbalanced counters. Right now
> it reports all counters, but it is again too much spamming of the kernel log.
>
> I think this change can be done as a separate patch before this patch.
> That way it can be picked up separately from the other changes in this series.
>
>>   			pr_info("   counters for queue %p, buffer %d:%s\n",
>> @@ -597,8 +635,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>   	/* Free vb2 buffers */
>>   	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>   	     ++buffer) {
>> -		kfree(q->bufs[buffer]);
>> -		q->bufs[buffer] = NULL;
>> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>> +
>> +		if (!vb)
>> +			continue;
>> +
>> +		vb2_queue_remove_buffer(q, vb);
>> +		kfree(vb);
>>   	}
>>   
>>   	q->num_buffers -= buffers;
>> @@ -634,7 +677,12 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>   {
>>   	unsigned int buffer;
>>   	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
>> -		if (vb2_buffer_in_use(q, q->bufs[buffer]))
>> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>> +
>> +		if (!vb)
>> +			continue;
>> +
>> +		if (vb2_buffer_in_use(q, vb))
>>   			return true;
>>   	}
>>   	return false;
>> @@ -642,7 +690,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>   
>>   void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>>   {
>> -	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
>> +	struct vb2_buffer *vb = vb2_get_buffer(q, index);
>> +
>> +	if (vb)
>> +		call_void_bufop(q, fill_user_buffer, vb, pb);
> I think that rather than passing the index (that then has to be verified)
> it is better to pass the vb2_buffer pointer directly and leave it up to
> the caller to do the index verification.
>
> Another option is to drop this function altogether and let the called
> call the fill_user_buffer function. Either works for me.
>
>>   }
>>   EXPORT_SYMBOL_GPL(vb2_core_querybuf);
>>   
>> @@ -1553,7 +1604,13 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
> Here too it is better to pass the vb2_buffer pointer instead of an index.
>
> This function assumes that the index is valid, so the called actually does the
> validation. Passing the vb pointer instead of the index makes more sense
> in this new situation.
>
> This is also true for two other core functions: vb2_core_qbuf and vb2_core_expbuf.
>
>>   	struct vb2_buffer *vb;
>>   	int ret;
>>   
>> -	vb = q->bufs[index];
>> +	vb = vb2_get_buffer(q, index);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		return -EINVAL;
>> +	}
> Changing that avoids having to add this check, so it simplifies the code.
>
> I think that this change can be done in a separate patch before this one.
>
> It makes sense to apply that regardless of the remainder of this series.
>
>> +
>>   	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
>>   		dprintk(q, 1, "invalid buffer state %s\n",
>>   			vb2_state_name(vb->state));
>> @@ -1624,7 +1681,11 @@ static int vb2_start_streaming(struct vb2_queue *q)
>>   		 * correctly return them to vb2.
>>   		 */
>>   		for (i = 0; i < q->num_buffers; ++i) {
>> -			vb = q->bufs[i];
>> +			vb = vb2_get_buffer(q, i);
>> +
>> +			if (!vb)
>> +				continue;
>> +
>>   			if (vb->state == VB2_BUF_STATE_ACTIVE)
>>   				vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
>>   		}
>> @@ -1652,7 +1713,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
>>   		return -EIO;
>>   	}
>>   
>> -	vb = q->bufs[index];
>> +	vb = vb2_get_buffer(q, index);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		return -EINVAL;
>> +	}
>>   
>>   	if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
>>   	    q->requires_requests) {
>> @@ -2028,12 +2094,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>   	 * to vb2 in stop_streaming().
>>   	 */
>>   	if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
>> -		for (i = 0; i < q->num_buffers; ++i)
>> -			if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
>> +		for (i = 0; i < q->num_buffers; ++i) {
>> +			struct vb2_buffer *vb = vb2_get_buffer(q, i);
>> +
>> +			if (!vb)
>> +				continue;
>> +
>> +			if (vb->state == VB2_BUF_STATE_ACTIVE) {
>>   				pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
>> -					q->bufs[i]);
>> -				vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
>> +					vb);
>> +				vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
>>   			}
>> +		}
>>   		/* Must be zero now */
>>   		WARN_ON(atomic_read(&q->owned_by_drv_count));
>>   	}
>> @@ -2067,9 +2139,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>   	 * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
>>   	 */
>>   	for (i = 0; i < q->num_buffers; ++i) {
>> -		struct vb2_buffer *vb = q->bufs[i];
>> -		struct media_request *req = vb->req_obj.req;
>> +		struct vb2_buffer *vb;
>> +		struct media_request *req;
>> +
>> +		vb = vb2_get_buffer(q, i);
>> +		if (!vb)
>> +			continue;
>>   
>> +		req = vb->req_obj.req;
>>   		/*
>>   		 * If a request is associated with this buffer, then
>>   		 * call buf_request_cancel() to give the driver to complete()
>> @@ -2219,7 +2296,10 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>>   	buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
>>   	plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>>   
>> -	vb = q->bufs[buffer];
>> +	vb = vb2_get_buffer(q, buffer);
>> +	if (!vb)
>> +		return -EINVAL;
>> +
>>   	if (vb->planes[plane].m.offset == off) {
>>   		*_buffer = buffer;
>>   		*_plane = plane;
>> @@ -2262,7 +2342,12 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
>>   		return -EINVAL;
>>   	}
>>   
>> -	vb = q->bufs[index];
>> +	vb = vb2_get_buffer(q, index);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		return -EINVAL;
>> +	}
>>   
>>   	if (plane >= vb->num_planes) {
>>   		dprintk(q, 1, "buffer plane out of range\n");
>> @@ -2339,7 +2424,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
>>   	if (ret)
>>   		goto unlock;
>>   
>> -	vb = q->bufs[buffer];
>> +	vb = vb2_get_buffer(q, buffer);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		ret = -EINVAL;
>> +		goto unlock;
>> +	}
>>   
>>   	/*
>>   	 * MMAP requires page_aligned buffers.
>> @@ -2396,7 +2487,12 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
>>   	if (ret)
>>   		goto unlock;
>>   
>> -	vb = q->bufs[buffer];
>> +	vb = vb2_get_buffer(q, buffer);
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		ret = -EINVAL;
>> +		goto unlock;
>> +	}
>>   
>>   	vaddr = vb2_plane_vaddr(vb, plane);
>>   	mutex_unlock(&q->mmap_lock);
>> @@ -2625,6 +2721,7 @@ struct vb2_fileio_data {
>>   static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>   {
>>   	struct vb2_fileio_data *fileio;
>> +	struct vb2_buffer *vb;
>>   	int i, ret;
>>   	unsigned int count = 0;
>>   
>> @@ -2679,7 +2776,13 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>   	 * Check if plane_count is correct
>>   	 * (multiplane buffers are not supported).
>>   	 */
>> -	if (q->bufs[0]->num_planes != 1) {
>> +	vb = vb2_get_buffer(q, 0);
>> +	if (!vb) {
>> +		ret = -EBUSY;
>> +		goto err_reqbufs;
>> +	}
> This cannot happen. These fileio helper functions implement the read() support
> and all the buffer allocation happens here. Userspace can never add or delete
> buffers later, so there will never be holes. It is safe to assume that
> vb2_get_buffer(q, i) will always return a valid vb pointer for i in the range
> of 0 - q->num_buffers-1.
>
> Perhaps add a comment to that effect, but otherwise you can drop the checks.
>
>> +
>> +	if (vb->num_planes != 1) {
>>   		ret = -EBUSY;
>>   		goto err_reqbufs;
>>   	}
>> @@ -2688,12 +2791,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>   	 * Get kernel address of each buffer.
>>   	 */
>>   	for (i = 0; i < q->num_buffers; i++) {
>> -		fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
>> +		vb = vb2_get_buffer(q, i);
>> +
>> +		if (!vb)
>> +			continue;
>> +
>> +		fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
>>   		if (fileio->bufs[i].vaddr == NULL) {
>>   			ret = -EINVAL;
>>   			goto err_reqbufs;
>>   		}
>> -		fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
>> +		fileio->bufs[i].size = vb2_plane_size(vb, 0);
>>   	}
>>   
>>   	/*
>> @@ -2821,15 +2929,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>   
>>   		fileio->cur_index = index;
>>   		buf = &fileio->bufs[index];
>> -		b = q->bufs[index];
>> +		b = vb2_get_buffer(q, index);
>> +
>> +		if (!b)
>> +			return -EINVAL;
>>   
>>   		/*
>>   		 * Get number of bytes filled by the driver
>>   		 */
>>   		buf->pos = 0;
>>   		buf->queued = 0;
>> -		buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
>> -				 : vb2_plane_size(q->bufs[index], 0);
>> +		buf->size = read ? vb2_get_plane_payload(b, 0)
>> +				 : vb2_plane_size(b, 0);
>>   		/* Compensate for data_offset on read in the multiplanar case. */
>>   		if (is_multiplanar && read &&
>>   				b->planes[0].data_offset < buf->size) {
>> @@ -2872,8 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>   	 * Queue next buffer if required.
>>   	 */
>>   	if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
>> -		struct vb2_buffer *b = q->bufs[index];
>> +		struct vb2_buffer *b = vb2_get_buffer(q, index);
>>   
>> +		if (!b) {
>> +			dprintk(q, 1, "can't find the requested buffer\n");
>> +			return -EINVAL;
>> +		}
>>   		/*
>>   		 * Check if this is the last buffer to read.
>>   		 */
>> @@ -2899,7 +3014,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>   		 */
>>   		buf->pos = 0;
>>   		buf->queued = 1;
>> -		buf->size = vb2_plane_size(q->bufs[index], 0);
>> +		buf->size = vb2_plane_size(b, 0);
>>   		fileio->q_count += 1;
>>   		/*
>>   		 * If we are queuing up buffers for the first time, then
>> @@ -2970,7 +3085,9 @@ static int vb2_thread(void *data)
>>   		 * Call vb2_dqbuf to get buffer back.
>>   		 */
>>   		if (prequeue) {
>> -			vb = q->bufs[index++];
>> +			vb = vb2_get_buffer(q, index++);
>> +			if (!vb)
>> +				continue;
>>   			prequeue--;
>>   		} else {
>>   			call_void_qop(q, wait_finish, q);
>> @@ -2979,7 +3096,7 @@ static int vb2_thread(void *data)
>>   			call_void_qop(q, wait_prepare, q);
>>   			dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
>>   			if (!ret)
>> -				vb = q->bufs[index];
>> +				vb = vb2_get_buffer(q, index);
>>   		}
>>   		if (ret || threadio->stop)
>>   			break;
>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> index c7a54d82a55e..724135d41f7f 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> @@ -383,8 +383,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>   		return -EINVAL;
>>   	}
>>   
>> -	if (q->bufs[b->index] == NULL) {
>> -		/* Should never happen */
>> +	if (!vb2_get_buffer(q, b->index)) {
>>   		dprintk(q, 1, "%s: buffer is NULL\n", opname);
> How about:
>
>    		dprintk(q, 1, "%s: buffer %u was deleted\n", opname, b->index);
>
> although perhaps that change is more appropriate in patch 09/10?
>
> Regardless, once it is possible to delete buffers, then this message should be
> adjusted accordingly.
>
>>   		return -EINVAL;
>>   	}
>> @@ -394,7 +393,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>   		return -EINVAL;
>>   	}
>>   
>> -	vb = q->bufs[b->index];
>> +	vb = vb2_get_buffer(q, b->index);
> This can be moved up to the 'if (!vb2_get_buffer(q, b->index)) {' check above.
> That avoids calling vb2_get_buffer twice.
>
>>   	vbuf = to_vb2_v4l2_buffer(vb);
>>   	ret = __verify_planes_array(vb, b);
>>   	if (ret)
>> @@ -628,11 +627,18 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
>>   struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
>>   {
>>   	unsigned int i;
>> +	struct vb2_buffer *vb2;
>>   
>> -	for (i = 0; i < q->num_buffers; i++)
>> -		if (q->bufs[i]->copied_timestamp &&
>> -		    q->bufs[i]->timestamp == timestamp)
>> -			return vb2_get_buffer(q, i);
> Perhaps add a comment here that this loop doesn't scale if there
> is a really large number of buffers and something more efficient
> will have to be found in that case.
>
>> +	for (i = 0; i < q->num_buffers; i++) {
>> +		vb2 = vb2_get_buffer(q, i);
>> +
>> +		if (!vb2)
>> +			continue;
>> +
>> +		if (vb2->copied_timestamp &&
>> +		    vb2->timestamp == timestamp)
>> +			return vb2;
>> +	}
>>   	return NULL;
>>   }
>>   EXPORT_SYMBOL_GPL(vb2_find_buffer);
>> @@ -664,7 +670,13 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
>>   		dprintk(q, 1, "buffer index out of range\n");
>>   		return -EINVAL;
>>   	}
>> -	vb = q->bufs[b->index];
>> +	vb = vb2_get_buffer(q, b->index);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		return -EINVAL;
>> +	}
>> +
>>   	ret = __verify_planes_array(vb, b);
>>   	if (!ret)
>>   		vb2_core_querybuf(q, b->index, b);
>> diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
>> index 982c2c777484..a462d6fe4ea9 100644
>> --- a/drivers/media/platform/amphion/vpu_dbg.c
>> +++ b/drivers/media/platform/amphion/vpu_dbg.c
>> @@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>   
>>   	vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
>>   	for (i = 0; i < vq->num_buffers; i++) {
>> -		struct vb2_buffer *vb = vq->bufs[i];
>> -		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> +		struct vb2_buffer *vb;
>> +		struct vb2_v4l2_buffer *vbuf;
>> +
>> +		vb = vb2_get_buffer(vq, i);
>> +		if (!vb)
>> +			continue;
>>   
>>   		if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>   			continue;
>> +
>> +		vbuf = to_vb2_v4l2_buffer(vb);
>> +
>>   		num = scnprintf(str, sizeof(str),
>>   				"output [%2d] state = %10s, %8s\n",
>>   				i, vb2_stat_name[vb->state],
>> @@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>   
>>   	vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
>>   	for (i = 0; i < vq->num_buffers; i++) {
>> -		struct vb2_buffer *vb = vq->bufs[i];
>> -		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> +		struct vb2_buffer *vb;
>> +		struct vb2_v4l2_buffer *vbuf;
>> +
>> +		vb = vb2_get_buffer(vq, i);
>> +		if (!vb)
>> +			continue;
>>   
>>   		if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>   			continue;
>> +
>> +		vbuf = to_vb2_v4l2_buffer(vb);
>> +
>>   		num = scnprintf(str, sizeof(str),
>>   				"capture[%2d] state = %10s, %8s\n",
>>   				i, vb2_stat_name[vb->state],
> This can be a separate patch, right? It doesn't depend on any core changes.
>
> And this can also be applied before this patch.

Hans, I would like to clarify this comment (and the following Ditto).
Are you against use vb2_get_buffer() outside core ?
or testing vb2_get_buffer() result ?
The goal of this patch was to remove all access like vq->bufs[i] and to make
sure that vb buffer are always valid.

Regards,
Benjamin

>
>> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> index 621038aab116..62910a1b8a98 100644
>> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> @@ -603,7 +603,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>   		return -EINVAL;
>>   	}
>>   
>> -	vb = vq->bufs[buf->index];
>> +	vb = vb2_get_buffer(vq, buf->index);
>> +	if (!vb) {
>> +		dev_err(ctx->jpeg->dev, "buffer not found\n");
>> +		return -EINVAL;
>> +	}
>>   	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
>>   	jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
>>   
> Ditto.
>
>> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>> index e393e3e668f8..3d2ae0e1b5b6 100644
>> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>> @@ -1696,7 +1696,7 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
>>   
>>   	/* update internal buffer's width/height */
>>   	for (i = 0; i < vq->num_buffers; i++) {
>> -		if (vb == vq->bufs[i]) {
>> +		if (vb == vb2_get_buffer(vq, i)) {
>>   			instance->dpb[i].width = w;
>>   			instance->dpb[i].height = h;
>>   			break;
> Ditto.
>
>> diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>> index 3a848ca32a0e..326be09bdb55 100644
>> --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
>> +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>> @@ -577,6 +577,10 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>   		}
>>   
>>   		vb2_buf = vb2_get_buffer(vq, buf->index);
>> +		if (!vb2_buf) {
>> +			dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
>> +			return -EINVAL;
>> +		}
>>   		stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
>>   		stream->bytesused = buf->bytesused;
>>   	}
> Ditto.
>
>> diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
>> index 318d675e5668..ba20ea998d19 100644
>> --- a/drivers/media/test-drivers/visl/visl-dec.c
>> +++ b/drivers/media/test-drivers/visl/visl-dec.c
>> @@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>   	for (i = 0; i < out_q->num_buffers; i++) {
>>   		char entry[] = "index: %u, state: %s, request_fd: %d, ";
>>   		u32 old_len = len;
>> -		char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
>> +		struct vb2_buffer *vb2;
>> +		char *q_status;
>> +
>> +		vb2 = vb2_get_buffer(out_q, i);
>> +		if (!vb2)
>> +			continue;
>> +
>> +		q_status = visl_get_vb2_state(vb2->state);
>>   
>>   		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>   				 entry, i, q_status,
>> -				 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
>> +				 to_vb2_v4l2_buffer(vb2)->request_fd);
>>   
>> -		len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
>> +		len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
>>   					   &buf[len],
>>   					   TPG_STR_BUF_SZ - len);
>>   
>> @@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>   	len = 0;
>>   	for (i = 0; i < cap_q->num_buffers; i++) {
>>   		u32 old_len = len;
>> -		char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
>> +		struct vb2_buffer *vb2;
>> +		char *q_status;
>> +
>> +		vb2 = vb2_get_buffer(cap_q, i);
>> +		if (!vb2)
>> +			continue;
>> +
>> +		q_status = visl_get_vb2_state(vb2->state);
>>   
>>   		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>   				 "index: %u, status: %s, timestamp: %llu, is_held: %d",
>> -				 cap_q->bufs[i]->index, q_status,
>> -				 cap_q->bufs[i]->timestamp,
>> -				 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
>> +				 vb2->index, q_status,
>> +				 vb2->timestamp,
>> +				 to_vb2_v4l2_buffer(vb2)->is_held);
>>   
>>   		tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
>>   		frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
> Ditto.
>
>> diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>> index d2174156573a..4b65c69fa60d 100644
>> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>> @@ -1061,7 +1061,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
>>   	if (ret)
>>   		return ret;
>>   
>> -	vb = pipe->vb_queue.bufs[buf->index];
>> +	vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
>>   	frame = vb_to_frame(vb);
>>   
>>   	buf->reserved = asd->frame_status[buf->index];
> Ditto.
>
> Background: I think it is really useful to merge a lot of the groundwork early
> on, where possible. It simplifies the remainder of the patch series.
>
> Regards,
>
> 	Hans
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions
  2023-08-30 16:24     ` Benjamin Gaignard
@ 2023-08-30 16:36       ` Hans Verkuil
  2023-08-31  7:54         ` Benjamin Gaignard
  0 siblings, 1 reply; 27+ messages in thread
From: Hans Verkuil @ 2023-08-30 16:36 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel

On 30/08/2023 18:24, Benjamin Gaignard wrote:
> 
> Le 30/08/2023 à 15:23, Hans Verkuil a écrit :
>> On 24/08/2023 11:21, Benjamin Gaignard wrote:
>>> The first step before changing how vb2 buffers are stored into queue
>>> is to avoid direct access to bufs arrays.
>>>
>>> This patch adds 2 helpers functions to add and remove vb2 buffers
>>> from a queue. With these 2 and vb2_get_buffer(), bufs field of
>>> struct vb2_queue becomes like a private member of the structure.
>>>
>>> After each call to vb2_get_buffer() we need to be sure that we get
>>> a valid pointer so check the return value of all of them.
>>>
>>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
>>>
>>> # Conflicts:
>>> #    drivers/media/common/videobuf2/videobuf2-core.c
>>> ---
>>>   .../media/common/videobuf2/videobuf2-core.c   | 203 ++++++++++++++----
>>>   .../media/common/videobuf2/videobuf2-v4l2.c   |  28 ++-
>>>   drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
>>>   .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
>>>   .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
>>>   drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
>>>   drivers/media/test-drivers/visl/visl-dec.c    |  28 ++-
>>>   .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
>>>   8 files changed, 230 insertions(+), 65 deletions(-)
>>>
>>> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
>>> index e06905533ef4..8aa13591b782 100644
>>> --- a/drivers/media/common/videobuf2/videobuf2-core.c
>>> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
>>> @@ -403,6 +403,37 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
>>>           vb->skip_cache_sync_on_finish = 1;
>>>   }
>>>   +/**
>>> + * vb2_queue_add_buffer() - add a buffer to a queue
>>> + * @q:    pointer to &struct vb2_queue with videobuf2 queue.
>>> + * @vb:    pointer to &struct vb2_buffer to be added to the queue.
>>> + * @index: index where add vb2_buffer in the queue
>>> + */
>>> +static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
>>> +{
>>> +    if (index < VB2_MAX_FRAME && !q->bufs[index]) {
>>> +        q->bufs[index] = vb;
>>> +        vb->index = index;
>>> +        vb->vb2_queue = q;
>>> +        return true;
>>> +    }
>>> +
>>> +    return false;
>>> +}
>>> +
>>> +/**
>>> + * vb2_queue_remove_buffer() - remove a buffer from a queue
>>> + * @q:    pointer to &struct vb2_queue with videobuf2 queue.
>>> + * @vb:    pointer to &struct vb2_buffer to be removed from the queue.
>>> + */
>>> +static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
>>> +{
>>> +    if (vb->index < VB2_MAX_FRAME) {
>>> +        q->bufs[vb->index] = NULL;
>>> +        vb->vb2_queue = NULL;
>>> +    }
>>> +}
>>> +
>>>   /*
>>>    * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
>>>    * video buffer memory for all buffers/planes on the queue and initializes the
>>> @@ -431,9 +462,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>           }
>>>             vb->state = VB2_BUF_STATE_DEQUEUED;
>>> -        vb->vb2_queue = q;
>>>           vb->num_planes = num_planes;
>>> -        vb->index = q->num_buffers + buffer;
>>>           vb->type = q->type;
>>>           vb->memory = memory;
>>>           init_buffer_cache_hints(q, vb);
>>> @@ -443,7 +472,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>           }
>>>           call_void_bufop(q, init_buffer, vb);
>>>   -        q->bufs[vb->index] = vb;
>>> +        if (!vb2_queue_add_buffer(q, vb, q->num_buffers + buffer)) {
>>> +            dprintk(q, 1, "failed adding buffer %d to queue\n", buffer);
>>> +            kfree(vb);
>>> +            break;
>>> +        }
>>>             /* Allocate video buffer memory for the MMAP type */
>>>           if (memory == VB2_MEMORY_MMAP) {
>>> @@ -451,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>               if (ret) {
>>>                   dprintk(q, 1, "failed allocating memory for buffer %d\n",
>>>                       buffer);
>>> -                q->bufs[vb->index] = NULL;
>>> +                vb2_queue_remove_buffer(q, vb);
>>>                   kfree(vb);
>>>                   break;
>>>               }
>>> @@ -466,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>                   dprintk(q, 1, "buffer %d %p initialization failed\n",
>>>                       buffer, vb);
>>>                   __vb2_buf_mem_free(vb);
>>> -                q->bufs[vb->index] = NULL;
>>> +                vb2_queue_remove_buffer(q, vb);
>>>                   kfree(vb);
>>>                   break;
>>>               }
>>> @@ -489,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
>>>         for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>            ++buffer) {
>>> -        vb = q->bufs[buffer];
>>> +        vb = vb2_get_buffer(q, buffer);
>>>           if (!vb)
>>>               continue;
>>>   @@ -517,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>       /* Call driver-provided cleanup function for each buffer, if provided */
>>>       for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>            ++buffer) {
>>> -        struct vb2_buffer *vb = q->bufs[buffer];
>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>             if (vb && vb->planes[0].mem_priv)
>>>               call_void_vb_qop(vb, buf_cleanup, vb);
>>> @@ -557,15 +590,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>           q->cnt_unprepare_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;
>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>> +        bool unbalanced;
>>> +
>>> +        if (!vb)
>>> +            continue;
>>> +
>>> +        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) {
>> I think we should drop the '|| debug' part. It is already annoying today to see these
>> messages when the debug parameter is > 0, and now the number of buffers is still
>> fairly small. But if we allow a lot more buffers, then this will really spam the
>> kernel log.
>>
>> I think this should be dropped, and we only report unbalanced buffers.
>>
>> And another optimization is to only report the unbalanced counters. Right now
>> it reports all counters, but it is again too much spamming of the kernel log.
>>
>> I think this change can be done as a separate patch before this patch.
>> That way it can be picked up separately from the other changes in this series.
>>
>>>               pr_info("   counters for queue %p, buffer %d:%s\n",
>>> @@ -597,8 +635,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>       /* Free vb2 buffers */
>>>       for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>            ++buffer) {
>>> -        kfree(q->bufs[buffer]);
>>> -        q->bufs[buffer] = NULL;
>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>> +
>>> +        if (!vb)
>>> +            continue;
>>> +
>>> +        vb2_queue_remove_buffer(q, vb);
>>> +        kfree(vb);
>>>       }
>>>         q->num_buffers -= buffers;
>>> @@ -634,7 +677,12 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>>   {
>>>       unsigned int buffer;
>>>       for (buffer = 0; buffer < q->num_buffers; ++buffer) {
>>> -        if (vb2_buffer_in_use(q, q->bufs[buffer]))
>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>> +
>>> +        if (!vb)
>>> +            continue;
>>> +
>>> +        if (vb2_buffer_in_use(q, vb))
>>>               return true;
>>>       }
>>>       return false;
>>> @@ -642,7 +690,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>>     void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>>>   {
>>> -    call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
>>> +    struct vb2_buffer *vb = vb2_get_buffer(q, index);
>>> +
>>> +    if (vb)
>>> +        call_void_bufop(q, fill_user_buffer, vb, pb);
>> I think that rather than passing the index (that then has to be verified)
>> it is better to pass the vb2_buffer pointer directly and leave it up to
>> the caller to do the index verification.
>>
>> Another option is to drop this function altogether and let the called
>> call the fill_user_buffer function. Either works for me.
>>
>>>   }
>>>   EXPORT_SYMBOL_GPL(vb2_core_querybuf);
>>>   @@ -1553,7 +1604,13 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
>> Here too it is better to pass the vb2_buffer pointer instead of an index.
>>
>> This function assumes that the index is valid, so the called actually does the
>> validation. Passing the vb pointer instead of the index makes more sense
>> in this new situation.
>>
>> This is also true for two other core functions: vb2_core_qbuf and vb2_core_expbuf.
>>
>>>       struct vb2_buffer *vb;
>>>       int ret;
>>>   -    vb = q->bufs[index];
>>> +    vb = vb2_get_buffer(q, index);
>>> +
>>> +    if (!vb) {
>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>> +        return -EINVAL;
>>> +    }
>> Changing that avoids having to add this check, so it simplifies the code.
>>
>> I think that this change can be done in a separate patch before this one.
>>
>> It makes sense to apply that regardless of the remainder of this series.
>>
>>> +
>>>       if (vb->state != VB2_BUF_STATE_DEQUEUED) {
>>>           dprintk(q, 1, "invalid buffer state %s\n",
>>>               vb2_state_name(vb->state));
>>> @@ -1624,7 +1681,11 @@ static int vb2_start_streaming(struct vb2_queue *q)
>>>            * correctly return them to vb2.
>>>            */
>>>           for (i = 0; i < q->num_buffers; ++i) {
>>> -            vb = q->bufs[i];
>>> +            vb = vb2_get_buffer(q, i);
>>> +
>>> +            if (!vb)
>>> +                continue;
>>> +
>>>               if (vb->state == VB2_BUF_STATE_ACTIVE)
>>>                   vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
>>>           }
>>> @@ -1652,7 +1713,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
>>>           return -EIO;
>>>       }
>>>   -    vb = q->bufs[index];
>>> +    vb = vb2_get_buffer(q, index);
>>> +
>>> +    if (!vb) {
>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>> +        return -EINVAL;
>>> +    }
>>>         if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
>>>           q->requires_requests) {
>>> @@ -2028,12 +2094,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>>        * to vb2 in stop_streaming().
>>>        */
>>>       if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
>>> -        for (i = 0; i < q->num_buffers; ++i)
>>> -            if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
>>> +        for (i = 0; i < q->num_buffers; ++i) {
>>> +            struct vb2_buffer *vb = vb2_get_buffer(q, i);
>>> +
>>> +            if (!vb)
>>> +                continue;
>>> +
>>> +            if (vb->state == VB2_BUF_STATE_ACTIVE) {
>>>                   pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
>>> -                    q->bufs[i]);
>>> -                vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
>>> +                    vb);
>>> +                vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
>>>               }
>>> +        }
>>>           /* Must be zero now */
>>>           WARN_ON(atomic_read(&q->owned_by_drv_count));
>>>       }
>>> @@ -2067,9 +2139,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>>        * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
>>>        */
>>>       for (i = 0; i < q->num_buffers; ++i) {
>>> -        struct vb2_buffer *vb = q->bufs[i];
>>> -        struct media_request *req = vb->req_obj.req;
>>> +        struct vb2_buffer *vb;
>>> +        struct media_request *req;
>>> +
>>> +        vb = vb2_get_buffer(q, i);
>>> +        if (!vb)
>>> +            continue;
>>>   +        req = vb->req_obj.req;
>>>           /*
>>>            * If a request is associated with this buffer, then
>>>            * call buf_request_cancel() to give the driver to complete()
>>> @@ -2219,7 +2296,10 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>>>       buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
>>>       plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>>>   -    vb = q->bufs[buffer];
>>> +    vb = vb2_get_buffer(q, buffer);
>>> +    if (!vb)
>>> +        return -EINVAL;
>>> +
>>>       if (vb->planes[plane].m.offset == off) {
>>>           *_buffer = buffer;
>>>           *_plane = plane;
>>> @@ -2262,7 +2342,12 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
>>>           return -EINVAL;
>>>       }
>>>   -    vb = q->bufs[index];
>>> +    vb = vb2_get_buffer(q, index);
>>> +
>>> +    if (!vb) {
>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>> +        return -EINVAL;
>>> +    }
>>>         if (plane >= vb->num_planes) {
>>>           dprintk(q, 1, "buffer plane out of range\n");
>>> @@ -2339,7 +2424,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
>>>       if (ret)
>>>           goto unlock;
>>>   -    vb = q->bufs[buffer];
>>> +    vb = vb2_get_buffer(q, buffer);
>>> +
>>> +    if (!vb) {
>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>> +        ret = -EINVAL;
>>> +        goto unlock;
>>> +    }
>>>         /*
>>>        * MMAP requires page_aligned buffers.
>>> @@ -2396,7 +2487,12 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
>>>       if (ret)
>>>           goto unlock;
>>>   -    vb = q->bufs[buffer];
>>> +    vb = vb2_get_buffer(q, buffer);
>>> +    if (!vb) {
>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>> +        ret = -EINVAL;
>>> +        goto unlock;
>>> +    }
>>>         vaddr = vb2_plane_vaddr(vb, plane);
>>>       mutex_unlock(&q->mmap_lock);
>>> @@ -2625,6 +2721,7 @@ struct vb2_fileio_data {
>>>   static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>   {
>>>       struct vb2_fileio_data *fileio;
>>> +    struct vb2_buffer *vb;
>>>       int i, ret;
>>>       unsigned int count = 0;
>>>   @@ -2679,7 +2776,13 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>        * Check if plane_count is correct
>>>        * (multiplane buffers are not supported).
>>>        */
>>> -    if (q->bufs[0]->num_planes != 1) {
>>> +    vb = vb2_get_buffer(q, 0);
>>> +    if (!vb) {
>>> +        ret = -EBUSY;
>>> +        goto err_reqbufs;
>>> +    }
>> This cannot happen. These fileio helper functions implement the read() support
>> and all the buffer allocation happens here. Userspace can never add or delete
>> buffers later, so there will never be holes. It is safe to assume that
>> vb2_get_buffer(q, i) will always return a valid vb pointer for i in the range
>> of 0 - q->num_buffers-1.
>>
>> Perhaps add a comment to that effect, but otherwise you can drop the checks.
>>
>>> +
>>> +    if (vb->num_planes != 1) {
>>>           ret = -EBUSY;
>>>           goto err_reqbufs;
>>>       }
>>> @@ -2688,12 +2791,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>        * Get kernel address of each buffer.
>>>        */
>>>       for (i = 0; i < q->num_buffers; i++) {
>>> -        fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
>>> +        vb = vb2_get_buffer(q, i);
>>> +
>>> +        if (!vb)
>>> +            continue;
>>> +
>>> +        fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
>>>           if (fileio->bufs[i].vaddr == NULL) {
>>>               ret = -EINVAL;
>>>               goto err_reqbufs;
>>>           }
>>> -        fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
>>> +        fileio->bufs[i].size = vb2_plane_size(vb, 0);
>>>       }
>>>         /*
>>> @@ -2821,15 +2929,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>             fileio->cur_index = index;
>>>           buf = &fileio->bufs[index];
>>> -        b = q->bufs[index];
>>> +        b = vb2_get_buffer(q, index);
>>> +
>>> +        if (!b)
>>> +            return -EINVAL;
>>>             /*
>>>            * Get number of bytes filled by the driver
>>>            */
>>>           buf->pos = 0;
>>>           buf->queued = 0;
>>> -        buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
>>> -                 : vb2_plane_size(q->bufs[index], 0);
>>> +        buf->size = read ? vb2_get_plane_payload(b, 0)
>>> +                 : vb2_plane_size(b, 0);
>>>           /* Compensate for data_offset on read in the multiplanar case. */
>>>           if (is_multiplanar && read &&
>>>                   b->planes[0].data_offset < buf->size) {
>>> @@ -2872,8 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>        * Queue next buffer if required.
>>>        */
>>>       if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
>>> -        struct vb2_buffer *b = q->bufs[index];
>>> +        struct vb2_buffer *b = vb2_get_buffer(q, index);
>>>   +        if (!b) {
>>> +            dprintk(q, 1, "can't find the requested buffer\n");
>>> +            return -EINVAL;
>>> +        }
>>>           /*
>>>            * Check if this is the last buffer to read.
>>>            */
>>> @@ -2899,7 +3014,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>            */
>>>           buf->pos = 0;
>>>           buf->queued = 1;
>>> -        buf->size = vb2_plane_size(q->bufs[index], 0);
>>> +        buf->size = vb2_plane_size(b, 0);
>>>           fileio->q_count += 1;
>>>           /*
>>>            * If we are queuing up buffers for the first time, then
>>> @@ -2970,7 +3085,9 @@ static int vb2_thread(void *data)
>>>            * Call vb2_dqbuf to get buffer back.
>>>            */
>>>           if (prequeue) {
>>> -            vb = q->bufs[index++];
>>> +            vb = vb2_get_buffer(q, index++);
>>> +            if (!vb)
>>> +                continue;
>>>               prequeue--;
>>>           } else {
>>>               call_void_qop(q, wait_finish, q);
>>> @@ -2979,7 +3096,7 @@ static int vb2_thread(void *data)
>>>               call_void_qop(q, wait_prepare, q);
>>>               dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
>>>               if (!ret)
>>> -                vb = q->bufs[index];
>>> +                vb = vb2_get_buffer(q, index);
>>>           }
>>>           if (ret || threadio->stop)
>>>               break;
>>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>> index c7a54d82a55e..724135d41f7f 100644
>>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>> @@ -383,8 +383,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>>           return -EINVAL;
>>>       }
>>>   -    if (q->bufs[b->index] == NULL) {
>>> -        /* Should never happen */
>>> +    if (!vb2_get_buffer(q, b->index)) {
>>>           dprintk(q, 1, "%s: buffer is NULL\n", opname);
>> How about:
>>
>>            dprintk(q, 1, "%s: buffer %u was deleted\n", opname, b->index);
>>
>> although perhaps that change is more appropriate in patch 09/10?
>>
>> Regardless, once it is possible to delete buffers, then this message should be
>> adjusted accordingly.
>>
>>>           return -EINVAL;
>>>       }
>>> @@ -394,7 +393,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>>           return -EINVAL;
>>>       }
>>>   -    vb = q->bufs[b->index];
>>> +    vb = vb2_get_buffer(q, b->index);
>> This can be moved up to the 'if (!vb2_get_buffer(q, b->index)) {' check above.
>> That avoids calling vb2_get_buffer twice.
>>
>>>       vbuf = to_vb2_v4l2_buffer(vb);
>>>       ret = __verify_planes_array(vb, b);
>>>       if (ret)
>>> @@ -628,11 +627,18 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
>>>   struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
>>>   {
>>>       unsigned int i;
>>> +    struct vb2_buffer *vb2;
>>>   -    for (i = 0; i < q->num_buffers; i++)
>>> -        if (q->bufs[i]->copied_timestamp &&
>>> -            q->bufs[i]->timestamp == timestamp)
>>> -            return vb2_get_buffer(q, i);
>> Perhaps add a comment here that this loop doesn't scale if there
>> is a really large number of buffers and something more efficient
>> will have to be found in that case.
>>
>>> +    for (i = 0; i < q->num_buffers; i++) {
>>> +        vb2 = vb2_get_buffer(q, i);
>>> +
>>> +        if (!vb2)
>>> +            continue;
>>> +
>>> +        if (vb2->copied_timestamp &&
>>> +            vb2->timestamp == timestamp)
>>> +            return vb2;
>>> +    }
>>>       return NULL;
>>>   }
>>>   EXPORT_SYMBOL_GPL(vb2_find_buffer);
>>> @@ -664,7 +670,13 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
>>>           dprintk(q, 1, "buffer index out of range\n");
>>>           return -EINVAL;
>>>       }
>>> -    vb = q->bufs[b->index];
>>> +    vb = vb2_get_buffer(q, b->index);
>>> +
>>> +    if (!vb) {
>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>> +        return -EINVAL;
>>> +    }
>>> +
>>>       ret = __verify_planes_array(vb, b);
>>>       if (!ret)
>>>           vb2_core_querybuf(q, b->index, b);
>>> diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
>>> index 982c2c777484..a462d6fe4ea9 100644
>>> --- a/drivers/media/platform/amphion/vpu_dbg.c
>>> +++ b/drivers/media/platform/amphion/vpu_dbg.c
>>> @@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>>         vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
>>>       for (i = 0; i < vq->num_buffers; i++) {
>>> -        struct vb2_buffer *vb = vq->bufs[i];
>>> -        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>> +        struct vb2_buffer *vb;
>>> +        struct vb2_v4l2_buffer *vbuf;
>>> +
>>> +        vb = vb2_get_buffer(vq, i);
>>> +        if (!vb)
>>> +            continue;
>>>             if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>>               continue;
>>> +
>>> +        vbuf = to_vb2_v4l2_buffer(vb);
>>> +
>>>           num = scnprintf(str, sizeof(str),
>>>                   "output [%2d] state = %10s, %8s\n",
>>>                   i, vb2_stat_name[vb->state],
>>> @@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>>         vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
>>>       for (i = 0; i < vq->num_buffers; i++) {
>>> -        struct vb2_buffer *vb = vq->bufs[i];
>>> -        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>> +        struct vb2_buffer *vb;
>>> +        struct vb2_v4l2_buffer *vbuf;
>>> +
>>> +        vb = vb2_get_buffer(vq, i);
>>> +        if (!vb)
>>> +            continue;
>>>             if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>>               continue;
>>> +
>>> +        vbuf = to_vb2_v4l2_buffer(vb);
>>> +
>>>           num = scnprintf(str, sizeof(str),
>>>                   "capture[%2d] state = %10s, %8s\n",
>>>                   i, vb2_stat_name[vb->state],
>> This can be a separate patch, right? It doesn't depend on any core changes.
>>
>> And this can also be applied before this patch.
> 
> Hans, I would like to clarify this comment (and the following Ditto).
> Are you against use vb2_get_buffer() outside core ?
> or testing vb2_get_buffer() result ?
> The goal of this patch was to remove all access like vq->bufs[i] and to make
> sure that vb buffer are always valid.

Sorry for the confusion. I meant that AFAICS each of these driver changes can be
done in the separate patch and that those separate patches can be applied before
this patch. I.e., they are independent.

I always prefer specific driver changes to be done as separate patches rather
than one patch modifying a lot of drivers in one go. That is not always possible,
of course, but in this case I think it is fine, unless I missed something.

Regards,

	Hans

> 
> Regards,
> Benjamin
> 
>>
>>> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>> index 621038aab116..62910a1b8a98 100644
>>> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>> @@ -603,7 +603,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>>           return -EINVAL;
>>>       }
>>>   -    vb = vq->bufs[buf->index];
>>> +    vb = vb2_get_buffer(vq, buf->index);
>>> +    if (!vb) {
>>> +        dev_err(ctx->jpeg->dev, "buffer not found\n");
>>> +        return -EINVAL;
>>> +    }
>>>       jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
>>>       jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
>>>   
>> Ditto.
>>
>>> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>> index e393e3e668f8..3d2ae0e1b5b6 100644
>>> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>> @@ -1696,7 +1696,7 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
>>>         /* update internal buffer's width/height */
>>>       for (i = 0; i < vq->num_buffers; i++) {
>>> -        if (vb == vq->bufs[i]) {
>>> +        if (vb == vb2_get_buffer(vq, i)) {
>>>               instance->dpb[i].width = w;
>>>               instance->dpb[i].height = h;
>>>               break;
>> Ditto.
>>
>>> diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>> index 3a848ca32a0e..326be09bdb55 100644
>>> --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>> +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>> @@ -577,6 +577,10 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>>           }
>>>             vb2_buf = vb2_get_buffer(vq, buf->index);
>>> +        if (!vb2_buf) {
>>> +            dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
>>> +            return -EINVAL;
>>> +        }
>>>           stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
>>>           stream->bytesused = buf->bytesused;
>>>       }
>> Ditto.
>>
>>> diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
>>> index 318d675e5668..ba20ea998d19 100644
>>> --- a/drivers/media/test-drivers/visl/visl-dec.c
>>> +++ b/drivers/media/test-drivers/visl/visl-dec.c
>>> @@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>>       for (i = 0; i < out_q->num_buffers; i++) {
>>>           char entry[] = "index: %u, state: %s, request_fd: %d, ";
>>>           u32 old_len = len;
>>> -        char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
>>> +        struct vb2_buffer *vb2;
>>> +        char *q_status;
>>> +
>>> +        vb2 = vb2_get_buffer(out_q, i);
>>> +        if (!vb2)
>>> +            continue;
>>> +
>>> +        q_status = visl_get_vb2_state(vb2->state);
>>>             len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>>                    entry, i, q_status,
>>> -                 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
>>> +                 to_vb2_v4l2_buffer(vb2)->request_fd);
>>>   -        len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
>>> +        len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
>>>                          &buf[len],
>>>                          TPG_STR_BUF_SZ - len);
>>>   @@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>>       len = 0;
>>>       for (i = 0; i < cap_q->num_buffers; i++) {
>>>           u32 old_len = len;
>>> -        char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
>>> +        struct vb2_buffer *vb2;
>>> +        char *q_status;
>>> +
>>> +        vb2 = vb2_get_buffer(cap_q, i);
>>> +        if (!vb2)
>>> +            continue;
>>> +
>>> +        q_status = visl_get_vb2_state(vb2->state);
>>>             len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>>                    "index: %u, status: %s, timestamp: %llu, is_held: %d",
>>> -                 cap_q->bufs[i]->index, q_status,
>>> -                 cap_q->bufs[i]->timestamp,
>>> -                 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
>>> +                 vb2->index, q_status,
>>> +                 vb2->timestamp,
>>> +                 to_vb2_v4l2_buffer(vb2)->is_held);
>>>             tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
>>>           frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
>> Ditto.
>>
>>> diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>> index d2174156573a..4b65c69fa60d 100644
>>> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>> @@ -1061,7 +1061,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
>>>       if (ret)
>>>           return ret;
>>>   -    vb = pipe->vb_queue.bufs[buf->index];
>>> +    vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
>>>       frame = vb_to_frame(vb);
>>>         buf->reserved = asd->frame_status[buf->index];
>> Ditto.
>>
>> Background: I think it is really useful to merge a lot of the groundwork early
>> on, where possible. It simplifies the remainder of the patch series.
>>
>> Regards,
>>
>>     Hans
>>


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions
  2023-08-30 16:36       ` Hans Verkuil
@ 2023-08-31  7:54         ` Benjamin Gaignard
  2023-08-31 10:22           ` Hans Verkuil
  0 siblings, 1 reply; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-31  7:54 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, tfiga, m.szyprowski, ming.qian, ezequiel,
	p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel


Le 30/08/2023 à 18:36, Hans Verkuil a écrit :
> On 30/08/2023 18:24, Benjamin Gaignard wrote:
>> Le 30/08/2023 à 15:23, Hans Verkuil a écrit :
>>> On 24/08/2023 11:21, Benjamin Gaignard wrote:
>>>> The first step before changing how vb2 buffers are stored into queue
>>>> is to avoid direct access to bufs arrays.
>>>>
>>>> This patch adds 2 helpers functions to add and remove vb2 buffers
>>>> from a queue. With these 2 and vb2_get_buffer(), bufs field of
>>>> struct vb2_queue becomes like a private member of the structure.
>>>>
>>>> After each call to vb2_get_buffer() we need to be sure that we get
>>>> a valid pointer so check the return value of all of them.
>>>>
>>>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
>>>>
>>>> # Conflicts:
>>>> #    drivers/media/common/videobuf2/videobuf2-core.c
>>>> ---
>>>>    .../media/common/videobuf2/videobuf2-core.c   | 203 ++++++++++++++----
>>>>    .../media/common/videobuf2/videobuf2-v4l2.c   |  28 ++-
>>>>    drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
>>>>    .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
>>>>    .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
>>>>    drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
>>>>    drivers/media/test-drivers/visl/visl-dec.c    |  28 ++-
>>>>    .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
>>>>    8 files changed, 230 insertions(+), 65 deletions(-)
>>>>
>>>> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
>>>> index e06905533ef4..8aa13591b782 100644
>>>> --- a/drivers/media/common/videobuf2/videobuf2-core.c
>>>> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
>>>> @@ -403,6 +403,37 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
>>>>            vb->skip_cache_sync_on_finish = 1;
>>>>    }
>>>>    +/**
>>>> + * vb2_queue_add_buffer() - add a buffer to a queue
>>>> + * @q:    pointer to &struct vb2_queue with videobuf2 queue.
>>>> + * @vb:    pointer to &struct vb2_buffer to be added to the queue.
>>>> + * @index: index where add vb2_buffer in the queue
>>>> + */
>>>> +static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
>>>> +{
>>>> +    if (index < VB2_MAX_FRAME && !q->bufs[index]) {
>>>> +        q->bufs[index] = vb;
>>>> +        vb->index = index;
>>>> +        vb->vb2_queue = q;
>>>> +        return true;
>>>> +    }
>>>> +
>>>> +    return false;
>>>> +}
>>>> +
>>>> +/**
>>>> + * vb2_queue_remove_buffer() - remove a buffer from a queue
>>>> + * @q:    pointer to &struct vb2_queue with videobuf2 queue.
>>>> + * @vb:    pointer to &struct vb2_buffer to be removed from the queue.
>>>> + */
>>>> +static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
>>>> +{
>>>> +    if (vb->index < VB2_MAX_FRAME) {
>>>> +        q->bufs[vb->index] = NULL;
>>>> +        vb->vb2_queue = NULL;
>>>> +    }
>>>> +}
>>>> +
>>>>    /*
>>>>     * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
>>>>     * video buffer memory for all buffers/planes on the queue and initializes the
>>>> @@ -431,9 +462,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>            }
>>>>              vb->state = VB2_BUF_STATE_DEQUEUED;
>>>> -        vb->vb2_queue = q;
>>>>            vb->num_planes = num_planes;
>>>> -        vb->index = q->num_buffers + buffer;
>>>>            vb->type = q->type;
>>>>            vb->memory = memory;
>>>>            init_buffer_cache_hints(q, vb);
>>>> @@ -443,7 +472,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>            }
>>>>            call_void_bufop(q, init_buffer, vb);
>>>>    -        q->bufs[vb->index] = vb;
>>>> +        if (!vb2_queue_add_buffer(q, vb, q->num_buffers + buffer)) {
>>>> +            dprintk(q, 1, "failed adding buffer %d to queue\n", buffer);
>>>> +            kfree(vb);
>>>> +            break;
>>>> +        }
>>>>              /* Allocate video buffer memory for the MMAP type */
>>>>            if (memory == VB2_MEMORY_MMAP) {
>>>> @@ -451,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>                if (ret) {
>>>>                    dprintk(q, 1, "failed allocating memory for buffer %d\n",
>>>>                        buffer);
>>>> -                q->bufs[vb->index] = NULL;
>>>> +                vb2_queue_remove_buffer(q, vb);
>>>>                    kfree(vb);
>>>>                    break;
>>>>                }
>>>> @@ -466,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>                    dprintk(q, 1, "buffer %d %p initialization failed\n",
>>>>                        buffer, vb);
>>>>                    __vb2_buf_mem_free(vb);
>>>> -                q->bufs[vb->index] = NULL;
>>>> +                vb2_queue_remove_buffer(q, vb);
>>>>                    kfree(vb);
>>>>                    break;
>>>>                }
>>>> @@ -489,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
>>>>          for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>             ++buffer) {
>>>> -        vb = q->bufs[buffer];
>>>> +        vb = vb2_get_buffer(q, buffer);
>>>>            if (!vb)
>>>>                continue;
>>>>    @@ -517,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>        /* Call driver-provided cleanup function for each buffer, if provided */
>>>>        for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>             ++buffer) {
>>>> -        struct vb2_buffer *vb = q->bufs[buffer];
>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>              if (vb && vb->planes[0].mem_priv)
>>>>                call_void_vb_qop(vb, buf_cleanup, vb);
>>>> @@ -557,15 +590,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>            q->cnt_unprepare_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;
>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>> +        bool unbalanced;
>>>> +
>>>> +        if (!vb)
>>>> +            continue;
>>>> +
>>>> +        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) {
>>> I think we should drop the '|| debug' part. It is already annoying today to see these
>>> messages when the debug parameter is > 0, and now the number of buffers is still
>>> fairly small. But if we allow a lot more buffers, then this will really spam the
>>> kernel log.
>>>
>>> I think this should be dropped, and we only report unbalanced buffers.
>>>
>>> And another optimization is to only report the unbalanced counters. Right now
>>> it reports all counters, but it is again too much spamming of the kernel log.
>>>
>>> I think this change can be done as a separate patch before this patch.
>>> That way it can be picked up separately from the other changes in this series.
>>>
>>>>                pr_info("   counters for queue %p, buffer %d:%s\n",
>>>> @@ -597,8 +635,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>        /* Free vb2 buffers */
>>>>        for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>             ++buffer) {
>>>> -        kfree(q->bufs[buffer]);
>>>> -        q->bufs[buffer] = NULL;
>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>> +
>>>> +        if (!vb)
>>>> +            continue;
>>>> +
>>>> +        vb2_queue_remove_buffer(q, vb);
>>>> +        kfree(vb);
>>>>        }
>>>>          q->num_buffers -= buffers;
>>>> @@ -634,7 +677,12 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>>>    {
>>>>        unsigned int buffer;
>>>>        for (buffer = 0; buffer < q->num_buffers; ++buffer) {
>>>> -        if (vb2_buffer_in_use(q, q->bufs[buffer]))
>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>> +
>>>> +        if (!vb)
>>>> +            continue;
>>>> +
>>>> +        if (vb2_buffer_in_use(q, vb))
>>>>                return true;
>>>>        }
>>>>        return false;
>>>> @@ -642,7 +690,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>>>      void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>>>>    {
>>>> -    call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
>>>> +    struct vb2_buffer *vb = vb2_get_buffer(q, index);
>>>> +
>>>> +    if (vb)
>>>> +        call_void_bufop(q, fill_user_buffer, vb, pb);
>>> I think that rather than passing the index (that then has to be verified)
>>> it is better to pass the vb2_buffer pointer directly and leave it up to
>>> the caller to do the index verification.
>>>
>>> Another option is to drop this function altogether and let the called
>>> call the fill_user_buffer function. Either works for me.
>>>
>>>>    }
>>>>    EXPORT_SYMBOL_GPL(vb2_core_querybuf);
>>>>    @@ -1553,7 +1604,13 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
>>> Here too it is better to pass the vb2_buffer pointer instead of an index.
>>>
>>> This function assumes that the index is valid, so the called actually does the
>>> validation. Passing the vb pointer instead of the index makes more sense
>>> in this new situation.
>>>
>>> This is also true for two other core functions: vb2_core_qbuf and vb2_core_expbuf.
>>>
>>>>        struct vb2_buffer *vb;
>>>>        int ret;
>>>>    -    vb = q->bufs[index];
>>>> +    vb = vb2_get_buffer(q, index);
>>>> +
>>>> +    if (!vb) {
>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>> +        return -EINVAL;
>>>> +    }
>>> Changing that avoids having to add this check, so it simplifies the code.
>>>
>>> I think that this change can be done in a separate patch before this one.
>>>
>>> It makes sense to apply that regardless of the remainder of this series.
>>>
>>>> +
>>>>        if (vb->state != VB2_BUF_STATE_DEQUEUED) {
>>>>            dprintk(q, 1, "invalid buffer state %s\n",
>>>>                vb2_state_name(vb->state));
>>>> @@ -1624,7 +1681,11 @@ static int vb2_start_streaming(struct vb2_queue *q)
>>>>             * correctly return them to vb2.
>>>>             */
>>>>            for (i = 0; i < q->num_buffers; ++i) {
>>>> -            vb = q->bufs[i];
>>>> +            vb = vb2_get_buffer(q, i);
>>>> +
>>>> +            if (!vb)
>>>> +                continue;
>>>> +
>>>>                if (vb->state == VB2_BUF_STATE_ACTIVE)
>>>>                    vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
>>>>            }
>>>> @@ -1652,7 +1713,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
>>>>            return -EIO;
>>>>        }
>>>>    -    vb = q->bufs[index];
>>>> +    vb = vb2_get_buffer(q, index);
>>>> +
>>>> +    if (!vb) {
>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>> +        return -EINVAL;
>>>> +    }
>>>>          if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
>>>>            q->requires_requests) {
>>>> @@ -2028,12 +2094,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>>>         * to vb2 in stop_streaming().
>>>>         */
>>>>        if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
>>>> -        for (i = 0; i < q->num_buffers; ++i)
>>>> -            if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
>>>> +        for (i = 0; i < q->num_buffers; ++i) {
>>>> +            struct vb2_buffer *vb = vb2_get_buffer(q, i);
>>>> +
>>>> +            if (!vb)
>>>> +                continue;
>>>> +
>>>> +            if (vb->state == VB2_BUF_STATE_ACTIVE) {
>>>>                    pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
>>>> -                    q->bufs[i]);
>>>> -                vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
>>>> +                    vb);
>>>> +                vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
>>>>                }
>>>> +        }
>>>>            /* Must be zero now */
>>>>            WARN_ON(atomic_read(&q->owned_by_drv_count));
>>>>        }
>>>> @@ -2067,9 +2139,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>>>         * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
>>>>         */
>>>>        for (i = 0; i < q->num_buffers; ++i) {
>>>> -        struct vb2_buffer *vb = q->bufs[i];
>>>> -        struct media_request *req = vb->req_obj.req;
>>>> +        struct vb2_buffer *vb;
>>>> +        struct media_request *req;
>>>> +
>>>> +        vb = vb2_get_buffer(q, i);
>>>> +        if (!vb)
>>>> +            continue;
>>>>    +        req = vb->req_obj.req;
>>>>            /*
>>>>             * If a request is associated with this buffer, then
>>>>             * call buf_request_cancel() to give the driver to complete()
>>>> @@ -2219,7 +2296,10 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>>>>        buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
>>>>        plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>>>>    -    vb = q->bufs[buffer];
>>>> +    vb = vb2_get_buffer(q, buffer);
>>>> +    if (!vb)
>>>> +        return -EINVAL;
>>>> +
>>>>        if (vb->planes[plane].m.offset == off) {
>>>>            *_buffer = buffer;
>>>>            *_plane = plane;
>>>> @@ -2262,7 +2342,12 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
>>>>            return -EINVAL;
>>>>        }
>>>>    -    vb = q->bufs[index];
>>>> +    vb = vb2_get_buffer(q, index);
>>>> +
>>>> +    if (!vb) {
>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>> +        return -EINVAL;
>>>> +    }
>>>>          if (plane >= vb->num_planes) {
>>>>            dprintk(q, 1, "buffer plane out of range\n");
>>>> @@ -2339,7 +2424,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
>>>>        if (ret)
>>>>            goto unlock;
>>>>    -    vb = q->bufs[buffer];
>>>> +    vb = vb2_get_buffer(q, buffer);
>>>> +
>>>> +    if (!vb) {
>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>> +        ret = -EINVAL;
>>>> +        goto unlock;
>>>> +    }
>>>>          /*
>>>>         * MMAP requires page_aligned buffers.
>>>> @@ -2396,7 +2487,12 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
>>>>        if (ret)
>>>>            goto unlock;
>>>>    -    vb = q->bufs[buffer];
>>>> +    vb = vb2_get_buffer(q, buffer);
>>>> +    if (!vb) {
>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>> +        ret = -EINVAL;
>>>> +        goto unlock;
>>>> +    }
>>>>          vaddr = vb2_plane_vaddr(vb, plane);
>>>>        mutex_unlock(&q->mmap_lock);
>>>> @@ -2625,6 +2721,7 @@ struct vb2_fileio_data {
>>>>    static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>    {
>>>>        struct vb2_fileio_data *fileio;
>>>> +    struct vb2_buffer *vb;
>>>>        int i, ret;
>>>>        unsigned int count = 0;
>>>>    @@ -2679,7 +2776,13 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>         * Check if plane_count is correct
>>>>         * (multiplane buffers are not supported).
>>>>         */
>>>> -    if (q->bufs[0]->num_planes != 1) {
>>>> +    vb = vb2_get_buffer(q, 0);
>>>> +    if (!vb) {
>>>> +        ret = -EBUSY;
>>>> +        goto err_reqbufs;
>>>> +    }
>>> This cannot happen. These fileio helper functions implement the read() support
>>> and all the buffer allocation happens here. Userspace can never add or delete
>>> buffers later, so there will never be holes. It is safe to assume that
>>> vb2_get_buffer(q, i) will always return a valid vb pointer for i in the range
>>> of 0 - q->num_buffers-1.
>>>
>>> Perhaps add a comment to that effect, but otherwise you can drop the checks.
>>>
>>>> +
>>>> +    if (vb->num_planes != 1) {
>>>>            ret = -EBUSY;
>>>>            goto err_reqbufs;
>>>>        }
>>>> @@ -2688,12 +2791,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>         * Get kernel address of each buffer.
>>>>         */
>>>>        for (i = 0; i < q->num_buffers; i++) {
>>>> -        fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
>>>> +        vb = vb2_get_buffer(q, i);
>>>> +
>>>> +        if (!vb)
>>>> +            continue;
>>>> +
>>>> +        fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
>>>>            if (fileio->bufs[i].vaddr == NULL) {
>>>>                ret = -EINVAL;
>>>>                goto err_reqbufs;
>>>>            }
>>>> -        fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
>>>> +        fileio->bufs[i].size = vb2_plane_size(vb, 0);
>>>>        }
>>>>          /*
>>>> @@ -2821,15 +2929,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>              fileio->cur_index = index;
>>>>            buf = &fileio->bufs[index];
>>>> -        b = q->bufs[index];
>>>> +        b = vb2_get_buffer(q, index);
>>>> +
>>>> +        if (!b)
>>>> +            return -EINVAL;
>>>>              /*
>>>>             * Get number of bytes filled by the driver
>>>>             */
>>>>            buf->pos = 0;
>>>>            buf->queued = 0;
>>>> -        buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
>>>> -                 : vb2_plane_size(q->bufs[index], 0);
>>>> +        buf->size = read ? vb2_get_plane_payload(b, 0)
>>>> +                 : vb2_plane_size(b, 0);
>>>>            /* Compensate for data_offset on read in the multiplanar case. */
>>>>            if (is_multiplanar && read &&
>>>>                    b->planes[0].data_offset < buf->size) {
>>>> @@ -2872,8 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>         * Queue next buffer if required.
>>>>         */
>>>>        if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
>>>> -        struct vb2_buffer *b = q->bufs[index];
>>>> +        struct vb2_buffer *b = vb2_get_buffer(q, index);
>>>>    +        if (!b) {
>>>> +            dprintk(q, 1, "can't find the requested buffer\n");
>>>> +            return -EINVAL;
>>>> +        }
>>>>            /*
>>>>             * Check if this is the last buffer to read.
>>>>             */
>>>> @@ -2899,7 +3014,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>             */
>>>>            buf->pos = 0;
>>>>            buf->queued = 1;
>>>> -        buf->size = vb2_plane_size(q->bufs[index], 0);
>>>> +        buf->size = vb2_plane_size(b, 0);
>>>>            fileio->q_count += 1;
>>>>            /*
>>>>             * If we are queuing up buffers for the first time, then
>>>> @@ -2970,7 +3085,9 @@ static int vb2_thread(void *data)
>>>>             * Call vb2_dqbuf to get buffer back.
>>>>             */
>>>>            if (prequeue) {
>>>> -            vb = q->bufs[index++];
>>>> +            vb = vb2_get_buffer(q, index++);
>>>> +            if (!vb)
>>>> +                continue;
>>>>                prequeue--;
>>>>            } else {
>>>>                call_void_qop(q, wait_finish, q);
>>>> @@ -2979,7 +3096,7 @@ static int vb2_thread(void *data)
>>>>                call_void_qop(q, wait_prepare, q);
>>>>                dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
>>>>                if (!ret)
>>>> -                vb = q->bufs[index];
>>>> +                vb = vb2_get_buffer(q, index);
>>>>            }
>>>>            if (ret || threadio->stop)
>>>>                break;
>>>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>> index c7a54d82a55e..724135d41f7f 100644
>>>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>> @@ -383,8 +383,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>>>            return -EINVAL;
>>>>        }
>>>>    -    if (q->bufs[b->index] == NULL) {
>>>> -        /* Should never happen */
>>>> +    if (!vb2_get_buffer(q, b->index)) {
>>>>            dprintk(q, 1, "%s: buffer is NULL\n", opname);
>>> How about:
>>>
>>>             dprintk(q, 1, "%s: buffer %u was deleted\n", opname, b->index);
>>>
>>> although perhaps that change is more appropriate in patch 09/10?
>>>
>>> Regardless, once it is possible to delete buffers, then this message should be
>>> adjusted accordingly.
>>>
>>>>            return -EINVAL;
>>>>        }
>>>> @@ -394,7 +393,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>>>            return -EINVAL;
>>>>        }
>>>>    -    vb = q->bufs[b->index];
>>>> +    vb = vb2_get_buffer(q, b->index);
>>> This can be moved up to the 'if (!vb2_get_buffer(q, b->index)) {' check above.
>>> That avoids calling vb2_get_buffer twice.
>>>
>>>>        vbuf = to_vb2_v4l2_buffer(vb);
>>>>        ret = __verify_planes_array(vb, b);
>>>>        if (ret)
>>>> @@ -628,11 +627,18 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
>>>>    struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
>>>>    {
>>>>        unsigned int i;
>>>> +    struct vb2_buffer *vb2;
>>>>    -    for (i = 0; i < q->num_buffers; i++)
>>>> -        if (q->bufs[i]->copied_timestamp &&
>>>> -            q->bufs[i]->timestamp == timestamp)
>>>> -            return vb2_get_buffer(q, i);
>>> Perhaps add a comment here that this loop doesn't scale if there
>>> is a really large number of buffers and something more efficient
>>> will have to be found in that case.
>>>
>>>> +    for (i = 0; i < q->num_buffers; i++) {
>>>> +        vb2 = vb2_get_buffer(q, i);
>>>> +
>>>> +        if (!vb2)
>>>> +            continue;
>>>> +
>>>> +        if (vb2->copied_timestamp &&
>>>> +            vb2->timestamp == timestamp)
>>>> +            return vb2;
>>>> +    }
>>>>        return NULL;
>>>>    }
>>>>    EXPORT_SYMBOL_GPL(vb2_find_buffer);
>>>> @@ -664,7 +670,13 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
>>>>            dprintk(q, 1, "buffer index out of range\n");
>>>>            return -EINVAL;
>>>>        }
>>>> -    vb = q->bufs[b->index];
>>>> +    vb = vb2_get_buffer(q, b->index);
>>>> +
>>>> +    if (!vb) {
>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>>        ret = __verify_planes_array(vb, b);
>>>>        if (!ret)
>>>>            vb2_core_querybuf(q, b->index, b);
>>>> diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
>>>> index 982c2c777484..a462d6fe4ea9 100644
>>>> --- a/drivers/media/platform/amphion/vpu_dbg.c
>>>> +++ b/drivers/media/platform/amphion/vpu_dbg.c
>>>> @@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>>>          vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
>>>>        for (i = 0; i < vq->num_buffers; i++) {
>>>> -        struct vb2_buffer *vb = vq->bufs[i];
>>>> -        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>>> +        struct vb2_buffer *vb;
>>>> +        struct vb2_v4l2_buffer *vbuf;
>>>> +
>>>> +        vb = vb2_get_buffer(vq, i);
>>>> +        if (!vb)
>>>> +            continue;
>>>>              if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>>>                continue;
>>>> +
>>>> +        vbuf = to_vb2_v4l2_buffer(vb);
>>>> +
>>>>            num = scnprintf(str, sizeof(str),
>>>>                    "output [%2d] state = %10s, %8s\n",
>>>>                    i, vb2_stat_name[vb->state],
>>>> @@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>>>          vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
>>>>        for (i = 0; i < vq->num_buffers; i++) {
>>>> -        struct vb2_buffer *vb = vq->bufs[i];
>>>> -        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>>> +        struct vb2_buffer *vb;
>>>> +        struct vb2_v4l2_buffer *vbuf;
>>>> +
>>>> +        vb = vb2_get_buffer(vq, i);
>>>> +        if (!vb)
>>>> +            continue;
>>>>              if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>>>                continue;
>>>> +
>>>> +        vbuf = to_vb2_v4l2_buffer(vb);
>>>> +
>>>>            num = scnprintf(str, sizeof(str),
>>>>                    "capture[%2d] state = %10s, %8s\n",
>>>>                    i, vb2_stat_name[vb->state],
>>> This can be a separate patch, right? It doesn't depend on any core changes.
>>>
>>> And this can also be applied before this patch.
>> Hans, I would like to clarify this comment (and the following Ditto).
>> Are you against use vb2_get_buffer() outside core ?
>> or testing vb2_get_buffer() result ?
>> The goal of this patch was to remove all access like vq->bufs[i] and to make
>> sure that vb buffer are always valid.
> Sorry for the confusion. I meant that AFAICS each of these driver changes can be
> done in the separate patch and that those separate patches can be applied before
> this patch. I.e., they are independent.
>
> I always prefer specific driver changes to be done as separate patches rather
> than one patch modifying a lot of drivers in one go. That is not always possible,
> of course, but in this case I think it is fine, unless I missed something.

All changes in the drivers use vb2_get_buffer() which is introduced in this patch
so I can't do them before.
If you want I can make a patch per driver but after this patch.

Regards,
Benjamin

>
> Regards,
>
> 	Hans
>
>> Regards,
>> Benjamin
>>
>>>> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>> index 621038aab116..62910a1b8a98 100644
>>>> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>> @@ -603,7 +603,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>>>            return -EINVAL;
>>>>        }
>>>>    -    vb = vq->bufs[buf->index];
>>>> +    vb = vb2_get_buffer(vq, buf->index);
>>>> +    if (!vb) {
>>>> +        dev_err(ctx->jpeg->dev, "buffer not found\n");
>>>> +        return -EINVAL;
>>>> +    }
>>>>        jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
>>>>        jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
>>>>    
>>> Ditto.
>>>
>>>> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>> index e393e3e668f8..3d2ae0e1b5b6 100644
>>>> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>> @@ -1696,7 +1696,7 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
>>>>          /* update internal buffer's width/height */
>>>>        for (i = 0; i < vq->num_buffers; i++) {
>>>> -        if (vb == vq->bufs[i]) {
>>>> +        if (vb == vb2_get_buffer(vq, i)) {
>>>>                instance->dpb[i].width = w;
>>>>                instance->dpb[i].height = h;
>>>>                break;
>>> Ditto.
>>>
>>>> diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>> index 3a848ca32a0e..326be09bdb55 100644
>>>> --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>> +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>> @@ -577,6 +577,10 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>>>            }
>>>>              vb2_buf = vb2_get_buffer(vq, buf->index);
>>>> +        if (!vb2_buf) {
>>>> +            dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
>>>> +            return -EINVAL;
>>>> +        }
>>>>            stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
>>>>            stream->bytesused = buf->bytesused;
>>>>        }
>>> Ditto.
>>>
>>>> diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
>>>> index 318d675e5668..ba20ea998d19 100644
>>>> --- a/drivers/media/test-drivers/visl/visl-dec.c
>>>> +++ b/drivers/media/test-drivers/visl/visl-dec.c
>>>> @@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>>>        for (i = 0; i < out_q->num_buffers; i++) {
>>>>            char entry[] = "index: %u, state: %s, request_fd: %d, ";
>>>>            u32 old_len = len;
>>>> -        char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
>>>> +        struct vb2_buffer *vb2;
>>>> +        char *q_status;
>>>> +
>>>> +        vb2 = vb2_get_buffer(out_q, i);
>>>> +        if (!vb2)
>>>> +            continue;
>>>> +
>>>> +        q_status = visl_get_vb2_state(vb2->state);
>>>>              len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>>>                     entry, i, q_status,
>>>> -                 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
>>>> +                 to_vb2_v4l2_buffer(vb2)->request_fd);
>>>>    -        len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
>>>> +        len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
>>>>                           &buf[len],
>>>>                           TPG_STR_BUF_SZ - len);
>>>>    @@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>>>        len = 0;
>>>>        for (i = 0; i < cap_q->num_buffers; i++) {
>>>>            u32 old_len = len;
>>>> -        char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
>>>> +        struct vb2_buffer *vb2;
>>>> +        char *q_status;
>>>> +
>>>> +        vb2 = vb2_get_buffer(cap_q, i);
>>>> +        if (!vb2)
>>>> +            continue;
>>>> +
>>>> +        q_status = visl_get_vb2_state(vb2->state);
>>>>              len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>>>                     "index: %u, status: %s, timestamp: %llu, is_held: %d",
>>>> -                 cap_q->bufs[i]->index, q_status,
>>>> -                 cap_q->bufs[i]->timestamp,
>>>> -                 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
>>>> +                 vb2->index, q_status,
>>>> +                 vb2->timestamp,
>>>> +                 to_vb2_v4l2_buffer(vb2)->is_held);
>>>>              tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
>>>>            frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
>>> Ditto.
>>>
>>>> diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>> index d2174156573a..4b65c69fa60d 100644
>>>> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>> @@ -1061,7 +1061,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
>>>>        if (ret)
>>>>            return ret;
>>>>    -    vb = pipe->vb_queue.bufs[buf->index];
>>>> +    vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
>>>>        frame = vb_to_frame(vb);
>>>>          buf->reserved = asd->frame_status[buf->index];
>>> Ditto.
>>>
>>> Background: I think it is really useful to merge a lot of the groundwork early
>>> on, where possible. It simplifies the remainder of the patch series.
>>>
>>> Regards,
>>>
>>>      Hans
>>>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions
  2023-08-31  7:54         ` Benjamin Gaignard
@ 2023-08-31 10:22           ` Hans Verkuil
  2023-08-31 12:06             ` Benjamin Gaignard
  0 siblings, 1 reply; 27+ messages in thread
From: Hans Verkuil @ 2023-08-31 10:22 UTC (permalink / raw)
  To: Benjamin Gaignard, mchehab, tfiga, m.szyprowski, ming.qian,
	ezequiel, p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel

On 31/08/2023 09:54, Benjamin Gaignard wrote:
> 
> Le 30/08/2023 à 18:36, Hans Verkuil a écrit :
>> On 30/08/2023 18:24, Benjamin Gaignard wrote:
>>> Le 30/08/2023 à 15:23, Hans Verkuil a écrit :
>>>> On 24/08/2023 11:21, Benjamin Gaignard wrote:
>>>>> The first step before changing how vb2 buffers are stored into queue
>>>>> is to avoid direct access to bufs arrays.
>>>>>
>>>>> This patch adds 2 helpers functions to add and remove vb2 buffers
>>>>> from a queue. With these 2 and vb2_get_buffer(), bufs field of
>>>>> struct vb2_queue becomes like a private member of the structure.
>>>>>
>>>>> After each call to vb2_get_buffer() we need to be sure that we get
>>>>> a valid pointer so check the return value of all of them.
>>>>>
>>>>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
>>>>>
>>>>> # Conflicts:
>>>>> #    drivers/media/common/videobuf2/videobuf2-core.c
>>>>> ---
>>>>>    .../media/common/videobuf2/videobuf2-core.c   | 203 ++++++++++++++----
>>>>>    .../media/common/videobuf2/videobuf2-v4l2.c   |  28 ++-
>>>>>    drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
>>>>>    .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
>>>>>    .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
>>>>>    drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
>>>>>    drivers/media/test-drivers/visl/visl-dec.c    |  28 ++-
>>>>>    .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
>>>>>    8 files changed, 230 insertions(+), 65 deletions(-)
>>>>>
>>>>> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
>>>>> index e06905533ef4..8aa13591b782 100644
>>>>> --- a/drivers/media/common/videobuf2/videobuf2-core.c
>>>>> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
>>>>> @@ -403,6 +403,37 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
>>>>>            vb->skip_cache_sync_on_finish = 1;
>>>>>    }
>>>>>    +/**
>>>>> + * vb2_queue_add_buffer() - add a buffer to a queue
>>>>> + * @q:    pointer to &struct vb2_queue with videobuf2 queue.
>>>>> + * @vb:    pointer to &struct vb2_buffer to be added to the queue.
>>>>> + * @index: index where add vb2_buffer in the queue
>>>>> + */
>>>>> +static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
>>>>> +{
>>>>> +    if (index < VB2_MAX_FRAME && !q->bufs[index]) {
>>>>> +        q->bufs[index] = vb;
>>>>> +        vb->index = index;
>>>>> +        vb->vb2_queue = q;
>>>>> +        return true;
>>>>> +    }
>>>>> +
>>>>> +    return false;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * vb2_queue_remove_buffer() - remove a buffer from a queue
>>>>> + * @q:    pointer to &struct vb2_queue with videobuf2 queue.
>>>>> + * @vb:    pointer to &struct vb2_buffer to be removed from the queue.
>>>>> + */
>>>>> +static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
>>>>> +{
>>>>> +    if (vb->index < VB2_MAX_FRAME) {
>>>>> +        q->bufs[vb->index] = NULL;
>>>>> +        vb->vb2_queue = NULL;
>>>>> +    }
>>>>> +}
>>>>> +
>>>>>    /*
>>>>>     * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
>>>>>     * video buffer memory for all buffers/planes on the queue and initializes the
>>>>> @@ -431,9 +462,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>>            }
>>>>>              vb->state = VB2_BUF_STATE_DEQUEUED;
>>>>> -        vb->vb2_queue = q;
>>>>>            vb->num_planes = num_planes;
>>>>> -        vb->index = q->num_buffers + buffer;
>>>>>            vb->type = q->type;
>>>>>            vb->memory = memory;
>>>>>            init_buffer_cache_hints(q, vb);
>>>>> @@ -443,7 +472,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>>            }
>>>>>            call_void_bufop(q, init_buffer, vb);
>>>>>    -        q->bufs[vb->index] = vb;
>>>>> +        if (!vb2_queue_add_buffer(q, vb, q->num_buffers + buffer)) {
>>>>> +            dprintk(q, 1, "failed adding buffer %d to queue\n", buffer);
>>>>> +            kfree(vb);
>>>>> +            break;
>>>>> +        }
>>>>>              /* Allocate video buffer memory for the MMAP type */
>>>>>            if (memory == VB2_MEMORY_MMAP) {
>>>>> @@ -451,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>>                if (ret) {
>>>>>                    dprintk(q, 1, "failed allocating memory for buffer %d\n",
>>>>>                        buffer);
>>>>> -                q->bufs[vb->index] = NULL;
>>>>> +                vb2_queue_remove_buffer(q, vb);
>>>>>                    kfree(vb);
>>>>>                    break;
>>>>>                }
>>>>> @@ -466,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>>                    dprintk(q, 1, "buffer %d %p initialization failed\n",
>>>>>                        buffer, vb);
>>>>>                    __vb2_buf_mem_free(vb);
>>>>> -                q->bufs[vb->index] = NULL;
>>>>> +                vb2_queue_remove_buffer(q, vb);
>>>>>                    kfree(vb);
>>>>>                    break;
>>>>>                }
>>>>> @@ -489,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
>>>>>          for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>>             ++buffer) {
>>>>> -        vb = q->bufs[buffer];
>>>>> +        vb = vb2_get_buffer(q, buffer);
>>>>>            if (!vb)
>>>>>                continue;
>>>>>    @@ -517,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>>        /* Call driver-provided cleanup function for each buffer, if provided */
>>>>>        for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>>             ++buffer) {
>>>>> -        struct vb2_buffer *vb = q->bufs[buffer];
>>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>>              if (vb && vb->planes[0].mem_priv)
>>>>>                call_void_vb_qop(vb, buf_cleanup, vb);
>>>>> @@ -557,15 +590,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>>            q->cnt_unprepare_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;
>>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>> +        bool unbalanced;
>>>>> +
>>>>> +        if (!vb)
>>>>> +            continue;
>>>>> +
>>>>> +        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) {
>>>> I think we should drop the '|| debug' part. It is already annoying today to see these
>>>> messages when the debug parameter is > 0, and now the number of buffers is still
>>>> fairly small. But if we allow a lot more buffers, then this will really spam the
>>>> kernel log.
>>>>
>>>> I think this should be dropped, and we only report unbalanced buffers.
>>>>
>>>> And another optimization is to only report the unbalanced counters. Right now
>>>> it reports all counters, but it is again too much spamming of the kernel log.
>>>>
>>>> I think this change can be done as a separate patch before this patch.
>>>> That way it can be picked up separately from the other changes in this series.
>>>>
>>>>>                pr_info("   counters for queue %p, buffer %d:%s\n",
>>>>> @@ -597,8 +635,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>>        /* Free vb2 buffers */
>>>>>        for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>>             ++buffer) {
>>>>> -        kfree(q->bufs[buffer]);
>>>>> -        q->bufs[buffer] = NULL;
>>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>> +
>>>>> +        if (!vb)
>>>>> +            continue;
>>>>> +
>>>>> +        vb2_queue_remove_buffer(q, vb);
>>>>> +        kfree(vb);
>>>>>        }
>>>>>          q->num_buffers -= buffers;
>>>>> @@ -634,7 +677,12 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>>>>    {
>>>>>        unsigned int buffer;
>>>>>        for (buffer = 0; buffer < q->num_buffers; ++buffer) {
>>>>> -        if (vb2_buffer_in_use(q, q->bufs[buffer]))
>>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>> +
>>>>> +        if (!vb)
>>>>> +            continue;
>>>>> +
>>>>> +        if (vb2_buffer_in_use(q, vb))
>>>>>                return true;
>>>>>        }
>>>>>        return false;
>>>>> @@ -642,7 +690,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>>>>      void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>>>>>    {
>>>>> -    call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
>>>>> +    struct vb2_buffer *vb = vb2_get_buffer(q, index);
>>>>> +
>>>>> +    if (vb)
>>>>> +        call_void_bufop(q, fill_user_buffer, vb, pb);
>>>> I think that rather than passing the index (that then has to be verified)
>>>> it is better to pass the vb2_buffer pointer directly and leave it up to
>>>> the caller to do the index verification.
>>>>
>>>> Another option is to drop this function altogether and let the called
>>>> call the fill_user_buffer function. Either works for me.
>>>>
>>>>>    }
>>>>>    EXPORT_SYMBOL_GPL(vb2_core_querybuf);
>>>>>    @@ -1553,7 +1604,13 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
>>>> Here too it is better to pass the vb2_buffer pointer instead of an index.
>>>>
>>>> This function assumes that the index is valid, so the called actually does the
>>>> validation. Passing the vb pointer instead of the index makes more sense
>>>> in this new situation.
>>>>
>>>> This is also true for two other core functions: vb2_core_qbuf and vb2_core_expbuf.
>>>>
>>>>>        struct vb2_buffer *vb;
>>>>>        int ret;
>>>>>    -    vb = q->bufs[index];
>>>>> +    vb = vb2_get_buffer(q, index);
>>>>> +
>>>>> +    if (!vb) {
>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>> +        return -EINVAL;
>>>>> +    }
>>>> Changing that avoids having to add this check, so it simplifies the code.
>>>>
>>>> I think that this change can be done in a separate patch before this one.
>>>>
>>>> It makes sense to apply that regardless of the remainder of this series.
>>>>
>>>>> +
>>>>>        if (vb->state != VB2_BUF_STATE_DEQUEUED) {
>>>>>            dprintk(q, 1, "invalid buffer state %s\n",
>>>>>                vb2_state_name(vb->state));
>>>>> @@ -1624,7 +1681,11 @@ static int vb2_start_streaming(struct vb2_queue *q)
>>>>>             * correctly return them to vb2.
>>>>>             */
>>>>>            for (i = 0; i < q->num_buffers; ++i) {
>>>>> -            vb = q->bufs[i];
>>>>> +            vb = vb2_get_buffer(q, i);
>>>>> +
>>>>> +            if (!vb)
>>>>> +                continue;
>>>>> +
>>>>>                if (vb->state == VB2_BUF_STATE_ACTIVE)
>>>>>                    vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
>>>>>            }
>>>>> @@ -1652,7 +1713,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
>>>>>            return -EIO;
>>>>>        }
>>>>>    -    vb = q->bufs[index];
>>>>> +    vb = vb2_get_buffer(q, index);
>>>>> +
>>>>> +    if (!vb) {
>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>>          if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
>>>>>            q->requires_requests) {
>>>>> @@ -2028,12 +2094,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>>>>         * to vb2 in stop_streaming().
>>>>>         */
>>>>>        if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
>>>>> -        for (i = 0; i < q->num_buffers; ++i)
>>>>> -            if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
>>>>> +        for (i = 0; i < q->num_buffers; ++i) {
>>>>> +            struct vb2_buffer *vb = vb2_get_buffer(q, i);
>>>>> +
>>>>> +            if (!vb)
>>>>> +                continue;
>>>>> +
>>>>> +            if (vb->state == VB2_BUF_STATE_ACTIVE) {
>>>>>                    pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
>>>>> -                    q->bufs[i]);
>>>>> -                vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
>>>>> +                    vb);
>>>>> +                vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
>>>>>                }
>>>>> +        }
>>>>>            /* Must be zero now */
>>>>>            WARN_ON(atomic_read(&q->owned_by_drv_count));
>>>>>        }
>>>>> @@ -2067,9 +2139,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>>>>         * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
>>>>>         */
>>>>>        for (i = 0; i < q->num_buffers; ++i) {
>>>>> -        struct vb2_buffer *vb = q->bufs[i];
>>>>> -        struct media_request *req = vb->req_obj.req;
>>>>> +        struct vb2_buffer *vb;
>>>>> +        struct media_request *req;
>>>>> +
>>>>> +        vb = vb2_get_buffer(q, i);
>>>>> +        if (!vb)
>>>>> +            continue;
>>>>>    +        req = vb->req_obj.req;
>>>>>            /*
>>>>>             * If a request is associated with this buffer, then
>>>>>             * call buf_request_cancel() to give the driver to complete()
>>>>> @@ -2219,7 +2296,10 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>>>>>        buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
>>>>>        plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>>>>>    -    vb = q->bufs[buffer];
>>>>> +    vb = vb2_get_buffer(q, buffer);
>>>>> +    if (!vb)
>>>>> +        return -EINVAL;
>>>>> +
>>>>>        if (vb->planes[plane].m.offset == off) {
>>>>>            *_buffer = buffer;
>>>>>            *_plane = plane;
>>>>> @@ -2262,7 +2342,12 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
>>>>>            return -EINVAL;
>>>>>        }
>>>>>    -    vb = q->bufs[index];
>>>>> +    vb = vb2_get_buffer(q, index);
>>>>> +
>>>>> +    if (!vb) {
>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>>          if (plane >= vb->num_planes) {
>>>>>            dprintk(q, 1, "buffer plane out of range\n");
>>>>> @@ -2339,7 +2424,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
>>>>>        if (ret)
>>>>>            goto unlock;
>>>>>    -    vb = q->bufs[buffer];
>>>>> +    vb = vb2_get_buffer(q, buffer);
>>>>> +
>>>>> +    if (!vb) {
>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>> +        ret = -EINVAL;
>>>>> +        goto unlock;
>>>>> +    }
>>>>>          /*
>>>>>         * MMAP requires page_aligned buffers.
>>>>> @@ -2396,7 +2487,12 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
>>>>>        if (ret)
>>>>>            goto unlock;
>>>>>    -    vb = q->bufs[buffer];
>>>>> +    vb = vb2_get_buffer(q, buffer);
>>>>> +    if (!vb) {
>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>> +        ret = -EINVAL;
>>>>> +        goto unlock;
>>>>> +    }
>>>>>          vaddr = vb2_plane_vaddr(vb, plane);
>>>>>        mutex_unlock(&q->mmap_lock);
>>>>> @@ -2625,6 +2721,7 @@ struct vb2_fileio_data {
>>>>>    static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>>    {
>>>>>        struct vb2_fileio_data *fileio;
>>>>> +    struct vb2_buffer *vb;
>>>>>        int i, ret;
>>>>>        unsigned int count = 0;
>>>>>    @@ -2679,7 +2776,13 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>>         * Check if plane_count is correct
>>>>>         * (multiplane buffers are not supported).
>>>>>         */
>>>>> -    if (q->bufs[0]->num_planes != 1) {
>>>>> +    vb = vb2_get_buffer(q, 0);
>>>>> +    if (!vb) {
>>>>> +        ret = -EBUSY;
>>>>> +        goto err_reqbufs;
>>>>> +    }
>>>> This cannot happen. These fileio helper functions implement the read() support
>>>> and all the buffer allocation happens here. Userspace can never add or delete
>>>> buffers later, so there will never be holes. It is safe to assume that
>>>> vb2_get_buffer(q, i) will always return a valid vb pointer for i in the range
>>>> of 0 - q->num_buffers-1.
>>>>
>>>> Perhaps add a comment to that effect, but otherwise you can drop the checks.
>>>>
>>>>> +
>>>>> +    if (vb->num_planes != 1) {
>>>>>            ret = -EBUSY;
>>>>>            goto err_reqbufs;
>>>>>        }
>>>>> @@ -2688,12 +2791,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>>         * Get kernel address of each buffer.
>>>>>         */
>>>>>        for (i = 0; i < q->num_buffers; i++) {
>>>>> -        fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
>>>>> +        vb = vb2_get_buffer(q, i);
>>>>> +
>>>>> +        if (!vb)
>>>>> +            continue;
>>>>> +
>>>>> +        fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
>>>>>            if (fileio->bufs[i].vaddr == NULL) {
>>>>>                ret = -EINVAL;
>>>>>                goto err_reqbufs;
>>>>>            }
>>>>> -        fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
>>>>> +        fileio->bufs[i].size = vb2_plane_size(vb, 0);
>>>>>        }
>>>>>          /*
>>>>> @@ -2821,15 +2929,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>>              fileio->cur_index = index;
>>>>>            buf = &fileio->bufs[index];
>>>>> -        b = q->bufs[index];
>>>>> +        b = vb2_get_buffer(q, index);
>>>>> +
>>>>> +        if (!b)
>>>>> +            return -EINVAL;
>>>>>              /*
>>>>>             * Get number of bytes filled by the driver
>>>>>             */
>>>>>            buf->pos = 0;
>>>>>            buf->queued = 0;
>>>>> -        buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
>>>>> -                 : vb2_plane_size(q->bufs[index], 0);
>>>>> +        buf->size = read ? vb2_get_plane_payload(b, 0)
>>>>> +                 : vb2_plane_size(b, 0);
>>>>>            /* Compensate for data_offset on read in the multiplanar case. */
>>>>>            if (is_multiplanar && read &&
>>>>>                    b->planes[0].data_offset < buf->size) {
>>>>> @@ -2872,8 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>>         * Queue next buffer if required.
>>>>>         */
>>>>>        if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
>>>>> -        struct vb2_buffer *b = q->bufs[index];
>>>>> +        struct vb2_buffer *b = vb2_get_buffer(q, index);
>>>>>    +        if (!b) {
>>>>> +            dprintk(q, 1, "can't find the requested buffer\n");
>>>>> +            return -EINVAL;
>>>>> +        }
>>>>>            /*
>>>>>             * Check if this is the last buffer to read.
>>>>>             */
>>>>> @@ -2899,7 +3014,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>>             */
>>>>>            buf->pos = 0;
>>>>>            buf->queued = 1;
>>>>> -        buf->size = vb2_plane_size(q->bufs[index], 0);
>>>>> +        buf->size = vb2_plane_size(b, 0);
>>>>>            fileio->q_count += 1;
>>>>>            /*
>>>>>             * If we are queuing up buffers for the first time, then
>>>>> @@ -2970,7 +3085,9 @@ static int vb2_thread(void *data)
>>>>>             * Call vb2_dqbuf to get buffer back.
>>>>>             */
>>>>>            if (prequeue) {
>>>>> -            vb = q->bufs[index++];
>>>>> +            vb = vb2_get_buffer(q, index++);
>>>>> +            if (!vb)
>>>>> +                continue;
>>>>>                prequeue--;
>>>>>            } else {
>>>>>                call_void_qop(q, wait_finish, q);
>>>>> @@ -2979,7 +3096,7 @@ static int vb2_thread(void *data)
>>>>>                call_void_qop(q, wait_prepare, q);
>>>>>                dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
>>>>>                if (!ret)
>>>>> -                vb = q->bufs[index];
>>>>> +                vb = vb2_get_buffer(q, index);
>>>>>            }
>>>>>            if (ret || threadio->stop)
>>>>>                break;
>>>>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>>> index c7a54d82a55e..724135d41f7f 100644
>>>>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>>> @@ -383,8 +383,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>>>>            return -EINVAL;
>>>>>        }
>>>>>    -    if (q->bufs[b->index] == NULL) {
>>>>> -        /* Should never happen */
>>>>> +    if (!vb2_get_buffer(q, b->index)) {
>>>>>            dprintk(q, 1, "%s: buffer is NULL\n", opname);
>>>> How about:
>>>>
>>>>             dprintk(q, 1, "%s: buffer %u was deleted\n", opname, b->index);
>>>>
>>>> although perhaps that change is more appropriate in patch 09/10?
>>>>
>>>> Regardless, once it is possible to delete buffers, then this message should be
>>>> adjusted accordingly.
>>>>
>>>>>            return -EINVAL;
>>>>>        }
>>>>> @@ -394,7 +393,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>>>>            return -EINVAL;
>>>>>        }
>>>>>    -    vb = q->bufs[b->index];
>>>>> +    vb = vb2_get_buffer(q, b->index);
>>>> This can be moved up to the 'if (!vb2_get_buffer(q, b->index)) {' check above.
>>>> That avoids calling vb2_get_buffer twice.
>>>>
>>>>>        vbuf = to_vb2_v4l2_buffer(vb);
>>>>>        ret = __verify_planes_array(vb, b);
>>>>>        if (ret)
>>>>> @@ -628,11 +627,18 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
>>>>>    struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
>>>>>    {
>>>>>        unsigned int i;
>>>>> +    struct vb2_buffer *vb2;
>>>>>    -    for (i = 0; i < q->num_buffers; i++)
>>>>> -        if (q->bufs[i]->copied_timestamp &&
>>>>> -            q->bufs[i]->timestamp == timestamp)
>>>>> -            return vb2_get_buffer(q, i);
>>>> Perhaps add a comment here that this loop doesn't scale if there
>>>> is a really large number of buffers and something more efficient
>>>> will have to be found in that case.
>>>>
>>>>> +    for (i = 0; i < q->num_buffers; i++) {
>>>>> +        vb2 = vb2_get_buffer(q, i);
>>>>> +
>>>>> +        if (!vb2)
>>>>> +            continue;
>>>>> +
>>>>> +        if (vb2->copied_timestamp &&
>>>>> +            vb2->timestamp == timestamp)
>>>>> +            return vb2;
>>>>> +    }
>>>>>        return NULL;
>>>>>    }
>>>>>    EXPORT_SYMBOL_GPL(vb2_find_buffer);
>>>>> @@ -664,7 +670,13 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
>>>>>            dprintk(q, 1, "buffer index out of range\n");
>>>>>            return -EINVAL;
>>>>>        }
>>>>> -    vb = q->bufs[b->index];
>>>>> +    vb = vb2_get_buffer(q, b->index);
>>>>> +
>>>>> +    if (!vb) {
>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>> +
>>>>>        ret = __verify_planes_array(vb, b);
>>>>>        if (!ret)
>>>>>            vb2_core_querybuf(q, b->index, b);
>>>>> diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
>>>>> index 982c2c777484..a462d6fe4ea9 100644
>>>>> --- a/drivers/media/platform/amphion/vpu_dbg.c
>>>>> +++ b/drivers/media/platform/amphion/vpu_dbg.c
>>>>> @@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>>>>          vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
>>>>>        for (i = 0; i < vq->num_buffers; i++) {
>>>>> -        struct vb2_buffer *vb = vq->bufs[i];
>>>>> -        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>>>> +        struct vb2_buffer *vb;
>>>>> +        struct vb2_v4l2_buffer *vbuf;
>>>>> +
>>>>> +        vb = vb2_get_buffer(vq, i);
>>>>> +        if (!vb)
>>>>> +            continue;
>>>>>              if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>>>>                continue;
>>>>> +
>>>>> +        vbuf = to_vb2_v4l2_buffer(vb);
>>>>> +
>>>>>            num = scnprintf(str, sizeof(str),
>>>>>                    "output [%2d] state = %10s, %8s\n",
>>>>>                    i, vb2_stat_name[vb->state],
>>>>> @@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>>>>          vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
>>>>>        for (i = 0; i < vq->num_buffers; i++) {
>>>>> -        struct vb2_buffer *vb = vq->bufs[i];
>>>>> -        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>>>> +        struct vb2_buffer *vb;
>>>>> +        struct vb2_v4l2_buffer *vbuf;
>>>>> +
>>>>> +        vb = vb2_get_buffer(vq, i);
>>>>> +        if (!vb)
>>>>> +            continue;
>>>>>              if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>>>>                continue;
>>>>> +
>>>>> +        vbuf = to_vb2_v4l2_buffer(vb);
>>>>> +
>>>>>            num = scnprintf(str, sizeof(str),
>>>>>                    "capture[%2d] state = %10s, %8s\n",
>>>>>                    i, vb2_stat_name[vb->state],
>>>> This can be a separate patch, right? It doesn't depend on any core changes.
>>>>
>>>> And this can also be applied before this patch.
>>> Hans, I would like to clarify this comment (and the following Ditto).
>>> Are you against use vb2_get_buffer() outside core ?
>>> or testing vb2_get_buffer() result ?
>>> The goal of this patch was to remove all access like vq->bufs[i] and to make
>>> sure that vb buffer are always valid.
>> Sorry for the confusion. I meant that AFAICS each of these driver changes can be
>> done in the separate patch and that those separate patches can be applied before
>> this patch. I.e., they are independent.
>>
>> I always prefer specific driver changes to be done as separate patches rather
>> than one patch modifying a lot of drivers in one go. That is not always possible,
>> of course, but in this case I think it is fine, unless I missed something.
> 
> All changes in the drivers use vb2_get_buffer() which is introduced in this patch
> so I can't do them before.
> If you want I can make a patch per driver but after this patch.

??? vb2_get_buffer() has been defined in include/media/videobuf2-core.h for a long
time (2019 to be precise).

Regards,

	Hans

> 
> Regards,
> Benjamin
> 
>>
>> Regards,
>>
>>     Hans
>>
>>> Regards,
>>> Benjamin
>>>
>>>>> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>>> index 621038aab116..62910a1b8a98 100644
>>>>> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>>> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>>> @@ -603,7 +603,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>>>>            return -EINVAL;
>>>>>        }
>>>>>    -    vb = vq->bufs[buf->index];
>>>>> +    vb = vb2_get_buffer(vq, buf->index);
>>>>> +    if (!vb) {
>>>>> +        dev_err(ctx->jpeg->dev, "buffer not found\n");
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>>        jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
>>>>>        jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
>>>>>    
>>>> Ditto.
>>>>
>>>>> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>>> index e393e3e668f8..3d2ae0e1b5b6 100644
>>>>> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>>> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>>> @@ -1696,7 +1696,7 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
>>>>>          /* update internal buffer's width/height */
>>>>>        for (i = 0; i < vq->num_buffers; i++) {
>>>>> -        if (vb == vq->bufs[i]) {
>>>>> +        if (vb == vb2_get_buffer(vq, i)) {
>>>>>                instance->dpb[i].width = w;
>>>>>                instance->dpb[i].height = h;
>>>>>                break;
>>>> Ditto.
>>>>
>>>>> diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>>> index 3a848ca32a0e..326be09bdb55 100644
>>>>> --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>>> +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>>> @@ -577,6 +577,10 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>>>>            }
>>>>>              vb2_buf = vb2_get_buffer(vq, buf->index);
>>>>> +        if (!vb2_buf) {
>>>>> +            dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
>>>>> +            return -EINVAL;
>>>>> +        }
>>>>>            stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
>>>>>            stream->bytesused = buf->bytesused;
>>>>>        }
>>>> Ditto.
>>>>
>>>>> diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
>>>>> index 318d675e5668..ba20ea998d19 100644
>>>>> --- a/drivers/media/test-drivers/visl/visl-dec.c
>>>>> +++ b/drivers/media/test-drivers/visl/visl-dec.c
>>>>> @@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>>>>        for (i = 0; i < out_q->num_buffers; i++) {
>>>>>            char entry[] = "index: %u, state: %s, request_fd: %d, ";
>>>>>            u32 old_len = len;
>>>>> -        char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
>>>>> +        struct vb2_buffer *vb2;
>>>>> +        char *q_status;
>>>>> +
>>>>> +        vb2 = vb2_get_buffer(out_q, i);
>>>>> +        if (!vb2)
>>>>> +            continue;
>>>>> +
>>>>> +        q_status = visl_get_vb2_state(vb2->state);
>>>>>              len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>>>>                     entry, i, q_status,
>>>>> -                 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
>>>>> +                 to_vb2_v4l2_buffer(vb2)->request_fd);
>>>>>    -        len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
>>>>> +        len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
>>>>>                           &buf[len],
>>>>>                           TPG_STR_BUF_SZ - len);
>>>>>    @@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>>>>        len = 0;
>>>>>        for (i = 0; i < cap_q->num_buffers; i++) {
>>>>>            u32 old_len = len;
>>>>> -        char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
>>>>> +        struct vb2_buffer *vb2;
>>>>> +        char *q_status;
>>>>> +
>>>>> +        vb2 = vb2_get_buffer(cap_q, i);
>>>>> +        if (!vb2)
>>>>> +            continue;
>>>>> +
>>>>> +        q_status = visl_get_vb2_state(vb2->state);
>>>>>              len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>>>>                     "index: %u, status: %s, timestamp: %llu, is_held: %d",
>>>>> -                 cap_q->bufs[i]->index, q_status,
>>>>> -                 cap_q->bufs[i]->timestamp,
>>>>> -                 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
>>>>> +                 vb2->index, q_status,
>>>>> +                 vb2->timestamp,
>>>>> +                 to_vb2_v4l2_buffer(vb2)->is_held);
>>>>>              tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
>>>>>            frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
>>>> Ditto.
>>>>
>>>>> diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>>> index d2174156573a..4b65c69fa60d 100644
>>>>> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>>> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>>> @@ -1061,7 +1061,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
>>>>>        if (ret)
>>>>>            return ret;
>>>>>    -    vb = pipe->vb_queue.bufs[buf->index];
>>>>> +    vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
>>>>>        frame = vb_to_frame(vb);
>>>>>          buf->reserved = asd->frame_status[buf->index];
>>>> Ditto.
>>>>
>>>> Background: I think it is really useful to merge a lot of the groundwork early
>>>> on, where possible. It simplifies the remainder of the patch series.
>>>>
>>>> Regards,
>>>>
>>>>      Hans
>>>>


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions
  2023-08-31 10:22           ` Hans Verkuil
@ 2023-08-31 12:06             ` Benjamin Gaignard
  0 siblings, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-08-31 12:06 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, tfiga, m.szyprowski, ming.qian, ezequiel,
	p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel


Le 31/08/2023 à 12:22, Hans Verkuil a écrit :
> On 31/08/2023 09:54, Benjamin Gaignard wrote:
>> Le 30/08/2023 à 18:36, Hans Verkuil a écrit :
>>> On 30/08/2023 18:24, Benjamin Gaignard wrote:
>>>> Le 30/08/2023 à 15:23, Hans Verkuil a écrit :
>>>>> On 24/08/2023 11:21, Benjamin Gaignard wrote:
>>>>>> The first step before changing how vb2 buffers are stored into queue
>>>>>> is to avoid direct access to bufs arrays.
>>>>>>
>>>>>> This patch adds 2 helpers functions to add and remove vb2 buffers
>>>>>> from a queue. With these 2 and vb2_get_buffer(), bufs field of
>>>>>> struct vb2_queue becomes like a private member of the structure.
>>>>>>
>>>>>> After each call to vb2_get_buffer() we need to be sure that we get
>>>>>> a valid pointer so check the return value of all of them.
>>>>>>
>>>>>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
>>>>>>
>>>>>> # Conflicts:
>>>>>> #    drivers/media/common/videobuf2/videobuf2-core.c
>>>>>> ---
>>>>>>     .../media/common/videobuf2/videobuf2-core.c   | 203 ++++++++++++++----
>>>>>>     .../media/common/videobuf2/videobuf2-v4l2.c   |  28 ++-
>>>>>>     drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
>>>>>>     .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
>>>>>>     .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
>>>>>>     drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
>>>>>>     drivers/media/test-drivers/visl/visl-dec.c    |  28 ++-
>>>>>>     .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
>>>>>>     8 files changed, 230 insertions(+), 65 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
>>>>>> index e06905533ef4..8aa13591b782 100644
>>>>>> --- a/drivers/media/common/videobuf2/videobuf2-core.c
>>>>>> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
>>>>>> @@ -403,6 +403,37 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
>>>>>>             vb->skip_cache_sync_on_finish = 1;
>>>>>>     }
>>>>>>     +/**
>>>>>> + * vb2_queue_add_buffer() - add a buffer to a queue
>>>>>> + * @q:    pointer to &struct vb2_queue with videobuf2 queue.
>>>>>> + * @vb:    pointer to &struct vb2_buffer to be added to the queue.
>>>>>> + * @index: index where add vb2_buffer in the queue
>>>>>> + */
>>>>>> +static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
>>>>>> +{
>>>>>> +    if (index < VB2_MAX_FRAME && !q->bufs[index]) {
>>>>>> +        q->bufs[index] = vb;
>>>>>> +        vb->index = index;
>>>>>> +        vb->vb2_queue = q;
>>>>>> +        return true;
>>>>>> +    }
>>>>>> +
>>>>>> +    return false;
>>>>>> +}
>>>>>> +
>>>>>> +/**
>>>>>> + * vb2_queue_remove_buffer() - remove a buffer from a queue
>>>>>> + * @q:    pointer to &struct vb2_queue with videobuf2 queue.
>>>>>> + * @vb:    pointer to &struct vb2_buffer to be removed from the queue.
>>>>>> + */
>>>>>> +static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
>>>>>> +{
>>>>>> +    if (vb->index < VB2_MAX_FRAME) {
>>>>>> +        q->bufs[vb->index] = NULL;
>>>>>> +        vb->vb2_queue = NULL;
>>>>>> +    }
>>>>>> +}
>>>>>> +
>>>>>>     /*
>>>>>>      * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
>>>>>>      * video buffer memory for all buffers/planes on the queue and initializes the
>>>>>> @@ -431,9 +462,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>>>             }
>>>>>>               vb->state = VB2_BUF_STATE_DEQUEUED;
>>>>>> -        vb->vb2_queue = q;
>>>>>>             vb->num_planes = num_planes;
>>>>>> -        vb->index = q->num_buffers + buffer;
>>>>>>             vb->type = q->type;
>>>>>>             vb->memory = memory;
>>>>>>             init_buffer_cache_hints(q, vb);
>>>>>> @@ -443,7 +472,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>>>             }
>>>>>>             call_void_bufop(q, init_buffer, vb);
>>>>>>     -        q->bufs[vb->index] = vb;
>>>>>> +        if (!vb2_queue_add_buffer(q, vb, q->num_buffers + buffer)) {
>>>>>> +            dprintk(q, 1, "failed adding buffer %d to queue\n", buffer);
>>>>>> +            kfree(vb);
>>>>>> +            break;
>>>>>> +        }
>>>>>>               /* Allocate video buffer memory for the MMAP type */
>>>>>>             if (memory == VB2_MEMORY_MMAP) {
>>>>>> @@ -451,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>>>                 if (ret) {
>>>>>>                     dprintk(q, 1, "failed allocating memory for buffer %d\n",
>>>>>>                         buffer);
>>>>>> -                q->bufs[vb->index] = NULL;
>>>>>> +                vb2_queue_remove_buffer(q, vb);
>>>>>>                     kfree(vb);
>>>>>>                     break;
>>>>>>                 }
>>>>>> @@ -466,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>>>>>                     dprintk(q, 1, "buffer %d %p initialization failed\n",
>>>>>>                         buffer, vb);
>>>>>>                     __vb2_buf_mem_free(vb);
>>>>>> -                q->bufs[vb->index] = NULL;
>>>>>> +                vb2_queue_remove_buffer(q, vb);
>>>>>>                     kfree(vb);
>>>>>>                     break;
>>>>>>                 }
>>>>>> @@ -489,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
>>>>>>           for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>>>              ++buffer) {
>>>>>> -        vb = q->bufs[buffer];
>>>>>> +        vb = vb2_get_buffer(q, buffer);
>>>>>>             if (!vb)
>>>>>>                 continue;
>>>>>>     @@ -517,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>>>         /* Call driver-provided cleanup function for each buffer, if provided */
>>>>>>         for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>>>              ++buffer) {
>>>>>> -        struct vb2_buffer *vb = q->bufs[buffer];
>>>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>>>               if (vb && vb->planes[0].mem_priv)
>>>>>>                 call_void_vb_qop(vb, buf_cleanup, vb);
>>>>>> @@ -557,15 +590,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>>>             q->cnt_unprepare_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;
>>>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>>> +        bool unbalanced;
>>>>>> +
>>>>>> +        if (!vb)
>>>>>> +            continue;
>>>>>> +
>>>>>> +        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) {
>>>>> I think we should drop the '|| debug' part. It is already annoying today to see these
>>>>> messages when the debug parameter is > 0, and now the number of buffers is still
>>>>> fairly small. But if we allow a lot more buffers, then this will really spam the
>>>>> kernel log.
>>>>>
>>>>> I think this should be dropped, and we only report unbalanced buffers.
>>>>>
>>>>> And another optimization is to only report the unbalanced counters. Right now
>>>>> it reports all counters, but it is again too much spamming of the kernel log.
>>>>>
>>>>> I think this change can be done as a separate patch before this patch.
>>>>> That way it can be picked up separately from the other changes in this series.
>>>>>
>>>>>>                 pr_info("   counters for queue %p, buffer %d:%s\n",
>>>>>> @@ -597,8 +635,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>>>>>         /* Free vb2 buffers */
>>>>>>         for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>>>>>              ++buffer) {
>>>>>> -        kfree(q->bufs[buffer]);
>>>>>> -        q->bufs[buffer] = NULL;
>>>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>>> +
>>>>>> +        if (!vb)
>>>>>> +            continue;
>>>>>> +
>>>>>> +        vb2_queue_remove_buffer(q, vb);
>>>>>> +        kfree(vb);
>>>>>>         }
>>>>>>           q->num_buffers -= buffers;
>>>>>> @@ -634,7 +677,12 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>>>>>     {
>>>>>>         unsigned int buffer;
>>>>>>         for (buffer = 0; buffer < q->num_buffers; ++buffer) {
>>>>>> -        if (vb2_buffer_in_use(q, q->bufs[buffer]))
>>>>>> +        struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>>>>> +
>>>>>> +        if (!vb)
>>>>>> +            continue;
>>>>>> +
>>>>>> +        if (vb2_buffer_in_use(q, vb))
>>>>>>                 return true;
>>>>>>         }
>>>>>>         return false;
>>>>>> @@ -642,7 +690,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>>>>>       void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>>>>>>     {
>>>>>> -    call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
>>>>>> +    struct vb2_buffer *vb = vb2_get_buffer(q, index);
>>>>>> +
>>>>>> +    if (vb)
>>>>>> +        call_void_bufop(q, fill_user_buffer, vb, pb);
>>>>> I think that rather than passing the index (that then has to be verified)
>>>>> it is better to pass the vb2_buffer pointer directly and leave it up to
>>>>> the caller to do the index verification.
>>>>>
>>>>> Another option is to drop this function altogether and let the called
>>>>> call the fill_user_buffer function. Either works for me.
>>>>>
>>>>>>     }
>>>>>>     EXPORT_SYMBOL_GPL(vb2_core_querybuf);
>>>>>>     @@ -1553,7 +1604,13 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
>>>>> Here too it is better to pass the vb2_buffer pointer instead of an index.
>>>>>
>>>>> This function assumes that the index is valid, so the called actually does the
>>>>> validation. Passing the vb pointer instead of the index makes more sense
>>>>> in this new situation.
>>>>>
>>>>> This is also true for two other core functions: vb2_core_qbuf and vb2_core_expbuf.
>>>>>
>>>>>>         struct vb2_buffer *vb;
>>>>>>         int ret;
>>>>>>     -    vb = q->bufs[index];
>>>>>> +    vb = vb2_get_buffer(q, index);
>>>>>> +
>>>>>> +    if (!vb) {
>>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>>> +        return -EINVAL;
>>>>>> +    }
>>>>> Changing that avoids having to add this check, so it simplifies the code.
>>>>>
>>>>> I think that this change can be done in a separate patch before this one.
>>>>>
>>>>> It makes sense to apply that regardless of the remainder of this series.
>>>>>
>>>>>> +
>>>>>>         if (vb->state != VB2_BUF_STATE_DEQUEUED) {
>>>>>>             dprintk(q, 1, "invalid buffer state %s\n",
>>>>>>                 vb2_state_name(vb->state));
>>>>>> @@ -1624,7 +1681,11 @@ static int vb2_start_streaming(struct vb2_queue *q)
>>>>>>              * correctly return them to vb2.
>>>>>>              */
>>>>>>             for (i = 0; i < q->num_buffers; ++i) {
>>>>>> -            vb = q->bufs[i];
>>>>>> +            vb = vb2_get_buffer(q, i);
>>>>>> +
>>>>>> +            if (!vb)
>>>>>> +                continue;
>>>>>> +
>>>>>>                 if (vb->state == VB2_BUF_STATE_ACTIVE)
>>>>>>                     vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
>>>>>>             }
>>>>>> @@ -1652,7 +1713,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
>>>>>>             return -EIO;
>>>>>>         }
>>>>>>     -    vb = q->bufs[index];
>>>>>> +    vb = vb2_get_buffer(q, index);
>>>>>> +
>>>>>> +    if (!vb) {
>>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>>> +        return -EINVAL;
>>>>>> +    }
>>>>>>           if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
>>>>>>             q->requires_requests) {
>>>>>> @@ -2028,12 +2094,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>>>>>          * to vb2 in stop_streaming().
>>>>>>          */
>>>>>>         if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
>>>>>> -        for (i = 0; i < q->num_buffers; ++i)
>>>>>> -            if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
>>>>>> +        for (i = 0; i < q->num_buffers; ++i) {
>>>>>> +            struct vb2_buffer *vb = vb2_get_buffer(q, i);
>>>>>> +
>>>>>> +            if (!vb)
>>>>>> +                continue;
>>>>>> +
>>>>>> +            if (vb->state == VB2_BUF_STATE_ACTIVE) {
>>>>>>                     pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
>>>>>> -                    q->bufs[i]);
>>>>>> -                vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
>>>>>> +                    vb);
>>>>>> +                vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
>>>>>>                 }
>>>>>> +        }
>>>>>>             /* Must be zero now */
>>>>>>             WARN_ON(atomic_read(&q->owned_by_drv_count));
>>>>>>         }
>>>>>> @@ -2067,9 +2139,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>>>>>          * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
>>>>>>          */
>>>>>>         for (i = 0; i < q->num_buffers; ++i) {
>>>>>> -        struct vb2_buffer *vb = q->bufs[i];
>>>>>> -        struct media_request *req = vb->req_obj.req;
>>>>>> +        struct vb2_buffer *vb;
>>>>>> +        struct media_request *req;
>>>>>> +
>>>>>> +        vb = vb2_get_buffer(q, i);
>>>>>> +        if (!vb)
>>>>>> +            continue;
>>>>>>     +        req = vb->req_obj.req;
>>>>>>             /*
>>>>>>              * If a request is associated with this buffer, then
>>>>>>              * call buf_request_cancel() to give the driver to complete()
>>>>>> @@ -2219,7 +2296,10 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>>>>>>         buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
>>>>>>         plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>>>>>>     -    vb = q->bufs[buffer];
>>>>>> +    vb = vb2_get_buffer(q, buffer);
>>>>>> +    if (!vb)
>>>>>> +        return -EINVAL;
>>>>>> +
>>>>>>         if (vb->planes[plane].m.offset == off) {
>>>>>>             *_buffer = buffer;
>>>>>>             *_plane = plane;
>>>>>> @@ -2262,7 +2342,12 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
>>>>>>             return -EINVAL;
>>>>>>         }
>>>>>>     -    vb = q->bufs[index];
>>>>>> +    vb = vb2_get_buffer(q, index);
>>>>>> +
>>>>>> +    if (!vb) {
>>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>>> +        return -EINVAL;
>>>>>> +    }
>>>>>>           if (plane >= vb->num_planes) {
>>>>>>             dprintk(q, 1, "buffer plane out of range\n");
>>>>>> @@ -2339,7 +2424,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
>>>>>>         if (ret)
>>>>>>             goto unlock;
>>>>>>     -    vb = q->bufs[buffer];
>>>>>> +    vb = vb2_get_buffer(q, buffer);
>>>>>> +
>>>>>> +    if (!vb) {
>>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>>> +        ret = -EINVAL;
>>>>>> +        goto unlock;
>>>>>> +    }
>>>>>>           /*
>>>>>>          * MMAP requires page_aligned buffers.
>>>>>> @@ -2396,7 +2487,12 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
>>>>>>         if (ret)
>>>>>>             goto unlock;
>>>>>>     -    vb = q->bufs[buffer];
>>>>>> +    vb = vb2_get_buffer(q, buffer);
>>>>>> +    if (!vb) {
>>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>>> +        ret = -EINVAL;
>>>>>> +        goto unlock;
>>>>>> +    }
>>>>>>           vaddr = vb2_plane_vaddr(vb, plane);
>>>>>>         mutex_unlock(&q->mmap_lock);
>>>>>> @@ -2625,6 +2721,7 @@ struct vb2_fileio_data {
>>>>>>     static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>>>     {
>>>>>>         struct vb2_fileio_data *fileio;
>>>>>> +    struct vb2_buffer *vb;
>>>>>>         int i, ret;
>>>>>>         unsigned int count = 0;
>>>>>>     @@ -2679,7 +2776,13 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>>>          * Check if plane_count is correct
>>>>>>          * (multiplane buffers are not supported).
>>>>>>          */
>>>>>> -    if (q->bufs[0]->num_planes != 1) {
>>>>>> +    vb = vb2_get_buffer(q, 0);
>>>>>> +    if (!vb) {
>>>>>> +        ret = -EBUSY;
>>>>>> +        goto err_reqbufs;
>>>>>> +    }
>>>>> This cannot happen. These fileio helper functions implement the read() support
>>>>> and all the buffer allocation happens here. Userspace can never add or delete
>>>>> buffers later, so there will never be holes. It is safe to assume that
>>>>> vb2_get_buffer(q, i) will always return a valid vb pointer for i in the range
>>>>> of 0 - q->num_buffers-1.
>>>>>
>>>>> Perhaps add a comment to that effect, but otherwise you can drop the checks.
>>>>>
>>>>>> +
>>>>>> +    if (vb->num_planes != 1) {
>>>>>>             ret = -EBUSY;
>>>>>>             goto err_reqbufs;
>>>>>>         }
>>>>>> @@ -2688,12 +2791,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>>>>>          * Get kernel address of each buffer.
>>>>>>          */
>>>>>>         for (i = 0; i < q->num_buffers; i++) {
>>>>>> -        fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
>>>>>> +        vb = vb2_get_buffer(q, i);
>>>>>> +
>>>>>> +        if (!vb)
>>>>>> +            continue;
>>>>>> +
>>>>>> +        fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
>>>>>>             if (fileio->bufs[i].vaddr == NULL) {
>>>>>>                 ret = -EINVAL;
>>>>>>                 goto err_reqbufs;
>>>>>>             }
>>>>>> -        fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
>>>>>> +        fileio->bufs[i].size = vb2_plane_size(vb, 0);
>>>>>>         }
>>>>>>           /*
>>>>>> @@ -2821,15 +2929,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>>>               fileio->cur_index = index;
>>>>>>             buf = &fileio->bufs[index];
>>>>>> -        b = q->bufs[index];
>>>>>> +        b = vb2_get_buffer(q, index);
>>>>>> +
>>>>>> +        if (!b)
>>>>>> +            return -EINVAL;
>>>>>>               /*
>>>>>>              * Get number of bytes filled by the driver
>>>>>>              */
>>>>>>             buf->pos = 0;
>>>>>>             buf->queued = 0;
>>>>>> -        buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
>>>>>> -                 : vb2_plane_size(q->bufs[index], 0);
>>>>>> +        buf->size = read ? vb2_get_plane_payload(b, 0)
>>>>>> +                 : vb2_plane_size(b, 0);
>>>>>>             /* Compensate for data_offset on read in the multiplanar case. */
>>>>>>             if (is_multiplanar && read &&
>>>>>>                     b->planes[0].data_offset < buf->size) {
>>>>>> @@ -2872,8 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>>>          * Queue next buffer if required.
>>>>>>          */
>>>>>>         if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
>>>>>> -        struct vb2_buffer *b = q->bufs[index];
>>>>>> +        struct vb2_buffer *b = vb2_get_buffer(q, index);
>>>>>>     +        if (!b) {
>>>>>> +            dprintk(q, 1, "can't find the requested buffer\n");
>>>>>> +            return -EINVAL;
>>>>>> +        }
>>>>>>             /*
>>>>>>              * Check if this is the last buffer to read.
>>>>>>              */
>>>>>> @@ -2899,7 +3014,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>>>>>              */
>>>>>>             buf->pos = 0;
>>>>>>             buf->queued = 1;
>>>>>> -        buf->size = vb2_plane_size(q->bufs[index], 0);
>>>>>> +        buf->size = vb2_plane_size(b, 0);
>>>>>>             fileio->q_count += 1;
>>>>>>             /*
>>>>>>              * If we are queuing up buffers for the first time, then
>>>>>> @@ -2970,7 +3085,9 @@ static int vb2_thread(void *data)
>>>>>>              * Call vb2_dqbuf to get buffer back.
>>>>>>              */
>>>>>>             if (prequeue) {
>>>>>> -            vb = q->bufs[index++];
>>>>>> +            vb = vb2_get_buffer(q, index++);
>>>>>> +            if (!vb)
>>>>>> +                continue;
>>>>>>                 prequeue--;
>>>>>>             } else {
>>>>>>                 call_void_qop(q, wait_finish, q);
>>>>>> @@ -2979,7 +3096,7 @@ static int vb2_thread(void *data)
>>>>>>                 call_void_qop(q, wait_prepare, q);
>>>>>>                 dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
>>>>>>                 if (!ret)
>>>>>> -                vb = q->bufs[index];
>>>>>> +                vb = vb2_get_buffer(q, index);
>>>>>>             }
>>>>>>             if (ret || threadio->stop)
>>>>>>                 break;
>>>>>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>>>> index c7a54d82a55e..724135d41f7f 100644
>>>>>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>>>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>>>>>> @@ -383,8 +383,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>>>>>             return -EINVAL;
>>>>>>         }
>>>>>>     -    if (q->bufs[b->index] == NULL) {
>>>>>> -        /* Should never happen */
>>>>>> +    if (!vb2_get_buffer(q, b->index)) {
>>>>>>             dprintk(q, 1, "%s: buffer is NULL\n", opname);
>>>>> How about:
>>>>>
>>>>>              dprintk(q, 1, "%s: buffer %u was deleted\n", opname, b->index);
>>>>>
>>>>> although perhaps that change is more appropriate in patch 09/10?
>>>>>
>>>>> Regardless, once it is possible to delete buffers, then this message should be
>>>>> adjusted accordingly.
>>>>>
>>>>>>             return -EINVAL;
>>>>>>         }
>>>>>> @@ -394,7 +393,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>>>>>             return -EINVAL;
>>>>>>         }
>>>>>>     -    vb = q->bufs[b->index];
>>>>>> +    vb = vb2_get_buffer(q, b->index);
>>>>> This can be moved up to the 'if (!vb2_get_buffer(q, b->index)) {' check above.
>>>>> That avoids calling vb2_get_buffer twice.
>>>>>
>>>>>>         vbuf = to_vb2_v4l2_buffer(vb);
>>>>>>         ret = __verify_planes_array(vb, b);
>>>>>>         if (ret)
>>>>>> @@ -628,11 +627,18 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
>>>>>>     struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
>>>>>>     {
>>>>>>         unsigned int i;
>>>>>> +    struct vb2_buffer *vb2;
>>>>>>     -    for (i = 0; i < q->num_buffers; i++)
>>>>>> -        if (q->bufs[i]->copied_timestamp &&
>>>>>> -            q->bufs[i]->timestamp == timestamp)
>>>>>> -            return vb2_get_buffer(q, i);
>>>>> Perhaps add a comment here that this loop doesn't scale if there
>>>>> is a really large number of buffers and something more efficient
>>>>> will have to be found in that case.
>>>>>
>>>>>> +    for (i = 0; i < q->num_buffers; i++) {
>>>>>> +        vb2 = vb2_get_buffer(q, i);
>>>>>> +
>>>>>> +        if (!vb2)
>>>>>> +            continue;
>>>>>> +
>>>>>> +        if (vb2->copied_timestamp &&
>>>>>> +            vb2->timestamp == timestamp)
>>>>>> +            return vb2;
>>>>>> +    }
>>>>>>         return NULL;
>>>>>>     }
>>>>>>     EXPORT_SYMBOL_GPL(vb2_find_buffer);
>>>>>> @@ -664,7 +670,13 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
>>>>>>             dprintk(q, 1, "buffer index out of range\n");
>>>>>>             return -EINVAL;
>>>>>>         }
>>>>>> -    vb = q->bufs[b->index];
>>>>>> +    vb = vb2_get_buffer(q, b->index);
>>>>>> +
>>>>>> +    if (!vb) {
>>>>>> +        dprintk(q, 1, "can't find the requested buffer\n");
>>>>>> +        return -EINVAL;
>>>>>> +    }
>>>>>> +
>>>>>>         ret = __verify_planes_array(vb, b);
>>>>>>         if (!ret)
>>>>>>             vb2_core_querybuf(q, b->index, b);
>>>>>> diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
>>>>>> index 982c2c777484..a462d6fe4ea9 100644
>>>>>> --- a/drivers/media/platform/amphion/vpu_dbg.c
>>>>>> +++ b/drivers/media/platform/amphion/vpu_dbg.c
>>>>>> @@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>>>>>           vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
>>>>>>         for (i = 0; i < vq->num_buffers; i++) {
>>>>>> -        struct vb2_buffer *vb = vq->bufs[i];
>>>>>> -        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>>>>> +        struct vb2_buffer *vb;
>>>>>> +        struct vb2_v4l2_buffer *vbuf;
>>>>>> +
>>>>>> +        vb = vb2_get_buffer(vq, i);
>>>>>> +        if (!vb)
>>>>>> +            continue;
>>>>>>               if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>>>>>                 continue;
>>>>>> +
>>>>>> +        vbuf = to_vb2_v4l2_buffer(vb);
>>>>>> +
>>>>>>             num = scnprintf(str, sizeof(str),
>>>>>>                     "output [%2d] state = %10s, %8s\n",
>>>>>>                     i, vb2_stat_name[vb->state],
>>>>>> @@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>>>>>           vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
>>>>>>         for (i = 0; i < vq->num_buffers; i++) {
>>>>>> -        struct vb2_buffer *vb = vq->bufs[i];
>>>>>> -        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>>>>> +        struct vb2_buffer *vb;
>>>>>> +        struct vb2_v4l2_buffer *vbuf;
>>>>>> +
>>>>>> +        vb = vb2_get_buffer(vq, i);
>>>>>> +        if (!vb)
>>>>>> +            continue;
>>>>>>               if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>>>>>                 continue;
>>>>>> +
>>>>>> +        vbuf = to_vb2_v4l2_buffer(vb);
>>>>>> +
>>>>>>             num = scnprintf(str, sizeof(str),
>>>>>>                     "capture[%2d] state = %10s, %8s\n",
>>>>>>                     i, vb2_stat_name[vb->state],
>>>>> This can be a separate patch, right? It doesn't depend on any core changes.
>>>>>
>>>>> And this can also be applied before this patch.
>>>> Hans, I would like to clarify this comment (and the following Ditto).
>>>> Are you against use vb2_get_buffer() outside core ?
>>>> or testing vb2_get_buffer() result ?
>>>> The goal of this patch was to remove all access like vq->bufs[i] and to make
>>>> sure that vb buffer are always valid.
>>> Sorry for the confusion. I meant that AFAICS each of these driver changes can be
>>> done in the separate patch and that those separate patches can be applied before
>>> this patch. I.e., they are independent.
>>>
>>> I always prefer specific driver changes to be done as separate patches rather
>>> than one patch modifying a lot of drivers in one go. That is not always possible,
>>> of course, but in this case I think it is fine, unless I missed something.
>> All changes in the drivers use vb2_get_buffer() which is introduced in this patch
>> so I can't do them before.
>> If you want I can make a patch per driver but after this patch.
> ??? vb2_get_buffer() has been defined in include/media/videobuf2-core.h for a long
> time (2019 to be precise).

Yes I have made a mistake, sorry for the noise.

>
> Regards,
>
> 	Hans
>
>> Regards,
>> Benjamin
>>
>>> Regards,
>>>
>>>      Hans
>>>
>>>> Regards,
>>>> Benjamin
>>>>
>>>>>> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>>>> index 621038aab116..62910a1b8a98 100644
>>>>>> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>>>> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>>>>>> @@ -603,7 +603,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>>>>>             return -EINVAL;
>>>>>>         }
>>>>>>     -    vb = vq->bufs[buf->index];
>>>>>> +    vb = vb2_get_buffer(vq, buf->index);
>>>>>> +    if (!vb) {
>>>>>> +        dev_err(ctx->jpeg->dev, "buffer not found\n");
>>>>>> +        return -EINVAL;
>>>>>> +    }
>>>>>>         jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
>>>>>>         jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
>>>>>>     
>>>>> Ditto.
>>>>>
>>>>>> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>>>> index e393e3e668f8..3d2ae0e1b5b6 100644
>>>>>> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>>>> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>>>>>> @@ -1696,7 +1696,7 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
>>>>>>           /* update internal buffer's width/height */
>>>>>>         for (i = 0; i < vq->num_buffers; i++) {
>>>>>> -        if (vb == vq->bufs[i]) {
>>>>>> +        if (vb == vb2_get_buffer(vq, i)) {
>>>>>>                 instance->dpb[i].width = w;
>>>>>>                 instance->dpb[i].height = h;
>>>>>>                 break;
>>>>> Ditto.
>>>>>
>>>>>> diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>>>> index 3a848ca32a0e..326be09bdb55 100644
>>>>>> --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>>>> +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>>>>>> @@ -577,6 +577,10 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>>>>>             }
>>>>>>               vb2_buf = vb2_get_buffer(vq, buf->index);
>>>>>> +        if (!vb2_buf) {
>>>>>> +            dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
>>>>>> +            return -EINVAL;
>>>>>> +        }
>>>>>>             stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
>>>>>>             stream->bytesused = buf->bytesused;
>>>>>>         }
>>>>> Ditto.
>>>>>
>>>>>> diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
>>>>>> index 318d675e5668..ba20ea998d19 100644
>>>>>> --- a/drivers/media/test-drivers/visl/visl-dec.c
>>>>>> +++ b/drivers/media/test-drivers/visl/visl-dec.c
>>>>>> @@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>>>>>         for (i = 0; i < out_q->num_buffers; i++) {
>>>>>>             char entry[] = "index: %u, state: %s, request_fd: %d, ";
>>>>>>             u32 old_len = len;
>>>>>> -        char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
>>>>>> +        struct vb2_buffer *vb2;
>>>>>> +        char *q_status;
>>>>>> +
>>>>>> +        vb2 = vb2_get_buffer(out_q, i);
>>>>>> +        if (!vb2)
>>>>>> +            continue;
>>>>>> +
>>>>>> +        q_status = visl_get_vb2_state(vb2->state);
>>>>>>               len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>>>>>                      entry, i, q_status,
>>>>>> -                 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
>>>>>> +                 to_vb2_v4l2_buffer(vb2)->request_fd);
>>>>>>     -        len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
>>>>>> +        len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
>>>>>>                            &buf[len],
>>>>>>                            TPG_STR_BUF_SZ - len);
>>>>>>     @@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>>>>>         len = 0;
>>>>>>         for (i = 0; i < cap_q->num_buffers; i++) {
>>>>>>             u32 old_len = len;
>>>>>> -        char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
>>>>>> +        struct vb2_buffer *vb2;
>>>>>> +        char *q_status;
>>>>>> +
>>>>>> +        vb2 = vb2_get_buffer(cap_q, i);
>>>>>> +        if (!vb2)
>>>>>> +            continue;
>>>>>> +
>>>>>> +        q_status = visl_get_vb2_state(vb2->state);
>>>>>>               len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>>>>>                      "index: %u, status: %s, timestamp: %llu, is_held: %d",
>>>>>> -                 cap_q->bufs[i]->index, q_status,
>>>>>> -                 cap_q->bufs[i]->timestamp,
>>>>>> -                 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
>>>>>> +                 vb2->index, q_status,
>>>>>> +                 vb2->timestamp,
>>>>>> +                 to_vb2_v4l2_buffer(vb2)->is_held);
>>>>>>               tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
>>>>>>             frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
>>>>> Ditto.
>>>>>
>>>>>> diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>>>> index d2174156573a..4b65c69fa60d 100644
>>>>>> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>>>> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>>>>>> @@ -1061,7 +1061,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
>>>>>>         if (ret)
>>>>>>             return ret;
>>>>>>     -    vb = pipe->vb_queue.bufs[buf->index];
>>>>>> +    vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
>>>>>>         frame = vb_to_frame(vb);
>>>>>>           buf->reserved = asd->frame_status[buf->index];
>>>>> Ditto.
>>>>>
>>>>> Background: I think it is really useful to merge a lot of the groundwork early
>>>>> on, where possible. It simplifies the remainder of the patch series.
>>>>>
>>>>> Regards,
>>>>>
>>>>>       Hans
>>>>>
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions
  2023-08-30 13:23   ` Hans Verkuil
  2023-08-30 16:24     ` Benjamin Gaignard
@ 2023-09-01 12:29     ` Benjamin Gaignard
  1 sibling, 0 replies; 27+ messages in thread
From: Benjamin Gaignard @ 2023-09-01 12:29 UTC (permalink / raw)
  To: Hans Verkuil, mchehab, tfiga, m.szyprowski, ming.qian, ezequiel,
	p.zabel, gregkh, nicolas.dufresne
  Cc: linux-media, linux-kernel, linux-arm-kernel, linux-mediatek,
	linux-arm-msm, linux-rockchip, linux-staging, kernel


Le 30/08/2023 à 15:23, Hans Verkuil a écrit :
> On 24/08/2023 11:21, Benjamin Gaignard wrote:
>> The first step before changing how vb2 buffers are stored into queue
>> is to avoid direct access to bufs arrays.
>>
>> This patch adds 2 helpers functions to add and remove vb2 buffers
>> from a queue. With these 2 and vb2_get_buffer(), bufs field of
>> struct vb2_queue becomes like a private member of the structure.
>>
>> After each call to vb2_get_buffer() we need to be sure that we get
>> a valid pointer so check the return value of all of them.
>>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
>>
>> # Conflicts:
>> #	drivers/media/common/videobuf2/videobuf2-core.c
>> ---
>>   .../media/common/videobuf2/videobuf2-core.c   | 203 ++++++++++++++----
>>   .../media/common/videobuf2/videobuf2-v4l2.c   |  28 ++-
>>   drivers/media/platform/amphion/vpu_dbg.c      |  22 +-
>>   .../platform/mediatek/jpeg/mtk_jpeg_core.c    |   6 +-
>>   .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c |   2 +-
>>   drivers/media/platform/st/sti/hva/hva-v4l2.c  |   4 +
>>   drivers/media/test-drivers/visl/visl-dec.c    |  28 ++-
>>   .../staging/media/atomisp/pci/atomisp_ioctl.c |   2 +-
>>   8 files changed, 230 insertions(+), 65 deletions(-)
>>
>> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
>> index e06905533ef4..8aa13591b782 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-core.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
>> @@ -403,6 +403,37 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
>>   		vb->skip_cache_sync_on_finish = 1;
>>   }
>>   
>> +/**
>> + * vb2_queue_add_buffer() - add a buffer to a queue
>> + * @q:	pointer to &struct vb2_queue with videobuf2 queue.
>> + * @vb:	pointer to &struct vb2_buffer to be added to the queue.
>> + * @index: index where add vb2_buffer in the queue
>> + */
>> +static bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, int index)
>> +{
>> +	if (index < VB2_MAX_FRAME && !q->bufs[index]) {
>> +		q->bufs[index] = vb;
>> +		vb->index = index;
>> +		vb->vb2_queue = q;
>> +		return true;
>> +	}
>> +
>> +	return false;
>> +}
>> +
>> +/**
>> + * vb2_queue_remove_buffer() - remove a buffer from a queue
>> + * @q:	pointer to &struct vb2_queue with videobuf2 queue.
>> + * @vb:	pointer to &struct vb2_buffer to be removed from the queue.
>> + */
>> +static void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
>> +{
>> +	if (vb->index < VB2_MAX_FRAME) {
>> +		q->bufs[vb->index] = NULL;
>> +		vb->vb2_queue = NULL;
>> +	}
>> +}
>> +
>>   /*
>>    * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
>>    * video buffer memory for all buffers/planes on the queue and initializes the
>> @@ -431,9 +462,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>   		}
>>   
>>   		vb->state = VB2_BUF_STATE_DEQUEUED;
>> -		vb->vb2_queue = q;
>>   		vb->num_planes = num_planes;
>> -		vb->index = q->num_buffers + buffer;
>>   		vb->type = q->type;
>>   		vb->memory = memory;
>>   		init_buffer_cache_hints(q, vb);
>> @@ -443,7 +472,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>   		}
>>   		call_void_bufop(q, init_buffer, vb);
>>   
>> -		q->bufs[vb->index] = vb;
>> +		if (!vb2_queue_add_buffer(q, vb, q->num_buffers + buffer)) {
>> +			dprintk(q, 1, "failed adding buffer %d to queue\n", buffer);
>> +			kfree(vb);
>> +			break;
>> +		}
>>   
>>   		/* Allocate video buffer memory for the MMAP type */
>>   		if (memory == VB2_MEMORY_MMAP) {
>> @@ -451,7 +484,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>   			if (ret) {
>>   				dprintk(q, 1, "failed allocating memory for buffer %d\n",
>>   					buffer);
>> -				q->bufs[vb->index] = NULL;
>> +				vb2_queue_remove_buffer(q, vb);
>>   				kfree(vb);
>>   				break;
>>   			}
>> @@ -466,7 +499,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
>>   				dprintk(q, 1, "buffer %d %p initialization failed\n",
>>   					buffer, vb);
>>   				__vb2_buf_mem_free(vb);
>> -				q->bufs[vb->index] = NULL;
>> +				vb2_queue_remove_buffer(q, vb);
>>   				kfree(vb);
>>   				break;
>>   			}
>> @@ -489,7 +522,7 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
>>   
>>   	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>   	     ++buffer) {
>> -		vb = q->bufs[buffer];
>> +		vb = vb2_get_buffer(q, buffer);
>>   		if (!vb)
>>   			continue;
>>   
>> @@ -517,7 +550,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>   	/* Call driver-provided cleanup function for each buffer, if provided */
>>   	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>   	     ++buffer) {
>> -		struct vb2_buffer *vb = q->bufs[buffer];
>> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>>   
>>   		if (vb && vb->planes[0].mem_priv)
>>   			call_void_vb_qop(vb, buf_cleanup, vb);
>> @@ -557,15 +590,20 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>   		q->cnt_unprepare_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;
>> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>> +		bool unbalanced;
>> +
>> +		if (!vb)
>> +			continue;
>> +
>> +		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) {
> I think we should drop the '|| debug' part. It is already annoying today to see these
> messages when the debug parameter is > 0, and now the number of buffers is still
> fairly small. But if we allow a lot more buffers, then this will really spam the
> kernel log.
>
> I think this should be dropped, and we only report unbalanced buffers.
>
> And another optimization is to only report the unbalanced counters. Right now
> it reports all counters, but it is again too much spamming of the kernel log.
>
> I think this change can be done as a separate patch before this patch.
> That way it can be picked up separately from the other changes in this series.
>
>>   			pr_info("   counters for queue %p, buffer %d:%s\n",
>> @@ -597,8 +635,13 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
>>   	/* Free vb2 buffers */
>>   	for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
>>   	     ++buffer) {
>> -		kfree(q->bufs[buffer]);
>> -		q->bufs[buffer] = NULL;
>> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>> +
>> +		if (!vb)
>> +			continue;
>> +
>> +		vb2_queue_remove_buffer(q, vb);
>> +		kfree(vb);
>>   	}
>>   
>>   	q->num_buffers -= buffers;
>> @@ -634,7 +677,12 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>   {
>>   	unsigned int buffer;
>>   	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
>> -		if (vb2_buffer_in_use(q, q->bufs[buffer]))
>> +		struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
>> +
>> +		if (!vb)
>> +			continue;
>> +
>> +		if (vb2_buffer_in_use(q, vb))
>>   			return true;
>>   	}
>>   	return false;
>> @@ -642,7 +690,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>   
>>   void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>>   {
>> -	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
>> +	struct vb2_buffer *vb = vb2_get_buffer(q, index);
>> +
>> +	if (vb)
>> +		call_void_bufop(q, fill_user_buffer, vb, pb);
> I think that rather than passing the index (that then has to be verified)
> it is better to pass the vb2_buffer pointer directly and leave it up to
> the caller to do the index verification.

That will be be in v6

>
> Another option is to drop this function altogether and let the called
> call the fill_user_buffer function. Either works for me.
>
>>   }
>>   EXPORT_SYMBOL_GPL(vb2_core_querybuf);
>>   
>> @@ -1553,7 +1604,13 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
> Here too it is better to pass the vb2_buffer pointer instead of an index.
>
> This function assumes that the index is valid, so the called actually does the
> validation. Passing the vb pointer instead of the index makes more sense
> in this new situation.
>
> This is also true for two other core functions: vb2_core_qbuf and vb2_core_expbuf.
>
>>   	struct vb2_buffer *vb;
>>   	int ret;
>>   
>> -	vb = q->bufs[index];
>> +	vb = vb2_get_buffer(q, index);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		return -EINVAL;
>> +	}
> Changing that avoids having to add this check, so it simplifies the code.
>
> I think that this change can be done in a separate patch before this one.
>
> It makes sense to apply that regardless of the remainder of this series.
>
>> +
>>   	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
>>   		dprintk(q, 1, "invalid buffer state %s\n",
>>   			vb2_state_name(vb->state));
>> @@ -1624,7 +1681,11 @@ static int vb2_start_streaming(struct vb2_queue *q)
>>   		 * correctly return them to vb2.
>>   		 */
>>   		for (i = 0; i < q->num_buffers; ++i) {
>> -			vb = q->bufs[i];
>> +			vb = vb2_get_buffer(q, i);
>> +
>> +			if (!vb)
>> +				continue;
>> +
>>   			if (vb->state == VB2_BUF_STATE_ACTIVE)
>>   				vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
>>   		}
>> @@ -1652,7 +1713,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
>>   		return -EIO;
>>   	}
>>   
>> -	vb = q->bufs[index];
>> +	vb = vb2_get_buffer(q, index);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		return -EINVAL;
>> +	}
>>   
>>   	if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
>>   	    q->requires_requests) {
>> @@ -2028,12 +2094,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>   	 * to vb2 in stop_streaming().
>>   	 */
>>   	if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
>> -		for (i = 0; i < q->num_buffers; ++i)
>> -			if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
>> +		for (i = 0; i < q->num_buffers; ++i) {
>> +			struct vb2_buffer *vb = vb2_get_buffer(q, i);
>> +
>> +			if (!vb)
>> +				continue;
>> +
>> +			if (vb->state == VB2_BUF_STATE_ACTIVE) {
>>   				pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
>> -					q->bufs[i]);
>> -				vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
>> +					vb);
>> +				vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
>>   			}
>> +		}
>>   		/* Must be zero now */
>>   		WARN_ON(atomic_read(&q->owned_by_drv_count));
>>   	}
>> @@ -2067,9 +2139,14 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
>>   	 * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
>>   	 */
>>   	for (i = 0; i < q->num_buffers; ++i) {
>> -		struct vb2_buffer *vb = q->bufs[i];
>> -		struct media_request *req = vb->req_obj.req;
>> +		struct vb2_buffer *vb;
>> +		struct media_request *req;
>> +
>> +		vb = vb2_get_buffer(q, i);
>> +		if (!vb)
>> +			continue;
>>   
>> +		req = vb->req_obj.req;
>>   		/*
>>   		 * If a request is associated with this buffer, then
>>   		 * call buf_request_cancel() to give the driver to complete()
>> @@ -2219,7 +2296,10 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
>>   	buffer = (off >> (PLANE_INDEX_SHIFT + PAGE_SHIFT)) & MAX_BUFFERS;
>>   	plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;
>>   
>> -	vb = q->bufs[buffer];
>> +	vb = vb2_get_buffer(q, buffer);
>> +	if (!vb)
>> +		return -EINVAL;
>> +
>>   	if (vb->planes[plane].m.offset == off) {
>>   		*_buffer = buffer;
>>   		*_plane = plane;
>> @@ -2262,7 +2342,12 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
>>   		return -EINVAL;
>>   	}
>>   
>> -	vb = q->bufs[index];
>> +	vb = vb2_get_buffer(q, index);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		return -EINVAL;
>> +	}
>>   
>>   	if (plane >= vb->num_planes) {
>>   		dprintk(q, 1, "buffer plane out of range\n");
>> @@ -2339,7 +2424,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
>>   	if (ret)
>>   		goto unlock;
>>   
>> -	vb = q->bufs[buffer];
>> +	vb = vb2_get_buffer(q, buffer);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		ret = -EINVAL;
>> +		goto unlock;
>> +	}
>>   
>>   	/*
>>   	 * MMAP requires page_aligned buffers.
>> @@ -2396,7 +2487,12 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
>>   	if (ret)
>>   		goto unlock;
>>   
>> -	vb = q->bufs[buffer];
>> +	vb = vb2_get_buffer(q, buffer);
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		ret = -EINVAL;
>> +		goto unlock;
>> +	}
>>   
>>   	vaddr = vb2_plane_vaddr(vb, plane);
>>   	mutex_unlock(&q->mmap_lock);
>> @@ -2625,6 +2721,7 @@ struct vb2_fileio_data {
>>   static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>   {
>>   	struct vb2_fileio_data *fileio;
>> +	struct vb2_buffer *vb;
>>   	int i, ret;
>>   	unsigned int count = 0;
>>   
>> @@ -2679,7 +2776,13 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>   	 * Check if plane_count is correct
>>   	 * (multiplane buffers are not supported).
>>   	 */
>> -	if (q->bufs[0]->num_planes != 1) {
>> +	vb = vb2_get_buffer(q, 0);
>> +	if (!vb) {
>> +		ret = -EBUSY;
>> +		goto err_reqbufs;
>> +	}
> This cannot happen. These fileio helper functions implement the read() support
> and all the buffer allocation happens here. Userspace can never add or delete
> buffers later, so there will never be holes. It is safe to assume that
> vb2_get_buffer(q, i) will always return a valid vb pointer for i in the range
> of 0 - q->num_buffers-1.
>
> Perhaps add a comment to that effect, but otherwise you can drop the checks.

I will reuse your words and put that in v6

>
>> +
>> +	if (vb->num_planes != 1) {
>>   		ret = -EBUSY;
>>   		goto err_reqbufs;
>>   	}
>> @@ -2688,12 +2791,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
>>   	 * Get kernel address of each buffer.
>>   	 */
>>   	for (i = 0; i < q->num_buffers; i++) {
>> -		fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
>> +		vb = vb2_get_buffer(q, i);
>> +
>> +		if (!vb)
>> +			continue;
>> +
>> +		fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
>>   		if (fileio->bufs[i].vaddr == NULL) {
>>   			ret = -EINVAL;
>>   			goto err_reqbufs;
>>   		}
>> -		fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
>> +		fileio->bufs[i].size = vb2_plane_size(vb, 0);
>>   	}
>>   
>>   	/*
>> @@ -2821,15 +2929,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>   
>>   		fileio->cur_index = index;
>>   		buf = &fileio->bufs[index];
>> -		b = q->bufs[index];
>> +		b = vb2_get_buffer(q, index);
>> +
>> +		if (!b)
>> +			return -EINVAL;
>>   
>>   		/*
>>   		 * Get number of bytes filled by the driver
>>   		 */
>>   		buf->pos = 0;
>>   		buf->queued = 0;
>> -		buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
>> -				 : vb2_plane_size(q->bufs[index], 0);
>> +		buf->size = read ? vb2_get_plane_payload(b, 0)
>> +				 : vb2_plane_size(b, 0);
>>   		/* Compensate for data_offset on read in the multiplanar case. */
>>   		if (is_multiplanar && read &&
>>   				b->planes[0].data_offset < buf->size) {
>> @@ -2872,8 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>   	 * Queue next buffer if required.
>>   	 */
>>   	if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
>> -		struct vb2_buffer *b = q->bufs[index];
>> +		struct vb2_buffer *b = vb2_get_buffer(q, index);
>>   
>> +		if (!b) {
>> +			dprintk(q, 1, "can't find the requested buffer\n");
>> +			return -EINVAL;
>> +		}
>>   		/*
>>   		 * Check if this is the last buffer to read.
>>   		 */
>> @@ -2899,7 +3014,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
>>   		 */
>>   		buf->pos = 0;
>>   		buf->queued = 1;
>> -		buf->size = vb2_plane_size(q->bufs[index], 0);
>> +		buf->size = vb2_plane_size(b, 0);
>>   		fileio->q_count += 1;
>>   		/*
>>   		 * If we are queuing up buffers for the first time, then
>> @@ -2970,7 +3085,9 @@ static int vb2_thread(void *data)
>>   		 * Call vb2_dqbuf to get buffer back.
>>   		 */
>>   		if (prequeue) {
>> -			vb = q->bufs[index++];
>> +			vb = vb2_get_buffer(q, index++);
>> +			if (!vb)
>> +				continue;
>>   			prequeue--;
>>   		} else {
>>   			call_void_qop(q, wait_finish, q);
>> @@ -2979,7 +3096,7 @@ static int vb2_thread(void *data)
>>   			call_void_qop(q, wait_prepare, q);
>>   			dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
>>   			if (!ret)
>> -				vb = q->bufs[index];
>> +				vb = vb2_get_buffer(q, index);
>>   		}
>>   		if (ret || threadio->stop)
>>   			break;
>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> index c7a54d82a55e..724135d41f7f 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> @@ -383,8 +383,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>   		return -EINVAL;
>>   	}
>>   
>> -	if (q->bufs[b->index] == NULL) {
>> -		/* Should never happen */
>> +	if (!vb2_get_buffer(q, b->index)) {
>>   		dprintk(q, 1, "%s: buffer is NULL\n", opname);
> How about:
>
>    		dprintk(q, 1, "%s: buffer %u was deleted\n", opname, b->index);
>
> although perhaps that change is more appropriate in patch 09/10?
>
> Regardless, once it is possible to delete buffers, then this message should be
> adjusted accordingly.

I will update the same in the patch introducing DELETE_BUFS

>
>>   		return -EINVAL;
>>   	}
>> @@ -394,7 +393,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
>>   		return -EINVAL;
>>   	}
>>   
>> -	vb = q->bufs[b->index];
>> +	vb = vb2_get_buffer(q, b->index);
> This can be moved up to the 'if (!vb2_get_buffer(q, b->index)) {' check above.
> That avoids calling vb2_get_buffer twice.
ok
>
>>   	vbuf = to_vb2_v4l2_buffer(vb);
>>   	ret = __verify_planes_array(vb, b);
>>   	if (ret)
>> @@ -628,11 +627,18 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
>>   struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
>>   {
>>   	unsigned int i;
>> +	struct vb2_buffer *vb2;
>>   
>> -	for (i = 0; i < q->num_buffers; i++)
>> -		if (q->bufs[i]->copied_timestamp &&
>> -		    q->bufs[i]->timestamp == timestamp)
>> -			return vb2_get_buffer(q, i);
> Perhaps add a comment here that this loop doesn't scale if there
> is a really large number of buffers and something more efficient
> will have to be found in that case.

You will have it in v6

>
>> +	for (i = 0; i < q->num_buffers; i++) {
>> +		vb2 = vb2_get_buffer(q, i);
>> +
>> +		if (!vb2)
>> +			continue;
>> +
>> +		if (vb2->copied_timestamp &&
>> +		    vb2->timestamp == timestamp)
>> +			return vb2;
>> +	}
>>   	return NULL;
>>   }
>>   EXPORT_SYMBOL_GPL(vb2_find_buffer);
>> @@ -664,7 +670,13 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
>>   		dprintk(q, 1, "buffer index out of range\n");
>>   		return -EINVAL;
>>   	}
>> -	vb = q->bufs[b->index];
>> +	vb = vb2_get_buffer(q, b->index);
>> +
>> +	if (!vb) {
>> +		dprintk(q, 1, "can't find the requested buffer\n");
>> +		return -EINVAL;
>> +	}
>> +
>>   	ret = __verify_planes_array(vb, b);
>>   	if (!ret)
>>   		vb2_core_querybuf(q, b->index, b);
>> diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
>> index 982c2c777484..a462d6fe4ea9 100644
>> --- a/drivers/media/platform/amphion/vpu_dbg.c
>> +++ b/drivers/media/platform/amphion/vpu_dbg.c
>> @@ -140,11 +140,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>   
>>   	vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
>>   	for (i = 0; i < vq->num_buffers; i++) {
>> -		struct vb2_buffer *vb = vq->bufs[i];
>> -		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> +		struct vb2_buffer *vb;
>> +		struct vb2_v4l2_buffer *vbuf;
>> +
>> +		vb = vb2_get_buffer(vq, i);
>> +		if (!vb)
>> +			continue;
>>   
>>   		if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>   			continue;
>> +
>> +		vbuf = to_vb2_v4l2_buffer(vb);
>> +
>>   		num = scnprintf(str, sizeof(str),
>>   				"output [%2d] state = %10s, %8s\n",
>>   				i, vb2_stat_name[vb->state],
>> @@ -155,11 +162,18 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
>>   
>>   	vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
>>   	for (i = 0; i < vq->num_buffers; i++) {
>> -		struct vb2_buffer *vb = vq->bufs[i];
>> -		struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>> +		struct vb2_buffer *vb;
>> +		struct vb2_v4l2_buffer *vbuf;
>> +
>> +		vb = vb2_get_buffer(vq, i);
>> +		if (!vb)
>> +			continue;
>>   
>>   		if (vb->state == VB2_BUF_STATE_DEQUEUED)
>>   			continue;
>> +
>> +		vbuf = to_vb2_v4l2_buffer(vb);
>> +
>>   		num = scnprintf(str, sizeof(str),
>>   				"capture[%2d] state = %10s, %8s\n",
>>   				i, vb2_stat_name[vb->state],
> This can be a separate patch, right? It doesn't depend on any core changes.
>
> And this can also be applied before this patch.
>
>> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> index 621038aab116..62910a1b8a98 100644
>> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> @@ -603,7 +603,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>   		return -EINVAL;
>>   	}
>>   
>> -	vb = vq->bufs[buf->index];
>> +	vb = vb2_get_buffer(vq, buf->index);
>> +	if (!vb) {
>> +		dev_err(ctx->jpeg->dev, "buffer not found\n");
>> +		return -EINVAL;
>> +	}
>>   	jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
>>   	jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
>>   
> Ditto.
>
>> diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>> index e393e3e668f8..3d2ae0e1b5b6 100644
>> --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>> +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
>> @@ -1696,7 +1696,7 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
>>   
>>   	/* update internal buffer's width/height */
>>   	for (i = 0; i < vq->num_buffers; i++) {
>> -		if (vb == vq->bufs[i]) {
>> +		if (vb == vb2_get_buffer(vq, i)) {
>>   			instance->dpb[i].width = w;
>>   			instance->dpb[i].height = h;
>>   			break;
> Ditto.
>
>> diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>> index 3a848ca32a0e..326be09bdb55 100644
>> --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
>> +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
>> @@ -577,6 +577,10 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
>>   		}
>>   
>>   		vb2_buf = vb2_get_buffer(vq, buf->index);
>> +		if (!vb2_buf) {
>> +			dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
>> +			return -EINVAL;
>> +		}
>>   		stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
>>   		stream->bytesused = buf->bytesused;
>>   	}
> Ditto.
>
>> diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
>> index 318d675e5668..ba20ea998d19 100644
>> --- a/drivers/media/test-drivers/visl/visl-dec.c
>> +++ b/drivers/media/test-drivers/visl/visl-dec.c
>> @@ -290,13 +290,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>   	for (i = 0; i < out_q->num_buffers; i++) {
>>   		char entry[] = "index: %u, state: %s, request_fd: %d, ";
>>   		u32 old_len = len;
>> -		char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
>> +		struct vb2_buffer *vb2;
>> +		char *q_status;
>> +
>> +		vb2 = vb2_get_buffer(out_q, i);
>> +		if (!vb2)
>> +			continue;
>> +
>> +		q_status = visl_get_vb2_state(vb2->state);
>>   
>>   		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>   				 entry, i, q_status,
>> -				 to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
>> +				 to_vb2_v4l2_buffer(vb2)->request_fd);
>>   
>> -		len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
>> +		len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
>>   					   &buf[len],
>>   					   TPG_STR_BUF_SZ - len);
>>   
>> @@ -342,13 +349,20 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
>>   	len = 0;
>>   	for (i = 0; i < cap_q->num_buffers; i++) {
>>   		u32 old_len = len;
>> -		char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
>> +		struct vb2_buffer *vb2;
>> +		char *q_status;
>> +
>> +		vb2 = vb2_get_buffer(cap_q, i);
>> +		if (!vb2)
>> +			continue;
>> +
>> +		q_status = visl_get_vb2_state(vb2->state);
>>   
>>   		len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
>>   				 "index: %u, status: %s, timestamp: %llu, is_held: %d",
>> -				 cap_q->bufs[i]->index, q_status,
>> -				 cap_q->bufs[i]->timestamp,
>> -				 to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
>> +				 vb2->index, q_status,
>> +				 vb2->timestamp,
>> +				 to_vb2_v4l2_buffer(vb2)->is_held);
>>   
>>   		tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
>>   		frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
> Ditto.
>
>> diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>> index d2174156573a..4b65c69fa60d 100644
>> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>> @@ -1061,7 +1061,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
>>   	if (ret)
>>   		return ret;
>>   
>> -	vb = pipe->vb_queue.bufs[buf->index];
>> +	vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
>>   	frame = vb_to_frame(vb);
>>   
>>   	buf->reserved = asd->frame_status[buf->index];
> Ditto.
>
> Background: I think it is really useful to merge a lot of the groundwork early
> on, where possible. It simplifies the remainder of the patch series.
>
> Regards,
>
> 	Hans
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2023-09-01 12:40 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-24  9:21 [PATCH v5 00/10] Add DELETE_BUF ioctl Benjamin Gaignard
2023-08-24  9:21 ` [PATCH v5 01/10] media: videobuf2: Rework offset 'cookie' encoding pattern Benjamin Gaignard
2023-08-30 12:25   ` Hans Verkuil
2023-08-30 12:51     ` Benjamin Gaignard
2023-08-24  9:21 ` [PATCH v5 02/10] media: videobuf2: Access vb2_queue bufs array through helper functions Benjamin Gaignard
2023-08-30 13:23   ` Hans Verkuil
2023-08-30 16:24     ` Benjamin Gaignard
2023-08-30 16:36       ` Hans Verkuil
2023-08-31  7:54         ` Benjamin Gaignard
2023-08-31 10:22           ` Hans Verkuil
2023-08-31 12:06             ` Benjamin Gaignard
2023-09-01 12:29     ` Benjamin Gaignard
2023-08-24  9:21 ` [PATCH v5 03/10] media: videobuf2: Be more flexible on the number of queue stored buffers Benjamin Gaignard
2023-08-30 13:27   ` Hans Verkuil
2023-08-24  9:21 ` [PATCH v5 04/10] media: verisilicon: Refactor postprocessor to store more buffers Benjamin Gaignard
2023-08-24  9:21 ` [PATCH v5 05/10] media: verisilicon: Store chroma and motion vectors offset Benjamin Gaignard
2023-08-24  9:21 ` [PATCH v5 06/10] media: verisilicon: vp9: Use destination buffer height to compute chroma offset Benjamin Gaignard
2023-08-24  9:21 ` [PATCH v5 07/10] media: verisilicon: postproc: Fix down scale test Benjamin Gaignard
2023-08-24  9:21 ` [PATCH v5 08/10] media: verisilicon: vp9: Allow to change resolution while streaming Benjamin Gaignard
2023-08-24  9:21 ` [PATCH v5 09/10] media: v4l2: Add DELETE_BUFS ioctl Benjamin Gaignard
2023-08-30 13:45   ` Hans Verkuil
2023-08-30 13:51   ` Hans Verkuil
2023-08-24  9:21 ` [PATCH v5 10/10] media: v4l2: Add mem2mem helpers for " Benjamin Gaignard
2023-08-25 10:29   ` kernel test robot
2023-08-25 15:34     ` Benjamin Gaignard
2023-08-25 12:26   ` kernel test robot
2023-08-30 13:53   ` Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).