On 07/01/2026 09:35, Christian König wrote:
On 12/19/25 14:42, 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.

Also, since we have removed the RCU protection around the handle lookup we
also removed the RCU freeing of the list.

Signed-off-by: Tvrtko Ursulin <[email protected]>
---
v2:
  * Dropped RCU freeing of the list.
---
  drivers/gpu/drm/amd/amdgpu/amdgpu.h         |  4 +-
  drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 81 +++++++++------------
  drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h |  3 +-
  drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c     | 11 +--
  4 files changed, 42 insertions(+), 57 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 80dba6276aa8..ec3cbe70012a 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>
@@ -499,8 +500,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 fbac929f711c..59def86cdc04 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -37,14 +37,6 @@
  #define AMDGPU_BO_LIST_MAX_PRIORITY   32u
  #define AMDGPU_BO_LIST_NUM_BUCKETS    (AMDGPU_BO_LIST_MAX_PRIORITY + 1)
-static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu)
-{
-       struct amdgpu_bo_list *list = container_of(rcu, struct amdgpu_bo_list,
-                                                  rhead);
-
-       kvfree(list);
-}
-
  static void amdgpu_bo_list_free(struct kref *ref)
  {
        struct amdgpu_bo_list *list = container_of(ref, struct amdgpu_bo_list,
@@ -53,7 +45,8 @@ static void amdgpu_bo_list_free(struct kref *ref)
amdgpu_bo_list_for_each_entry(e, list)
                amdgpu_bo_unref(&e->bo);
-       call_rcu(&list->rhead, amdgpu_bo_list_free_rcu);
+
+       kvfree(list);
  }
static int amdgpu_bo_list_entry_cmp(const void *_a, const void *_b)
@@ -146,31 +139,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(&list->refcount);
+       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)
@@ -215,12 +197,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;
+       struct amdgpu_device *adev = drm_to_adev(dev);
+       struct drm_amdgpu_bo_list_entry *info = NULL;
+       struct amdgpu_bo_list *list, *prev, *curr;
        union drm_amdgpu_bo_list *args = data;
        uint32_t handle = args->in.list_handle;
-       struct drm_amdgpu_bo_list_entry *info = NULL;
-       struct amdgpu_bo_list *list, *old;
        int r;
r = amdgpu_bo_create_list_entry_array(&args->in, &info);
@@ -234,19 +216,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);

It's usually good practice to make *_put() functions take NULL as argument.

Done.

Regards,

Tvrtko


Apart from that looks good to me.

Regards,
Christian.

                handle = 0;
+
                break;
case AMDGPU_BO_LIST_OP_UPDATE:
@@ -255,16 +237,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 1acf53f8b2f9..cf127bc66f53 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h
@@ -43,7 +43,6 @@ struct amdgpu_bo_list_entry {
  };
struct amdgpu_bo_list {
-       struct rcu_head rhead;
        struct kref refcount;
        struct amdgpu_bo *gds_obj;
        struct amdgpu_bo *gws_obj;
@@ -54,7 +53,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