diff options
author | Jean-Sébastien Pédron <dumbbell@FreeBSD.org> | 2023-02-11 10:12:08 +0000 |
---|---|---|
committer | Jean-Sébastien Pédron <dumbbell@FreeBSD.org> | 2023-02-14 22:01:02 +0000 |
commit | 3102ea3b15b6c3ed1ea50716d65980b680375ebc (patch) | |
tree | c4b2fe35e58b6f7c19ffe4920f2d29116c9bb90b /sys/compat/linuxkpi/common/src | |
parent | 364391a9bb5eb85af5f711a952ba40a4b1f768da (diff) | |
download | src-3102ea3b15b6c3ed1ea50716d65980b680375ebc.tar.gz src-3102ea3b15b6c3ed1ea50716d65980b680375ebc.zip |
linuxkpi: Accept NULL as a value in `linux_xarray`
Linux' XArray allows to store a NULL pointer as a value. `xa_load()`
would return NULL for both an unused index and an index set to NULL. But
it impacts `xa_alloc()` which needs to find the next available index.
However, our implementation relies on a radix tree (see `linux_radix.c`)
which does not accept NULL pointers as values. I'm not sure if this is a
limitation or a feature, so to work around this, a NULL value is
replaced by `NULL_VALUE`, an unlikely address, when we pass it to
linux_radix.
Reviewed by: emaste, manu
Approved by: emaste, manu
Differential Revision: https://reviews.freebsd.org/D38543
Diffstat (limited to 'sys/compat/linuxkpi/common/src')
-rw-r--r-- | sys/compat/linuxkpi/common/src/linux_xarray.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/sys/compat/linuxkpi/common/src/linux_xarray.c b/sys/compat/linuxkpi/common/src/linux_xarray.c index a41784103852..e8a107fa6f27 100644 --- a/sys/compat/linuxkpi/common/src/linux_xarray.c +++ b/sys/compat/linuxkpi/common/src/linux_xarray.c @@ -32,15 +32,33 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_pageout.h> /* + * Linux' XArray allows to store a NULL pointer as a value. xa_load() would + * return NULL for both an unused index and an index set to NULL. But it + * impacts xa_alloc() which needs to find the next available index. + * + * However, our implementation relies on a radix tree (see `linux_radix.c`) + * which does not accept NULL pointers as values. I'm not sure this is a + * limitation or a feature, so to work around this, a NULL value is replaced by + * `NULL_VALUE`, an unlikely address, when we pass it to linux_radix. + */ +#define NULL_VALUE (void *)0x1 + +/* * This function removes the element at the given index and returns * the pointer to the removed element, if any. */ void * __xa_erase(struct xarray *xa, uint32_t index) { + void *retval; + XA_ASSERT_LOCKED(xa); - return (radix_tree_delete(&xa->root, index)); + retval = radix_tree_delete(&xa->root, index); + if (retval == NULL_VALUE) + retval = NULL; + + return (retval); } void * @@ -68,6 +86,9 @@ xa_load(struct xarray *xa, uint32_t index) retval = radix_tree_lookup(&xa->root, index); xa_unlock(xa); + if (retval == NULL_VALUE) + retval = NULL; + return (retval); } @@ -109,6 +130,8 @@ __xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t MPASS((mask & (mask + 1)) == 0); *pindex = (xa->flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0; + if (ptr == NULL) + ptr = NULL_VALUE; retry: retval = radix_tree_insert(&xa->root, *pindex, ptr); @@ -137,6 +160,9 @@ xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t gf { int retval; + if (ptr == NULL) + ptr = NULL_VALUE; + xa_lock(xa); retval = __xa_alloc(xa, pindex, ptr, mask, gfp); xa_unlock(xa); @@ -166,6 +192,8 @@ __xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, MPASS((mask & (mask + 1)) == 0); *pnext_index = (xa->flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0; + if (ptr == NULL) + ptr = NULL_VALUE; retry: retval = radix_tree_insert(&xa->root, *pnext_index, ptr); @@ -220,6 +248,8 @@ __xa_insert(struct xarray *xa, uint32_t index, void *ptr, gfp_t gfp) int retval; XA_ASSERT_LOCKED(xa); + if (ptr == NULL) + ptr = NULL_VALUE; retry: retval = radix_tree_insert(&xa->root, index, ptr); @@ -262,11 +292,15 @@ __xa_store(struct xarray *xa, uint32_t index, void *ptr, gfp_t gfp) int retval; XA_ASSERT_LOCKED(xa); + if (ptr == NULL) + ptr = NULL_VALUE; retry: retval = radix_tree_store(&xa->root, index, &ptr); switch (retval) { case 0: + if (ptr == NULL_VALUE) + ptr = NULL; break; case -ENOMEM: if (likely(gfp & M_WAITOK)) { @@ -374,6 +408,8 @@ __xa_next(struct xarray *xa, unsigned long *pindex, bool not_first) found = radix_tree_iter_find(&xa->root, &iter, &ppslot); if (likely(found)) { retval = *ppslot; + if (retval == NULL_VALUE) + retval = NULL; *pindex = iter.index; } else { retval = NULL; |