Am 2021-07-19 um 5:18 p.m. schrieb Alex Sierra:
> [Why]
> Avoid conflict with address ranges mapped by SVM
> mechanism that try to be allocated again through
> ioctl_alloc in the same process. And viceversa.
>
> [How]
> For ioctl_alloc_memory_of_gpu allocations
> Check if the address range passed into ioctl memory
> alloc does not exist already in the kfd_process
> svms->objects interval tree.
>
> For SVM allocations
> Look for the address range into the interval tree VA from
> the VM inside of each pdds used in a kfd_process.
>
> Signed-off-by: Alex Sierra <alex.sie...@amd.com>

Two nitpicks inline. With that fixed, the patch is

Reviewed-by: Felix Kuehling <felix.kuehl...@amd.com>


> ---
>  drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 13 ++++
>  drivers/gpu/drm/amd/amdkfd/kfd_svm.c     | 79 +++++++++++++++++++-----
>  2 files changed, 75 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c 
> b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> index 67541c30327a..f39baaa22a62 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> @@ -1251,6 +1251,7 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file 
> *filep,
>       struct kfd_process_device *pdd;
>       void *mem;
>       struct kfd_dev *dev;
> +     struct svm_range_list *svms = &p->svms;
>       int idr_handle;
>       long err;
>       uint64_t offset = args->mmap_offset;
> @@ -1259,6 +1260,18 @@ static int kfd_ioctl_alloc_memory_of_gpu(struct file 
> *filep,
>       if (args->size == 0)
>               return -EINVAL;
>  
> +#if IS_ENABLED(CONFIG_HSA_AMD_SVM)
> +     mutex_lock(&svms->lock);
> +     if (interval_tree_iter_first(&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);
> +             mutex_unlock(&svms->lock);
> +             return -EADDRINUSE;
> +     }
> +     mutex_unlock(&svms->lock);
> +#endif
>       dev = kfd_device_by_id(args->gpu_id);
>       if (!dev)
>               return -EINVAL;
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c 
> b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
> index 31f3f24cef6a..043ee0467916 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
> @@ -2581,9 +2581,54 @@ int svm_range_list_init(struct kfd_process *p)
>       return 0;
>  }
>  
> +/**
> + * svm_range_is_vm_bo_mapped - check if virtual address range mapped already

I find the function name a bit confusing. The name suggests something
about a BO, but the description only talks about address ranges. Also,
there is no BO parameter.

Maybe a better name would be svm_range_check_vm.


> + * @p: current kfd_process
> + * @start: range start address, in pages
> + * @last: range last address, in pages
> + *
> + * The purpose is to avoid virtual address ranges already allocated by
> + * kfd_ioctl_alloc_memory_of_gpu ioctl.
> + * It looks for each pdd in the kfd_process.
> + *
> + * Context: Process context
> + *
> + * Return 0 - OK, if the range is not mapped.
> + * 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
> +svm_range_is_vm_bo_mapped(struct kfd_process *p, uint64_t start, uint64_t 
> last)
> +{
> +     uint32_t i;
> +     int r;
> +
> +     for (i = 0; i < p->n_pdds; i++) {
> +             struct amdgpu_vm *vm;
> +
> +             if (!p->pdds[i]->drm_priv)
> +                     continue;
> +
> +             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;
> +             }
> +             amdgpu_bo_unreserve(vm->root.bo);
> +     }
> +
> +     return 0;
> +}
> +
>  /**
>   * svm_range_is_valid - check if virtual address range is valid
> - * @mm: current process mm_struct
> + * @mm: current kfd_process

Please fix the variable name here: mm -> p.

Regards,
  Felix


>   * @start: range start address, in pages
>   * @size: range size, in pages
>   *
> @@ -2592,28 +2637,27 @@ int svm_range_list_init(struct kfd_process *p)
>   * Context: Process context
>   *
>   * Return:
> - *  true - valid svm range
> - *  false - invalid svm range
> + *  0 - OK, otherwise error code
>   */
> -static bool
> -svm_range_is_valid(struct mm_struct *mm, uint64_t start, uint64_t size)
> +static int
> +svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size)
>  {
>       const unsigned long device_vma = VM_IO | VM_PFNMAP | VM_MIXEDMAP;
>       struct vm_area_struct *vma;
>       unsigned long end;
> +     unsigned long start_unchg = start;
>  
>       start <<= PAGE_SHIFT;
>       end = start + (size << PAGE_SHIFT);
> -
>       do {
> -             vma = find_vma(mm, start);
> +             vma = find_vma(p->mm, start);
>               if (!vma || start < vma->vm_start ||
>                   (vma->vm_flags & device_vma))
> -                     return false;
> +                     return -EFAULT;
>               start = min(end, vma->vm_end);
>       } while (start < end);
>  
> -     return true;
> +     return svm_range_is_vm_bo_mapped(p, start_unchg, (end - 1) >> 
> PAGE_SHIFT);
>  }
>  
>  /**
> @@ -2913,9 +2957,9 @@ svm_range_set_attr(struct kfd_process *p, uint64_t 
> start, uint64_t size,
>  
>       svm_range_list_lock_and_flush_work(svms, mm);
>  
> -     if (!svm_range_is_valid(mm, start, size)) {
> -             pr_debug("invalid range\n");
> -             r = -EFAULT;
> +     r = svm_range_is_valid(p, start, size);
> +     if (r) {
> +             pr_debug("invalid range r=%d\n", r);
>               mmap_write_unlock(mm);
>               goto out;
>       }
> @@ -3016,17 +3060,18 @@ svm_range_get_attr(struct kfd_process *p, uint64_t 
> start, uint64_t size,
>       uint32_t flags = 0xffffffff;
>       int gpuidx;
>       uint32_t i;
> +     int r = 0;
>  
>       pr_debug("svms 0x%p [0x%llx 0x%llx] nattr 0x%x\n", &p->svms, start,
>                start + size - 1, nattr);
>  
>       mmap_read_lock(mm);
> -     if (!svm_range_is_valid(mm, start, size)) {
> -             pr_debug("invalid range\n");
> -             mmap_read_unlock(mm);
> -             return -EINVAL;
> -     }
> +     r = svm_range_is_valid(p, start, size);
>       mmap_read_unlock(mm);
> +     if (r) {
> +             pr_debug("invalid range r=%d\n", r);
> +             return r;
> +     }
>  
>       for (i = 0; i < nattr; i++) {
>               switch (attrs[i].type) {
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to