* [PATCH 0/2] drm/msm: fix dma-buf sharing on targets without per-process pgtables
@ 2026-08-22 8:48 Dmitry Baryshkov
2026-08-22 8:48 ` [PATCH 1/2] drm/msm: factor out a locking put_iova_spaces() wrapper Dmitry Baryshkov
2026-08-22 8:48 ` [PATCH 2/2] drm/msm: don't tear down shared VM mappings on handle close Dmitry Baryshkov
0 siblings, 2 replies; 5+ messages in thread
From: Dmitry Baryshkov @ 2026-08-22 8:48 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Konrad Dybcio, Akhil P Oommen, Sumit Semwal, Christian König,
Antonino Maniscalco
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, linux-media,
linaro-mm-sig
Targets without per-process pgtables -- everything pre-a6xx, plus a6xx
parts where split pagetables are unavailable -- hand every DRM file the
GPU's global VM. The rest of the driver still treats a context VM as
private to that context, so closing a handle tears down mappings other
files are still using, and frees the iova for immediate reuse.
A dma-buf shared between two clients therefore keeps sampling an address
that the next allocation has taken over. On a530 this is every
ext_image_dma_buf_import sampling test, reading back all zeros.
A VM shared between contexts needs the lazy, refcounted teardown the
driver already implements for kms->vm. Rather than adding a second
mechanism, the first patch makes that machinery reusable and the second
one puts the shared GPU VM behind it.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
Dmitry Baryshkov (2):
drm/msm: factor out a locking put_iova_spaces() wrapper
drm/msm: don't tear down shared VM mappings on handle close
drivers/gpu/drm/msm/msm_gem.c | 45 ++++++++++++++++++++++++++++---------------
drivers/gpu/drm/msm/msm_gpu.c | 4 +++-
drivers/gpu/drm/msm/msm_gpu.h | 3 +++
3 files changed, 36 insertions(+), 16 deletions(-)
---
base-commit: 6b8c8af514d739d0335f5579b585e02babe8a727
change-id: 20260822-msm-fix-export-c4a4cd9239fc
Best regards,
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] drm/msm: factor out a locking put_iova_spaces() wrapper
2026-08-22 8:48 [PATCH 0/2] drm/msm: fix dma-buf sharing on targets without per-process pgtables Dmitry Baryshkov
@ 2026-08-22 8:48 ` Dmitry Baryshkov
2026-08-22 9:03 ` sashiko-bot
2026-08-22 8:48 ` [PATCH 2/2] drm/msm: don't tear down shared VM mappings on handle close Dmitry Baryshkov
1 sibling, 1 reply; 5+ messages in thread
From: Dmitry Baryshkov @ 2026-08-22 8:48 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Konrad Dybcio, Akhil P Oommen, Sumit Semwal, Christian König,
Antonino Maniscalco
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, linux-media,
linaro-mm-sig
put_iova_spaces() asserts that the caller already holds the VM and object
locks, but is not named accordingly. Both of the callers which do not
hold those locks yet -- msm_gem_close() and msm_gem_vma_put() -- open-code
the same lock, tear down, unlock sequence around it.
Rename it to put_iova_spaces_locked() and give the plain name to a wrapper
taking both locks, mirroring the get_and_pin_iova_range_locked() /
msm_gem_get_and_pin_iova_range() pair in the same file. No functional
change.
Assisted-by: LLM
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/gpu/drm/msm/msm_gem.c | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index c4cff3d53d81..f90afffe3442 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -47,13 +47,23 @@ static int msm_gem_open(struct drm_gem_object *obj, struct drm_file *file)
return 0;
}
+static void put_iova_spaces_locked(struct drm_gem_object *obj,
+ struct drm_gpuvm *vm, bool close,
+ const char *reason);
+
static void put_iova_spaces(struct drm_gem_object *obj, struct drm_gpuvm *vm,
- bool close, const char *reason);
+ bool close, const char *reason)
+{
+ struct drm_exec exec;
+
+ msm_gem_lock_vm_and_obj(&exec, obj, vm);
+ put_iova_spaces_locked(obj, vm, close, reason);
+ drm_exec_fini(&exec); /* drop locks */
+}
static void msm_gem_close(struct drm_gem_object *obj, struct drm_file *file)
{
struct msm_context *ctx = file->driver_priv;
- struct drm_exec exec;
update_ctx_mem(file, -obj->size);
msm_gem_vma_put(obj);
@@ -81,9 +91,7 @@ static void msm_gem_close(struct drm_gem_object *obj, struct drm_file *file)
dma_resv_wait_timeout(obj->resv, DMA_RESV_USAGE_BOOKKEEP, false,
MAX_SCHEDULE_TIMEOUT);
- msm_gem_lock_vm_and_obj(&exec, obj, ctx->vm);
put_iova_spaces(obj, ctx->vm, true, "close");
- drm_exec_fini(&exec); /* drop locks */
}
/*
@@ -106,11 +114,7 @@ void msm_gem_vma_put(struct drm_gem_object *obj)
return;
#ifdef CONFIG_DRM_MSM_KMS
- struct drm_exec exec;
-
- msm_gem_lock_vm_and_obj(&exec, obj, priv->kms->vm);
put_iova_spaces(obj, priv->kms->vm, true, "vma_put");
- drm_exec_fini(&exec); /* drop locks */
#endif
}
@@ -409,8 +413,8 @@ static struct drm_gpuva *lookup_vma(struct drm_gem_object *obj,
* mapping.
*/
static void
-put_iova_spaces(struct drm_gem_object *obj, struct drm_gpuvm *vm,
- bool close, const char *reason)
+put_iova_spaces_locked(struct drm_gem_object *obj, struct drm_gpuvm *vm,
+ bool close, const char *reason)
{
struct drm_gpuvm_bo *vm_bo, *tmp;
@@ -669,7 +673,7 @@ void msm_gem_unpin_iova(struct drm_gem_object *obj, struct drm_gpuvm *vm)
msm_gem_unpin_locked(obj);
}
if (!is_kms_vm(vm))
- put_iova_spaces(obj, vm, true, "close");
+ put_iova_spaces_locked(obj, vm, true, "close");
drm_exec_fini(&exec); /* drop locks */
}
@@ -831,7 +835,7 @@ void msm_gem_purge(struct drm_gem_object *obj)
GEM_WARN_ON(!is_purgeable(msm_obj));
/* Get rid of any iommu mapping(s): */
- put_iova_spaces(obj, NULL, false, "purge");
+ put_iova_spaces_locked(obj, NULL, false, "purge");
msm_gem_vunmap(obj);
@@ -869,7 +873,7 @@ void msm_gem_evict(struct drm_gem_object *obj)
GEM_WARN_ON(is_unevictable(msm_obj));
/* Get rid of any iommu mapping(s): */
- put_iova_spaces(obj, NULL, false, "evict");
+ put_iova_spaces_locked(obj, NULL, false, "evict");
drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
@@ -1082,7 +1086,7 @@ static void msm_gem_free_object(struct drm_gem_object *obj)
drm_exec_retry_on_contention(&exec);
}
}
- put_iova_spaces(obj, NULL, true, "free");
+ put_iova_spaces_locked(obj, NULL, true, "free");
drm_exec_fini(&exec); /* drop locks */
}
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] drm/msm: don't tear down shared VM mappings on handle close
2026-08-22 8:48 [PATCH 0/2] drm/msm: fix dma-buf sharing on targets without per-process pgtables Dmitry Baryshkov
2026-08-22 8:48 ` [PATCH 1/2] drm/msm: factor out a locking put_iova_spaces() wrapper Dmitry Baryshkov
@ 2026-08-22 8:48 ` Dmitry Baryshkov
2026-08-22 9:07 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Dmitry Baryshkov @ 2026-08-22 8:48 UTC (permalink / raw)
To: Rob Clark, Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang,
Sean Paul, Marijn Suijten, David Airlie, Simona Vetter,
Konrad Dybcio, Akhil P Oommen, Sumit Semwal, Christian König,
Antonino Maniscalco
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, linux-media,
linaro-mm-sig
On targets (like A530 / MSM8996) without per-process pgtables
msm_gpu_create_private_vm() uses the global VM, so all DRM files share
one GPU address space. msm_gem_close() unmaps the object from ctx->vm,
which on those targets pulls the buffer out from under every other file
that still has it open, and frees the iova for immediate reuse.
A dma-buf imported into a second file hits this as soon as the exporter
closes its handle: the importer's texture keeps sampling the old
address, which the next allocation has taken over. On a530 this is
every ext_image_dma_buf_import sampling test, reading back all zeros.
The VMA teardown a shared VM needs is the one already used for kms->vm
-- defer it to the @vma_ref drop, when the last handle and dma_buf
reference are gone. That restores the pre-drm_gpuvm lifetime without
reintroducing the reference loop, since a BO with a live vma_ref is held
by userspace anyway.
Fixes: 111fdd2198e6 ("drm/msm: drm_gpuvm conversion")
Assisted-by: LLM
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
---
drivers/gpu/drm/msm/msm_gem.c | 13 ++++++++++++-
drivers/gpu/drm/msm/msm_gpu.c | 4 +++-
drivers/gpu/drm/msm/msm_gpu.h | 3 +++
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index f90afffe3442..e73cf49c360e 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -63,6 +63,7 @@ static void put_iova_spaces(struct drm_gem_object *obj, struct drm_gpuvm *vm,
static void msm_gem_close(struct drm_gem_object *obj, struct drm_file *file)
{
+ struct msm_drm_private *priv = obj->dev->dev_private;
struct msm_context *ctx = file->driver_priv;
update_ctx_mem(file, -obj->size);
@@ -84,6 +85,10 @@ static void msm_gem_close(struct drm_gem_object *obj, struct drm_file *file)
if (msm_context_is_vmbind(ctx))
return;
+ /* A global VM's VMAs are torn down by the @vma_ref drop above */
+ if (priv->gpu && ctx->vm == priv->gpu->vm)
+ return;
+
/*
* TODO we might need to kick this to a queue to avoid blocking
* in CLOSE ioctl
@@ -95,7 +100,7 @@ static void msm_gem_close(struct drm_gem_object *obj, struct drm_file *file)
}
/*
- * Get/put for kms->vm VMA
+ * Get/put for VMAs in VMs shared between contexts: kms->vm, gpu->vm
*/
void msm_gem_vma_get(struct drm_gem_object *obj)
@@ -110,6 +115,12 @@ void msm_gem_vma_put(struct drm_gem_object *obj)
if (atomic_dec_return(&to_msm_bo(obj)->vma_ref))
return;
+ if (priv->gpu && priv->gpu->vm_shared) {
+ dma_resv_wait_timeout(obj->resv, DMA_RESV_USAGE_BOOKKEEP, false,
+ MAX_SCHEDULE_TIMEOUT);
+ put_iova_spaces(obj, priv->gpu->vm, true, "vma_put");
+ }
+
if (!priv->kms)
return;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 0c2c35636251..31d84e2b123a 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -879,8 +879,10 @@ msm_gpu_create_private_vm(struct msm_gpu *gpu, struct task_struct *task,
to_msm_vm(vm)->pid = get_pid(task_pid(task));
}
- if (IS_ERR_OR_NULL(vm) && kernel_managed)
+ if (IS_ERR_OR_NULL(vm) && kernel_managed) {
vm = drm_gpuvm_get(gpu->vm);
+ gpu->vm_shared = true;
+ }
return vm;
}
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index d27d54bdb7a7..7722776e9129 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -223,6 +223,9 @@ struct msm_gpu {
struct drm_gpuvm *vm;
+ /** @vm_shared: Has @vm been handed out as a context VM? */
+ bool vm_shared;
+
/* Power Control: */
struct regulator *gpu_reg, *gpu_cx;
struct clk_bulk_data *grp_clks;
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] drm/msm: factor out a locking put_iova_spaces() wrapper
2026-08-22 8:48 ` [PATCH 1/2] drm/msm: factor out a locking put_iova_spaces() wrapper Dmitry Baryshkov
@ 2026-08-22 9:03 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-08-22 9:03 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: dri-devel, media-ci
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] The VMA reference count (`vma_ref`) is decremented and checked outside of the VMA/object lock, leading to a TOCTOU race where an active VMA can be unmapped and freed while in use by another thread.
--
--- Patch [1]: [PATCH 1/2] drm/msm: factor out a locking put_iova_spaces() wrapper ---
commit 3d4e26e168daef686a19b61570238be2722c0b4d
Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Subject: drm/msm: factor out a locking put_iova_spaces() wrapper
This commit factors out a locking put_iova_spaces_locked() wrapper and
updates callers. It aims to clean up redundant lock, tear down, and unlock
sequences around the teardown path.
> diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
> index de4e60e28a711..8b979d84bb958 100644
> --- a/drivers/gpu/drm/msm/msm_gem.c
> +++ b/drivers/gpu/drm/msm/msm_gem.c
[ ... ]
> @@ -105,11 +113,7 @@ void msm_gem_vma_put(struct drm_gem_object *obj)
> return;
>
> #ifdef CONFIG_DRM_MSM_KMS
> - struct drm_exec exec;
> -
> - msm_gem_lock_vm_and_obj(&exec, obj, priv->kms->vm);
> put_iova_spaces(obj, priv->kms->vm, true, "vma_put");
> - drm_exec_fini(&exec); /* drop locks */
> #endif
> }
[ ... ]
> @@ -408,8 +412,8 @@ static struct drm_gpuva *lookup_vma(struct drm_gem_object *obj,
> * mapping.
> */
> static void
> -put_iova_spaces(struct drm_gem_object *obj, struct drm_gpuvm *vm,
> - bool close, const char *reason)
> +put_iova_spaces_locked(struct drm_gem_object *obj, struct drm_gpuvm *vm,
> + bool close, const char *reason)
> {
> struct drm_gpuvm_bo *vm_bo, *tmp;
[Severity: Critical]
This is a pre-existing issue, but can the lockless decrement of vma_ref in
msm_gem_vma_put() cause a race condition?
If CPU1 calls msm_gem_close() -> msm_gem_vma_put() and decrements vma_ref to
0, but gets preempted before taking the lock and calling put_iova_spaces():
CPU2 could concurrently open the GEM object (e.g., via flink), calling
msm_gem_open() -> msm_gem_vma_get(), incrementing vma_ref back to 1,
mapping the object, and submitting a job.
When CPU1 resumes, it continues into put_iova_spaces() and eventually
put_iova_spaces_locked():
drivers/gpu/drm/msm/msm_gem.c:put_iova_spaces_locked() {
...
drm_gpuvm_bo_for_each_va_safe (vma, vmatmp, vm_bo) {
msm_gem_vma_unmap(vma, reason);
if (close)
msm_gem_vma_close(vma);
}
...
}
Since vma_ref isn't re-checked inside the lock, the IOVA space is torn down
unconditionally. Could this result in tearing down an active IOVA mapping
while the GPU is executing a job, leading to an IOMMU fault or memory
corruption?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260822-msm-fix-export-v1-0-917b3cbedd43@oss.qualcomm.com?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] drm/msm: don't tear down shared VM mappings on handle close
2026-08-22 8:48 ` [PATCH 2/2] drm/msm: don't tear down shared VM mappings on handle close Dmitry Baryshkov
@ 2026-08-22 9:07 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-08-22 9:07 UTC (permalink / raw)
To: Dmitry Baryshkov; +Cc: dri-devel, media-ci
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Sleeping in atomic context
- [High] Deferred teardown TOCTOU race via flink name re-opening causing IOVA Use-After-Free
--
--- Patch [2]: [PATCH 2/2] drm/msm: don't tear down shared VM mappings on handle close ---
commit c4a550033efcf938dc9587175385266d18df3979
Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
drm/msm: don't tear down shared VM mappings on handle close
This patch defers the teardown of shared GPU VM mappings until the vma_ref
count drops to zero. This aims to prevent pulling the buffer out from under
other files that still have it open when sharing a global VM address space
on targets without per-process pgtables.
Fixes: 111fdd2198e6 ("drm/msm: drm_gpuvm conversion")
> diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
> index 8b979d84bb958..f17ecd97b72a3 100644
> --- a/drivers/gpu/drm/msm/msm_gem.c
> +++ b/drivers/gpu/drm/msm/msm_gem.c
[ ... ]
> @@ -109,6 +114,12 @@ void msm_gem_vma_put(struct drm_gem_object *obj)
> if (atomic_dec_return(&to_msm_bo(obj)->vma_ref))
> return;
>
> + if (priv->gpu && priv->gpu->vm_shared) {
> + dma_resv_wait_timeout(obj->resv, DMA_RESV_USAGE_BOOKKEEP, false,
> + MAX_SCHEDULE_TIMEOUT);
> + put_iova_spaces(obj, priv->gpu->vm, true, "vma_put");
> + }
> +
[Severity: High]
This is a pre-existing issue, but can this lockless vma_ref check lead to an
IOVA use-after-free if a GEM handle is concurrently closed and re-opened via
flink?
If Thread A closes the last handle, atomic_dec_return() drops vma_ref to 0
and it proceeds to unmap the buffer. However, the flink name remains valid
until drm_gem_object_handle_put_unlocked() runs. If Thread B calls
DRM_IOCTL_GEM_OPEN concurrently, msm_gem_open() can increment vma_ref back to
1 and submit a job using the IOVA. Thread A then acquires locks in
put_iova_spaces() and unconditionally unmaps the buffer via
put_iova_spaces_locked() without re-verifying vma_ref:
drivers/gpu/drm/msm/msm_gem.c:put_iova_spaces_locked() {
...
drm_gpuvm_bo_for_each_va_safe (vma, vmatmp, vm_bo) {
msm_gem_vma_unmap(vma, reason);
if (close)
msm_gem_vma_close(vma);
}
}
Will this destroy Thread B's mapping while its job is running, freeing the
IOVA for immediate reuse?
[Severity: High]
This isn't a bug introduced by this patch, but does adding these blocking
calls cause a scheduling while atomic panic when tearing down a writeback
connector?
The drm core function drm_writeback_connector_cleanup() holds a spinlock with
IRQs disabled when tearing down pending jobs:
drivers/gpu/drm/drm_writeback.c:drm_writeback_connector_cleanup() {
spin_lock_irqsave(&wb_connector->job_lock, flags);
list_for_each_entry_safe(pos, n, &wb_connector->job_queue, list_entry) {
list_del(&pos->list_entry);
drm_writeback_cleanup_job(pos);
}
}
This calls into msm_gem_vma_put() through the teardown path
(dpu_wb_conn_cleanup_job -> dpu_encoder_cleanup_wb_job ->
dpu_encoder_phys_wb_cleanup_wb_job -> msm_framebuffer_cleanup ->
msm_gem_vma_put).
Since dma_resv_wait_timeout() can wait indefinitely and put_iova_spaces()
acquires ww_mutexes via drm_exec, could this result in sleeping while holding
a spinlock with IRQs disabled?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260822-msm-fix-export-v1-0-917b3cbedd43@oss.qualcomm.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-22 9:08 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-22 8:48 [PATCH 0/2] drm/msm: fix dma-buf sharing on targets without per-process pgtables Dmitry Baryshkov
2026-08-22 8:48 ` [PATCH 1/2] drm/msm: factor out a locking put_iova_spaces() wrapper Dmitry Baryshkov
2026-08-22 9:03 ` sashiko-bot
2026-08-22 8:48 ` [PATCH 2/2] drm/msm: don't tear down shared VM mappings on handle close Dmitry Baryshkov
2026-08-22 9:07 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox