Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/drm2/linux linux: Rework radix tree shims.



details:   https://anonhg.NetBSD.org/src/rev/cb7be244dbe5
branches:  trunk
changeset: 1028810:cb7be244dbe5
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sun Dec 19 12:05:25 2021 +0000

description:
linux: Rework radix tree shims.

diffstat:

 sys/external/bsd/drm2/include/linux/xarray.h |    8 +-
 sys/external/bsd/drm2/linux/linux_xa.c       |  181 ++++++++++++++++++--------
 2 files changed, 125 insertions(+), 64 deletions(-)

diffs (truncated from 307 to 300 lines):

diff -r f743c3fd7d3a -r cb7be244dbe5 sys/external/bsd/drm2/include/linux/xarray.h
--- a/sys/external/bsd/drm2/include/linux/xarray.h      Sun Dec 19 12:05:18 2021 +0000
+++ b/sys/external/bsd/drm2/include/linux/xarray.h      Sun Dec 19 12:05:25 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: xarray.h,v 1.8 2021/12/19 11:51:07 riastradh Exp $     */
+/*     $NetBSD: xarray.h,v 1.9 2021/12/19 12:05:25 riastradh Exp $     */
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
 #ifndef        _LINUX_XARRAY_H_
 #define        _LINUX_XARRAY_H_
 
-#include <sys/radixtree.h>
+#include <sys/rbtree.h>
 
 #include <linux/slab.h>
 
@@ -43,14 +43,14 @@
 
 struct xarray {
        kmutex_t                xa_lock;
-       struct radix_tree       xa_tree;
+       struct rb_tree          xa_tree;
        gfp_t                   xa_gfp;
 };
 
 #define        xa_for_each(XA, INDEX, ENTRY)                                         \
        for ((INDEX) = 0, (ENTRY) = xa_find((XA), &(INDEX), ULONG_MAX, -1);   \
                (ENTRY) != NULL;                                              \
-               (ENTRY) = xa_find_after((XA), &(INDEX), ULONG_MAX, 0))
+               (ENTRY) = xa_find_after((XA), &(INDEX), ULONG_MAX, -1))
 
 #define        XA_ERROR(error) ((void *)(((uintptr_t)error << 2) | 2))
 
diff -r f743c3fd7d3a -r cb7be244dbe5 sys/external/bsd/drm2/linux/linux_xa.c
--- a/sys/external/bsd/drm2/linux/linux_xa.c    Sun Dec 19 12:05:18 2021 +0000
+++ b/sys/external/bsd/drm2/linux/linux_xa.c    Sun Dec 19 12:05:25 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_xa.c,v 1.2 2021/12/19 12:05:18 riastradh Exp $   */
+/*     $NetBSD: linux_xa.c,v 1.3 2021/12/19 12:05:25 riastradh Exp $   */
 
 /*-
  * Copyright (c) 2021 The NetBSD Foundation, Inc.
@@ -27,14 +27,59 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_xa.c,v 1.2 2021/12/19 12:05:18 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_xa.c,v 1.3 2021/12/19 12:05:25 riastradh Exp $");
 
-#include <sys/radixtree.h>
+/*
+ * This is a lame-o implementation of the Linux xarray data type, which
+ * implements a map from 64-bit integers to pointers.  The operations
+ * it supports are designed to be implemented by a radix tree, but
+ * NetBSD's radixtree(9) doesn't quite support them all, and it's a bit
+ * of work to implement them, so this just uses a red/black tree
+ * instead at the cost of some performance in certain types of lookups
+ * (and negative-lookups -- finding a free key).
+ */
 
-#include <uvm/uvm_pdaemon.h>
+#include <sys/rbtree.h>
 
 #include <linux/xarray.h>
 
+struct node {
+       struct rb_node  n_rb;
+       uint64_t        n_key;
+       void            *n_datum;
+};
+
+static int
+compare_nodes(void *cookie, const void *va, const void *vb)
+{
+       const struct node *a = va, *b = vb;
+
+       if (a->n_key < b->n_key)
+               return -1;
+       if (a->n_key > b->n_key)
+               return +1;
+       return 0;
+}
+
+static int
+compare_node_key(void *cookie, const void *vn, const void *vk)
+{
+       const struct node *n = vn;
+       const uint64_t *k = vk;
+
+       if (n->n_key < *k)
+               return -1;
+       if (n->n_key > *k)
+               return +1;
+       return 0;
+}
+
+static const rb_tree_ops_t xa_rb_ops = {
+       .rbto_compare_nodes = compare_nodes,
+       .rbto_compare_key = compare_node_key,
+       .rbto_node_offset = offsetof(struct node, n_rb),
+};
+
 const struct xa_limit xa_limit_32b = { .min = 0, .max = UINT32_MAX };
 
 void
@@ -42,91 +87,102 @@
 {
 
        mutex_init(&xa->xa_lock, MUTEX_DEFAULT, IPL_VM);
-       radix_tree_init_tree(&xa->xa_tree);
+       rb_tree_init(&xa->xa_tree, &xa_rb_ops);
        xa->xa_gfp = gfp;
 }
 
 void
 xa_destroy(struct xarray *xa)
 {
+       struct node *n;
 
-       KASSERT(radix_tree_empty_tree_p(&xa->xa_tree));
-       radix_tree_fini_tree(&xa->xa_tree);
+       /*
+        * Linux allows xa to remain populated on destruction; it is
+        * our job to free any internal node structures.
+        */
+       while ((n = RB_TREE_MIN(&xa->xa_tree)) != NULL) {
+               rb_tree_remove_node(&xa->xa_tree, n);
+               kmem_free(n, sizeof(*n));
+       }
        mutex_destroy(&xa->xa_lock);
 }
 
 void *
 xa_load(struct xarray *xa, unsigned long key)
 {
-       void *datum;
+       const uint64_t key64 = key;
+       struct node *n;
 
        /* XXX pserialize */
        mutex_enter(&xa->xa_lock);
-       datum = radix_tree_lookup_node(&xa->xa_tree, key);
+       n = rb_tree_find_node(&xa->xa_tree, &key64);
        mutex_exit(&xa->xa_lock);
 
-       return datum;
+       return n ? n->n_datum : NULL;
 }
 
 void *
 xa_store(struct xarray *xa, unsigned long key, void *datum, gfp_t gfp)
 {
-       void *collision;
-       int error;
+       struct node *n, *collision;
 
        KASSERT(datum != NULL);
        KASSERT(((uintptr_t)datum & 0x3) == 0);
 
-retry: mutex_enter(&xa->xa_lock);
-       collision = radix_tree_lookup_node(&xa->xa_tree, key);
-       error = radix_tree_insert_node(&xa->xa_tree, key, datum);
+       n = kmem_zalloc(sizeof(*n), gfp & __GFP_WAIT ? KM_SLEEP : KM_NOSLEEP);
+       if (n == NULL)
+               return XA_ERROR(-ENOMEM);
+       n->n_key = key;
+       n->n_datum = datum;
+
+       mutex_enter(&xa->xa_lock);
+       collision = rb_tree_insert_node(&xa->xa_tree, n);
        mutex_exit(&xa->xa_lock);
-       if (error) {
-               if (gfp & __GFP_WAIT) {
-                       uvm_wait("xa");
-                       goto retry;
-               }
-               /* XXX errno NetBSD->Linux */
-               return XA_ERROR(-error);
+
+       if (collision != n) {
+               datum = collision->n_datum;
+               kmem_free(collision, sizeof(*collision));
        }
-
-       return collision;
+       return datum;
 }
 
 int
 xa_alloc(struct xarray *xa, uint32_t *idp, void *datum, struct xa_limit limit,
     gfp_t gfp)
 {
-       uint32_t key = limit.min;
-       void *collision;
+       uint64_t key64 = limit.min;
+       struct node *n, *n1, *collision __diagused;
        int error;
 
        KASSERTMSG(limit.min < limit.max, "min=%"PRIu32" max=%"PRIu32,
            limit.min, limit.max);
 
-retry: mutex_enter(&xa->xa_lock);
-       /* XXX use the radix tree to make this fast */
-       while ((collision = radix_tree_lookup_node(&xa->xa_tree, key))
-           != NULL) {
-               if (key++ == limit.max)
+       n = kmem_zalloc(sizeof(*n), gfp & __GFP_WAIT ? KM_SLEEP : KM_NOSLEEP);
+       if (n == NULL)
+               return -ENOMEM;
+       n->n_datum = datum;
+
+       mutex_enter(&xa->xa_lock);
+       while ((n1 = rb_tree_find_node_geq(&xa->xa_tree, &key64)) != NULL &&
+           n1->n_key == key64) {
+               if (key64 == limit.max) {
+                       error = -EBUSY;
                        goto out;
+               }
+               KASSERT(key64 < UINT32_MAX);
+               key64++;
        }
-       error = radix_tree_insert_node(&xa->xa_tree, key, datum);
+       /* Found a hole -- insert in it.  */
+       KASSERT(n1 == NULL || n1->n_key > key64);
+       n->n_key = key64;
+       collision = rb_tree_insert_node(&xa->xa_tree, n);
+       KASSERT(collision == n);
+       error = 0;
 out:   mutex_exit(&xa->xa_lock);
 
-       if (collision)
-               return -EBUSY;
-       if (error) {
-               if (gfp & __GFP_WAIT) {
-                       uvm_wait("xa");
-                       goto retry;
-               }
-               /* XXX errno NetBSD->Linux */
-               return -error;
-       }
-
-       /* Success!  */
-       *idp = key;
+       if (error)
+               return error;
+       *idp = key64;
        return 0;
 }
 
@@ -134,23 +190,20 @@
 xa_find(struct xarray *xa, unsigned long *startp, unsigned long max,
     unsigned tagmask)
 {
-       uint64_t key = *startp;
-       void *candidate = NULL;
+       uint64_t key64 = *startp;
+       struct node *n = NULL;
+
+       KASSERT(tagmask == -1); /* not yet supported */
 
        mutex_enter(&xa->xa_lock);
-       for (; key < max; key++, candidate = NULL) {
-               candidate = radix_tree_lookup_node(&xa->xa_tree, key);
-               if (candidate == NULL)
-                       continue;
-               if (tagmask == -1 ||
-                   radix_tree_get_tag(&xa->xa_tree, key, tagmask))
-                       break;
-       }
+       n = rb_tree_find_node_geq(&xa->xa_tree, &key64);
        mutex_exit(&xa->xa_lock);
 
-       if (candidate)
-               *startp = key;
-       return candidate;
+       if (n == NULL || n->n_key > max)
+               return NULL;
+
+       *startp = n->n_key;
+       return n->n_datum;
 }
 
 void *
@@ -171,11 +224,19 @@
 void *
 xa_erase(struct xarray *xa, unsigned long key)
 {
-       void *datum;
+       uint64_t key64 = key;
+       struct node *n;
+       void *datum = NULL;
 
        mutex_enter(&xa->xa_lock);
-       datum = radix_tree_remove_node(&xa->xa_tree, key);
+       n = rb_tree_find_node(&xa->xa_tree, &key64);
+       if (n)
+               rb_tree_remove_node(&xa->xa_tree, n);
        mutex_exit(&xa->xa_lock);



Home | Main Index | Thread Index | Old Index