[PATCH v2 1/8] media: videobuf2: Access vb2_queue bufs array through helper functions
Benjamin Gaignard
benjamin.gaignard at collabora.com
Mon May 22 04:19:25 PDT 2023
Le 18/05/2023 à 12:37, Tomasz Figa a écrit :
> Hi Benjamin,
>
> On Tue, Mar 21, 2023 at 11:28:48AM +0100, 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.
>>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard at collabora.com>
>> ---
>> .../media/common/videobuf2/videobuf2-core.c | 84 +++++++++++--------
>> .../media/common/videobuf2/videobuf2-v4l2.c | 17 ++--
>> drivers/media/platform/amphion/vpu_dbg.c | 4 +-
>> .../platform/mediatek/jpeg/mtk_jpeg_core.c | 2 +-
>> .../vcodec/vdec/vdec_vp9_req_lat_if.c | 2 +-
>> drivers/media/test-drivers/visl/visl-dec.c | 16 ++--
>> .../staging/media/atomisp/pci/atomisp_ioctl.c | 2 +-
>> include/media/videobuf2-core.h | 26 ++++++
>> 8 files changed, 101 insertions(+), 52 deletions(-)
>>
> Sorry for being late with review and thanks a lot for working on this.
> This is a quite a long overdue functionality.
>
> [snip]
>
>> @@ -2679,7 +2689,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;
> Out of curiosity, is there any reason for specifically chosing -EBUSY here?
>
> It shouldn't be possible for this to happen, but since we're
> dealing with a pointer here, a NULL check is a good thing. I guess that makes
> -EBUSY as good as any other code here.
I have used -EBUSY to be aligned with the other errors case of this function.
In the following patches I introduce DELETE_BUF ioctl and deleting a buffer from
the array could create case where vb is NULL.
>
> I see some other similar places in the code, with a comment "This shouldn't
> happen" and a dprinkt(). Maybe it would be good to add those here too?
I'm working on that in v3 of this series.
>
>> + goto err_reqbufs;
>> + }
>> +
>> + if (vb->num_planes != 1) {
>> ret = -EBUSY;
>> goto err_reqbufs;
>> }
>> @@ -2688,12 +2704,14 @@ 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);
>> +
>> + 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 +2839,15 @@ 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);
>>
>> /*
>> * 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,7 +2890,7 @@ 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);
>>
>> /*
>> * Check if this is the last buffer to read.
>> @@ -2899,7 +2917,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(vb2_get_buffer(q, index), 0);
>> fileio->q_count += 1;
>> /*
>> * If we are queuing up buffers for the first time, then
>> @@ -2970,7 +2988,7 @@ 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++);
>> prequeue--;
>> } else {
>> call_void_qop(q, wait_finish, q);
>> @@ -2979,7 +2997,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 1f5d235a8441..01b2bb957239 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> @@ -383,7 +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) {
>> + if (!vb2_get_buffer(q, b->index)) {
>> /* Should never happen */
>> dprintk(q, 1, "%s: buffer is NULL\n", opname);
>> return -EINVAL;
>> @@ -394,7 +394,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 +628,14 @@ 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->copied_timestamp &&
>> + vb2->timestamp == timestamp)
>> + return vb2;
>> + }
>> return NULL;
>> }
>> EXPORT_SYMBOL_GPL(vb2_find_buffer);
>> @@ -664,7 +667,7 @@ 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);
>> 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 44b830ae01d8..8a423c1f6b55 100644
>> --- a/drivers/media/platform/amphion/vpu_dbg.c
>> +++ b/drivers/media/platform/amphion/vpu_dbg.c
>> @@ -133,7 +133,7 @@ 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_buffer *vb = vb2_get_buffer(vq, i);
>> struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>
>> if (vb->state == VB2_BUF_STATE_DEQUEUED)
>> @@ -148,7 +148,7 @@ 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_buffer *vb = vb2_get_buffer(vq, i);
>> struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>
>> if (vb->state == VB2_BUF_STATE_DEQUEUED)
>> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> index 969516a940ba..0be07f691d9a 100644
>> --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
>> @@ -603,7 +603,7 @@ 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);
>> 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/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
>> index cbb6728b8a40..f5958b6d834a 100644
>> --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
>> +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
>> @@ -1701,7 +1701,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/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
>> index 318d675e5668..328016b456ba 100644
>> --- a/drivers/media/test-drivers/visl/visl-dec.c
>> +++ b/drivers/media/test-drivers/visl/visl-dec.c
>> @@ -290,13 +290,14 @@ 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 = vb2_get_buffer(out_q, i);
>> + char *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 +343,14 @@ 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 = vb2_get_buffer(cap_q, i);
>> + char *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 d1314bdbf7d5..c7778860f3d4 100644
>> --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>> +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
>> @@ -1095,7 +1095,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];
>> diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
>> index 4b6a9d2ea372..5b1e3d801546 100644
>> --- a/include/media/videobuf2-core.h
>> +++ b/include/media/videobuf2-core.h
>> @@ -1244,6 +1244,32 @@ static inline struct vb2_buffer *vb2_get_buffer(struct vb2_queue *q,
>> return NULL;
>> }
>>
>> +/**
>> + * 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.
>> + */
>> +static inline bool vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
> Could we make index an argument to this function and actually assign it to
> vb->index if the operation succeeds?
> Similarly, could we assign q to vb->vb2_queue in this function as well?
>
> I have plans to make the vb2_buffer struct represent a buffer, rather than
> an entry in the queue, because the memory can actually outlive the queue,
> e.g. when REQBUFS(0) happens, but an exported DMA-buf still references the
> buffer. Currently the DMA-buf object is tied to the allocator-private
> struct, but that one has a pointer to a vb2_buffer, which becomes invalid
> in such scenario with current implementation.
I will do that in v3.
>
>> +{
>> + if (vb->index < VB2_MAX_FRAME) {
>> + q->bufs[vb->index] = vb;
>> + 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 inline void vb2_queue_remove_buffer(struct vb2_queue *q, struct vb2_buffer *vb)
>> +{
>> + if (vb->index < VB2_MAX_FRAME)
>> + q->bufs[vb->index] = NULL;
> Here we could also NULLify vb->vb2_queue. Right now I think the struct
> would be just kfree()d instantly after returning to the caller, but with
> the design I mentioned above, it could still stay there until the last
> reference goes away.
Same I will do that in v3.
Thanks for your feedback.
Benjamin
>
> Best regards,
> Tomasz
>
More information about the Linux-mediatek
mailing list