diff mbox series

[v3] media: videobuf2-dma-sg: fix vmap and vunmap callbacks

Message ID 20231031230435.3356103-1-m.grzeschik@pengutronix.de
State New
Headers show
Series [v3] media: videobuf2-dma-sg: fix vmap and vunmap callbacks | expand

Commit Message

Michael Grzeschik Oct. 31, 2023, 11:04 p.m. UTC
For dmabuf import users to be able to use the vaddr from another
videobuf2-dma-sg source, the exporter needs to set a proper vaddr on
vb2_dma_sg_dmabuf_ops_vmap callback.

This patch adds vmap on map if buf->vaddr was not set, and also
adds the vb2_dma_sg_dmabuf_ops_vunmap function to remove the mapping
afterwards.

Cc: stable@kernel.org
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>

---
v2 -> v3: resend as a single patch
v1 -> v2: using vmap and vunmap instead of vm_map_ram and vm_unmap_ram

 .../media/common/videobuf2/videobuf2-dma-sg.c    | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

Tomasz Figa Nov. 21, 2023, 4:10 a.m. UTC | #1
Hi Hans,


On Mon, Nov 20, 2023 at 10:27 PM Hans Verkuil <hverkuil@xs4all.nl> wrote:
>
> Tomasz,
>
> Can you review this?

I did review it a few weeks ago, with some comments pending:
https://patchwork.kernel.org/project/linux-media/patch/20231031230435.3356103-1-m.grzeschik@pengutronix.de/#25577798

Best,
Tomasz

>
> Michael, I have one comment below:
>
> On 01/11/2023 00:04, Michael Grzeschik wrote:
> > For dmabuf import users to be able to use the vaddr from another
> > videobuf2-dma-sg source, the exporter needs to set a proper vaddr on
> > vb2_dma_sg_dmabuf_ops_vmap callback.
> >
> > This patch adds vmap on map if buf->vaddr was not set, and also
> > adds the vb2_dma_sg_dmabuf_ops_vunmap function to remove the mapping
> > afterwards.
> >
> > Cc: stable@kernel.org
> > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> >
> > ---
> > v2 -> v3: resend as a single patch
> > v1 -> v2: using vmap and vunmap instead of vm_map_ram and vm_unmap_ram
> >
> >  .../media/common/videobuf2/videobuf2-dma-sg.c    | 16 ++++++++++++++++
> >  1 file changed, 16 insertions(+)
> >
> > diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
> > index 28f3fdfe23a298..05b43edda94a7e 100644
> > --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
> > +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
> > @@ -489,11 +489,26 @@ static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf,
> >  {
> >       struct vb2_dma_sg_buf *buf = dbuf->priv;
> >
> > +     if (!buf->vaddr)
> > +             buf->vaddr = vmap(buf->pages, buf->num_pages, VM_MAP,
> > +                               PAGE_KERNEL);
>
> Shouldn't this check for success and return an error code if it fails?
>
> Regards,
>
>         Hans
>
> > +
> >       iosys_map_set_vaddr(map, buf->vaddr);
> >
> >       return 0;
> >  }
> >
> > +static void vb2_dma_sg_dmabuf_ops_vunmap(struct dma_buf *dbuf,
> > +                                   struct iosys_map *map)
> > +{
> > +     struct vb2_dma_sg_buf *buf = dbuf->priv;
> > +
> > +     if (buf->vaddr)
> > +             vunmap(buf->vaddr);
> > +
> > +     buf->vaddr = NULL;
> > +}
> > +
> >  static int vb2_dma_sg_dmabuf_ops_mmap(struct dma_buf *dbuf,
> >       struct vm_area_struct *vma)
> >  {
> > @@ -508,6 +523,7 @@ static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = {
> >       .begin_cpu_access = vb2_dma_sg_dmabuf_ops_begin_cpu_access,
> >       .end_cpu_access = vb2_dma_sg_dmabuf_ops_end_cpu_access,
> >       .vmap = vb2_dma_sg_dmabuf_ops_vmap,
> > +     .vunmap = vb2_dma_sg_dmabuf_ops_vunmap,
> >       .mmap = vb2_dma_sg_dmabuf_ops_mmap,
> >       .release = vb2_dma_sg_dmabuf_ops_release,
> >  };
>
Michael Grzeschik Nov. 21, 2023, 1:30 p.m. UTC | #2
On Wed, Nov 01, 2023 at 12:48:21PM +0900, Tomasz Figa wrote:
>Hi Michael,
>
>
>On Wed, Nov 1, 2023 at 8:04 AM Michael Grzeschik
><m.grzeschik@pengutronix.de> wrote:
>>
>> For dmabuf import users to be able to use the vaddr from another
>> videobuf2-dma-sg source, the exporter needs to set a proper vaddr on
>> vb2_dma_sg_dmabuf_ops_vmap callback.
>>
>> This patch adds vmap on map if buf->vaddr was not set, and also
>> adds the vb2_dma_sg_dmabuf_ops_vunmap function to remove the mapping
>> afterwards.
>>
>> Cc: stable@kernel.org
>> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
>>
>> ---
>> v2 -> v3: resend as a single patch
>> v1 -> v2: using vmap and vunmap instead of vm_map_ram and vm_unmap_ram
>>
>
>First of all, thanks for the patch!
>
>Please check my comments inline.
>
>>  .../media/common/videobuf2/videobuf2-dma-sg.c    | 16 ++++++++++++++++
>>  1 file changed, 16 insertions(+)
>>
>> diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
>> index 28f3fdfe23a298..05b43edda94a7e 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
>> @@ -489,11 +489,26 @@ static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf,
>>  {
>>         struct vb2_dma_sg_buf *buf = dbuf->priv;
>>
>> +       if (!buf->vaddr)
>> +               buf->vaddr = vmap(buf->pages, buf->num_pages, VM_MAP,
>> +                                 PAGE_KERNEL);
>> +
>
>Would it make sense to use vb2_dma_sg_vaddr() instead of open coding
>the mapping again?
>

So in the end the whole patch would look like this:

	buf->vaddr = vb2_dma_sg_vaddr(NULL, buf);
	if (!buf->vaddr)
		return -ENOMEM;

>>         iosys_map_set_vaddr(map, buf->vaddr);
>>
>>         return 0;
>>  }
>>
>> +static void vb2_dma_sg_dmabuf_ops_vunmap(struct dma_buf *dbuf,
>> +                                     struct iosys_map *map)
>> +{
>> +       struct vb2_dma_sg_buf *buf = dbuf->priv;
>> +
>> +       if (buf->vaddr)
>> +               vunmap(buf->vaddr);
>> +
>> +       buf->vaddr = NULL;
>> +}
>
>This could be potentially dangerous. Please consider the situation
>when the exporting V4L2 driver needs the CPU mapping for its own
>usage. It would call vb2_dma_sg_vaddr(), which would return the
>mapping. Then the importer could call vunmap, which would destroy the
>mapping that is still in use by the exporter internally.
>
>The idea of the current implementation is that we just create a kernel
>mapping when it's needed first and just keep it around until the
>entire buffer is destroyed.

In this patch I will drop the while vunmap callback then.

Michael
Tomasz Figa Nov. 22, 2023, 5:49 a.m. UTC | #3
On Tue, Nov 21, 2023 at 10:30 PM Michael Grzeschik <mgr@pengutronix.de> wrote:
>
> On Wed, Nov 01, 2023 at 12:48:21PM +0900, Tomasz Figa wrote:
> >Hi Michael,
> >
> >
> >On Wed, Nov 1, 2023 at 8:04 AM Michael Grzeschik
> ><m.grzeschik@pengutronix.de> wrote:
> >>
> >> For dmabuf import users to be able to use the vaddr from another
> >> videobuf2-dma-sg source, the exporter needs to set a proper vaddr on
> >> vb2_dma_sg_dmabuf_ops_vmap callback.
> >>
> >> This patch adds vmap on map if buf->vaddr was not set, and also
> >> adds the vb2_dma_sg_dmabuf_ops_vunmap function to remove the mapping
> >> afterwards.
> >>
> >> Cc: stable@kernel.org
> >> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> >>
> >> ---
> >> v2 -> v3: resend as a single patch
> >> v1 -> v2: using vmap and vunmap instead of vm_map_ram and vm_unmap_ram
> >>
> >
> >First of all, thanks for the patch!
> >
> >Please check my comments inline.
> >
> >>  .../media/common/videobuf2/videobuf2-dma-sg.c    | 16 ++++++++++++++++
> >>  1 file changed, 16 insertions(+)
> >>
> >> diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
> >> index 28f3fdfe23a298..05b43edda94a7e 100644
> >> --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
> >> +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
> >> @@ -489,11 +489,26 @@ static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf,
> >>  {
> >>         struct vb2_dma_sg_buf *buf = dbuf->priv;
> >>
> >> +       if (!buf->vaddr)
> >> +               buf->vaddr = vmap(buf->pages, buf->num_pages, VM_MAP,
> >> +                                 PAGE_KERNEL);
> >> +
> >
> >Would it make sense to use vb2_dma_sg_vaddr() instead of open coding
> >the mapping again?
> >
>
> So in the end the whole patch would look like this:
>
>         buf->vaddr = vb2_dma_sg_vaddr(NULL, buf);
>         if (!buf->vaddr)
>                 return -ENOMEM;

Yes, but buf->vaddr is already updated by vb2_dma_sg_vaddr(), so we
should just save the return value to a local variable.

>
> >>         iosys_map_set_vaddr(map, buf->vaddr);
> >>
> >>         return 0;
> >>  }
> >>
> >> +static void vb2_dma_sg_dmabuf_ops_vunmap(struct dma_buf *dbuf,
> >> +                                     struct iosys_map *map)
> >> +{
> >> +       struct vb2_dma_sg_buf *buf = dbuf->priv;
> >> +
> >> +       if (buf->vaddr)
> >> +               vunmap(buf->vaddr);
> >> +
> >> +       buf->vaddr = NULL;
> >> +}
> >
> >This could be potentially dangerous. Please consider the situation
> >when the exporting V4L2 driver needs the CPU mapping for its own
> >usage. It would call vb2_dma_sg_vaddr(), which would return the
> >mapping. Then the importer could call vunmap, which would destroy the
> >mapping that is still in use by the exporter internally.
> >
> >The idea of the current implementation is that we just create a kernel
> >mapping when it's needed first and just keep it around until the
> >entire buffer is destroyed.
>
> In this patch I will drop the while vunmap callback then.

Ack.

I think in the long term we may want to rework vb2_plane_vaddr()
semantics so that the mapping can be reference counted, but that would
require quite a bit of a change around the vb2 framework and existing
drivers. (Has been on my list for a while...)

Best regards,
Tomasz
diff mbox series

Patch

diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
index 28f3fdfe23a298..05b43edda94a7e 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
@@ -489,11 +489,26 @@  static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf,
 {
 	struct vb2_dma_sg_buf *buf = dbuf->priv;
 
+	if (!buf->vaddr)
+		buf->vaddr = vmap(buf->pages, buf->num_pages, VM_MAP,
+				  PAGE_KERNEL);
+
 	iosys_map_set_vaddr(map, buf->vaddr);
 
 	return 0;
 }
 
+static void vb2_dma_sg_dmabuf_ops_vunmap(struct dma_buf *dbuf,
+				      struct iosys_map *map)
+{
+	struct vb2_dma_sg_buf *buf = dbuf->priv;
+
+	if (buf->vaddr)
+		vunmap(buf->vaddr);
+
+	buf->vaddr = NULL;
+}
+
 static int vb2_dma_sg_dmabuf_ops_mmap(struct dma_buf *dbuf,
 	struct vm_area_struct *vma)
 {
@@ -508,6 +523,7 @@  static const struct dma_buf_ops vb2_dma_sg_dmabuf_ops = {
 	.begin_cpu_access = vb2_dma_sg_dmabuf_ops_begin_cpu_access,
 	.end_cpu_access = vb2_dma_sg_dmabuf_ops_end_cpu_access,
 	.vmap = vb2_dma_sg_dmabuf_ops_vmap,
+	.vunmap = vb2_dma_sg_dmabuf_ops_vunmap,
 	.mmap = vb2_dma_sg_dmabuf_ops_mmap,
 	.release = vb2_dma_sg_dmabuf_ops_release,
 };