Re: [PATCH v2 1/3] media: videobuf2-core: release all planes first in __prepare_dmabuf()

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

 



Hi Tomasz,

Thanks for the review.

On Fri, May 17, 2024 at 8:11 PM Tomasz Figa <tfiga@xxxxxxxxxxxx> wrote:
>
> Hi Yunke,
>
> On Wed, Apr 03, 2024 at 06:13:04PM +0900, Yunke Cao wrote:
> > The existing implementation, validating planes, checking if the planes
> > changed, releasing previous planes and reaquiring new planes all happens in
> > the same for loop.
> >
> > Split the for loop into 3 parts
> > 1. In the first for loop, validate planes and check if planes changed.
> > 2. Call __vb2_buf_dmabuf_put() to release all planes.
> > 3. In the second for loop, reaquire new planes.
> >
> > Signed-off-by: Yunke Cao <yunkec@xxxxxxxxxxxx>
> > ---
> >  .../media/common/videobuf2/videobuf2-core.c   | 64 ++++++++++---------
> >  1 file changed, 34 insertions(+), 30 deletions(-)
> >
>
> Thanks for the second revision and sorry for the delay. Please check my
> comments inline.
>
> > diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> > index b6bf8f232f48..702f7b6f783a 100644
> > --- a/drivers/media/common/videobuf2/videobuf2-core.c
> > +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> > @@ -1341,11 +1341,13 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
> >       for (plane = 0; plane < vb->num_planes; ++plane) {
> >               struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd);
> >
> > +             planes[plane].dbuf = dbuf;
> > +
> >               if (IS_ERR_OR_NULL(dbuf)) {
> >                       dprintk(q, 1, "invalid dmabuf fd for plane %d\n",
> >                               plane);
> >                       ret = -EINVAL;
> > -                     goto err;
> > +                     goto err_put_dbuf;
>
> nit: Maybe err_put_planes, since we're cleaning up the planes[] array?
>

err_put_planes sounds good to me.

> >               }
> >
> >               /* use DMABUF size if length is not provided */
> > @@ -1356,17 +1358,14 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
> >                       dprintk(q, 1, "invalid dmabuf length %u for plane %d, minimum length %u\n",
> >                               planes[plane].length, plane,
> >                               vb->planes[plane].min_length);
> > -                     dma_buf_put(dbuf);
> >                       ret = -EINVAL;
> > -                     goto err;
> > +                     goto err_put_dbuf;
> >               }
> >
> >               /* Skip the plane if already verified */
> >               if (dbuf == vb->planes[plane].dbuf &&
> > -                     vb->planes[plane].length == planes[plane].length) {
> > -                     dma_buf_put(dbuf);
> > +                 vb->planes[plane].length == planes[plane].length)
> >                       continue;
> > -             }
> >
> >               dprintk(q, 3, "buffer for plane %d changed\n", plane);
> >
> > @@ -1375,29 +1374,30 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
> >                       vb->copied_timestamp = 0;
> >                       call_void_vb_qop(vb, buf_cleanup, vb);
>
> Would it make sense to also move these two to the if (reacquired) part
> below, since they are done once for the entire vb?
>

Yes, Will do in the next version.

> >               }
> > +     }
> >
> > -             /* Release previously acquired memory if present */
> > -             __vb2_plane_dmabuf_put(vb, &vb->planes[plane]);
> > -             vb->planes[plane].bytesused = 0;
> > -             vb->planes[plane].length = 0;
> > -             vb->planes[plane].m.fd = 0;
> > -             vb->planes[plane].data_offset = 0;
>
> I don't see the code below setting the 4 fields above to zero. Is it
> intended?
>

I thought these were not necessary anymore.
But now that I look more carefully, it is useful when there is an error below.
I will add them back in the next version. Thanks for catching this!

> > +     if (reacquired) {
> > +             __vb2_buf_dmabuf_put(vb);
> > +
> > +             for (plane = 0; plane < vb->num_planes; ++plane) {
> > +                     /* Acquire each plane's memory */
> > +                     mem_priv = call_ptr_memop(attach_dmabuf,
> > +                                               vb,
> > +                                               q->alloc_devs[plane] ? : q->dev,
> > +                                               planes[plane].dbuf,
> > +                                               planes[plane].length);
> > +                     if (IS_ERR(mem_priv)) {
> > +                             dprintk(q, 1, "failed to attach dmabuf\n");
> > +                             ret = PTR_ERR(mem_priv);
> > +                             goto err_put_dbuf;
>
> Hmm, I think in this case we need to also clean up the partially acquired
> planes of vb.
>
> > +                     }
> >
> > -             /* Acquire each plane's memory */
> > -             mem_priv = call_ptr_memop(attach_dmabuf,
> > -                                       vb,
> > -                                       q->alloc_devs[plane] ? : q->dev,
> > -                                       dbuf,
> > -                                       planes[plane].length);
> > -             if (IS_ERR(mem_priv)) {
> > -                     dprintk(q, 1, "failed to attach dmabuf\n");
> > -                     ret = PTR_ERR(mem_priv);
> > -                     dma_buf_put(dbuf);
> > -                     goto err;
> > +                     vb->planes[plane].dbuf = planes[plane].dbuf;
> > +                     vb->planes[plane].mem_priv = mem_priv;
> >               }
> > -
> > -             vb->planes[plane].dbuf = dbuf;
> > -             vb->planes[plane].mem_priv = mem_priv;
> > +     } else {
> > +             for (plane = 0; plane < vb->num_planes; ++plane)
> > +                     dma_buf_put(planes[plane].dbuf);
> >       }
> >
> >       /*
> > @@ -1413,7 +1413,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
> >               if (ret) {
> >                       dprintk(q, 1, "failed to map dmabuf for plane %d\n",
> >                               plane);
> > -                     goto err;
> > +                     goto err_put_vb2_buf;
> >               }
> >               vb->planes[plane].dbuf_mapped = 1;
> >       }
>
> I think this entire loop can also go under the (reacquired) case, since
> (!reacquired) means that all the planes were identical (and thus are
> alreday mapped). Given that now we release all the planes in one go, we
> could even simplify it by dropping the dbuf_mapped check from the loop.
>
> > @@ -1437,7 +1437,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
> >               ret = call_vb_qop(vb, buf_init, vb);
> >               if (ret) {
> >                       dprintk(q, 1, "buffer initialization failed\n");
> > -                     goto err;
> > +                     goto err_put_vb2_buf;
> >               }
> >       }
>
> Same for this block.
>
> >
> > @@ -1445,11 +1445,15 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
> >       if (ret) {
> >               dprintk(q, 1, "buffer preparation failed\n");
> >               call_void_vb_qop(vb, buf_cleanup, vb);
> > -             goto err;
> > +             goto err_put_vb2_buf;
> >       }
> >
> >       return 0;
> > -err:
> > +
> > +err_put_dbuf:
> > +     for (plane = 0; plane < vb->num_planes; ++plane)
>
> dma_buf_put() will throw a warning if the dmabuf pointer is NULL and just
> plain crash if IS_ERR(), so we shouldn't call it on array elements that we
> didn't succeed for.
>

I see. Will do in the next version.

> > +             dma_buf_put(planes[plane].dbuf);
> > +err_put_vb2_buf:
> >       /* In case of errors, release planes that were already acquired */
> >       __vb2_buf_dmabuf_put(vb);
>
> Actually, would it make sense to invert the order of clean-up steps here?
> In case if only the first loop fails, we don't really need to do anything with
> vb. Or am I missing something?
>

It seems the original implementation will call __vb2_buf_dmabuf_put(vb)
whenever dma_buf_get() returns err or length < min_length. I was trying
to keep the same behavior here. Do you have any preference?

Also, if "call_vb_qop(vb, buf_prepare, vb);" fails, I think we only need
__vb2_buf_dmabuf_put(), but not dma_buf_put().

Best,
Yunke

> Best regards,
> Tomasz





[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