Re: [PATCH] media: vb2: refactor setting flags and caps, fix missing cap

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 1/18/24 12:14, Tomasz Figa wrote:
> Hi Hans,
> 
> On Tue, Jan 16, 2024 at 11:05 PM Hans Verkuil <hverkuil-cisco@xxxxxxxxx> wrote:
>>
>> Several functions implementing VIDIOC_REQBUFS and _CREATE_BUFS all use almost
>> the same code to fill in the flags and capability fields. Refactor this into a
>> new vb2_set_flags_and_caps() function that replaces the old fill_buf_caps()
>> and validate_memory_flags() functions.
>>
>> This also fixes a bug where vb2_ioctl_create_bufs() would not set the
>> V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS cap and also not fill in the
>> max_num_buffers field.
>>
>> Fixes: d055a76c0065 ("media: core: Report the maximum possible number of buffers for the queue")
>> Signed-off-by: Hans Verkuil <hverkuil-cisco@xxxxxxxxx>
>> ---
>>  .../media/common/videobuf2/videobuf2-v4l2.c   | 55 +++++++++----------
>>  1 file changed, 26 insertions(+), 29 deletions(-)
>>
> 
> Thanks for the patch! Please check my comments inline.
> 
>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> index 54d572c3b515..c575198e8354 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> @@ -671,8 +671,20 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
>>  }
>>  EXPORT_SYMBOL(vb2_querybuf);
>>
>> -static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
>> +static void vb2_set_flags_and_caps(struct vb2_queue *q, u32 memory,
>> +                                  u32 *flags, u32 *caps, u32 *max_num_bufs)
>>  {
>> +       if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) {
>> +               /*
>> +                * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only,
>> +                * but in order to avoid bugs we zero out all bits.
>> +                */
>> +               *flags = 0;
>> +       } else {
>> +               /* Clear all unknown flags. */
>> +               *flags &= V4L2_MEMORY_FLAG_NON_COHERENT;
>> +       }
>> +
>>         *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
>>         if (q->io_modes & VB2_MMAP)
>>                 *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
>> @@ -686,21 +698,9 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
>>                 *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS;
>>         if (q->supports_requests)
>>                 *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS;
>> -}
>> -
>> -static void validate_memory_flags(struct vb2_queue *q,
>> -                                 int memory,
>> -                                 u32 *flags)
>> -{
>> -       if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) {
>> -               /*
>> -                * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only,
>> -                * but in order to avoid bugs we zero out all bits.
>> -                */
>> -               *flags = 0;
>> -       } else {
>> -               /* Clear all unknown flags. */
>> -               *flags &= V4L2_MEMORY_FLAG_NON_COHERENT;
>> +       if (max_num_bufs) {
>> +               *max_num_bufs = q->max_num_buffers;
>> +               *caps |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS;
>>         }
>>  }
>>
>> @@ -709,8 +709,8 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
>>         int ret = vb2_verify_memory_type(q, req->memory, req->type);
>>         u32 flags = req->flags;
> 
> I think we have a bug here, we check the memory type, but just let the
> code continue even if it's invalid.

It should be harmless. The old code did the same, BTW.

> 
>>
>> -       fill_buf_caps(q, &req->capabilities);
>> -       validate_memory_flags(q, req->memory, &flags);
>> +       vb2_set_flags_and_caps(q, req->memory, &flags,
>> +                              &req->capabilities, NULL);
>>         req->flags = flags;
>>         return ret ? ret : vb2_core_reqbufs(q, req->memory,
>>                                             req->flags, &req->count);
>> @@ -751,11 +751,9 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
>>         int ret = vb2_verify_memory_type(q, create->memory, f->type);
>>         unsigned i;
>>
> 
> Ditto.
> 
>> -       fill_buf_caps(q, &create->capabilities);
>> -       validate_memory_flags(q, create->memory, &create->flags);
>>         create->index = vb2_get_num_buffers(q);
>> -       create->max_num_buffers = q->max_num_buffers;
>> -       create->capabilities |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS;
>> +       vb2_set_flags_and_caps(q, create->memory, &create->flags,
>> +                              &create->capabilities, &create->max_num_buffers);
>>         if (create->count == 0)
>>                 return ret != -EBUSY ? ret : 0;
>>
>> @@ -1006,8 +1004,8 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv,
>>         int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
>>         u32 flags = p->flags;
>>
>> -       fill_buf_caps(vdev->queue, &p->capabilities);
>> -       validate_memory_flags(vdev->queue, p->memory, &flags);
>> +       vb2_set_flags_and_caps(vdev->queue, p->memory, &flags,
>> +                              &p->capabilities, NULL);
> 
> Could we just call vb2_reqbufs() instead of vb2_core_reqbufs() and
> avoid all the duplicate checks?
> 
>>         p->flags = flags;
>>         if (res)
>>                 return res;
>> @@ -1026,12 +1024,11 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
>>                           struct v4l2_create_buffers *p)
>>  {
>>         struct video_device *vdev = video_devdata(file);
>> -       int res = vb2_verify_memory_type(vdev->queue, p->memory,
>> -                       p->format.type);
>> +       int res = vb2_verify_memory_type(vdev->queue, p->memory, p->format.type);
>>
>> -       p->index = vdev->queue->num_buffers;
>> -       fill_buf_caps(vdev->queue, &p->capabilities);
>> -       validate_memory_flags(vdev->queue, p->memory, &p->flags);
>> +       p->index = vb2_get_num_buffers(vdev->queue);
>> +       vb2_set_flags_and_caps(vdev->queue, p->memory, &p->flags,
>> +                              &p->capabilities, &p->max_num_buffers);
> 
> This function in fact already calls vb2_create_bufs() which includes
> all the checks above, except the one for vb2_queue_is_bus() that
> continues down below, so maybe we can just remove them?

Same answer for both reqbufs and create_bufs: it has to do with the
order in which checks are done.

When using vb2_ioctl_reqbufs you want to first check vb2_verify_memory_type()
and return if that's wrong. Next you check if the queue is busy and return
-EBUSY. Only then do you call vb2_core_reqbufs() (or vb2_create_bufs()).

Note that this is a fixes patch (that should have been in the subject, sorry
for that), and I don't want to make more changes than strictly necessary.

What really should happen is that the last users of vb2_reqbufs and
vb2_create_bufs are converted to use vb2_ioctl_reqbufs/create_bufs. But
that's another story.

Regards,

	Hans

> 
> Best regards,
> Tomasz
> 
>>         /*
>>          * If count == 0, then just check if memory and type are valid.
>>          * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.
>> --
>> 2.42.0
>>
>>





[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux