* [RFC PATCH v10 0/4] drm/virtio: userptr blobs for native-context compute
@ 2026-11-06 8:26 Honglei Huang
2026-11-06 8:26 ` [RFC PATCH v10 1/4] drm/virtio: add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Honglei Huang @ 2026-11-06 8:26 UTC (permalink / raw)
To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann
Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization,
linux-kernel, Honglei Huang
This series adds virtio-gpu userptr support for ROCm native compute
contexts. The guest kernel pins an existing userspace mapping with
FOLL_LONGTERM and exposes it to the host as ordinary CREATE_BLOB
backing entries, avoiding a second shmem allocation and memcpy.
A non-zero userptr field selects that path. Probe
VIRTGPU_PARAM_USERPTR before using the field so an older guest kernel
rejects the request instead of silently creating a shmem blob.
See overall detail in virglrenderer pr [1]
Patches overview:
1. Add VIRTIO_GPU_CAPSET_ROCM capability for compute workloads
2. Extend DRM/virtio UAPI with userptr, PARAM_USERPTR,
USE_READONLY, and F_BLOB_READONLY
3. Implement core userptr functionality with page management
4. Wire blob ioctl creation to userptr objects and probe the
readonly feature
V10 changes:
- Require DMA_ATTR_REQUIRE_COHERENT on create and restore mappings.
- Use drm_gem_object_put() after UUID assignment or handle creation
failure.
- Drop the new_pinned < 0 check.
- Validate the userptr address against the host's blob_alignment in
verify_blob().
V9 changes:
- Marked series RFC pending a virtio-gpu spec update for
F_BLOB_READONLY / BLOB_FLAG_USE_READONLY (Odaki)
- Moved VIRTIO_GPU_CAPSET_ROCM/VIRTGPU_DRM_CAPSET_ROCM from ID 8 to
10 to avoid the gfxstream/rutabaga_gfx 7-9 collision (Odaki)
- Added the missing VIRTGPU_DRM_CAPSET_ROCM alias (Odaki, sashiko-bot)
- Dropped the kernel/guest-internal wire-flag comment from the UAPI
header and reworded "Guest VA" to "address" in the userptr field
comment (Odaki)
- Fixed a BUG() on every virtio-gpu probe: VIRTIO_GPU_F_BLOB_READONLY
was queried with virtio_has_feature() but never added to the
driver's features[] array (Odaki)
- Removed the dead TRANSFER_TO_HOST userptr DMA-sync branches added
to virtgpu_vq.c; verify_blob() already rejects VIRTGPU_BLOB_MEM_GUEST
for that ioctl, so the branches were unreachable (Odaki)
- Documented the DMA mapping and bounce buffer behavior of
virtio_gpu_userptr_restore() and dropped the zero-copy claim from
the commit title and message (Odaki)
V8 changes:
- Drop guest-only USERPTR ioctl flags; a non-zero userptr field
selects the path
- Add VIRTGPU_PARAM_USERPTR so older kernels do not silently
ignore the new field
- Request GPU-readonly backing with virtio wire flag USE_READONLY
- Accept USE_READONLY and omit FOLL_WRITE only if the host
advertised VIRTIO_GPU_F_BLOB_READONLY
- Restore userptr blobs after hibernation without the shmem path
V7 changes:
- Mask guest-only DRM flags out of CREATE_BLOB wire blob_flags
- Clear userptr->pages after pin failure to avoid double-free
- DMA-map userptr SG only when virtio_gpu_use_dma_api() is required
- Use DMA_TO_DEVICE for readonly blobs
- Sync userptr SG for the device on TRANSFER_TO_HOST
- Mark writable pages dirty when unpinning
- Reject USERPTR unless blob_mem is VIRTGPU_BLOB_MEM_GUEST
- Disallow PRIME export of userptr objects
- Note that CAPSET_ROCM uses ID 8 because ID 7 is taken by VIRCL
V6 changes:
- Rebase onto drm-misc-next
- Keep USE_USERPTR / USERPTR_RDONLY as guest-only DRM flags; drop the
virtio wire-header patch (5 patches down to 4)
- Fix userptr lifetime, DMA mapping, memlock accounting, alignment
checks, and PRIME SG export
- Updated corresponding cover letter and commit messages
V5 changes:
- Add VIRTIO_GPU_BLOB_FLAG_USERPTR_RDONLY definition to patch 2
- Dropped unused VIRTIO_GPU_F_RESOURCE_USERPTR feature bit in patch 2
- Included VIRTIO_GPU_BLOB_FLAG_USERPTR_RDONLY in
VIRTGPU_BLOB_FLAG_USE_MASK in patch 5
- Add check for userptr feature in patch 5 before creating userptr blob resource
- Updated corresponding cover letter and commit messages
V4 changes:
- Renamed VIRTIO_GPU_CAPSET_HSAKMT to VIRTIO_GPU_CAPSET_ROCM
- Remove userptr feature probing cause it can reuse the guest
blob resource code path, reduce patch count from 6 to 5
- Updated corresponding commit messages
- Consolidated userptr feature detection in final patch
- Update corresponding cover letter content
V3 changes:
- Split into focused patches for easier review
- Removed complex interval tree userptr management
- Simplified resource creation without deduplication
- Added VIRTGPU_PARAM_RESOURCE_USERPTR for feature detection
- Improved UAPI documentation and error handling
- Removed MMU notifier dependencies for simplicity
- Fixed resource lifecycle management issues
V2: - Split add HSAKMT context and blob userptr resource to two patches.
- Remove MMU notifier related patches, cause use not moveable user space
memory with MMU notifier is not a good idea.
- Remove HSAKMT context check when create context, let all the context
support the userptr feature.
- Remove MMU notifier related content in cover letter.
- Add more comments for patch 6 in cover letter.
[1]: https://gitlab.freedesktop.org/virgl/virglrenderer/-/merge_requests/1708
Honglei Huang (4):
drm/virtio: add VIRTIO_GPU_CAPSET_ROCM capability
drm/virtio: add userptr blob resource to the UAPI
drm/virtio: implement userptr resource support
drm/virtio: wire blob ioctl creation to userptr objects
drivers/gpu/drm/virtio/Makefile | 3 +-
drivers/gpu/drm/virtio/virtgpu_debugfs.c | 1 +
drivers/gpu/drm/virtio/virtgpu_drv.c | 1 +
drivers/gpu/drm/virtio/virtgpu_drv.h | 42 +++
drivers/gpu/drm/virtio/virtgpu_ioctl.c | 49 +++-
drivers/gpu/drm/virtio/virtgpu_kms.c | 8 +-
drivers/gpu/drm/virtio/virtgpu_object.c | 22 ++
drivers/gpu/drm/virtio/virtgpu_userptr.c | 350 +++++++++++++++++++++++
include/uapi/drm/virtgpu_drm.h | 11 +
include/uapi/linux/virtio_gpu.h | 6 +
10 files changed, 480 insertions(+), 13 deletions(-)
create mode 100644 drivers/gpu/drm/virtio/virtgpu_userptr.c
base-commit: 1ecab8b0bad393750c60cc3819ce9c256595463c
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread* [RFC PATCH v10 1/4] drm/virtio: add VIRTIO_GPU_CAPSET_ROCM capability 2026-11-06 8:26 [RFC PATCH v10 0/4] drm/virtio: userptr blobs for native-context compute Honglei Huang @ 2026-11-06 8:26 ` Honglei Huang 2026-11-06 8:30 ` sashiko-bot 2026-11-06 8:26 ` [RFC PATCH v10 2/4] drm/virtio: add userptr blob resource to the UAPI Honglei Huang ` (2 subsequent siblings) 3 siblings, 1 reply; 9+ messages in thread From: Honglei Huang @ 2026-11-06 8:26 UTC (permalink / raw) To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization, linux-kernel, Honglei Huang Add a new GPU capability set VIRTIO_GPU_CAPSET_ROCM to support ROCm compute workloads in virtualized environments. ROCm (Radeon Open Compute) is AMD's open-source software platform for GPU compute and HPC workloads. ID 7 is already used by the OpenCL capset (VIRCL), and gfxstream's rutabaga_gfx has already claimed IDs 7-9 ahead of any spec or kernel header update, so ROCm uses ID 10 to avoid a further collision. A matching virtio-gpu specification change is in progress to register this assignment. Also add the matching VIRTGPU_DRM_CAPSET_ROCM alias in virtgpu_drm.h for consistency with the other capability sets exposed through DRM_IOCTL_VIRTGPU_GET_CAPS. Signed-off-by: Honglei Huang <honghuan@amd.com> --- include/uapi/drm/virtgpu_drm.h | 1 + include/uapi/linux/virtio_gpu.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index 95587e12ae..9b886e9772 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -170,6 +170,7 @@ struct drm_virtgpu_3d_wait { #define VIRTGPU_DRM_CAPSET_VENUS 4 #define VIRTGPU_DRM_CAPSET_CROSS_DOMAIN 5 #define VIRTGPU_DRM_CAPSET_DRM 6 +#define VIRTGPU_DRM_CAPSET_ROCM 10 struct drm_virtgpu_get_caps { __u32 cap_set_id; __u32 cap_set_ver; diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h index 4f530d9005..e22049835e 100644 --- a/include/uapi/linux/virtio_gpu.h +++ b/include/uapi/linux/virtio_gpu.h @@ -321,6 +321,7 @@ struct virtio_gpu_cmd_submit { #define VIRTIO_GPU_CAPSET_VENUS 4 #define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5 #define VIRTIO_GPU_CAPSET_DRM 6 +#define VIRTIO_GPU_CAPSET_ROCM 10 /* VIRTIO_GPU_CMD_GET_CAPSET_INFO */ struct virtio_gpu_get_capset_info { -- 2.34.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v10 1/4] drm/virtio: add VIRTIO_GPU_CAPSET_ROCM capability 2026-11-06 8:26 ` [RFC PATCH v10 1/4] drm/virtio: add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang @ 2026-11-06 8:30 ` sashiko-bot 0 siblings, 0 replies; 9+ messages in thread From: sashiko-bot @ 2026-11-06 8:30 UTC (permalink / raw) To: Honglei Huang; +Cc: virtualization, Michael S. Tsirkin, Eugenio Perez > Add a new GPU capability set VIRTIO_GPU_CAPSET_ROCM to support ROCm > compute workloads in virtualized environments. > > ROCm (Radeon Open Compute) is AMD's open-source software platform for > GPU compute and HPC workloads. > > ID 7 is already used by the OpenCL capset (VIRCL), and gfxstream's > rutabaga_gfx has already claimed IDs 7-9 ahead of any spec or kernel > header update, so ROCm uses ID 10 to avoid a further collision. A > matching virtio-gpu specification change is in progress to register this > assignment. > > Also add the matching VIRTGPU_DRM_CAPSET_ROCM alias in virtgpu_drm.h for > consistency with the other capability sets exposed through > DRM_IOCTL_VIRTGPU_GET_CAPS. > > Signed-off-by: Honglei Huang <honghuan@amd.com> Sashiko has reviewed this patch and found no issues. -- Sashiko AI review · https://sashiko.dev/#/patchset/20261106082625.812860-1-honghuan@amd.com?part=1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC PATCH v10 2/4] drm/virtio: add userptr blob resource to the UAPI 2026-11-06 8:26 [RFC PATCH v10 0/4] drm/virtio: userptr blobs for native-context compute Honglei Huang 2026-11-06 8:26 ` [RFC PATCH v10 1/4] drm/virtio: add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang @ 2026-11-06 8:26 ` Honglei Huang 2026-11-06 8:34 ` sashiko-bot 2026-11-06 8:26 ` [RFC PATCH v10 3/4] drm/virtio: implement userptr resource support Honglei Huang 2026-11-06 8:26 ` [RFC PATCH v10 4/4] drm/virtio: wire blob ioctl creation to userptr objects Honglei Huang 3 siblings, 1 reply; 9+ messages in thread From: Honglei Huang @ 2026-11-06 8:26 UTC (permalink / raw) To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization, linux-kernel, Honglei Huang Add a userptr address field so userspace can request a blob backed by an existing process mapping. A non-zero userptr selects that path; probe VIRTGPU_PARAM_USERPTR before using the field. GPU-readonly backing is requested with the virtio CREATE_BLOB wire flag VIRTIO_GPU_BLOB_FLAG_USE_READONLY (also VIRTGPU_BLOB_FLAG_USE_READONLY). The device MUST NOT write such a resource. The guest pins without FOLL_WRITE only when the device advertised VIRTIO_GPU_F_BLOB_READONLY (VIRTGPU_PARAM_BLOB_READONLY). Signed-off-by: Honglei Huang <honghuan@amd.com> --- include/uapi/drm/virtgpu_drm.h | 10 ++++++++++ include/uapi/linux/virtio_gpu.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index 9b886e9772..c890c754d8 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -99,6 +99,8 @@ struct drm_virtgpu_execbuffer { #define VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs 7 /* Bitmask of supported capability set ids */ #define VIRTGPU_PARAM_EXPLICIT_DEBUG_NAME 8 /* Ability to set debug name from userspace */ #define VIRTGPU_PARAM_BLOB_ALIGNMENT 9 /* Device alignment requirements for blobs */ +#define VIRTGPU_PARAM_USERPTR 10 /* CREATE_BLOB userptr field is supported */ +#define VIRTGPU_PARAM_BLOB_READONLY 11 /* VIRTGPU_BLOB_FLAG_USE_READONLY is honored */ struct drm_virtgpu_getparam { __u64 param; @@ -187,6 +189,7 @@ struct drm_virtgpu_resource_create_blob { #define VIRTGPU_BLOB_FLAG_USE_MAPPABLE 0x0001 #define VIRTGPU_BLOB_FLAG_USE_SHAREABLE 0x0002 #define VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 +#define VIRTGPU_BLOB_FLAG_USE_READONLY 0x0008 /* zero is invalid blob_mem */ __u32 blob_mem; __u32 blob_flags; @@ -206,6 +209,13 @@ struct drm_virtgpu_resource_create_blob { #define DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING 0x0001 __u32 blob_hints; __u32 pad2; + + /* + * Non-zero selects the userptr path and is valid only with + * VIRTGPU_BLOB_MEM_GUEST. Must be 0 otherwise. Probe + * VIRTGPU_PARAM_USERPTR before using this field. + */ + __u64 userptr; }; #define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001 diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h index e22049835e..af95374758 100644 --- a/include/uapi/linux/virtio_gpu.h +++ b/include/uapi/linux/virtio_gpu.h @@ -72,6 +72,10 @@ * must be aligned to that value. */ #define VIRTIO_GPU_F_BLOB_ALIGNMENT 5 +/* + * VIRTIO_GPU_BLOB_FLAG_USE_READONLY + */ +#define VIRTIO_GPU_F_BLOB_READONLY 6 enum virtio_gpu_ctrl_type { VIRTIO_GPU_UNDEFINED = 0, @@ -415,6 +419,7 @@ struct virtio_gpu_resource_create_blob { #define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001 #define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002 #define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 +#define VIRTIO_GPU_BLOB_FLAG_USE_READONLY 0x0008 /* zero is invalid blob mem */ __le32 blob_mem; __le32 blob_flags; -- 2.34.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v10 2/4] drm/virtio: add userptr blob resource to the UAPI 2026-11-06 8:26 ` [RFC PATCH v10 2/4] drm/virtio: add userptr blob resource to the UAPI Honglei Huang @ 2026-11-06 8:34 ` sashiko-bot 0 siblings, 0 replies; 9+ messages in thread From: sashiko-bot @ 2026-11-06 8:34 UTC (permalink / raw) To: Honglei Huang; +Cc: virtualization, Michael S. Tsirkin, Eugenio Perez > Add a userptr address field so userspace can request a blob backed > by an existing process mapping. A non-zero userptr selects that > path; probe VIRTGPU_PARAM_USERPTR before using the field. > > GPU-readonly backing is requested with the virtio CREATE_BLOB wire > flag VIRTIO_GPU_BLOB_FLAG_USE_READONLY (also > VIRTGPU_BLOB_FLAG_USE_READONLY). The device MUST NOT write such a > resource. The guest pins without FOLL_WRITE only when the device > advertised VIRTIO_GPU_F_BLOB_READONLY (VIRTGPU_PARAM_BLOB_READONLY). > > Signed-off-by: Honglei Huang <honghuan@amd.com> Sashiko has reviewed this patch and found no issues. -- Sashiko AI review · https://sashiko.dev/#/patchset/20261106082625.812860-1-honghuan@amd.com?part=2 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC PATCH v10 3/4] drm/virtio: implement userptr resource support 2026-11-06 8:26 [RFC PATCH v10 0/4] drm/virtio: userptr blobs for native-context compute Honglei Huang 2026-11-06 8:26 ` [RFC PATCH v10 1/4] drm/virtio: add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang 2026-11-06 8:26 ` [RFC PATCH v10 2/4] drm/virtio: add userptr blob resource to the UAPI Honglei Huang @ 2026-11-06 8:26 ` Honglei Huang 2026-11-06 8:45 ` sashiko-bot 2026-11-06 8:26 ` [RFC PATCH v10 4/4] drm/virtio: wire blob ioctl creation to userptr objects Honglei Huang 3 siblings, 1 reply; 9+ messages in thread From: Honglei Huang @ 2026-11-06 8:26 UTC (permalink / raw) To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization, linux-kernel, Honglei Huang Add userptr blob objects so the guest kernel can pin an existing userspace mapping and advertise it as CREATE_BLOB backing entries. - New virtio_gpu_object_userptr type for userptr resources - Pin pages with pin_user_pages_fast() and FOLL_LONGTERM - Omit FOLL_WRITE when VIRTGPU_BLOB_FLAG_USE_READONLY is set - Charge FOLL_LONGTERM pins against RLIMIT_MEMLOCK - DMA-map the scatterlist only when virtio_gpu_use_dma_api() is required; use DMA_TO_DEVICE for USE_READONLY blobs - Mark writable pages dirty when unpinning - Keep pages pinned until RESOURCE_UNREF is queued; drop them from cleanup_object() on the unref response or on create failure - Clear userptr->pages on pin failure to avoid double-free on cleanup - Reject unaligned or overflowing userptr ranges at create time - Disallow PRIME export of userptr objects - Save CREATE_BLOB params and restore userptr resources after hibernation without using the shmem restore path Map with DMA_ATTR_REQUIRE_COHERENT at create time, on hibernation restore, and on unmap. Signed-off-by: Honglei Huang <honghuan@amd.com> --- drivers/gpu/drm/virtio/Makefile | 3 +- drivers/gpu/drm/virtio/virtgpu_drv.h | 42 +++ drivers/gpu/drm/virtio/virtgpu_object.c | 22 ++ drivers/gpu/drm/virtio/virtgpu_userptr.c | 350 +++++++++++++++++++++++ 4 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/virtio/virtgpu_userptr.c diff --git a/drivers/gpu/drm/virtio/Makefile b/drivers/gpu/drm/virtio/Makefile index d2e1788a82..fe7332a621 100644 --- a/drivers/gpu/drm/virtio/Makefile +++ b/drivers/gpu/drm/virtio/Makefile @@ -6,6 +6,7 @@ virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o virtgpu_vram.o \ virtgpu_display.o virtgpu_vq.o \ virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \ - virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o virtgpu_submit.o + virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o virtgpu_submit.o \ + virtgpu_userptr.o obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 9df4c71173..a29429b415 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -105,6 +105,7 @@ struct virtio_gpu_object_params { uint32_t blob_flags; uint64_t blob_id; uint32_t blob_hints; + uint64_t userptr; }; struct virtio_gpu_object { @@ -138,12 +139,42 @@ struct virtio_gpu_object_vram { struct drm_mm_node vram_node; }; +struct virtio_gpu_object_userptr; + +struct virtio_gpu_object_userptr_ops { + int (*get_pages)(struct virtio_gpu_object_userptr *userptr); + void (*put_pages)(struct virtio_gpu_object_userptr *userptr); +}; + +struct virtio_gpu_object_userptr { + struct virtio_gpu_object base; + const struct virtio_gpu_object_userptr_ops *ops; + /* Protects @pages, @sgt and @dma_mapped. */ + struct mutex lock; + + uint64_t start; + uint32_t npages; + uint32_t bo_handle; + uint32_t flags; + + struct virtio_gpu_device *vgdev; + struct drm_file *file; + struct page **pages; + struct sg_table *sgt; + bool dma_mapped; + enum dma_data_direction dma_dir; + struct mm_struct *mm; +}; + #define to_virtio_gpu_shmem(virtio_gpu_object) \ container_of((virtio_gpu_object), struct virtio_gpu_object_shmem, base) #define to_virtio_gpu_vram(virtio_gpu_object) \ container_of((virtio_gpu_object), struct virtio_gpu_object_vram, base) +#define to_virtio_gpu_userptr(virtio_gpu_object) \ + container_of((virtio_gpu_object), struct virtio_gpu_object_userptr, base) + struct virtio_gpu_object_array { struct ww_acquire_ctx ticket; struct list_head next; @@ -284,6 +315,7 @@ struct virtio_gpu_device { bool has_host_visible; bool has_context_init; bool has_blob_alignment; + bool has_blob_readonly; bool hibernated; struct virtio_shm_region host_visible_region; struct drm_mm host_visible_mm; @@ -562,4 +594,14 @@ void virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram *vram); int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, struct drm_file *file); +/* virtgpu_userptr.c */ +int virtio_gpu_userptr_create(struct virtio_gpu_device *vgdev, + struct drm_file *file, + struct virtio_gpu_object_params *params, + struct virtio_gpu_object **bo_ptr); +bool virtio_gpu_is_userptr(struct virtio_gpu_object *bo); +int virtio_gpu_userptr_restore(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object *bo, + struct virtio_gpu_mem_entry **ents, + unsigned int *nents); #endif diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c index 49899485be..ab21494b1c 100644 --- a/drivers/gpu/drm/virtio/virtgpu_object.c +++ b/drivers/gpu/drm/virtio/virtgpu_object.c @@ -91,6 +91,16 @@ void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo) drm_gem_free_mmap_offset(&vram->base.base.base); drm_gem_object_release(&vram->base.base.base); kfree(vram); + } else if (virtio_gpu_is_userptr(bo)) { + struct virtio_gpu_object_userptr *userptr = + to_virtio_gpu_userptr(bo); + + mutex_lock(&userptr->lock); + userptr->ops->put_pages(userptr); + mutex_unlock(&userptr->lock); + mutex_destroy(&userptr->lock); + drm_gem_object_release(&userptr->base.base.base); + kfree(userptr); } else { drm_gem_object_release(&bo->base.base); kfree(bo); @@ -316,6 +326,18 @@ int virtio_gpu_object_restore_all(struct virtio_gpu_device *vgdev) continue; } + if (virtio_gpu_is_userptr(bo)) { + ret = virtio_gpu_userptr_restore(vgdev, bo, &ents, + &nents); + if (ret) + break; + + virtio_gpu_cmd_resource_create_blob(vgdev, bo, + &bo->params, + ents, nents); + continue; + } + if (bo->params.blob || bo->attached) { ret = virtio_gpu_object_shmem_init(vgdev, bo, &ents, &nents); diff --git a/drivers/gpu/drm/virtio/virtgpu_userptr.c b/drivers/gpu/drm/virtio/virtgpu_userptr.c new file mode 100644 index 0000000000..b860693255 --- /dev/null +++ b/drivers/gpu/drm/virtio/virtgpu_userptr.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/dma-mapping.h> +#include <linux/limits.h> +#include <linux/mm.h> +#include <linux/overflow.h> +#include <linux/pid.h> +#include <linux/sched/mm.h> +#include <linux/sched/signal.h> +#include <linux/vmalloc.h> + +#include "virtgpu_drv.h" +#include <drm/drm_gem.h> + +static void virtio_gpu_userptr_free(struct drm_gem_object *obj) +{ + struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); + struct virtio_gpu_device *vgdev = obj->dev->dev_private; + + /* + * Pages stay pinned until RESOURCE_UNREF finishes. Its callback + * calls virtio_gpu_cleanup_object to drop them. + */ + if (bo->created) { + virtio_gpu_remove_from_restore_list(bo); + virtio_gpu_cmd_unref_resource(vgdev, bo, false); + virtio_gpu_notify(vgdev); + return; + } + + virtio_gpu_cleanup_object(bo); +} + +static struct dma_buf * +virtio_gpu_userptr_prime_export(struct drm_gem_object *obj, int flags) +{ + return ERR_PTR(-EINVAL); +} + +static const struct drm_gem_object_funcs virtio_gpu_userptr_funcs = { + .open = virtio_gpu_gem_object_open, + .close = virtio_gpu_gem_object_close, + .free = virtio_gpu_userptr_free, + .export = virtio_gpu_userptr_prime_export, +}; + +bool virtio_gpu_is_userptr(struct virtio_gpu_object *bo) +{ + return bo->base.base.funcs == &virtio_gpu_userptr_funcs; +} + +static int +virtio_gpu_userptr_get_pages(struct virtio_gpu_object_userptr *userptr) +{ + unsigned int flag = FOLL_LONGTERM; + unsigned int num_pages, pinned = 0; + int ret = 0; + + if (userptr->pages) + return 0; + + userptr->pages = kvmalloc_array(userptr->npages, sizeof(struct page *), + GFP_KERNEL); + if (!userptr->pages) + return -ENOMEM; + + if (!(userptr->flags & VIRTGPU_BLOB_FLAG_USE_READONLY)) + flag |= FOLL_WRITE; + + do { + num_pages = userptr->npages - pinned; + + ret = pin_user_pages_fast(userptr->start + pinned * PAGE_SIZE, + num_pages, flag, + userptr->pages + pinned); + + if (ret < 0) { + if (pinned) + unpin_user_pages(userptr->pages, pinned); + kvfree(userptr->pages); + userptr->pages = NULL; + return ret; + } + + pinned += ret; + + } while (pinned < userptr->npages); + + return 0; +} + +static void +virtio_gpu_userptr_unaccount(struct virtio_gpu_object_userptr *userptr) +{ + if (!userptr->mm) + return; + + atomic64_sub(userptr->npages, &userptr->mm->pinned_vm); + mmdrop(userptr->mm); + userptr->mm = NULL; +} + +static void +virtio_gpu_userptr_put_pages(struct virtio_gpu_object_userptr *userptr) +{ + struct drm_device *dev = userptr->base.base.base.dev; + + if (userptr->sgt) { + if (userptr->dma_mapped) + dma_unmap_sgtable(drm_dev_dma_dev(dev), userptr->sgt, + userptr->dma_dir, + DMA_ATTR_REQUIRE_COHERENT); + userptr->dma_mapped = false; + sg_free_table(userptr->sgt); + kfree(userptr->sgt); + userptr->sgt = NULL; + } + + if (userptr->pages) { + bool dirty = !(userptr->flags & VIRTGPU_BLOB_FLAG_USE_READONLY); + + unpin_user_pages_dirty_lock(userptr->pages, userptr->npages, + dirty); + kvfree(userptr->pages); + userptr->pages = NULL; + } + + virtio_gpu_userptr_unaccount(userptr); +} + +static int +virtio_gpu_userptr_get_entries(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object_userptr *userptr, + struct virtio_gpu_mem_entry **ents, + unsigned int *nents) +{ + bool use_dma_api = virtio_gpu_use_dma_api(vgdev->vdev); + struct scatterlist *sg; + unsigned int count; + int si; + + count = use_dma_api ? userptr->sgt->nents : userptr->sgt->orig_nents; + if (!count) + return -EINVAL; + + *ents = kvmalloc_array(count, sizeof(**ents), GFP_KERNEL); + if (!*ents) + return -ENOMEM; + + if (use_dma_api) { + for_each_sgtable_dma_sg(userptr->sgt, sg, si) { + (*ents)[si].addr = cpu_to_le64(sg_dma_address(sg)); + (*ents)[si].length = cpu_to_le32(sg_dma_len(sg)); + (*ents)[si].padding = 0; + } + } else { + for_each_sgtable_sg(userptr->sgt, sg, si) { + (*ents)[si].addr = cpu_to_le64(sg_phys(sg)); + (*ents)[si].length = cpu_to_le32(sg->length); + (*ents)[si].padding = 0; + } + } + + *nents = count; + return 0; +} + +int virtio_gpu_userptr_restore(struct virtio_gpu_device *vgdev, + struct virtio_gpu_object *bo, + struct virtio_gpu_mem_entry **ents, + unsigned int *nents) +{ + struct virtio_gpu_object_userptr *userptr = to_virtio_gpu_userptr(bo); + int ret; + + mutex_lock(&userptr->lock); + if (!userptr->sgt || !userptr->pages) { + mutex_unlock(&userptr->lock); + return -EINVAL; + } + + if (userptr->dma_mapped) { + struct device *dev = drm_dev_dma_dev(vgdev->ddev); + + dma_unmap_sgtable(dev, userptr->sgt, userptr->dma_dir, + DMA_ATTR_REQUIRE_COHERENT); + userptr->dma_mapped = false; + + ret = dma_map_sgtable(dev, userptr->sgt, userptr->dma_dir, + DMA_ATTR_REQUIRE_COHERENT); + if (ret) { + mutex_unlock(&userptr->lock); + return ret; + } + userptr->dma_mapped = true; + } + + ret = virtio_gpu_userptr_get_entries(vgdev, userptr, ents, nents); + mutex_unlock(&userptr->lock); + return ret; +} + +static int +virtio_gpu_userptr_init(struct drm_device *dev, struct drm_file *file, + struct virtio_gpu_object_userptr *userptr, + struct virtio_gpu_object_params *params, + const struct virtio_gpu_object_userptr_ops *ops) +{ + struct drm_gem_object *obj; + int ret; + + userptr->start = params->userptr; + userptr->npages = params->size >> PAGE_SHIFT; + userptr->flags = params->blob_flags; + + mutex_init(&userptr->lock); + userptr->vgdev = dev->dev_private; + userptr->file = file; + userptr->ops = ops; + + /* + * Get the resource id before GEM init, so a failed call here + * just needs a plain kfree and no special id zero check in the + * shared resource_id_put helper. + */ + ret = virtio_gpu_resource_id_get(userptr->vgdev, + &userptr->base.hw_res_handle); + if (ret) { + mutex_destroy(&userptr->lock); + return ret; + } + + obj = &userptr->base.base.base; + obj->funcs = &virtio_gpu_userptr_funcs; + + drm_gem_private_object_init(dev, obj, params->size); + INIT_LIST_HEAD(&userptr->base.restore_node); + + return 0; +} + +static const struct virtio_gpu_object_userptr_ops virtio_gpu_userptr_ops = { + .get_pages = virtio_gpu_userptr_get_pages, + .put_pages = virtio_gpu_userptr_put_pages, +}; + +int virtio_gpu_userptr_create(struct virtio_gpu_device *vgdev, + struct drm_file *file, + struct virtio_gpu_object_params *params, + struct virtio_gpu_object **bo_ptr) +{ + struct virtio_gpu_object_userptr *userptr; + struct virtio_gpu_mem_entry *ents = NULL; + struct sg_table *sgt; + struct mm_struct *mm; + unsigned long lock_limit; + unsigned long start; + unsigned long end; + s64 new_pinned; + unsigned int nents; + int ret; + + *bo_ptr = NULL; + + if (!params->size || !IS_ALIGNED(params->size, PAGE_SIZE) || + params->userptr != (unsigned long)params->userptr) + return -EINVAL; + + start = params->userptr; + if (!IS_ALIGNED(start, PAGE_SIZE) || + check_add_overflow(start, (unsigned long)params->size, &end)) + return -EINVAL; + + if (!can_do_mlock()) + return -EPERM; + + if (params->size >> PAGE_SHIFT > INT_MAX) + return -E2BIG; + + if (!access_ok((void __user *)start, params->size)) + return -EFAULT; + + userptr = kzalloc_obj(*userptr); + if (!userptr) + return -ENOMEM; + + ret = virtio_gpu_userptr_init(vgdev->ddev, file, userptr, params, + &virtio_gpu_userptr_ops); + if (ret) { + kfree(userptr); + return ret; + } + + mm = current->mm; + mmgrab(mm); + lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; + new_pinned = atomic64_add_return(userptr->npages, &mm->pinned_vm); + if (new_pinned > lock_limit && !capable(CAP_IPC_LOCK)) { + atomic64_sub(userptr->npages, &mm->pinned_vm); + mmdrop(mm); + ret = -ENOMEM; + goto err_cleanup; + } + userptr->mm = mm; + + mutex_lock(&userptr->lock); + ret = userptr->ops->get_pages(userptr); + mutex_unlock(&userptr->lock); + if (ret) + goto err_cleanup; + + sgt = drm_prime_pages_to_sg(vgdev->ddev, userptr->pages, + userptr->npages); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto err_cleanup; + } + + userptr->sgt = sgt; + + if (virtio_gpu_use_dma_api(vgdev->vdev)) { + enum dma_data_direction dir = + (userptr->flags & VIRTGPU_BLOB_FLAG_USE_READONLY) ? + DMA_TO_DEVICE : DMA_BIDIRECTIONAL; + + ret = dma_map_sgtable(drm_dev_dma_dev(vgdev->ddev), sgt, + dir, DMA_ATTR_REQUIRE_COHERENT); + if (ret) + goto err_cleanup; + + userptr->dma_dir = dir; + userptr->dma_mapped = true; + } + + ret = virtio_gpu_userptr_get_entries(vgdev, userptr, &ents, &nents); + if (ret) + goto err_cleanup; + + virtio_gpu_cmd_resource_create_blob(vgdev, &userptr->base, params, ents, + nents); + + userptr->base.params = *params; + virtio_gpu_add_object_to_restore_list(vgdev, &userptr->base); + + *bo_ptr = &userptr->base; + return 0; + +err_cleanup: + virtio_gpu_cleanup_object(&userptr->base); + return ret; +} -- 2.34.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v10 3/4] drm/virtio: implement userptr resource support 2026-11-06 8:26 ` [RFC PATCH v10 3/4] drm/virtio: implement userptr resource support Honglei Huang @ 2026-11-06 8:45 ` sashiko-bot 0 siblings, 0 replies; 9+ messages in thread From: sashiko-bot @ 2026-11-06 8:45 UTC (permalink / raw) To: Honglei Huang Cc: dri-devel, virtualization, Michael S. Tsirkin, Eugenio Perez Thank you for your contribution! Sashiko AI review found 2 potential issues to consider: - [Medium] drm/virtio: virtio_gpu_userptr_restore() skips DMA remap after failed map - [Low] drm/virtio: duplicated virtio_gpu_userptr_free() and dead userptr struct fields -- commit a322ca4c583b559738cbbb3a5e62c08918a07dd8 Author: Honglei Huang <honghuan@amd.com> drm/virtio: implement userptr resource support This commit adds virtio_gpu_object_userptr so the guest kernel can pin an existing userspace mapping with FOLL_LONGTERM and pass its backing pages to the host via VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB, including hibernation restore support. > diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h > index 9df4c7117341e..a29429b41561f 100644 > --- a/drivers/gpu/drm/virtio/virtgpu_drv.h > +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h [ ... ] > @@ -138,12 +139,42 @@ struct virtio_gpu_object_vram { > struct drm_mm_node vram_node; > }; > > +struct virtio_gpu_object_userptr; > + > +struct virtio_gpu_object_userptr_ops { > + int (*get_pages)(struct virtio_gpu_object_userptr *userptr); > + void (*put_pages)(struct virtio_gpu_object_userptr *userptr); > +}; > + > +struct virtio_gpu_object_userptr { > + struct virtio_gpu_object base; > + const struct virtio_gpu_object_userptr_ops *ops; > + /* Protects @pages, @sgt and @dma_mapped. */ > + struct mutex lock; > + > + uint64_t start; > + uint32_t npages; > + uint32_t bo_handle; > + uint32_t flags; > + > + struct virtio_gpu_device *vgdev; > + struct drm_file *file; > + struct page **pages; > + struct sg_table *sgt; > + bool dma_mapped; > + enum dma_data_direction dma_dir; > + struct mm_struct *mm; > +}; [ ... ] > diff --git a/drivers/gpu/drm/virtio/virtgpu_userptr.c b/drivers/gpu/drm/virtio/virtgpu_userptr.c > new file mode 100644 > index 0000000000000..b8606932550eb > --- /dev/null > +++ b/drivers/gpu/drm/virtio/virtgpu_userptr.c > @@ -0,0 +1,350 @@ [ ... ] > +static void virtio_gpu_userptr_free(struct drm_gem_object *obj) > +{ > + struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); > + struct virtio_gpu_device *vgdev = obj->dev->dev_private; > + > + /* > + * Pages stay pinned until RESOURCE_UNREF finishes. Its callback > + * calls virtio_gpu_cleanup_object to drop them. > + */ > + if (bo->created) { > + virtio_gpu_remove_from_restore_list(bo); > + virtio_gpu_cmd_unref_resource(vgdev, bo, false); > + virtio_gpu_notify(vgdev); > + return; > + } > + > + virtio_gpu_cleanup_object(bo); > +} [Severity: Low] This isn't a bug, but virtio_gpu_userptr_free() is identical to virtio_gpu_free_object() in drivers/gpu/drm/virtio/virtgpu_object.c and could reuse it directly if exported. In struct virtio_gpu_object_userptr, bo_handle is never used and file is only written in virtio_gpu_userptr_init() and never read (leaving an unreferenced struct drm_file pointer on an object that can outlive the file descriptor until RESOURCE_UNREF finishes). Also, struct virtio_gpu_object_userptr_ops has only one static implementation, so virtio_gpu_userptr_get_pages() and virtio_gpu_userptr_put_pages() can be called directly without the ops vtable. [ ... ] > +static int > +virtio_gpu_userptr_get_entries(struct virtio_gpu_device *vgdev, > + struct virtio_gpu_object_userptr *userptr, > + struct virtio_gpu_mem_entry **ents, > + unsigned int *nents) > +{ > + bool use_dma_api = virtio_gpu_use_dma_api(vgdev->vdev); > + struct scatterlist *sg; > + unsigned int count; > + int si; > + > + count = use_dma_api ? userptr->sgt->nents : userptr->sgt->orig_nents; > + if (!count) > + return -EINVAL; > + > + *ents = kvmalloc_array(count, sizeof(**ents), GFP_KERNEL); > + if (!*ents) > + return -ENOMEM; > + > + if (use_dma_api) { > + for_each_sgtable_dma_sg(userptr->sgt, sg, si) { > + (*ents)[si].addr = cpu_to_le64(sg_dma_address(sg)); > + (*ents)[si].length = cpu_to_le32(sg_dma_len(sg)); > + (*ents)[si].padding = 0; > + } > + } else { > + for_each_sgtable_sg(userptr->sgt, sg, si) { > + (*ents)[si].addr = cpu_to_le64(sg_phys(sg)); > + (*ents)[si].length = cpu_to_le32(sg->length); > + (*ents)[si].padding = 0; > + } > + } > + > + *nents = count; > + return 0; > +} > + > +int virtio_gpu_userptr_restore(struct virtio_gpu_device *vgdev, > + struct virtio_gpu_object *bo, > + struct virtio_gpu_mem_entry **ents, > + unsigned int *nents) > +{ > + struct virtio_gpu_object_userptr *userptr = to_virtio_gpu_userptr(bo); > + int ret; > + > + mutex_lock(&userptr->lock); > + if (!userptr->sgt || !userptr->pages) { > + mutex_unlock(&userptr->lock); > + return -EINVAL; > + } > + > + if (userptr->dma_mapped) { > + struct device *dev = drm_dev_dma_dev(vgdev->ddev); > + > + dma_unmap_sgtable(dev, userptr->sgt, userptr->dma_dir, > + DMA_ATTR_REQUIRE_COHERENT); > + userptr->dma_mapped = false; > + > + ret = dma_map_sgtable(dev, userptr->sgt, userptr->dma_dir, > + DMA_ATTR_REQUIRE_COHERENT); > + if (ret) { > + mutex_unlock(&userptr->lock); > + return ret; > + } > + userptr->dma_mapped = true; > + } > + > + ret = virtio_gpu_userptr_get_entries(vgdev, userptr, ents, nents); > + mutex_unlock(&userptr->lock); > + return ret; > +} [Severity: Medium] If dma_map_sgtable() fails in virtio_gpu_userptr_restore(), will a later restore attempt send unmapped DMA addresses to the host? When dma_map_sgtable() fails after dma_unmap_sgtable(), userptr->dma_mapped is left false while userptr->sgt->nents remains non-zero and the object stays on vgdev->obj_restore_list. A subsequent virtio_gpu_userptr_restore() call then skips remapping because userptr->dma_mapped is false, but virtio_gpu_userptr_get_entries() checks virtio_gpu_use_dma_api(vgdev->vdev) and reads the unmapped sg_dma_address(sg) entries anyway. Checking virtio_gpu_use_dma_api(vgdev->vdev) to decide whether dma_map_sgtable() is needed, and only checking userptr->dma_mapped before calling dma_unmap_sgtable(), would avoid this. -- Sashiko AI review · https://sashiko.dev/#/patchset/20261106082625.812860-1-honghuan@amd.com?part=3 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC PATCH v10 4/4] drm/virtio: wire blob ioctl creation to userptr objects 2026-11-06 8:26 [RFC PATCH v10 0/4] drm/virtio: userptr blobs for native-context compute Honglei Huang ` (2 preceding siblings ...) 2026-11-06 8:26 ` [RFC PATCH v10 3/4] drm/virtio: implement userptr resource support Honglei Huang @ 2026-11-06 8:26 ` Honglei Huang 2026-11-06 8:42 ` sashiko-bot 3 siblings, 1 reply; 9+ messages in thread From: Honglei Huang @ 2026-11-06 8:26 UTC (permalink / raw) To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization, linux-kernel, Honglei Huang Integrate userptr into the blob resource creation ioctl. - A non-zero userptr selects virtio_gpu_userptr_create() - Reject userptr unless blob_mem is VIRTGPU_BLOB_MEM_GUEST - Reject VIRTGPU_BLOB_FLAG_USE_READONLY unless the device advertised VIRTIO_GPU_F_BLOB_READONLY - Advertise VIRTGPU_PARAM_USERPTR and VIRTGPU_PARAM_BLOB_READONLY - Add VIRTIO_GPU_F_BLOB_READONLY to the driver's features[] array Signed-off-by: Honglei Huang <honghuan@amd.com> --- drivers/gpu/drm/virtio/virtgpu_debugfs.c | 1 + drivers/gpu/drm/virtio/virtgpu_drv.c | 1 + drivers/gpu/drm/virtio/virtgpu_ioctl.c | 49 +++++++++++++++++++----- drivers/gpu/drm/virtio/virtgpu_kms.c | 8 +++- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_debugfs.c b/drivers/gpu/drm/virtio/virtgpu_debugfs.c index 3a68a16b58..b8b9b40584 100644 --- a/drivers/gpu/drm/virtio/virtgpu_debugfs.c +++ b/drivers/gpu/drm/virtio/virtgpu_debugfs.c @@ -55,6 +55,7 @@ static int virtio_gpu_features(struct seq_file *m, void *data) vgdev->has_resource_assign_uuid); virtio_gpu_add_bool(m, "blob resources", vgdev->has_resource_blob); + virtio_gpu_add_bool(m, "blob readonly", vgdev->has_blob_readonly); virtio_gpu_add_bool(m, "context init", vgdev->has_context_init); virtio_gpu_add_int(m, "cap sets", vgdev->num_capsets); virtio_gpu_add_int(m, "scanouts", vgdev->num_scanouts); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 2aaa7cb080..f1edd20c37 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -182,6 +182,7 @@ static unsigned int features[] = { VIRTIO_GPU_F_RESOURCE_BLOB, VIRTIO_GPU_F_CONTEXT_INIT, VIRTIO_GPU_F_BLOB_ALIGNMENT, + VIRTIO_GPU_F_BLOB_READONLY, }; #ifdef CONFIG_PM_SLEEP diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 3d8e4ccdb7..e57750588d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -36,7 +36,10 @@ #define VIRTGPU_BLOB_FLAG_USE_MASK (VIRTGPU_BLOB_FLAG_USE_MAPPABLE | \ VIRTGPU_BLOB_FLAG_USE_SHAREABLE | \ - VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) + VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE | \ + VIRTGPU_BLOB_FLAG_USE_READONLY) + +#define VIRTGPU_BLOB_HINT_MASK DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING /* Must be called with &virtio_gpu_fpriv.struct_mutex held. */ static void virtio_gpu_create_context_locked(struct virtio_gpu_device *vgdev, @@ -122,6 +125,12 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, return -ENOENT; value = vgdev->blob_alignment; break; + case VIRTGPU_PARAM_USERPTR: + value = 1; + break; + case VIRTGPU_PARAM_BLOB_READONLY: + value = vgdev->has_blob_readonly ? 1 : 0; + break; default: return -EINVAL; } @@ -453,11 +462,23 @@ static int verify_blob(struct virtio_gpu_device *vgdev, if (rc_blob->blob_flags & ~VIRTGPU_BLOB_FLAG_USE_MASK) return -EINVAL; + if (rc_blob->blob_hints & ~VIRTGPU_BLOB_HINT_MASK) + return -EINVAL; + if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) { if (!vgdev->has_resource_assign_uuid) return -EINVAL; } + if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USE_READONLY) { + if (!vgdev->has_blob_readonly) + return -EINVAL; + } + + if (rc_blob->userptr && + rc_blob->blob_mem != VIRTGPU_BLOB_MEM_GUEST) + return -EINVAL; + switch (rc_blob->blob_mem) { case VIRTGPU_BLOB_MEM_GUEST: *guest_blob = true; @@ -495,10 +516,15 @@ static int verify_blob(struct virtio_gpu_device *vgdev, params->blob = true; params->blob_flags = rc_blob->blob_flags; params->blob_hints = rc_blob->blob_hints; + params->userptr = rc_blob->userptr; - if (vgdev->has_blob_alignment && - !IS_ALIGNED(params->size, vgdev->blob_alignment)) - return -EINVAL; + if (vgdev->has_blob_alignment) { + if (!IS_ALIGNED(params->size, vgdev->blob_alignment)) + return -EINVAL; + + if (!IS_ALIGNED(params->userptr, vgdev->blob_alignment)) + return -EINVAL; + } return 0; } @@ -518,9 +544,10 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev, struct virtio_gpu_fpriv *vfpriv = file->driver_priv; struct drm_virtgpu_resource_create_blob *rc_blob = data; - if (verify_blob(vgdev, vfpriv, ¶ms, rc_blob, - &guest_blob, &host3d_blob)) - return -EINVAL; + ret = verify_blob(vgdev, vfpriv, ¶ms, rc_blob, + &guest_blob, &host3d_blob); + if (ret) + return ret; if (vgdev->has_virgl_3d) virtio_gpu_create_context(dev, file); @@ -538,7 +565,9 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev, vfpriv->ctx_id, NULL, NULL); } - if (guest_blob) + if (guest_blob && params.userptr) + ret = virtio_gpu_userptr_create(vgdev, file, ¶ms, &bo); + else if (guest_blob) ret = virtio_gpu_object_create(vgdev, ¶ms, &bo, NULL); else if (!guest_blob && host3d_blob) ret = virtio_gpu_vram_create(vgdev, ¶ms, &bo); @@ -557,14 +586,14 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev, if (params.blob_flags & VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) { ret = virtio_gpu_resource_assign_uuid(vgdev, bo); if (ret) { - drm_gem_object_release(obj); + drm_gem_object_put(obj); return ret; } } ret = drm_gem_handle_create(file, obj, &handle); if (ret) { - drm_gem_object_release(obj); + drm_gem_object_put(obj); return ret; } diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 1d4d3bf46a..06c2bded49 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -249,15 +249,19 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev) vgdev->blob_alignment = blob_alignment; } + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_BLOB_READONLY)) + vgdev->has_blob_readonly = true; + DRM_INFO("features: %cvirgl %cedid %cresource_blob %chost_visible", vgdev->has_virgl_3d ? '+' : '-', vgdev->has_edid ? '+' : '-', vgdev->has_resource_blob ? '+' : '-', vgdev->has_host_visible ? '+' : '-'); - DRM_INFO("features: %ccontext_init %cblob_alignment\n", + DRM_INFO("features: %ccontext_init %cblob_alignment %cblob_readonly\n", vgdev->has_context_init ? '+' : '-', - vgdev->has_blob_alignment ? '+' : '-'); + vgdev->has_blob_alignment ? '+' : '-', + vgdev->has_blob_readonly ? '+' : '-'); ret = virtio_gpu_find_vqs(vgdev); if (ret) { -- 2.34.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v10 4/4] drm/virtio: wire blob ioctl creation to userptr objects 2026-11-06 8:26 ` [RFC PATCH v10 4/4] drm/virtio: wire blob ioctl creation to userptr objects Honglei Huang @ 2026-11-06 8:42 ` sashiko-bot 0 siblings, 0 replies; 9+ messages in thread From: sashiko-bot @ 2026-11-06 8:42 UTC (permalink / raw) To: Honglei Huang Cc: dri-devel, virtualization, Michael S. Tsirkin, Eugenio Perez Thank you for your contribution! Sashiko AI review found 1 potential issue to consider: - [Medium] drm/virtio: unnotified ctrlq strands blob on handle creation failure -- commit f8b823e6be2332eb525d4e0d0576cd0869cd03e1 Author: Honglei Huang <honghuan@amd.com> drm/virtio: wire blob ioctl creation to userptr objects This commit integrates userptr creation and read-only blob support into the blob resource creation and getparam ioctls, and switches the error paths in virtio_gpu_resource_create_blob_ioctl() from drm_gem_object_release() to drm_gem_object_put(). > diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c > index 3d8e4ccdb7c1f..e57750588df01 100644 > --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c > +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c [ ... ] > @@ -557,14 +586,14 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev, > if (params.blob_flags & VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE) { > ret = virtio_gpu_resource_assign_uuid(vgdev, bo); > if (ret) { > - drm_gem_object_release(obj); > + drm_gem_object_put(obj); > return ret; > } > } > > ret = drm_gem_handle_create(file, obj, &handle); > if (ret) { > - drm_gem_object_release(obj); > + drm_gem_object_put(obj); > return ret; > } [Severity: Medium] Can this leave obj stranded in vgdev->ctrlq when drm_gem_handle_create() fails after virtio_gpu_resource_assign_uuid() succeeds? Neither the blob creation helpers nor virtio_gpu_resource_assign_uuid() call virtio_gpu_notify(vgdev); notification normally happens at the end of virtio_gpu_gem_object_open() inside drm_gem_handle_create(). However, virtio_gpu_resource_assign_uuid() takes an extra reference on obj via virtio_gpu_array_add_obj() for the queued command buffer: drivers/gpu/drm/virtio/virtgpu_prime.c:virtio_gpu_resource_assign_uuid() { objs = virtio_gpu_array_alloc(1); if (!objs) return -ENOMEM; virtio_gpu_array_add_obj(objs, &bo->base.base); return virtio_gpu_cmd_resource_assign_uuid(vgdev, objs); } If drm_gem_handle_create() fails before virtio_gpu_gem_object_open() reaches virtio_gpu_notify(vgdev), drm_gem_object_put(obj) only drops obj->refcount from 2 to 1. Because the refcount does not reach 0, obj->funcs->free() is not called, leaving the queued commands un-kicked and keeping userptr pages pinned and charged to mm->pinned_vm until an unrelated command notifies ctrlq. Calling virtio_gpu_notify(vgdev) on the drm_gem_handle_create() failure path would ensure the queued command completes and drops its reference. -- Sashiko AI review · https://sashiko.dev/#/patchset/20261106082625.812860-1-honghuan@amd.com?part=4 ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-11-06 8:45 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-11-06 8:26 [RFC PATCH v10 0/4] drm/virtio: userptr blobs for native-context compute Honglei Huang 2026-11-06 8:26 ` [RFC PATCH v10 1/4] drm/virtio: add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang 2026-11-06 8:30 ` sashiko-bot 2026-11-06 8:26 ` [RFC PATCH v10 2/4] drm/virtio: add userptr blob resource to the UAPI Honglei Huang 2026-11-06 8:34 ` sashiko-bot 2026-11-06 8:26 ` [RFC PATCH v10 3/4] drm/virtio: implement userptr resource support Honglei Huang 2026-11-06 8:45 ` sashiko-bot 2026-11-06 8:26 ` [RFC PATCH v10 4/4] drm/virtio: wire blob ioctl creation to userptr objects Honglei Huang 2026-11-06 8:42 ` sashiko-bot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox