All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] drm/amdgpu: fix TTM device_list use-after-free on failed probe
@ 2026-11-13 14:41 Mario Limonciello
  2026-11-13 14:41 ` [PATCH 1/3] drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure Mario Limonciello
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 14:41 UTC (permalink / raw)
  To: Alex Deucher, Christian König; +Cc: amd-gfx, Mario Limonciello

When amdgpu probe fails after ttm_device_init() has succeeded, the freed
amdgpu_device stays linked on ttm_glob.device_list. The next
ttm_device_init() or ttm_global_swapout() then touches freed memory
(list_add corruption on the following bind).

Failure points are any error return in amdgpu_ttm_init() after
ttm_device_init(), and gmc_v*_sw_init() failing after amdgpu_bo_init().
In the latter case GMC's status.sw stays false, so amdgpu_device_ip_fini()
skips its sw_fini, which is the only path to amdgpu_bo_fini() ->
amdgpu_ttm_fini() -> ttm_device_fini(). The leaked MMIO_REMAP BO also
shows up as "Memory manager not clean" on the next bind.

Patch 1 unwinds amdgpu_ttm_init() through amdgpu_ttm_fini() and makes
that function safe on a partially initialized device.
Patch 2 unwinds amdgpu_bo_init() in the GMC sw_init paths (v6-v12).
Patch 3 releases the WC memtype and MTRR when amdgpu_bo_init() fails
after reserving them.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
Mario Limonciello (3):
      drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure
      drm/amdgpu: unwind bo_init on GMC sw_init failure
      drm/amdgpu: release WC memtype and MTRR when amdgpu_bo_init() fails

 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 20 +++++++++++---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c    | 43 ++++++++++++++++++------------
 drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c     | 10 +++++--
 drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c     | 10 +++++--
 drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c     | 10 +++++--
 drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c      |  6 ++++-
 drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c      | 14 +++++++---
 drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c      | 14 +++++++---
 drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c      | 10 +++++--
 9 files changed, 102 insertions(+), 35 deletions(-)
---
base-commit: 71830abced88ee7665010e79b51f0789b033cc3a
change-id: 20261113-superm1-amdgpu-memory-leak-a2a6b2a93efb

Best regards,
--  
Mario Limonciello <mario.limonciello@amd.com>


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

* [PATCH 1/3] drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure
  2026-11-13 14:41 [PATCH 0/3] drm/amdgpu: fix TTM device_list use-after-free on failed probe Mario Limonciello
@ 2026-11-13 14:41 ` Mario Limonciello
  2026-11-13 14:41 ` [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure Mario Limonciello
  2026-11-13 14:41 ` [PATCH 3/3] drm/amdgpu: release WC memtype and MTRR when amdgpu_bo_init() fails Mario Limonciello
  2 siblings, 0 replies; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 14:41 UTC (permalink / raw)
  To: Alex Deucher, Christian König; +Cc: amd-gfx, Mario Limonciello

If amdgpu_ttm_init() fails after ttm_device_init() succeeded, the error
paths just return. Nothing later calls ttm_device_fini() because the GMC
IP block never reaches sw_fini, so the freed amdgpu_device stays linked
on ttm_glob.device_list. The next ttm_device_init() or
ttm_global_swapout() then walks freed memory. The MMIO_REMAP BO created
in amdgpu_ttm_init() is also leaked, which shows up as "Memory manager
not clean" on the following bind.

Route every error after ttm_device_init() through amdgpu_ttm_fini(), and
mark the manager initialized as soon as ttm_device_init() succeeds so the
unwind also covers a pool init failure. Make amdgpu_ttm_fini() skip the
VRAM, GTT and PREEMPT managers when they were never registered, as it can
now run on a partially initialized device.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 43 ++++++++++++++++++++-------------
 1 file changed, 26 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 8dfa92967b630..7828caf8aba0d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -2153,20 +2153,21 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
 			"failed initializing buffer object driver(%d).\n", r);
 		return r;
 	}
+	/* from here on amdgpu_ttm_fini() is responsible for unwinding */
+	adev->mman.initialized = true;
 
 	r = amdgpu_ttm_pools_init(adev);
 	if (r) {
 		dev_err(adev->dev, "failed to init ttm pools(%d).\n", r);
-		return r;
+		goto err_fini;
 	}
-	adev->mman.initialized = true;
 
 	if (!adev->gmc.is_app_apu) {
 		/* Initialize VRAM pool with all of VRAM divided into pages */
 		r = amdgpu_vram_mgr_init(adev);
 		if (r) {
 			dev_err(adev->dev, "Failed initializing VRAM heap.\n");
-			return r;
+			goto err_fini;
 		}
 	}
 
@@ -2190,7 +2191,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
 
 	r = amdgpu_ttm_alloc_vram_resv_regions(adev);
 	if (r)
-		return r;
+		goto err_fini;
 
 	/* RAS loads and reserves bad pages */
 	amdgpu_ras_mgr_early_init_service(adev);
@@ -2239,7 +2240,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
 	r = amdgpu_gtt_mgr_init(adev, gtt_size);
 	if (r) {
 		dev_err(adev->dev, "Failed initializing GTT heap.\n");
-		return r;
+		goto err_fini;
 	}
 	dev_info(adev->dev, " %uM of GTT memory ready.\n",
 		 (unsigned int)(gtt_size / (1024 * 1024)));
@@ -2253,52 +2254,52 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
 	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_DOORBELL, adev->doorbell.size / PAGE_SIZE);
 	if (r) {
 		dev_err(adev->dev, "Failed initializing doorbell heap.\n");
-		return r;
+		goto err_fini;
 	}
 
 	/* Create a doorbell page for kernel usages */
 	r = amdgpu_doorbell_create_kernel_doorbells(adev);
 	if (r) {
 		dev_err(adev->dev, "Failed to initialize kernel doorbells.\n");
-		return r;
+		goto err_fini;
 	}
 
 	/* Initialize MMIO-remap pool (single page 4K) */
 	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_MMIO_REMAP, 1);
 	if (r) {
 		dev_err(adev->dev, "Failed initializing MMIO-remap heap.\n");
-		return r;
+		goto err_fini;
 	}
 
 	/* Allocate the singleton MMIO_REMAP BO if supported */
 	r = amdgpu_ttm_alloc_mmio_remap_bo(adev);
 	if (r)
-		return r;
+		goto err_fini;
 
 	/* Initialize preemptible memory pool */
 	r = amdgpu_preempt_mgr_init(adev);
 	if (r) {
 		dev_err(adev->dev, "Failed initializing PREEMPT heap.\n");
-		return r;
+		goto err_fini;
 	}
 
 	/* Initialize various on-chip memory pools */
 	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size);
 	if (r) {
 		dev_err(adev->dev, "Failed initializing GDS heap.\n");
-		return r;
+		goto err_fini;
 	}
 
 	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size);
 	if (r) {
 		dev_err(adev->dev, "Failed initializing gws heap.\n");
-		return r;
+		goto err_fini;
 	}
 
 	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size);
 	if (r) {
 		dev_err(adev->dev, "Failed initializing oa heap.\n");
-		return r;
+		goto err_fini;
 	}
 
 	if (adev->ualink.npa_size) {
@@ -2306,7 +2307,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
 					    adev->ualink.npa_size);
 		if (r) {
 			dev_err(adev->dev, "Failed initializing NPA heap.\n");
-			return r;
+			goto err_fini;
 		}
 	}
 
@@ -2318,6 +2319,10 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
 				"Debug VRAM access will use slowpath MM access\n");
 
 	return 0;
+
+err_fini:
+	amdgpu_ttm_fini(adev);
+	return r;
 }
 
 /*
@@ -2352,10 +2357,14 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
 		adev->mman.aper_base_kaddr = NULL;
 	}
 
-	if (!adev->gmc.is_app_apu)
+	/* may be called on a partially initialized TTM, skip unregistered managers */
+	if (!adev->gmc.is_app_apu &&
+	    ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM))
 		amdgpu_vram_mgr_fini(adev);
-	amdgpu_gtt_mgr_fini(adev);
-	amdgpu_preempt_mgr_fini(adev);
+	if (ttm_manager_type(&adev->mman.bdev, TTM_PL_TT))
+		amdgpu_gtt_mgr_fini(adev);
+	if (ttm_manager_type(&adev->mman.bdev, AMDGPU_PL_PREEMPT))
+		amdgpu_preempt_mgr_fini(adev);
 	amdgpu_doorbell_fini(adev);
 
 	ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS);

-- 
2.43.0


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

* [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure
  2026-11-13 14:41 [PATCH 0/3] drm/amdgpu: fix TTM device_list use-after-free on failed probe Mario Limonciello
  2026-11-13 14:41 ` [PATCH 1/3] drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure Mario Limonciello
@ 2026-11-13 14:41 ` Mario Limonciello
  2026-11-13 14:56   ` sashiko-bot
  2026-11-13 14:41 ` [PATCH 3/3] drm/amdgpu: release WC memtype and MTRR when amdgpu_bo_init() fails Mario Limonciello
  2 siblings, 1 reply; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 14:41 UTC (permalink / raw)
  To: Alex Deucher, Christian König; +Cc: amd-gfx, Mario Limonciello

When gmc_v*_sw_init() fails after amdgpu_bo_init(), the GMC block's
status.sw stays false, so amdgpu_device_ip_fini() skips its sw_fini and
amdgpu_bo_fini() (and thus ttm_device_fini()) is never called. The
freed device is left on ttm_glob.device_list.

Unwind on the failure paths after amdgpu_bo_init(): GART init failures
call amdgpu_bo_fini(); later failures (RAS sw init on v9-v12,
vm_fault_info allocation on v7/v8) also call amdgpu_vm_manager_fini().

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c | 10 ++++++++--
 drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c | 10 ++++++++--
 drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c | 10 ++++++++--
 drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c  |  6 +++++-
 drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c  | 14 +++++++++++---
 drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c  | 14 +++++++++++---
 drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c  | 10 ++++++++--
 7 files changed, 59 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
index 49f593fe2a876..e59fee3955af0 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
@@ -861,7 +861,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = gmc_v10_0_gart_init(adev);
 	if (r)
-		return r;
+		goto err_bo_fini;
 
 	/*
 	 * number of VMs
@@ -880,9 +880,15 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = amdgpu_gmc_ras_sw_init(adev);
 	if (r)
-		return r;
+		goto err_vm_fini;
 
 	return 0;
+
+err_vm_fini:
+	amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+	amdgpu_bo_fini(adev);
+	return r;
 }
 
 /**
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
index bc3b1ffb54886..e492a8fd8eb21 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c
@@ -859,7 +859,7 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = gmc_v11_0_gart_init(adev);
 	if (r)
-		return r;
+		goto err_bo_fini;
 
 	/*
 	 * number of VMs
@@ -879,9 +879,15 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = amdgpu_gmc_ras_sw_init(adev);
 	if (r)
-		return r;
+		goto err_vm_fini;
 
 	return 0;
+
+err_vm_fini:
+	amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+	amdgpu_bo_fini(adev);
+	return r;
 }
 
 /**
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
index 3bb13cfed92fe..acebd6697372f 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c
@@ -987,7 +987,7 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = gmc_v12_0_gart_init(adev);
 	if (r)
-		return r;
+		goto err_bo_fini;
 
 	if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0))
 		gmc_v12_1_init_nps_details(adev);
@@ -1021,12 +1021,18 @@ static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = amdgpu_gmc_ras_sw_init(adev);
 	if (r)
-		return r;
+		goto err_vm_fini;
 
 	if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0))
 		amdgpu_gmc_sysfs_init(adev);
 
 	return 0;
+
+err_vm_fini:
+	amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+	amdgpu_bo_fini(adev);
+	return r;
 }
 
 /**
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
index a7c353d1ac09d..925e9e243a143 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
@@ -817,7 +817,7 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = gmc_v6_0_gart_init(adev);
 	if (r)
-		return r;
+		goto err_bo_fini;
 
 	/*
 	 * number of VMs
@@ -840,6 +840,10 @@ static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
 	}
 
 	return 0;
+
+err_bo_fini:
+	amdgpu_bo_fini(adev);
+	return r;
 }
 
 static int gmc_v6_0_sw_fini(struct amdgpu_ip_block *ip_block)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index c09f5153679ea..3f3e4105bf3e6 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -999,7 +999,7 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = gmc_v7_0_gart_init(adev);
 	if (r)
-		return r;
+		goto err_bo_fini;
 
 	/*
 	 * number of VMs
@@ -1026,11 +1026,19 @@ static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block)
 	}
 
 	adev->gmc.vm_fault_info = kmalloc_obj(struct kfd_vm_fault_info);
-	if (!adev->gmc.vm_fault_info)
-		return -ENOMEM;
+	if (!adev->gmc.vm_fault_info) {
+		r = -ENOMEM;
+		goto err_vm_fini;
+	}
 	atomic_set_release(&adev->gmc.vm_fault_info_updated, 0);
 
 	return 0;
+
+err_vm_fini:
+	amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+	amdgpu_bo_fini(adev);
+	return r;
 }
 
 static int gmc_v7_0_sw_fini(struct amdgpu_ip_block *ip_block)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index 15592027e7c0c..cb6d6e2259f3b 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -1114,7 +1114,7 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = gmc_v8_0_gart_init(adev);
 	if (r)
-		return r;
+		goto err_bo_fini;
 
 	/*
 	 * number of VMs
@@ -1141,11 +1141,19 @@ static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block)
 	}
 
 	adev->gmc.vm_fault_info = kmalloc_obj(struct kfd_vm_fault_info);
-	if (!adev->gmc.vm_fault_info)
-		return -ENOMEM;
+	if (!adev->gmc.vm_fault_info) {
+		r = -ENOMEM;
+		goto err_vm_fini;
+	}
 	atomic_set_release(&adev->gmc.vm_fault_info_updated, 0);
 
 	return 0;
+
+err_vm_fini:
+	amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+	amdgpu_bo_fini(adev);
+	return r;
 }
 
 static int gmc_v8_0_sw_fini(struct amdgpu_ip_block *ip_block)
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index a705830ef436c..136e4130b7926 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -2026,7 +2026,7 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = gmc_v9_0_gart_init(adev);
 	if (r)
-		return r;
+		goto err_bo_fini;
 
 	gmc_v9_0_init_nps_details(adev);
 	/*
@@ -2066,12 +2066,18 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	r = amdgpu_gmc_ras_sw_init(adev);
 	if (r)
-		return r;
+		goto err_vm_fini;
 
 	if (amdgpu_is_multi_aid(adev))
 		amdgpu_gmc_sysfs_init(adev);
 
 	return 0;
+
+err_vm_fini:
+	amdgpu_vm_manager_fini(adev);
+err_bo_fini:
+	amdgpu_bo_fini(adev);
+	return r;
 }
 
 static int gmc_v9_0_sw_fini(struct amdgpu_ip_block *ip_block)

-- 
2.43.0


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

* [PATCH 3/3] drm/amdgpu: release WC memtype and MTRR when amdgpu_bo_init() fails
  2026-11-13 14:41 [PATCH 0/3] drm/amdgpu: fix TTM device_list use-after-free on failed probe Mario Limonciello
  2026-11-13 14:41 ` [PATCH 1/3] drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure Mario Limonciello
  2026-11-13 14:41 ` [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure Mario Limonciello
@ 2026-11-13 14:41 ` Mario Limonciello
  2 siblings, 0 replies; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 14:41 UTC (permalink / raw)
  To: Alex Deucher, Christian König; +Cc: amd-gfx, Mario Limonciello

amdgpu_bo_init() reserves the WC memtype for the VRAM aperture and adds
an MTRR before calling amdgpu_ttm_init(). If amdgpu_ttm_init() fails,
the GMC sw_init callers just return the error and GMC's sw_fini is never
run, so amdgpu_bo_fini(), the only place that drops the memtype and MTRR,
is never called. A later rebind then reserves the same aperture again
with the old reservation still held.

Undo the memtype reservation and the MTRR in amdgpu_bo_init() itself when
amdgpu_ttm_init() fails.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 6aa895f63aeaf..0b34458301f3f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -1108,11 +1108,13 @@ static const char * const amdgpu_vram_names[] = {
  */
 int amdgpu_bo_init(struct amdgpu_device *adev)
 {
+	int r;
+
 	/* On A+A platform, VRAM can be mapped as WB */
 	if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
 		/* reserve PAT memory space to WC for VRAM */
-		int r = arch_io_reserve_memtype_wc(adev->gmc.aper_base,
-				adev->gmc.aper_size);
+		r = arch_io_reserve_memtype_wc(adev->gmc.aper_base,
+					       adev->gmc.aper_size);
 
 		if (r) {
 			DRM_ERROR("Unable to set WC memtype for the aperture base\n");
@@ -1129,7 +1131,19 @@ int amdgpu_bo_init(struct amdgpu_device *adev)
 		 (unsigned long long)adev->gmc.aper_size >> 20);
 	drm_info(adev_to_drm(adev), "RAM width %dbits %s\n",
 		 adev->gmc.vram_width, amdgpu_vram_names[adev->gmc.vram_type]);
-	return amdgpu_ttm_init(adev);
+
+	r = amdgpu_ttm_init(adev);
+	if (r) {
+		/* the caller does not call amdgpu_bo_fini() when we fail */
+		if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
+			arch_phys_wc_del(adev->gmc.vram_mtrr);
+			arch_io_free_memtype_wc(adev->gmc.aper_base,
+						adev->gmc.aper_size);
+		}
+		return r;
+	}
+
+	return 0;
 }
 
 /**

-- 
2.43.0


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

* Re: [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure
  2026-11-13 14:41 ` [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure Mario Limonciello
@ 2026-11-13 14:56   ` sashiko-bot
  2026-11-13 15:47     ` Mario Limonciello
  0 siblings, 1 reply; 6+ messages in thread
From: sashiko-bot @ 2026-11-13 14:56 UTC (permalink / raw)
  To: Mario Limonciello; +Cc: amd-gfx

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] drm/amdgpu: gmc_v*_sw_init() calls amdgpu_bo_fini() with
  GART/PDB0 BOs pinned
--

commit 4e2abeed7577cfdf2a67e81d9af414ebfbc361c6
Author: Mario Limonciello <mario.limonciello@amd.com>

drm/amdgpu: unwind bo_init on GMC sw_init failure

This commit unwinds amdgpu_bo_init() and amdgpu_vm_manager_init() when
gmc_v*_sw_init() fails after initializing the memory manager across GMC v6
through v12.

> diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> index 49f593fe2a876..e59fee3955af0 100644
> --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
> @@ -861,7 +861,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
>  
>  	r = gmc_v10_0_gart_init(adev);
>  	if (r)
> -		return r;
> +		goto err_bo_fini;
>  
>  	/*
>  	 * number of VMs
> @@ -880,9 +880,15 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
>  
>  	r = amdgpu_gmc_ras_sw_init(adev);
>  	if (r)
> -		return r;
> +		goto err_vm_fini;
>  
>  	return 0;
> +
> +err_vm_fini:
> +	amdgpu_vm_manager_fini(adev);
> +err_bo_fini:
> +	amdgpu_bo_fini(adev);
> +	return r;
>  }

[Severity: Medium]
Does jumping to err_vm_fini tear down TTM while adev->gart.bo is still
pinned?

gmc_v10_0_gart_init() allocates and pins adev->gart.bo in VRAM.  If
amdgpu_gmc_ras_sw_init() fails, err_vm_fini calls amdgpu_bo_fini() without
first freeing the GART table as gmc_v10_0_sw_fini() does.  Because pinned
BOs cannot be evicted during amdgpu_ttm_fini(), gpu_buddy_fini() and
drm_mm_takedown() hit warnings and leak the pinned BOs and their backing
allocations.

The same missing GART cleanup affects the err_vm_fini paths in GMC v7, v8,
v9, v11, and v12.  On GMC v9 and v12, gmc_v*_gart_init() also allocates
and pins adev->gmc.pdb0_bo when amdgpu_gmc_is_pdb0_enabled() is true, so
both err_vm_fini and a failure in amdgpu_gmc_pdb0_alloc() within
gmc_v*_gart_init() reach amdgpu_bo_fini() with pinned BOs still allocated.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261113-superm1-amdgpu-memory-leak-v1-0-4a495cfc2c92@amd.com?part=2

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

* Re: [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure
  2026-11-13 14:56   ` sashiko-bot
@ 2026-11-13 15:47     ` Mario Limonciello
  0 siblings, 0 replies; 6+ messages in thread
From: Mario Limonciello @ 2026-11-13 15:47 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: amd-gfx



On 11/13/26 08:56, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue to consider:
> - [Medium] drm/amdgpu: gmc_v*_sw_init() calls amdgpu_bo_fini() with
>    GART/PDB0 BOs pinned
> --
> 
> commit 4e2abeed7577cfdf2a67e81d9af414ebfbc361c6
> Author: Mario Limonciello <mario.limonciello@amd.com>
> 
> drm/amdgpu: unwind bo_init on GMC sw_init failure
> 
> This commit unwinds amdgpu_bo_init() and amdgpu_vm_manager_init() when
> gmc_v*_sw_init() fails after initializing the memory manager across GMC v6
> through v12.
> 
>> diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
>> index 49f593fe2a876..e59fee3955af0 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c
>> @@ -861,7 +861,7 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
>>   
>>   	r = gmc_v10_0_gart_init(adev);
>>   	if (r)
>> -		return r;
>> +		goto err_bo_fini;
>>   
>>   	/*
>>   	 * number of VMs
>> @@ -880,9 +880,15 @@ static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block)
>>   
>>   	r = amdgpu_gmc_ras_sw_init(adev);
>>   	if (r)
>> -		return r;
>> +		goto err_vm_fini;
>>   
>>   	return 0;
>> +
>> +err_vm_fini:
>> +	amdgpu_vm_manager_fini(adev);
>> +err_bo_fini:
>> +	amdgpu_bo_fini(adev);
>> +	return r;
>>   }
> 
> [Severity: Medium]
> Does jumping to err_vm_fini tear down TTM while adev->gart.bo is still
> pinned?
> 
> gmc_v10_0_gart_init() allocates and pins adev->gart.bo in VRAM.  If
> amdgpu_gmc_ras_sw_init() fails, err_vm_fini calls amdgpu_bo_fini() without
> first freeing the GART table as gmc_v10_0_sw_fini() does.  Because pinned
> BOs cannot be evicted during amdgpu_ttm_fini(), gpu_buddy_fini() and
> drm_mm_takedown() hit warnings and leak the pinned BOs and their backing
> allocations.
> 
> The same missing GART cleanup affects the err_vm_fini paths in GMC v7, v8,
> v9, v11, and v12.  On GMC v9 and v12, gmc_v*_gart_init() also allocates
> and pins adev->gmc.pdb0_bo when amdgpu_gmc_is_pdb0_enabled() is true, so
> both err_vm_fini and a failure in amdgpu_gmc_pdb0_alloc() within
> gmc_v*_gart_init() reach amdgpu_bo_fini() with pinned BOs still allocated.
> 

This finding looks correct.  I'll re-spin.


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

end of thread, other threads:[~2026-11-13 15:47 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-13 14:41 [PATCH 0/3] drm/amdgpu: fix TTM device_list use-after-free on failed probe Mario Limonciello
2026-11-13 14:41 ` [PATCH 1/3] drm/amdgpu: unwind TTM on amdgpu_ttm_init() failure Mario Limonciello
2026-11-13 14:41 ` [PATCH 2/3] drm/amdgpu: unwind bo_init on GMC sw_init failure Mario Limonciello
2026-11-13 14:56   ` sashiko-bot
2026-11-13 15:47     ` Mario Limonciello
2026-11-13 14:41 ` [PATCH 3/3] drm/amdgpu: release WC memtype and MTRR when amdgpu_bo_init() fails Mario Limonciello

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.