prange->svm_bo stays set after the range drops its reference in svm_range_vram_node_free(), it is only cleared later by svm_range_bo_release(). Taking a new reference based on old->svm_bo can therefore hit a svm_bo with refcount 0 and svm_range_bo_release_async() pending, leaving the clone with a freed svm_bo.
Check old->ttm_res under old->lock instead, it is cleared together with the reference drop, same as svm_range_validate_svm_bo() does. Signed-off-by: Philip Yang <[email protected]> Signed-off-by: Mukul Joshi <[email protected]> --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index cfb428c72686..536e804bc2c5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -2158,7 +2158,14 @@ static struct svm_range *svm_range_clone(struct svm_range *old) svm_range_free(new, false); return NULL; } - if (old->svm_bo) { + + /* + * Only share svm_bo if old still holds a reference to it (ttm_res + * set). Otherwise old->svm_bo may already be at refcount 0 with + * svm_range_bo_release_async pending. + */ + mutex_lock(&old->lock); + if (old->ttm_res) { new->ttm_res = old->ttm_res; new->offset = old->offset; new->svm_bo = svm_range_bo_ref(old->svm_bo); @@ -2166,6 +2173,8 @@ static struct svm_range *svm_range_clone(struct svm_range *old) list_add(&new->svm_bo_list, &new->svm_bo->range_list); spin_unlock(&new->svm_bo->list_lock); } + mutex_unlock(&old->lock); + new->flags = old->flags; new->preferred_loc = old->preferred_loc; new->prefetch_loc = old->prefetch_loc; -- 2.50.1
