On 12/18/25 16:04, Tvrtko Ursulin wrote:
> 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;

Since you have this protected by xa_lock() now you don't need the 
kref_get_unless_zero() any more and can also drop the RCU handling in 
amdgpu_bo_list_free().

Alternatively stop using xa_lock() and use the RCU read side lock instead, but 
I clearly prefer this approach here.

Apart from that looks good to me.

Regards,
Christian.

> +     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;

Reply via email to