Re: [PATCH v5 5/5] media: virtio: Add USERPTR memory type support

Brian Daniels <[email protected]>
Newsgroups org.kernel.vger.linux-media,dev.linux.lists.virtualization,org.kernel.vger.linux-kernel
Message-ID <CAD4i_GSRAWxepyWrEDrNyPerzPr275Z=gWT+JF8Y8-HskOZ+Bw@mail.gmail.com>
On Mon, Aug 10, 2026 at 7:21 AM Laurent Pinchart
<[email protected]> wrote:
>
> On Thu, Jul 23, 2026 at 02:32:19PM -0400, Brian Daniels wrote:
> > From: Alexandre Courbot <[email protected]>
> >
> > This patch adds support for the USERPTR memory type to the virtio-media
> > driver.
> >
> > It adds the allow_userptr module parameter, implements the userptr
> > mapping logic in the scatterlist builder, and enables USERPTR in
> > reqbufs if allowed.
>
> USERPTR is deprecated, it shouldn't be used in new drivers or in new
> userspace code.

Good to know. Shall I remove this patch from the next revision then?

> > Signed-off-by: Alexandre Courbot <[email protected]>
> > Assisted-by: Antigravity:gemini-3.5-flash
> > Co-developed-by: Brian Daniels <[email protected]>
> > Signed-off-by: Brian Daniels <[email protected]>
> > ---
> >  drivers/media/virtio/scatterlist_builder.c | 64 ++++++++++++++++++++++
> >  drivers/media/virtio/scatterlist_builder.h |  3 +
> >  drivers/media/virtio/virtio_media_driver.c | 42 +++++++++-----
> >  drivers/media/virtio/virtio_media_ioctls.c | 11 +++-
> >  4 files changed, 104 insertions(+), 16 deletions(-)
> >
> > diff --git a/drivers/media/virtio/scatterlist_builder.c b/drivers/media/virtio/scatterlist_builder.c
> > index 97925b277..85c6a36b4 100644
> > --- a/drivers/media/virtio/scatterlist_builder.c
> > +++ b/drivers/media/virtio/scatterlist_builder.c
> > @@ -349,14 +349,30 @@ static int scatterlist_builder_add_userptr(struct scatterlist_builder *builder,
> >  int scatterlist_builder_add_buffer(struct scatterlist_builder *builder,
> >                                  struct v4l2_buffer *b)
> >  {
> > +     int i;
> >       int ret;
> >
> > +     /* Fixup: plane length must be zero if userptr is NULL */
> > +     if (!V4L2_TYPE_IS_MULTIPLANAR(b->type) &&
> > +         b->memory == V4L2_MEMORY_USERPTR && b->m.userptr == 0)
> > +             b->length = 0;
> > +
> >       /* v4l2_buffer */
> >       ret = scatterlist_builder_add_data(builder, b, sizeof(*b));
> >       if (ret)
> >               return ret;
> >
> >       if (V4L2_TYPE_IS_MULTIPLANAR(b->type) && b->length > 0) {
> > +             /* Fixup: plane length must be zero if userptr is NULL */
> > +             if (b->memory == V4L2_MEMORY_USERPTR) {
> > +                     for (i = 0; i < b->length; i++) {
> > +                             struct v4l2_plane *plane = &b->m.planes[i];
> > +
> > +                             if (plane->m.userptr == 0)
> > +                                     plane->length = 0;
> > +                     }
> > +             }
> > +
> >               /* Array of v4l2_planes */
> >               ret = scatterlist_builder_add_data(builder, b->m.planes,
> >                                                  sizeof(struct v4l2_plane) *
> > @@ -368,6 +384,54 @@ int scatterlist_builder_add_buffer(struct scatterlist_builder *builder,
> >       return 0;
> >  }
> >
> > +/**
> > + * scatterlist_builder_add_buffer_userptr() - Add the payload of a ``USERPTR``
> > + *                                            &struct v4l2_buffer to the
> > + *                                            descriptor chain.
> > + * @builder: builder to use.
> > + * @b: &struct v4l2_buffer whose ``USERPTR`` payload we want to add.
> > + *
> > + * Add an array of &struct virtio_media_sg_entry pointing to a ``USERPTR``
> > + * buffer's contents. Does nothing if the buffer is not of type ``USERPTR``.
> > + * This is split out of scatterlist_builder_add_buffer() because we only want
> > + * to add these to the device-readable part of the descriptor chain.
> > + */
> > +int scatterlist_builder_add_buffer_userptr(struct scatterlist_builder *builder,
> > +                                        struct v4l2_buffer *b)
> > +{
> > +     int i;
> > +     int ret;
> > +
> > +     if (b->memory != V4L2_MEMORY_USERPTR)
> > +             return 0;
> > +
> > +     if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
> > +             for (i = 0; i < b->length; i++) {
> > +                     struct v4l2_plane *plane = &b->m.planes[i];
> > +
> > +                     if (b->memory == V4L2_MEMORY_USERPTR &&
> > +                         plane->length > 0) {
> > +                             unsigned long uptr = plane->m.userptr;
> > +                             unsigned long len = plane->length;
> > +
> > +                             ret =
> > +                             scatterlist_builder_add_userptr(builder,
> > +                                                             uptr,
> > +                                                             len);
> > +                             if (ret)
> > +                                     return ret;
> > +                     }
> > +             }
> > +     } else if (b->length > 0) {
> > +             ret = scatterlist_builder_add_userptr(builder, b->m.userptr,
> > +                                                   b->length);
> > +             if (ret)
> > +                     return ret;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> >  /**
> >   * scatterlist_builder_retrieve_buffer() - Retrieve a &struct v4l2_buffer
> >   *                                         written by the device on the shadow
> > diff --git a/drivers/media/virtio/scatterlist_builder.h b/drivers/media/virtio/scatterlist_builder.h
> > index 47bfd7ae0..53d964a48 100644
> > --- a/drivers/media/virtio/scatterlist_builder.h
> > +++ b/drivers/media/virtio/scatterlist_builder.h
> > @@ -90,6 +90,9 @@ int scatterlist_builder_add_ioctl_resp(struct scatterlist_builder *builder,
> >  int scatterlist_builder_add_buffer(struct scatterlist_builder *builder,
> >                                  struct v4l2_buffer *buffer);
> >
> > +int scatterlist_builder_add_buffer_userptr(struct scatterlist_builder *builder,
> > +                                        struct v4l2_buffer *b);
> > +
> >  int scatterlist_builder_retrieve_buffer(struct scatterlist_builder *builder,
> >                                       size_t sg_index,
> >                                       struct v4l2_buffer *buffer,
> > diff --git a/drivers/media/virtio/virtio_media_driver.c b/drivers/media/virtio/virtio_media_driver.c
> > index c431c3eb2..b6f79593d 100644
> > --- a/drivers/media/virtio/virtio_media_driver.c
> > +++ b/drivers/media/virtio/virtio_media_driver.c
> > @@ -7,26 +7,29 @@
> >   */
> >
> >  #include <linux/bits.h>
> > +#include <linux/delay.h>
> >  #include <linux/device.h>
> >  #include <linux/dev_printk.h>
> > +#include <linux/mm.h>
> >  #include <linux/mutex.h>
> > +#include <linux/scatterlist.h>
> >  #include <linux/types.h>
> > +#include <linux/videodev2.h>
> > +#include <linux/vmalloc.h>
> > +#include <linux/wait.h>
> > +#include <linux/workqueue.h>
> >  #include <linux/module.h>
> > +#include <linux/moduleparam.h>
> >  #include <linux/virtio.h>
> >  #include <linux/virtio_config.h>
> >  #include <linux/virtio_ids.h>
> > -#include <linux/slab.h>
> > -#include <linux/scatterlist.h>
> > -#include <linux/vmalloc.h>
> > -#include <linux/workqueue.h>
> > -#include <linux/dma-mapping.h>
> > -#include <linux/poll.h>
> > -#include <linux/mm.h>
> >
> > +#include <media/frame_vector.h>
> >  #include <media/v4l2-dev.h>
> > -#include <media/v4l2-device.h>
> > -#include <media/v4l2-fh.h>
> >  #include <media/v4l2-event.h>
> > +#include <media/videobuf2-memops.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-ioctl.h>
> >
> >  #include "uapi/linux/virtio_media.h"
> >  #include "session.h"
> > @@ -40,6 +43,15 @@
> >  /* Bit mask for the VIRTIO_MEDIA_MMAP_FLAG_RW flag */
> >  #define VIRTIO_MEDIA_MMAP_FLAG_RW_MASK BIT(VIRTIO_MEDIA_MMAP_FLAG_RW)
> >
> > +/*
> > + * Whether USERPTR buffers are allowed.
> > + *
> > + * This is disabled by default as USERPTR buffers are dangerous, but the option
> > + * is left to enable them if desired.
> > + */
> > +bool virtio_media_allow_userptr;
> > +module_param_named(allow_userptr, virtio_media_allow_userptr, bool, 0660);
> > +
> >  /**
> >   * virtio_media_session_alloc() - Allocate a new session.
> >   * @vv: virtio-media device the session belongs to.
> > @@ -849,15 +861,11 @@ static int virtio_media_probe(struct virtio_device *virtio_dev)
> >                             VIRTIO_MEDIA_SHM_MMAP);
> >
> >       vd = &vv->video_dev;
> > +
> >       vd->v4l2_dev = &vv->v4l2_dev;
> >       vd->vfl_type = VFL_TYPE_VIDEO;
> >       vd->ioctl_ops = &virtio_media_ioctl_ops;
> >       vd->fops = &virtio_media_fops;
> > -     vd->release = video_device_release_empty;
> > -     strscpy(vd->name, "virtio-media", sizeof(vd->name));
> > -
> > -     video_set_drvdata(vd, vv);
> > -
> >       vd->device_caps = virtio_cread32(virtio_dev, 0);
> >       if (vd->device_caps & (V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE))
> >               vd->vfl_dir = VFL_DIR_M2M;
> > @@ -866,6 +874,10 @@ static int virtio_media_probe(struct virtio_device *virtio_dev)
> >               vd->vfl_dir = VFL_DIR_TX;
> >       else
> >               vd->vfl_dir = VFL_DIR_RX;
> > +     vd->release = video_device_release_empty;
> > +     strscpy(vd->name, "virtio-media", sizeof(vd->name));
> > +
> > +     video_set_drvdata(vd, vv);
> >
> >       ret = video_register_device(vd, virtio_cread32(virtio_dev, 4), 0);
> >       if (ret)
> > @@ -890,6 +902,7 @@ static int virtio_media_probe(struct virtio_device *virtio_dev)
> >       virtio_dev->config->del_vqs(virtio_dev);
> >  err_find_vqs:
> >       v4l2_device_unregister(&vv->v4l2_dev);
> > +
> >       return ret;
> >  }
> >
> > @@ -900,6 +913,7 @@ static void virtio_media_remove(struct virtio_device *virtio_dev)
> >
> >       cancel_work_sync(&vv->eventq_work);
> >       virtio_reset_device(virtio_dev);
> > +
> >       v4l2_device_unregister(&vv->v4l2_dev);
> >       virtio_dev->config->del_vqs(virtio_dev);
> >       video_unregister_device(&vv->video_dev);
> > diff --git a/drivers/media/virtio/virtio_media_ioctls.c b/drivers/media/virtio/virtio_media_ioctls.c
> > index f0b82b5ec..88465f239 100644
> > --- a/drivers/media/virtio/virtio_media_ioctls.c
> > +++ b/drivers/media/virtio/virtio_media_ioctls.c
> > @@ -273,6 +273,12 @@ static int virtio_media_send_buffer_ioctl(struct v4l2_fh *fh, u32 ioctl,
> >               return ret;
> >
> >       end_buf_sg = builder.cur_sg;
> > +
> > +     /* Payload of SHARED_PAGES buffers, if relevant */
> > +     ret = scatterlist_builder_add_buffer_userptr(&builder, b);
> > +     if (ret < 0)
> > +             return ret;
> > +
> >       num_cmd_sgs = builder.cur_sg;
> >
> >       /* Response descriptor */
> > @@ -719,7 +725,7 @@ static int virtio_media_reqbufs(struct file *file, void *fh,
> >       if (b->type > VIRTIO_MEDIA_LAST_QUEUE)
> >               return -EINVAL;
> >
> > -     if (b->memory == V4L2_MEMORY_USERPTR)
> > +     if (b->memory == V4L2_MEMORY_USERPTR && !virtio_media_allow_userptr)
> >               return -EINVAL;
> >
> >       ret = virtio_media_send_wr_ioctl(vfh, VIDIOC_REQBUFS, b, sizeof(*b),
> > @@ -752,7 +758,8 @@ static int virtio_media_reqbufs(struct file *file, void *fh,
> >       if (V4L2_TYPE_IS_MULTIPLANAR(b->type))
> >               session->uses_mplane = true;
> >
> > -     b->capabilities &= ~V4L2_BUF_CAP_SUPPORTS_USERPTR;
> > +     if (!virtio_media_allow_userptr)
> > +             b->capabilities &= ~V4L2_BUF_CAP_SUPPORTS_USERPTR;
> >
> >       /* We do not support DMABUF yet. */
> >       b->capabilities &= ~V4L2_BUF_CAP_SUPPORTS_DMABUF;
>
> --
> Regards,
>
> Laurent Pinchart
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.