mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
XArray: Handle NULL pointers differently for allocation
For allocating XArrays, it makes sense to distinguish beteen erasing an entry and storing NULL. Storing NULL keeps the index allocated with a NULL pointer associated with it while xa_erase() frees the index. Some existing IDR users rely on this ability. Signed-off-by: Matthew Wilcox <willy@infradead.org>
This commit is contained in:
parent
611f318637
commit
d9c480435a
@ -119,18 +119,27 @@ Finally, you can remove all entries from an XArray by calling
|
|||||||
to free the entries first. You can do this by iterating over all present
|
to free the entries first. You can do this by iterating over all present
|
||||||
entries in the XArray using the :c:func:`xa_for_each` iterator.
|
entries in the XArray using the :c:func:`xa_for_each` iterator.
|
||||||
|
|
||||||
ID assignment
|
Allocating XArrays
|
||||||
-------------
|
------------------
|
||||||
|
|
||||||
|
If you use :c:func:`DEFINE_XARRAY_ALLOC` to define the XArray, or
|
||||||
|
initialise it by passing ``XA_FLAGS_ALLOC`` to :c:func:`xa_init_flags`,
|
||||||
|
the XArray changes to track whether entries are in use or not.
|
||||||
|
|
||||||
You can call :c:func:`xa_alloc` to store the entry at any unused index
|
You can call :c:func:`xa_alloc` to store the entry at any unused index
|
||||||
in the XArray. If you need to modify the array from interrupt context,
|
in the XArray. If you need to modify the array from interrupt context,
|
||||||
you can use :c:func:`xa_alloc_bh` or :c:func:`xa_alloc_irq` to disable
|
you can use :c:func:`xa_alloc_bh` or :c:func:`xa_alloc_irq` to disable
|
||||||
interrupts while allocating the ID. Unlike :c:func:`xa_store`, allocating
|
interrupts while allocating the ID.
|
||||||
a ``NULL`` pointer does not delete an entry. Instead it reserves an
|
|
||||||
entry like :c:func:`xa_reserve` and you can release it using either
|
Using :c:func:`xa_store`, :c:func:`xa_cmpxchg` or :c:func:`xa_insert`
|
||||||
:c:func:`xa_erase` or :c:func:`xa_release`. To use ID assignment, the
|
will mark the entry as being allocated. Unlike a normal XArray, storing
|
||||||
XArray must be defined with :c:func:`DEFINE_XARRAY_ALLOC`, or initialised
|
``NULL`` will mark the entry as being in use, like :c:func:`xa_reserve`.
|
||||||
by passing ``XA_FLAGS_ALLOC`` to :c:func:`xa_init_flags`,
|
To free an entry, use :c:func:`xa_erase` (or :c:func:`xa_release` if
|
||||||
|
you only want to free the entry if it's ``NULL``).
|
||||||
|
|
||||||
|
You cannot use ``XA_MARK_0`` with an allocating XArray as this mark
|
||||||
|
is used to track whether an entry is free or not. The other marks are
|
||||||
|
available for your use.
|
||||||
|
|
||||||
Memory allocation
|
Memory allocation
|
||||||
-----------------
|
-----------------
|
||||||
@ -338,7 +347,8 @@ to :c:func:`xas_retry`, and retry the operation if it returns ``true``.
|
|||||||
- :c:func:`xa_is_zero`
|
- :c:func:`xa_is_zero`
|
||||||
- Zero entries appear as ``NULL`` through the Normal API, but occupy
|
- Zero entries appear as ``NULL`` through the Normal API, but occupy
|
||||||
an entry in the XArray which can be used to reserve the index for
|
an entry in the XArray which can be used to reserve the index for
|
||||||
future use.
|
future use. This is used by allocating XArrays for allocated entries
|
||||||
|
which are ``NULL``.
|
||||||
|
|
||||||
Other internal entries may be added in the future. As far as possible, they
|
Other internal entries may be added in the future. As far as possible, they
|
||||||
will be handled by :c:func:`xas_retry`.
|
will be handled by :c:func:`xas_retry`.
|
||||||
|
13
lib/xarray.c
13
lib/xarray.c
@ -1382,10 +1382,12 @@ void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp)
|
|||||||
|
|
||||||
if (WARN_ON_ONCE(xa_is_internal(entry)))
|
if (WARN_ON_ONCE(xa_is_internal(entry)))
|
||||||
return XA_ERROR(-EINVAL);
|
return XA_ERROR(-EINVAL);
|
||||||
|
if (xa_track_free(xa) && !entry)
|
||||||
|
entry = XA_ZERO_ENTRY;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
curr = xas_store(&xas, entry);
|
curr = xas_store(&xas, entry);
|
||||||
if (xa_track_free(xa) && entry)
|
if (xa_track_free(xa))
|
||||||
xas_clear_mark(&xas, XA_FREE_MARK);
|
xas_clear_mark(&xas, XA_FREE_MARK);
|
||||||
} while (__xas_nomem(&xas, gfp));
|
} while (__xas_nomem(&xas, gfp));
|
||||||
|
|
||||||
@ -1446,6 +1448,8 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index,
|
|||||||
|
|
||||||
if (WARN_ON_ONCE(xa_is_internal(entry)))
|
if (WARN_ON_ONCE(xa_is_internal(entry)))
|
||||||
return XA_ERROR(-EINVAL);
|
return XA_ERROR(-EINVAL);
|
||||||
|
if (xa_track_free(xa) && !entry)
|
||||||
|
entry = XA_ZERO_ENTRY;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
curr = xas_load(&xas);
|
curr = xas_load(&xas);
|
||||||
@ -1453,7 +1457,7 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index,
|
|||||||
curr = NULL;
|
curr = NULL;
|
||||||
if (curr == old) {
|
if (curr == old) {
|
||||||
xas_store(&xas, entry);
|
xas_store(&xas, entry);
|
||||||
if (xa_track_free(xa) && entry)
|
if (xa_track_free(xa))
|
||||||
xas_clear_mark(&xas, XA_FREE_MARK);
|
xas_clear_mark(&xas, XA_FREE_MARK);
|
||||||
}
|
}
|
||||||
} while (__xas_nomem(&xas, gfp));
|
} while (__xas_nomem(&xas, gfp));
|
||||||
@ -1487,8 +1491,11 @@ int __xa_reserve(struct xarray *xa, unsigned long index, gfp_t gfp)
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
curr = xas_load(&xas);
|
curr = xas_load(&xas);
|
||||||
if (!curr)
|
if (!curr) {
|
||||||
xas_store(&xas, XA_ZERO_ENTRY);
|
xas_store(&xas, XA_ZERO_ENTRY);
|
||||||
|
if (xa_track_free(xa))
|
||||||
|
xas_clear_mark(&xas, XA_FREE_MARK);
|
||||||
|
}
|
||||||
} while (__xas_nomem(&xas, gfp));
|
} while (__xas_nomem(&xas, gfp));
|
||||||
|
|
||||||
return xas_error(&xas);
|
return xas_error(&xas);
|
||||||
|
Loading…
Reference in New Issue
Block a user