* [PATCH 0/2] drm/amdkfd: fix SVM error handling
@ 2026-11-08 5:13 Aveline Noir
2026-11-08 5:13 ` [PATCH 1/2] drm/amdkfd: handle SVM interval notifier registration failures Aveline Noir
2026-11-08 5:13 ` [PATCH 2/2] drm/amdkfd: check HMM errors before testing range validity Aveline Noir
0 siblings, 2 replies; 5+ messages in thread
From: Aveline Noir @ 2026-11-08 5:13 UTC (permalink / raw)
To: Felix Kuehling, Alex Deucher, Christian König
Cc: David Airlie, Simona Vetter, Philip Yang, Sunil Khatri, honghuan,
honglei1.huang, psirt, amd-gfx, dri-devel, linux-kernel
These patches fix two error paths found while reviewing KFD SVM range
handling. A failed interval notifier registration can leave a published
range without a notifier, and an HMM allocation failure can lead to a
NULL notifier dereference during validation.
The fixes were tested with targeted KUnit tests under KVM with KASAN and
lockdep. The error paths use injected failures or equivalent failure
states; no AMD GPU was tested.
---
Aveline Noir (2):
drm/amdkfd: handle SVM interval notifier registration failures
drm/amdkfd: check HMM errors before testing range validity
drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 58 +++++++++++++++++++++++++++---------
1 file changed, 44 insertions(+), 14 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261108-kfd-svm-baseline-errors-20261107-355a3d0c4792
Best regards,
--
Aveline Noir <jm5905938@gmail.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] drm/amdkfd: handle SVM interval notifier registration failures
2026-11-08 5:13 [PATCH 0/2] drm/amdkfd: fix SVM error handling Aveline Noir
@ 2026-11-08 5:13 ` Aveline Noir
2026-11-08 5:35 ` sashiko-bot
2026-11-08 5:13 ` [PATCH 2/2] drm/amdkfd: check HMM errors before testing range validity Aveline Noir
1 sibling, 1 reply; 5+ messages in thread
From: Aveline Noir @ 2026-11-08 5:13 UTC (permalink / raw)
To: Felix Kuehling, Alex Deucher, Christian König
Cc: David Airlie, Simona Vetter, Philip Yang, Sunil Khatri, honghuan,
honglei1.huang, psirt, amd-gfx, dri-devel, linux-kernel
The first interval notifier registration for an mm can fail while
initializing the interval tree. svm_range_add_notifier_locked() ignores
that error, so SET_ATTR and retry-fault handling can publish an SVM range
without a registered notifier. Subsequent HMM access can then dereference
an uninitialized notifier.
Propagate the registration error and register staged ranges before
publishing the SET_ATTR transaction. Remove successful registrations on
failure before freeing the staged ranges, preserving the original ranges
and the existing memory-accounting rollback. Also free an unpublished
retry-fault range and return its registration error.
Fixes: b1c46c7d622b ("drm/amdkfd: validate svm range system memory")
Signed-off-by: Aveline Noir <jm5905938@gmail.com>
---
drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 56 +++++++++++++++++++++++++++---------
1 file changed, 43 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index ed5e3318877b..8184cbbb829e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -106,16 +106,21 @@ static void svm_range_unlink(struct svm_range *prange)
interval_tree_remove(&prange->it_node, &prange->svms->objects);
}
-static void
+static int
svm_range_add_notifier_locked(struct mm_struct *mm, struct svm_range *prange)
{
+ int r;
+
pr_debug("svms 0x%p prange 0x%p [0x%lx 0x%lx]\n", prange->svms,
prange, prange->start, prange->last);
- mmu_interval_notifier_insert_locked(&prange->notifier, mm,
+ r = mmu_interval_notifier_insert_locked(&prange->notifier, mm,
prange->start << PAGE_SHIFT,
prange->npages << PAGE_SHIFT,
&svm_range_mn_ops);
+ if (r)
+ prange->notifier.mm = NULL;
+ return r;
}
/**
@@ -2257,6 +2262,7 @@ svm_range_split_new(struct svm_range_list *svms, uint64_t start, uint64_t last,
/**
* svm_range_add - add svm range and handle overlap
* @p: the range add to this process svms
+ * @mm: the process address space, write locked by the caller
* @start: page size aligned
* @size: page size aligned
* @nattr: number of attributes
@@ -2285,7 +2291,8 @@ svm_range_split_new(struct svm_range_list *svms, uint64_t start, uint64_t last,
* 0 - OK, otherwise error code
*/
static int
-svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size,
+svm_range_add(struct kfd_process *p, struct mm_struct *mm,
+ uint64_t start, uint64_t size,
uint32_t nattr, struct kfd_ioctl_svm_attribute *attrs,
struct list_head *update_list, struct list_head *insert_list,
struct list_head *remove_list, struct list_head *remap_list)
@@ -2373,17 +2380,38 @@ svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size,
}
/* add a final range at the end if needed */
- if (start <= last)
+ if (start <= last) {
r = svm_range_split_new(svms, start, last,
READ_ONCE(max_svm_range_pages),
&new_list, update_list);
+ if (r)
+ goto out;
+ }
+
+ /* Register all notifiers before publishing any of the new ranges. */
+ list_for_each_entry(prange, &new_list, list) {
+ r = svm_range_add_notifier_locked(mm, prange);
+ if (r)
+ goto out;
+ }
+ list_for_each_entry(prange, insert_list, list) {
+ r = svm_range_add_notifier_locked(mm, prange);
+ if (r)
+ goto out;
+ }
out:
if (r) {
- list_for_each_entry_safe(prange, tmp, insert_list, list)
+ list_for_each_entry_safe(prange, tmp, insert_list, list) {
+ if (prange->notifier.mm)
+ mmu_interval_notifier_remove(&prange->notifier);
svm_range_free(prange, false);
- list_for_each_entry_safe(prange, tmp, &new_list, list)
+ }
+ list_for_each_entry_safe(prange, tmp, &new_list, list) {
+ if (prange->notifier.mm)
+ mmu_interval_notifier_remove(&prange->notifier);
svm_range_free(prange, true);
+ }
} else {
list_splice(&new_list, insert_list);
}
@@ -3011,8 +3039,12 @@ svm_range *svm_range_create_unregistered_range(struct kfd_node *node,
if (is_heap_stack)
prange->preferred_loc = KFD_IOCTL_SVM_LOCATION_SYSMEM;
+ r = svm_range_add_notifier_locked(mm, prange);
+ if (r) {
+ svm_range_free(prange, true);
+ return ERR_PTR(r);
+ }
svm_range_add_to_svms(prange);
- svm_range_add_notifier_locked(mm, prange);
return prange;
}
@@ -3203,11 +3235,11 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
goto retry_write_locked;
}
prange = svm_range_create_unregistered_range(node, p, mm, addr);
- if (!prange) {
+ if (IS_ERR_OR_NULL(prange)) {
pr_debug("failed to create unregistered range svms 0x%p address [0x%llx]\n",
svms, addr);
mmap_write_downgrade(mm);
- r = -EFAULT;
+ r = prange ? PTR_ERR(prange) : -EFAULT;
goto out_unlock_svms;
}
}
@@ -3839,7 +3871,7 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
mutex_lock(&svms->lock);
/* Add new range and split existing ranges as needed */
- r = svm_range_add(p, start, size, nattr, attrs, &update_list,
+ r = svm_range_add(p, mm, start, size, nattr, attrs, &update_list,
&insert_list, &remove_list, &remap_list);
if (r) {
mutex_unlock(&svms->lock);
@@ -3847,10 +3879,8 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
goto out;
}
/* Apply changes as a transaction */
- list_for_each_entry_safe(prange, next, &insert_list, list) {
+ list_for_each_entry_safe(prange, next, &insert_list, list)
svm_range_add_to_svms(prange);
- svm_range_add_notifier_locked(mm, prange);
- }
list_for_each_entry(prange, &update_list, update_list)
svm_range_apply_attrs(p, prange, nattr, attrs, &update_mapping);
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] drm/amdkfd: check HMM errors before testing range validity
2026-11-08 5:13 [PATCH 0/2] drm/amdkfd: fix SVM error handling Aveline Noir
2026-11-08 5:13 ` [PATCH 1/2] drm/amdkfd: handle SVM interval notifier registration failures Aveline Noir
@ 2026-11-08 5:13 ` Aveline Noir
1 sibling, 0 replies; 5+ messages in thread
From: Aveline Noir @ 2026-11-08 5:13 UTC (permalink / raw)
To: Felix Kuehling, Alex Deucher, Christian König
Cc: David Airlie, Simona Vetter, Philip Yang, Sunil Khatri, honghuan,
honglei1.huang, psirt, amd-gfx, dri-devel, linux-kernel
If the first PFN-array allocation in amdgpu_hmm_range_get_pages() fails,
the allocated HMM range still has a NULL notifier. The validity condition
in svm_range_validate_and_map() calls amdgpu_hmm_range_valid() before
checking the error, dereferencing that NULL notifier.
Check the error first so failed requests retain their original error and
reach the existing cleanup without testing an uninitialized HMM range.
Fixes: c0de552910bb ("drm/amdkfd: clean up the code to free hmm_range")
Signed-off-by: Aveline Noir <jm5905938@gmail.com>
---
drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 8184cbbb829e..79455e23a030 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -1901,7 +1901,7 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
* Override return value to TRY AGAIN only if prior returns
* were successful
*/
- if (range && !amdgpu_hmm_range_valid(range) && !r) {
+ if (!r && range && !amdgpu_hmm_range_valid(range)) {
pr_debug("hmm update the range, need validate again\n");
r = -EAGAIN;
}
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] drm/amdkfd: handle SVM interval notifier registration failures
2026-11-08 5:13 ` [PATCH 1/2] drm/amdkfd: handle SVM interval notifier registration failures Aveline Noir
@ 2026-11-08 5:35 ` sashiko-bot
2026-11-08 9:25 ` Aveline Noir
0 siblings, 1 reply; 5+ messages in thread
From: sashiko-bot @ 2026-11-08 5:35 UTC (permalink / raw)
To: Aveline Noir; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found no new issues
in this patch, but noticed 1 related pre-existing issue it does not
introduce:
- [High] drm/amdkfd: incorrect address unit in svm_range_restore_pages()
[1]
--
commit 1895ed01e5a9a263f9ad3ebb51b71149e38c2024
Author: Aveline Noir <jm5905938@gmail.com>
drm/amdkfd: handle SVM interval notifier registration failures
This commit propagates MMU interval notifier registration errors and
registers staged SVM ranges before publishing them to the process SVMS
or handling retry faults.
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
> index ed5e3318877be..8184cbbb829ef 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
[ ... ]
> @@ -3203,11 +3235,11 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
> goto retry_write_locked;
> }
> prange = svm_range_create_unregistered_range(node, p, mm, addr);
> - if (!prange) {
> + if (IS_ERR_OR_NULL(prange)) {
> pr_debug("failed to create unregistered range svms 0x%p address [0x%llx]\n",
> svms, addr);
> mmap_write_downgrade(mm);
> - r = -EFAULT;
> + r = prange ? PTR_ERR(prange) : -EFAULT;
> goto out_unlock_svms;
> }
> }
[Severity: High]
This problem wasn't introduced by this patch, but does
svm_range_restore_pages() pass a page number instead of a byte address to
amdgpu_gmc_filter_faults_remove() [1]?
amdgpu_vm_handle_fault() passes addr >> PAGE_SHIFT into
svm_range_restore_pages(), which then passes addr unchanged to
amdgpu_gmc_filter_faults_remove() on the -EAGAIN exit path (and when
svm_range_skip_recover() returns true):
drivers/gpu/drm/amd/amdkfd/kfd_svm.c:svm_range_restore_pages() {
...
if (r == -EAGAIN) {
pr_debug("recover vm fault later\n");
amdgpu_gmc_filter_faults_remove(node->adev, addr, pasid);
r = 0;
}
}
amdgpu_gmc_filter_faults_remove() hashes its address argument via
amdgpu_gmc_fault_key(addr, pasid), which expects the page-aligned byte
address that amdgpu_gmc_filter_faults() originally inserted. Passing the
shifted page number produces a mismatched key, so the fault entry is never
removed from the hardware fault filter and subsequent retries of the fault
are suppressed, leading to unrecoverable page faults and GPU hangs.
[1] https://sashiko.dev/#/bug/linux-c3a1de9c-2a28-405f-a897-3418639e7854
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261108-kfd-svm-baseline-errors-20261107-v1-0-9ef4008019ab@gmail.com?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] drm/amdkfd: handle SVM interval notifier registration failures
2026-11-08 5:35 ` sashiko-bot
@ 2026-11-08 9:25 ` Aveline Noir
0 siblings, 0 replies; 5+ messages in thread
From: Aveline Noir @ 2026-11-08 9:25 UTC (permalink / raw)
To: sashiko-reviews
Cc: David Airlie, Alex Deucher, amd-gfx, Christian König,
dri-devel, Felix Kuehling, honghuan, honglei1.huang, linux-kernel,
Philip Yang, psirt, sashiko-bot, Simona Vetter, Sunil Khatri
Hi Sashiko,
On Sun, 08 Nov 2026 05:35:46 +0000 sashiko-bot@kernel.org wrote:
> This problem wasn't introduced by this patch, but does
> svm_range_restore_pages() pass a page number instead of a byte address to
> amdgpu_gmc_filter_faults_remove() [1]?
Yes, I'll fix this in a separate patch.
Thanks,
Aveline Noir
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-11-08 9:28 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-08 5:13 [PATCH 0/2] drm/amdkfd: fix SVM error handling Aveline Noir
2026-11-08 5:13 ` [PATCH 1/2] drm/amdkfd: handle SVM interval notifier registration failures Aveline Noir
2026-11-08 5:35 ` sashiko-bot
2026-11-08 9:25 ` Aveline Noir
2026-11-08 5:13 ` [PATCH 2/2] drm/amdkfd: check HMM errors before testing range validity Aveline Noir
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.