@@ -37,8 +37,7 @@ bool xb_test_bit(const struct xb *xb, unsigned long bit);
void xb_clear_bit(struct xb *xb, unsigned long bit);
void xb_clear_bit_range(struct xb *xb, unsigned long start,
unsigned long nbits);
-unsigned long xb_find_set(struct xb *xb, unsigned long size,
- unsigned long offset);
+bool xb_find_set(struct xb *xb, unsigned long max, unsigned long *bit);
unsigned long xb_find_zero(struct xb *xb, unsigned long size,
unsigned long offset);
@@ -150,48 +150,39 @@ EXPORT_SYMBOL(xb_test_bit);
/**
* xb_find_set - find the next set bit in a range of bits
* @xb: the xbitmap to search from
- * @offset: the offset in the range to start searching
- * @size: the size of the range
+ * @max: the maximum position to search to
+ * @bit: the first bit to examine, and on exit, the found bit
*
- * Returns: the found bit or, @size if no set bit is found.
+ * Returns: %true if a set bit was found. @bit will be updated.
*/
-unsigned long xb_find_set(struct xb *xb, unsigned long size,
- unsigned long offset)
+bool xb_find_set(struct xb *xb, unsigned long max, unsigned long *bit)
{
- struct radix_tree_root *root = &xb->xbrt;
- struct radix_tree_node *node;
+ struct radix_tree_iter iter;
void __rcu **slot;
struct ida_bitmap *bitmap;
- unsigned long index = offset / IDA_BITMAP_BITS;
- unsigned long index_end = size / IDA_BITMAP_BITS;
- unsigned long bit = offset % IDA_BITMAP_BITS;
-
- if (unlikely(offset >= size))
- return size;
-
- while (index <= index_end) {
- unsigned long ret;
- unsigned int nbits = size - index * IDA_BITMAP_BITS;
-
- bitmap = __radix_tree_lookup(root, index, &node, &slot);
- if (!node) {
- index = (index | RADIX_TREE_MAP_MASK) + 1;
- continue;
- }
-
+ unsigned long index = *bit / IDA_BITMAP_BITS;
+ unsigned int first = *bit % IDA_BITMAP_BITS;
+ unsigned long index_end = max / IDA_BITMAP_BITS;
+
+ radix_tree_for_each_slot(slot, &xb->xbrt, &iter, index) {
+ if (iter.index > index_end)
+ break;
+ bitmap = radix_tree_deref_slot(slot);
if (bitmap) {
- if (nbits > IDA_BITMAP_BITS)
- nbits = IDA_BITMAP_BITS;
-
- ret = find_next_bit(bitmap->bitmap, nbits, bit);
- if (ret != nbits)
- return ret + index * IDA_BITMAP_BITS;
+ unsigned int nbits = IDA_BITMAP_BITS;
+ if (iter.index == index_end)
+ nbits = max % IDA_BITMAP_BITS + 1;
+
+ first = find_next_bit(bitmap->bitmap, nbits, first);
+ if (first != nbits) {
+ *bit = first + iter.index * IDA_BITMAP_BITS;
+ return true;
+ }
}
- bit = 0;
- index++;
+ first = 0;
}
- return size;
+ return false;
}
EXPORT_SYMBOL(xb_find_set);
@@ -246,19 +237,30 @@ static DEFINE_XB(xb1);
void xbitmap_check_bit(unsigned long bit)
{
+ unsigned long nbit = 0;
+
xb_preload(GFP_KERNEL);
assert(!xb_test_bit(&xb1, bit));
assert(xb_set_bit(&xb1, bit) == 0);
assert(xb_test_bit(&xb1, bit));
- assert(xb_clear_bit(&xb1, bit) == 0);
+ assert(xb_find_set(&xb1, ULONG_MAX, &nbit) == true);
+ assert(nbit == bit);
+ assert(xb_find_set(&xb1, ULONG_MAX, &nbit) == true);
+ assert(nbit == bit);
+ nbit++;
+ assert(xb_find_set(&xb1, ULONG_MAX, &nbit) == false);
+ assert(nbit == bit + 1);
+ xb_clear_bit(&xb1, bit);
assert(xb_empty(&xb1));
- assert(xb_clear_bit(&xb1, bit) == 0);
+ xb_clear_bit(&xb1, bit);
assert(xb_empty(&xb1));
xb_preload_end();
}
static void xbitmap_check_bit_range(void)
{
+ unsigned long nbit;
+
/*
* Regular tests
* set bit 2000, 2001, 2040
@@ -273,14 +275,23 @@ static void xbitmap_check_bit_range(void)
assert(!xb_set_bit(&xb1, 2000));
assert(!xb_set_bit(&xb1, 2001));
assert(!xb_set_bit(&xb1, 2040));
- assert(xb_find_set(&xb1, 2048, 0) == 2000);
- assert(xb_find_set(&xb1, 2002, 2000) == 2000);
- assert(xb_find_set(&xb1, 2041, 2002) == 2040);
- assert(xb_find_set(&xb1, 2040, 2002) == 2040);
+ nbit = 0;
+ assert(xb_find_set(&xb1, 2048, &nbit) == true);
+ assert(nbit == 2000);
+ assert(xb_find_set(&xb1, 2002, &nbit) == true);
+ assert(nbit == 2000);
+ nbit = 2002;
+ assert(xb_find_set(&xb1, 2041, &nbit) == true);
+ assert(nbit == 2040);
+ nbit = 2002;
+ assert(xb_find_set(&xb1, 2040, &nbit) == true);
+ assert(nbit == 2040);
assert(xb_find_zero(&xb1, 2048, 2000) == 2002);
assert(xb_find_zero(&xb1, 2060, 2048) == 2048);
xb_clear_bit_range(&xb1, 0, 2048);
- assert(xb_find_set(&xb1, 2048, 0) == 2048);
+ nbit = 0;
+ assert(xb_find_set(&xb1, 2048, &nbit) == false);
+ assert(nbit == 0);
xb_preload_end();
/*
@@ -295,15 +306,22 @@ static void xbitmap_check_bit_range(void)
xb_preload_end();
xb_preload(GFP_KERNEL);
assert(!xb_set_bit(&xb1, ULONG_MAX - 4));
- assert(xb_find_set(&xb1, ULONG_MAX, ULONG_MAX - 4) == ULONG_MAX - 4);
- assert(xb_find_set(&xb1, ULONG_MAX + 4, ULONG_MAX - 3) ==
- ULONG_MAX + 4);
+ nbit = ULONG_MAX - 4;
+ assert(xb_find_set(&xb1, ULONG_MAX, &nbit) == true);
+ assert(nbit == ULONG_MAX - 4);
+ nbit++;
+ assert(xb_find_set(&xb1, ULONG_MAX + 4, &nbit) == false);
+ assert(nbit == ULONG_MAX - 3);
assert(xb_find_zero(&xb1, ULONG_MAX + 4, ULONG_MAX - 4) ==
ULONG_MAX + 4);
xb_clear_bit_range(&xb1, ULONG_MAX - 4, 4);
- assert(xb_find_set(&xb1, ULONG_MAX, ULONG_MAX - 10) == ULONG_MAX);
+ nbit = ULONG_MAX - 10;
+ assert(xb_find_set(&xb1, ULONG_MAX, &nbit) == false);
+ assert(nbit == ULONG_MAX - 10);
xb_clear_bit_range(&xb1, 0, 2);
- assert(xb_find_set(&xb1, 2, 0) == 2);
+ nbit = 0;
+ assert(xb_find_set(&xb1, 2, &nbit) == false);
+ assert(nbit == 0);
xb_preload_end();
}
@@ -313,6 +331,10 @@ void xbitmap_checks(void)
xbitmap_check_bit(0);
xbitmap_check_bit(30);
xbitmap_check_bit(31);
+ xbitmap_check_bit(62);
+ xbitmap_check_bit(63);
+ xbitmap_check_bit(64);
+ xbitmap_check_bit(700);
xbitmap_check_bit(1023);
xbitmap_check_bit(1024);
xbitmap_check_bit(1025);
@@ -1,9 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
CFLAGS += -I. -I../../include -g -O2 -Wall -D_LGPL_SOURCE -fsanitize=address
-LDFLAGS += -fsanitize=address
-LDLIBS+= -lpthread -lurcu
-TARGETS = main idr-test multiorder
+LDFLAGS += -fsanitize=address $(LDLIBS)
+LDLIBS := -lpthread -lurcu
+TARGETS = main idr-test multiorder xbitmap
CORE_OFILES := radix-tree.o idr.o linux.o test.o find_bit.o
OFILES = main.o $(CORE_OFILES) regression1.o regression2.o regression3.o \
tag_check.o multiorder.o idr-test.o iteration_check.o benchmark.o \
@@ -17,6 +17,4 @@
#define pr_debug printk
#define pr_cont printk
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-
#endif /* _KERNEL_H */