[PATCH 3/4] drm/amdkfd: avoid svm conflicting with userptr address
Philip Yang
Philip.Yang at amd.com
Wed Oct 6 14:32:09 UTC 2021
For ioctl_alloc_memory_of_gpu to alloc userptr bo, check userptr address
does not exist in svm->objects.
For svm range allocation, look for address in the userptr range of
interval tree VA nodes.
Change helper svm_range_check_vm to return amdgpu_bo, which will be used
to avoid creating new svm range overlap with bo later.
Signed-off-by: Philip Yang <Philip.Yang at amd.com>
---
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 17 +++++---
drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 55 +++++++++++++++++++-----
2 files changed, 57 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index f1e7edeb4e6b..34dfa6a938bf 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1255,6 +1255,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
long err;
uint64_t offset = args->mmap_offset;
uint32_t flags = args->flags;
+ unsigned long start, last;
if (args->size == 0)
return -EINVAL;
@@ -1266,11 +1267,17 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file *filep,
svm_range_list_lock_and_flush_work(&p->svms, current->mm);
mutex_lock(&p->svms.lock);
mmap_write_unlock(current->mm);
- if (interval_tree_iter_first(&p->svms.objects,
- args->va_addr >> PAGE_SHIFT,
- (args->va_addr + args->size - 1) >> PAGE_SHIFT)) {
- pr_err("Address: 0x%llx already allocated by SVM\n",
- args->va_addr);
+
+ if (flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) {
+ start = args->mmap_offset >> PAGE_SHIFT;
+ last = (args->mmap_offset + args->size - 1) >> PAGE_SHIFT;
+ } else {
+ start = args->va_addr >> PAGE_SHIFT;
+ last = (args->va_addr + args->size - 1) >> PAGE_SHIFT;
+ }
+
+ if (interval_tree_iter_first(&p->svms.objects, start, last)) {
+ pr_err("[0x%lx 0x%lx] already allocated by SVM\n", start, last);
mutex_unlock(&p->svms.lock);
return -EADDRINUSE;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 7f0743fcfcc3..d49c08618714 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -2679,15 +2679,18 @@ int svm_range_list_init(struct kfd_process *p)
*
* Context: Process context
*
- * Return 0 - OK, if the range is not mapped.
+ * Return NULL - if the range is not mapped.
+ * amdgpu_bo - if the range is mapped by old API
* Otherwise error code:
- * -EADDRINUSE - if address is mapped already by kfd_ioctl_alloc_memory_of_gpu
* -ERESTARTSYS - A wait for the buffer to become unreserved was interrupted by
* a signal. Release all buffer reservations and return to user-space.
*/
-static int
+static struct amdgpu_bo *
svm_range_check_vm(struct kfd_process *p, uint64_t start, uint64_t last)
{
+ struct amdgpu_bo_va_mapping *mapping;
+ struct interval_tree_node *node;
+ struct amdgpu_bo *bo = NULL;
uint32_t i;
int r;
@@ -2700,16 +2703,42 @@ svm_range_check_vm(struct kfd_process *p, uint64_t start, uint64_t last)
vm = drm_priv_to_vm(p->pdds[i]->drm_priv);
r = amdgpu_bo_reserve(vm->root.bo, false);
if (r)
- return r;
- if (interval_tree_iter_first(&vm->va, start, last)) {
- pr_debug("Range [0x%llx 0x%llx] already mapped\n", start, last);
- amdgpu_bo_unreserve(vm->root.bo);
- return -EADDRINUSE;
+ return ERR_PTR(r);
+ node = interval_tree_iter_first(&vm->va, start, last);
+ if (node) {
+ pr_debug("range [0x%llx 0x%llx] already TTM mapped\n",
+ start, last);
+ mapping = container_of((struct rb_node *)node,
+ struct amdgpu_bo_va_mapping, rb);
+ bo = mapping->bo_va->base.bo;
+ goto out_unreserve;
+ }
+
+ /* Check userptr by searching entire vm->va interval tree */
+ node = interval_tree_iter_first(&vm->va, 0, ~0ULL);
+ while (node) {
+ mapping = container_of((struct rb_node *)node,
+ struct amdgpu_bo_va_mapping, rb);
+ bo = mapping->bo_va->base.bo;
+
+ if (amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm,
+ start << PAGE_SHIFT,
+ last << PAGE_SHIFT)) {
+ pr_debug("[0x%llx 0x%llx] userptr mapped\n",
+ start, last);
+ goto out_unreserve;
+ }
+ bo = NULL;
+ node = interval_tree_iter_next(node, 0, ~0ULL);
}
+
+out_unreserve:
amdgpu_bo_unreserve(vm->root.bo);
+ if (bo)
+ break;
}
- return 0;
+ return bo;
}
/**
@@ -2732,6 +2761,7 @@ svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size)
struct vm_area_struct *vma;
unsigned long end;
unsigned long start_unchg = start;
+ struct amdgpu_bo *bo;
start <<= PAGE_SHIFT;
end = start + (size << PAGE_SHIFT);
@@ -2743,7 +2773,12 @@ svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size)
start = min(end, vma->vm_end);
} while (start < end);
- return svm_range_check_vm(p, start_unchg, (end - 1) >> PAGE_SHIFT);
+ bo = svm_range_check_vm(p, start_unchg, (end - 1) >> PAGE_SHIFT);
+ if (IS_ERR(bo))
+ return PTR_ERR(bo);
+ if (bo)
+ return -EADDRINUSE;
+ return 0;
}
/**
--
2.17.1
More information about the amd-gfx
mailing list