From: Matthew Dillon Date: Sat, 9 Mar 2019 19:24:26 +0000 (-0800) Subject: kernel - Fix IDR bugs X-Git-Tag: v5.7.0~484 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/d0975e245898ed621e15cfb81acdd4a402082d44 kernel - Fix IDR bugs * 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 --- diff --git a/share/man/man9/idr.9 b/share/man/man9/idr.9 index 777787e411..07509b790f 100644 --- a/share/man/man9/idr.9 +++ b/share/man/man9/idr.9 @@ -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. diff --git a/sys/libkern/linux_idr.c b/sys/libkern/linux_idr.c index 2688160531..86b7a6b3dd 100644 --- a/sys/libkern/linux_idr.c +++ b/sys/libkern/linux_idr.c @@ -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; diff --git a/sys/sys/idr.h b/sys/sys/idr.h index 79951fa2fa..f148eec809 100644 --- a/sys/sys/idr.h +++ b/sys/sys/idr.h @@ -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);