All of lore.kernel.org
 help / color / mirror / Atom feed
* [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; 8+ 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] 8+ 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; 8+ 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] 8+ 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
                     ` (2 more replies)
  1 sibling, 3 replies; 8+ 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] 8+ 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; 8+ 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] 8+ 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
  2026-10-05 15:00     ` Rob Clark
  2026-10-05 14:54   ` Rob Clark
  2026-10-09  2:16   ` Alexey Minnekhanov
  2 siblings, 1 reply; 8+ 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] 8+ 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
@ 2026-10-05 14:54   ` Rob Clark
  2026-10-09  2:16   ` Alexey Minnekhanov
  2 siblings, 0 replies; 8+ messages in thread
From: Rob Clark @ 2026-10-05 14:54 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: 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, linux-arm-msm, dri-devel, freedreno,
	linux-kernel, linux-media, linaro-mm-sig

On Sat, Aug 22, 2026 at 1:49 AM Dmitry Baryshkov
<dmitry.baryshkov@oss.qualcomm.com> wrote:
>
> 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;

nit, this seems unnecessary, just check if vm == gpu->vm

> +
>         /* Power Control: */
>         struct regulator *gpu_reg, *gpu_cx;
>         struct clk_bulk_data *grp_clks;
>
> --
> 2.47.3
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] drm/msm: don't tear down shared VM mappings on handle close
  2026-08-22  9:07   ` sashiko-bot
@ 2026-10-05 15:00     ` Rob Clark
  0 siblings, 0 replies; 8+ messages in thread
From: Rob Clark @ 2026-10-05 15:00 UTC (permalink / raw)
  To: sashiko-reviews, Dmitry Baryshkov; +Cc: dri-devel, media-ci, freedreno

On Sat, Aug 22, 2026 at 2:08 AM <sashiko-bot@kernel.org> wrote:
>
> 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:

This is already invalid, the flink name doesn't hold a ref to the obj.
The exporter must hold the obj live (by not closing the handle) of an
flink exported BO.

>
> 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);
>     }
> }

Hmm, someone should look at this.. maybe we could move to an on-stack
list under a lock, and then do cleanup outside of the lock?

BR,
-R

>
> 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] 8+ 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
  2026-10-05 14:54   ` Rob Clark
@ 2026-10-09  2:16   ` Alexey Minnekhanov
  2 siblings, 0 replies; 8+ messages in thread
From: Alexey Minnekhanov @ 2026-10-09  2:16 UTC (permalink / raw)
  To: Dmitry Baryshkov, 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 22.08.2026 11:48, Dmitry Baryshkov wrote:
> 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(-)
>

Tested on device with a512, previously faults were easily reproducible,
like almost on every window/popup close.
They looked like

  gpu fault: ttbr0=0000000046fdf000 iova=0000000004635f00 dir=READ 
type=TRANSLATION source=1030001 (0,0,0,0)
  gpu fault: ttbr0=0000000046fdf000 iova=000000000462d700 dir=READ 
type=TRANSLATION source=2030001 (0,0,0,0)
  gpu fault: ttbr0=0000000046fdf000 iova=0000000004c6e380 dir=READ 
type=TRANSLATION source=4030001 (0,0,0,0)
  gpu fault: ttbr0=0000000046fdf000 iova=000000000497eb00 dir=READ 
type=TRANSLATION source=2030001 (0,0,0,0)

and now cannot be seen anymore with these series applied.

Tested-by: Alexey Minnekhanov <alexeymin@minlexx.ru>

--
Regards,
Alexey Minnekhanov

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-10-09  2:17 UTC | newest]

Thread overview: 8+ 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
2026-10-05 15:00     ` Rob Clark
2026-10-05 14:54   ` Rob Clark
2026-10-09  2:16   ` Alexey Minnekhanov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.