IDR is deprecated so let's replace it with xarray. Conversion is mostly 1:1 apart from AMDGPU_BO_LIST_OP_UPDATE which was implemented with idr_replace, and has now been replaced with a sequence of xa_load and xa_cmpxchg. Should userspace attempt multi-threaded update operations on the same handle it could theoretically hit a new -ENOENT path. But I believe this is purely theoretical and still safe.
Signed-off-by: Tvrtko Ursulin <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 4 +- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 72 ++++++++++----------- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 11 ++-- 4 files changed, 41 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 9f9774f58ce1..0a5b802bd3c3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -50,6 +50,7 @@ #include <linux/hashtable.h> #include <linux/dma-fence.h> #include <linux/pci.h> +#include <linux/xarray.h> #include <drm/ttm/ttm_bo.h> #include <drm/ttm/ttm_placement.h> @@ -500,8 +501,7 @@ struct amdgpu_fpriv { struct amdgpu_bo_va *prt_va; struct amdgpu_bo_va *csa_va; struct amdgpu_bo_va *seq64_va; - struct mutex bo_list_lock; - struct idr bo_list_handles; + struct xarray bo_list_handles; struct amdgpu_ctx_mgr ctx_mgr; struct amdgpu_userq_mgr userq_mgr; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 66fb37b64388..628d32fd2fae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -149,31 +149,20 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, } -static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id) -{ - struct amdgpu_bo_list *list; - - mutex_lock(&fpriv->bo_list_lock); - list = idr_remove(&fpriv->bo_list_handles, id); - mutex_unlock(&fpriv->bo_list_lock); - if (list) - kref_put(&list->refcount, amdgpu_bo_list_free); -} - -int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, +int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, u32 id, struct amdgpu_bo_list **result) { - rcu_read_lock(); - *result = idr_find(&fpriv->bo_list_handles, id); + struct amdgpu_bo_list *list; - if (*result && kref_get_unless_zero(&(*result)->refcount)) { - rcu_read_unlock(); - return 0; - } + xa_lock(&fpriv->bo_list_handles); + list = xa_load(&fpriv->bo_list_handles, id); + if (list && !kref_get_unless_zero(&list->refcount)) + list = NULL; + xa_unlock(&fpriv->bo_list_handles); - rcu_read_unlock(); - *result = NULL; - return -ENOENT; + *result = list; + + return list ? 0 : -ENOENT; } void amdgpu_bo_list_put(struct amdgpu_bo_list *list) @@ -219,12 +208,12 @@ int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv = filp->driver_priv; - union drm_amdgpu_bo_list *args = data; - uint32_t handle = args->in.list_handle; + struct amdgpu_device *adev = drm_to_adev(dev); struct drm_amdgpu_bo_list_entry *info = NULL; - struct amdgpu_bo_list *list, *old; + struct amdgpu_bo_list *list, *prev, *curr; + uint32_t handle = args->in.list_handle; + union drm_amdgpu_bo_list *args = data; int r; r = amdgpu_bo_create_list_entry_array(&args->in, &info); @@ -238,19 +227,19 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, if (r) goto error_free; - mutex_lock(&fpriv->bo_list_lock); - r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL); - mutex_unlock(&fpriv->bo_list_lock); - if (r < 0) { + r = xa_alloc(&fpriv->bo_list_handles, &handle, list, + xa_limit_32b, GFP_KERNEL); + if (r) goto error_put_list; - } - handle = r; break; case AMDGPU_BO_LIST_OP_DESTROY: - amdgpu_bo_list_destroy(fpriv, handle); + list = xa_erase(&fpriv->bo_list_handles, handle); + if (list) + amdgpu_bo_list_put(list); handle = 0; + break; case AMDGPU_BO_LIST_OP_UPDATE: @@ -259,16 +248,23 @@ int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, if (r) goto error_free; - mutex_lock(&fpriv->bo_list_lock); - old = idr_replace(&fpriv->bo_list_handles, list, handle); - mutex_unlock(&fpriv->bo_list_lock); + curr = xa_load(&fpriv->bo_list_handles, handle); + if (!curr) { + r = -ENOENT; + goto error_put_list; + } - if (IS_ERR(old)) { - r = PTR_ERR(old); + prev = xa_cmpxchg(&fpriv->bo_list_handles, handle, curr, list, + GFP_KERNEL); + if (xa_is_err(prev)) { + r = xa_err(prev); + goto error_put_list; + } else if (prev != curr) { + r = -ENOENT; goto error_put_list; } - amdgpu_bo_list_put(old); + amdgpu_bo_list_put(curr); break; default: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index 2b5e7c46a39d..0989f1090c63 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -58,7 +58,7 @@ struct amdgpu_bo_list { struct amdgpu_bo_list_entry entries[] __counted_by(num_entries); }; -int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, +int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, u32 id, struct amdgpu_bo_list **result); void amdgpu_bo_list_put(struct amdgpu_bo_list *list); int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 6ee77f431d56..88f104041157 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1445,8 +1445,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) if (r) goto error_vm; - mutex_init(&fpriv->bo_list_lock); - idr_init_base(&fpriv->bo_list_handles, 1); + xa_init_flags(&fpriv->bo_list_handles, XA_FLAGS_ALLOC1); r = amdgpu_userq_mgr_init(&fpriv->userq_mgr, file_priv, adev); if (r) @@ -1492,8 +1491,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, struct amdgpu_fpriv *fpriv = file_priv->driver_priv; struct amdgpu_bo_list *list; struct amdgpu_bo *pd; + unsigned long handle; u32 pasid; - int handle; if (!fpriv) return; @@ -1529,11 +1528,9 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, amdgpu_pasid_free_delayed(pd->tbo.base.resv, pasid); amdgpu_bo_unref(&pd); - idr_for_each_entry(&fpriv->bo_list_handles, list, handle) + xa_for_each(&fpriv->bo_list_handles, handle, list) amdgpu_bo_list_put(list); - - idr_destroy(&fpriv->bo_list_handles); - mutex_destroy(&fpriv->bo_list_lock); + xa_destroy(&fpriv->bo_list_handles); kfree(fpriv); file_priv->driver_priv = NULL; -- 2.51.1
