These turned out not to be needed.
Signed-off-by: Matthew Wilcox <willy@infradead.org>
``ULONG_MAX`` then the XArray is not the data type for you. The most
important user of the XArray is the page cache.
-Each non-``NULL`` entry in the array has three bits associated with
-it called marks. Each mark may be set or cleared independently of
-the others. You can iterate over entries which are marked.
-
-Normal pointers may be stored in the XArray directly. They must be 4-byte
-aligned, which is true for any pointer returned from kmalloc() and
-alloc_page(). It isn't true for arbitrary user-space pointers,
-nor for function pointers. You can store pointers to statically allocated
-objects, as long as those objects have an alignment of at least 4.
-
-You can also store integers between 0 and ``LONG_MAX`` in the XArray.
-You must first convert it into an entry using xa_mk_value().
-When you retrieve an entry from the XArray, you can check whether it is
-a value entry by calling xa_is_value(), and convert it back to
-an integer by calling xa_to_value().
-
-Some users want to store tagged pointers instead of using the marks
-described above. They can call xa_tag_pointer() to create an
-entry with a tag, xa_untag_pointer() to turn a tagged entry
-back into an untagged pointer and xa_pointer_tag() to retrieve
-the tag of an entry. Tagged pointers use the same bits that are used
-to distinguish value entries from normal pointers, so each user must
-decide whether they want to store value entries or tagged pointers in
+Normal pointers may be stored in the XArray directly. You can also store
+integers between 0 and ``LONG_MAX`` in the XArray. You must first convert
+integers into an entry using xa_mk_value(). When you retrieve an entry
+from the XArray, you can check whether it is a value entry by calling
+xa_is_value(), and convert it back to an integer by calling xa_to_value().
+
+Some users want to tag the pointers they store in the XArray. You can
+call xa_tag_pointer() to create an entry with a tag, xa_untag_pointer()
+to turn a tagged entry back into an untagged pointer and xa_pointer_tag()
+to retrieve the tag of an entry. Tagged pointers use the same bits that
+are used to distinguish value entries from normal pointers, so you must
+decide whether you want to store value entries or tagged pointers in
any particular XArray.
-The XArray does not support storing IS_ERR() pointers as some
-conflict with value entries or internal entries.
+Storing IS_ERR() pointers is not recommended as the values used
+to represent some errors conflict with value entries or internal entries.
An unusual feature of the XArray is the ability to create entries which
occupy a range of indices. Once stored to, looking up any index in
the range will return the same entry as looking up any other index in
the range. Setting a mark on one index will set it on all of them.
-Storing to any index will store to all of them. Multi-index entries can
-be explicitly split into smaller entries, or storing ``NULL`` into any
-entry will cause the XArray to forget about the range.
+Storing to any index will store to all of them. Multi-index entries
+can be explicitly split into smaller entries, or storing ``NULL`` into
+any entry will cause the XArray to forget about the range.
+
+The XArray supports a reserved entry called ``XA_ZERO_ENTRY``. This entry
+generally reads back as ``NULL`` and is skipped by iteration, but the
+entry will be seen as occupied. It does not normally need to be named
+by users of the normal API, but may be needed in some special cases.
+It is exposed through the advanced API.
Normal API
==========
allocated ones. A freshly-initialised XArray contains a ``NULL``
pointer at every index.
-You can then set entries using xa_store() and get entries
-using xa_load(). xa_store will overwrite any entry with the
-new entry and return the previous entry stored at that index. You can
-use xa_erase() instead of calling xa_store() with a
-``NULL`` entry. There is no difference between an entry that has never
-been stored to, one that has been erased and one that has most recently
-had ``NULL`` stored to it.
+You can then set entries using xa_store() and get entries using xa_load().
+xa_store overwrites any entry with the new entry and return the previous
+entry stored at that index. You can use xa_erase() to reset an entry to
+``NULL``. Calling xa_store() with a ``NULL`` entry is the same
+as calling xa_erase() unless you are using an allocating array
+(see below).
+
+If you want to only store a new entry to an index if the current entry is
+``NULL``, you can use xa_insert() which returns ``-EBUSY`` if the
+entry is not empty. If you pass ``NULL`` as the entry to be inserted,
+it will instead store a reserved entry. Attempting to insert an entry over
+a reserved entry will fail.
You can conditionally replace an entry at an index by using
xa_cmpxchg(). Like cmpxchg(), it will only succeed if
the entry at that index has the 'old' value. It also returns the entry
which was at that index; if it returns the same entry which was passed as
-'old', then xa_cmpxchg() succeeded.
-
-If you want to only store a new entry to an index if the current entry
-at that index is ``NULL``, you can use xa_insert() which
-returns ``-EBUSY`` if the entry is not empty.
-
-You can enquire whether a mark is set on an entry by using
-xa_get_mark(). If the entry is not ``NULL``, you can set a mark
-on it by using xa_set_mark() and remove the mark from an entry by
-calling xa_clear_mark(). You can ask whether any entry in the
-XArray has a particular mark set by calling xa_marked().
+'old', then xa_cmpxchg() succeeded. Unlike xa_insert(),
+xa_cmpxchg() does not convert either of its arguments from
+``NULL`` to ``XA_ZERO_ENTRY``.
You can copy entries out of the XArray into a plain array by calling
xa_extract(). Or you can iterate over the present entries in
indices. Storing into one index may result in the entry retrieved by
some, but not all of the other indices changing.
-Sometimes you need to ensure that a subsequent call to xa_store()
-will not need to allocate memory. The xa_reserve() function
-will store a reserved entry at the indicated index. Users of the
-normal API will see this entry as containing ``NULL``. If you do
-not need to use the reserved entry, you can call xa_release()
-to remove the unused entry. If another user has stored to the entry
-in the meantime, xa_release() will do nothing; if instead you
-want the entry to become ``NULL``, you should use xa_erase().
-Using xa_insert() on a reserved entry will fail.
-
If all entries in the array are ``NULL``, the xa_empty() function
will return ``true``.
to free the entries first. You can do this by iterating over all present
entries in the XArray using the xa_for_each() iterator.
+Search Marks
+------------
+
+Each entry in the array has three bits associated with it called marks.
+Each mark may be set or cleared independently of the others. You can
+efficiently iterate over all marked entries in the array by using the
+xa_for_each_marked() iterator.
+
+You can enquire whether a mark is set on an entry by using
+xa_get_mark(). If the entry is not ``NULL``, you can set a mark
+on it by using xa_set_mark() and remove the mark from an entry by
+calling xa_clear_mark(). You can ask whether any entry in the
+XArray has a particular mark set by calling xa_marked().
+
Allocating XArrays
------------------
you can use xa_alloc_bh() or xa_alloc_irq() to disable
interrupts while allocating the ID.
-Using xa_store(), xa_cmpxchg() or xa_insert() will
-also mark the entry as being allocated. Unlike a normal XArray, storing
-``NULL`` will mark the entry as being in use, like xa_reserve().
-To free an entry, use xa_erase() (or xa_release() if
-you only want to free the entry if it's ``NULL``).
+A successful call to xa_store() or xa_insert() will
+also mark the entry as being allocated. Unlike a normal XArray,
+storing ``NULL`` will store a reserved entry and mark the entry as
+being in use.
By default, the lowest free entry is allocated starting from 0. If you
want to allocate entries starting at 1, it is more efficient to use
Memory allocation
-----------------
-The xa_store(), xa_cmpxchg(), xa_alloc(),
-xa_reserve() and xa_insert() functions take a gfp_t
-parameter in case the XArray needs to allocate memory to store this entry.
-If the entry is being deleted, no memory allocation needs to be performed,
-and the GFP flags specified will be ignored.
+The xa_store(), xa_cmpxchg(), xa_alloc() and xa_insert() functions take
+a gfp_t parameter in case the XArray needs to allocate memory to store
+this entry. If the entry is being deleted, no memory allocation needs
+to be performed, and the GFP flags specified will be ignored.
It is possible for no memory to be allocatable, particularly if you pass
a restrictive set of GFP flags. In that case, the functions return a
* xa_alloc()
* xa_alloc_bh()
* xa_alloc_irq()
- * xa_reserve()
- * xa_reserve_bh()
- * xa_reserve_irq()
* xa_destroy()
* xa_set_mark()
* xa_clear_mark()
* @entry: New entry.
* @gfp: Memory allocation flags.
*
- * Inserting a NULL entry will store a reserved entry (like xa_reserve())
- * if no entry is present. Inserting will fail if a reserved entry is
- * present, even though loading from this index will return NULL.
+ * Inserting a NULL entry will store a reserved entry if no entry is
+ * present. Inserting will fail if a reserved entry is present, even
+ * though loading from this index will return NULL.
*
* Context: Any context. Takes and releases the xa_lock. May sleep if
* the @gfp flags permit.
* @entry: New entry.
* @gfp: Memory allocation flags.
*
- * Inserting a NULL entry will store a reserved entry (like xa_reserve())
- * if no entry is present. Inserting will fail if a reserved entry is
- * present, even though loading from this index will return NULL.
+ * Inserting a NULL entry will store a reserved entry if no entry is
+ * present. Inserting will fail if a reserved entry is present, even
+ * though loading from this index will return NULL.
*
* Context: Any context. Takes and releases the xa_lock while
* disabling softirqs. May sleep if the @gfp flags permit.
* @entry: New entry.
* @gfp: Memory allocation flags.
*
- * Inserting a NULL entry will store a reserved entry (like xa_reserve())
- * if no entry is present. Inserting will fail if a reserved entry is
- * present, even though loading from this index will return NULL.
+ * Inserting a NULL entry will store a reserved entry if no entry is
+ * present. Inserting will fail if a reserved entry is present, even
+ * though loading from this index will return NULL.
*
* Context: Process context. Takes and releases the xa_lock while
* disabling interrupts. May sleep if the @gfp flags permit.
return err;
}
-/**
- * xa_reserve() - Reserve this index in the XArray.
- * @xa: XArray.
- * @index: Index into array.
- * @gfp: Memory allocation flags.
- *
- * Ensures there is somewhere to store an entry at @index in the array.
- * If there is already something stored at @index, this function does
- * nothing. If there was nothing there, the entry is marked as reserved.
- * Loading from a reserved entry returns a %NULL pointer.
- *
- * If you do not use the entry that you have reserved, call xa_release()
- * or xa_erase() to free any unnecessary memory.
- *
- * Context: Any context. Takes and releases the xa_lock.
- * May sleep if the @gfp flags permit.
- * Return: 0 if the reservation succeeded or -ENOMEM if it failed.
- */
-static inline __must_check
-int xa_reserve(struct xarray *xa, unsigned long index, gfp_t gfp)
-{
- return xa_err(xa_cmpxchg(xa, index, NULL, XA_ZERO_ENTRY, gfp));
-}
-
-/**
- * xa_reserve_bh() - Reserve this index in the XArray.
- * @xa: XArray.
- * @index: Index into array.
- * @gfp: Memory allocation flags.
- *
- * A softirq-disabling version of xa_reserve().
- *
- * Context: Any context. Takes and releases the xa_lock while
- * disabling softirqs.
- * Return: 0 if the reservation succeeded or -ENOMEM if it failed.
- */
-static inline __must_check
-int xa_reserve_bh(struct xarray *xa, unsigned long index, gfp_t gfp)
-{
- return xa_err(xa_cmpxchg_bh(xa, index, NULL, XA_ZERO_ENTRY, gfp));
-}
-
-/**
- * xa_reserve_irq() - Reserve this index in the XArray.
- * @xa: XArray.
- * @index: Index into array.
- * @gfp: Memory allocation flags.
- *
- * An interrupt-disabling version of xa_reserve().
- *
- * Context: Process context. Takes and releases the xa_lock while
- * disabling interrupts.
- * Return: 0 if the reservation succeeded or -ENOMEM if it failed.
- */
-static inline __must_check
-int xa_reserve_irq(struct xarray *xa, unsigned long index, gfp_t gfp)
-{
- return xa_err(xa_cmpxchg_irq(xa, index, NULL, XA_ZERO_ENTRY, gfp));
-}
-
-/**
- * xa_release() - Release a reserved entry.
- * @xa: XArray.
- * @index: Index of entry.
- *
- * After calling xa_reserve(), you can call this function to release the
- * reservation. If the entry at @index has been stored to, this function
- * will do nothing.
- */
-static inline void xa_release(struct xarray *xa, unsigned long index)
-{
- xa_cmpxchg(xa, index, XA_ZERO_ENTRY, NULL, 0);
-}
-
/* Everything below here is the Advanced API. Proceed with caution. */
/*
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kmemleak.h>
+#include <linux/list.h>
#include <linux/percpu.h>
#include <linux/preempt.h> /* in_interrupt() */
#include <linux/rcupdate.h>
/* An array with a reserved entry is not empty */
XA_BUG_ON(xa, !xa_empty(xa));
- XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0);
+ XA_BUG_ON(xa, xa_insert(xa, 12345678, NULL, GFP_KERNEL) != 0);
XA_BUG_ON(xa, xa_empty(xa));
XA_BUG_ON(xa, xa_load(xa, 12345678));
- xa_release(xa, 12345678);
- XA_BUG_ON(xa, !xa_empty(xa));
-
- /* Releasing a used entry does nothing */
- XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0);
- XA_BUG_ON(xa, xa_store_index(xa, 12345678, GFP_NOWAIT) != NULL);
- xa_release(xa, 12345678);
- xa_erase_index(xa, 12345678);
+ XA_BUG_ON(xa, xa_erase(xa, 12345678) != NULL);
XA_BUG_ON(xa, !xa_empty(xa));
/* cmpxchg sees a reserved entry as ZERO */
- XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0);
+ XA_BUG_ON(xa, xa_insert(xa, 12345678, NULL, GFP_KERNEL) != 0);
XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, XA_ZERO_ENTRY,
xa_mk_value(12345678), GFP_NOWAIT) != NULL);
- xa_release(xa, 12345678);
xa_erase_index(xa, 12345678);
XA_BUG_ON(xa, !xa_empty(xa));
/* xa_insert treats it as busy */
- XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0);
+ XA_BUG_ON(xa, xa_insert(xa, 12345678, NULL, GFP_KERNEL) != 0);
XA_BUG_ON(xa, xa_insert(xa, 12345678, xa_mk_value(12345678), 0) !=
-EBUSY);
XA_BUG_ON(xa, xa_empty(xa));
/* Can iterate through a reserved entry */
xa_store_index(xa, 5, GFP_KERNEL);
- XA_BUG_ON(xa, xa_reserve(xa, 6, GFP_KERNEL) != 0);
+ XA_BUG_ON(xa, xa_insert(xa, 6, NULL, GFP_KERNEL) != 0);
xa_store_index(xa, 7, GFP_KERNEL);
count = 0;
XA_LIMIT(5, 10), GFP_KERNEL) != 0);
XA_BUG_ON(xa, id != 8);
- xa_release(xa, 6);
+ XA_BUG_ON(xa, xa_erase(xa, 6) != NULL);
XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_value(6),
XA_LIMIT(5, 10), GFP_KERNEL) != 0);
XA_BUG_ON(xa, id != 6);
}
for (i = 0; i < 8; i++) {
- XA_BUG_ON(xa, xa_reserve(xa, 0, GFP_KERNEL) != 0);
+ XA_BUG_ON(xa, xa_insert(xa, 0, NULL, GFP_KERNEL) != 0);
XA_BUG_ON(xa, xa_store(xa, 0, name + i, 0) != NULL);
xa_erase(xa, 0);
}
* @entry: New entry.
* @gfp: Memory allocation flags.
*
- * Inserting a NULL entry will store a reserved entry (like xa_reserve())
- * if no entry is present. Inserting will fail if a reserved entry is
- * present, even though loading from this index will return NULL.
+ * Inserting a NULL entry will store a reserved entry if no entry is
+ * present. Inserting will fail if a reserved entry is present, even
+ * though loading from this index will return NULL.
*
* Context: Any context. Expects xa_lock to be held on entry. May
* release and reacquire xa_lock if @gfp flags permit.
LDFLAGS += -fsanitize=address -fsanitize=undefined
LDLIBS+= -lpthread -lurcu
TARGETS = main idr-test multiorder xarray
-CORE_OFILES := xarray.o radix-tree.o idr.o linux.o test.o find_bit.o bitmap.o
+CORE_OFILES := xarray.o linux.o radix-tree.o test.o find_bit.o bitmap.o
OFILES = main.o $(CORE_OFILES) regression1.o regression2.o regression4.o \
- tag_check.o multiorder.o idr-test.o iteration_check.o benchmark.o
+ tag_check.o multiorder.o idr.o idr-test.o \
+ iteration_check.o benchmark.o
ifndef SHIFT
SHIFT=3