kernel - Fix IDR bugs
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 9 Mar 2019 19:24:26 +0000 (11:24 -0800)
committerFran├žois Tigeot <ftigeot@wolfpond.org>
Mon, 11 Mar 2019 22:13:45 +0000 (23:13 +0100)
* Allow ptr to be NULL in idr_remove() and idr_replace().

* Note that linux ERR returns from idr_replace() still not implemented
  (requires the related ERR macros to be moved out of drm).  idr_replace()
  still returns NULL when the id cannot be found.

Requested-by: aly
share/man/man9/idr.9
sys/libkern/linux_idr.c
sys/sys/idr.h

index 777787e..07509b7 100644 (file)
@@ -129,7 +129,8 @@ The
 .Fn idr_remove
 function removes the specified
 .Fa id
-from the tree.
+from the tree, returning its pointer.
+NULL is returned if the id could not be found.
 .Pp
 The
 .Fn idr_remove_all
@@ -146,5 +147,6 @@ with the new pointer
 .Fa ptr .
 It returns
 .Dv NULL
-if the pointer is not found.
-This behavior is different from the Linux API.
+if the id is not found.
+This behavior is different from the Linux API, which returns ERR_PTR(-ENOENT)
+if the id could not be found.
index 2688160..86b7a6b 100644 (file)
@@ -58,6 +58,7 @@
 #define MALLOC_DEFINE(a, b, c)
 #define lwkt_gettoken(x)
 #define lwkt_reltoken(x)
+#undef kmalloc
 #define kmalloc(bytes, zone, flags)    calloc(bytes, 1)
 #define lwkt_token_init(a, b)
 #define lwkt_token_uninit(a)
@@ -72,7 +73,7 @@ main(int ac, char **av)
 {
        char buf[256];
        struct idr idr;
-       intptr_t generation = 0x10000000;
+       intptr_t generation = 0x0;
        int error;
        int id;
 
@@ -459,7 +460,7 @@ idr_grow(struct idr *idp, int want)
        idp->idr_nexpands++;
 }
 
-void
+void *
 idr_remove(struct idr *idp, int id)
 {
        void *ptr;
@@ -467,16 +468,19 @@ idr_remove(struct idr *idp, int id)
        lwkt_gettoken(&idp->idr_token);
        if (id < 0 || id >= idp->idr_count) {
                lwkt_reltoken(&idp->idr_token);
-               return;
-       }
-       if ((ptr = idp->idr_nodes[id].data) == NULL) {
-               lwkt_reltoken(&idp->idr_token);
-               return;
+               return NULL;
        }
+        if (idp->idr_nodes[id].allocated == 0) {
+                lwkt_reltoken(&idp->idr_token);
+                return NULL;
+        }
+       ptr = idp->idr_nodes[id].data;
        idp->idr_nodes[id].data = NULL;
        idr_reserve(idp, id, -1);
        idrfixup(idp, id);
        lwkt_reltoken(&idp->idr_token);
+
+       return ptr;
 }
 
 /*
@@ -549,7 +553,7 @@ idr_replace(struct idr *idp, void *ptr, int id)
 
        lwkt_gettoken(&idp->idr_token);
        idrnp = idr_get_node(idp, id);
-       if (idrnp == NULL || ptr == NULL) {
+       if (idrnp == NULL) {
                ret = NULL;
        } else {
                ret = idrnp->data;
index 79951fa..f148eec 100644 (file)
@@ -39,8 +39,7 @@
  * IDR is a small Integer ID management library that provides an interface to
  * map integers with some pointer that can later be retrieved.
  *
- * NOTE: Pointer mapped by integer can't be NULL.
- *
+ * NOTE: Maintains compatibility with linux, allowing NULL pointers.
  */
 
 
@@ -73,7 +72,7 @@ struct idr {
 
 void   *idr_find(struct idr *idp, int id);
 void   *idr_replace(struct idr *idp, void *ptr, int id);
-void    idr_remove(struct idr *idp, int id);
+void   *idr_remove(struct idr *idp, int id);
 void    idr_remove_all(struct idr *idp);
 void    idr_destroy(struct idr *idp);
 int     idr_for_each(struct idr *idp, int (*fn)(int id, void *p, void *data), void *data);