On 6/12/2026 10:38 PM, Huang, Honglei wrote:
+static int
+amdgpu_svm_attr_validate_range_vma(struct amdgpu_svm_attr_tree *attr_tree,
+                   unsigned long start_page,
+                   unsigned long last_page)
+{
+    struct vm_area_struct *vma;
+    struct mm_struct *mm;
+    unsigned long start, end;
+    int ret = 0;
+
+    if (start_page > last_page)
+        return -EINVAL;
+
+    if (last_page == ULONG_MAX)
+        return -EINVAL;
+
+    start = start_page << PAGE_SHIFT;
+    end = (last_page + 1) << PAGE_SHIFT;
+    mm = attr_tree->svm->gpusvm.mm;
+    if (!mm)
+        return -EFAULT;
+
+    mmap_read_lock(mm);
+    while (start < end) {
+        vma = amdgpu_svm_check_vma(mm, start);
+        if (IS_ERR(vma)) {
+            ret = PTR_ERR(vma);
+            break;
+        }
+
+        start = min(end, vma->vm_end);
+    }

That's complete nonsense as well.

The result becomes invalid as soon as you drop the lock again, so just completely drop the check.

hmm_range fault will tell us if the fault was succesful or not.

Got it will drop.>

I dropped that check in my local fix, but there is a regression:
A KFD test failed after dropping the VMA check:
KFDSVMRangeTest.InvalidRangeTest

it does a set attr on an invalid
address: 0x10000 and expects it to fail. Removing the check from the
fault path is correct hmm_range_fault() reports the real outcome
there.

But in xnack on mode set/get-attr are asynchronous fault ioctls with lazy fault to report errors, so an unmapped range was silently accepted.

I double checked what Xe does, actually Xe SVM also do legality checks, but it checks xe_vma instead of mm vma, see code below.

Abandoning or retaining the check are all acceptable. I am only reporting the test results and the current approach of XE SVM here. I just need a decision on my end.

Xe implementation:
int xe_vm_madvise_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file)
{
        ...
        if (!madvise_args_are_sane(vm->xe, args)) {
                err = -EINVAL;
                goto put_vm;
        }
        ...
        err = xe_vm_alloc_madvise_vma(vm, args->start, args->range);
        if (err)
                goto madv_fini;

        err = get_vmas(vm, &madvise_range);
        if (err || !madvise_range.num_vmas)
                goto madv_fini;   /* no vmas in range -> rejected */
        ...
}


drm_gpuvm_for_each_va_range(gpuva, &vm->gpuvm, addr, addr + range) {
                struct xe_vma *vma = gpuva_to_vma(gpuva);

                if (xe_vma_bo(vma))
                        madvise_range->has_bo_vmas = true;
                else if (xe_vma_is_cpu_addr_mirror(vma) || 
xe_vma_is_userptr(vma))
                        madvise_range->has_svm_userptr_vmas = true;
...


Regards,
Honglei


Regards,
Christian.

Reply via email to