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

