diff options
| -rw-r--r-- | Documentation/core-api/xarray.rst | 15 | ||||
| -rw-r--r-- | include/linux/xarray.h | 227 | ||||
| -rw-r--r-- | lib/test_xarray.c | 57 | ||||
| -rw-r--r-- | lib/xarray.c | 92 |
4 files changed, 278 insertions, 113 deletions
diff --git a/Documentation/core-api/xarray.rst b/Documentation/core-api/xarray.rst index 6a6d67acaf69..5d54b27c6eba 100644 --- a/Documentation/core-api/xarray.rst +++ b/Documentation/core-api/xarray.rst | |||
| @@ -108,12 +108,13 @@ some, but not all of the other indices changing. | |||
| 108 | 108 | ||
| 109 | Sometimes you need to ensure that a subsequent call to :c:func:`xa_store` | 109 | Sometimes you need to ensure that a subsequent call to :c:func:`xa_store` |
| 110 | will not need to allocate memory. The :c:func:`xa_reserve` function | 110 | will not need to allocate memory. The :c:func:`xa_reserve` function |
| 111 | will store a reserved entry at the indicated index. Users of the normal | 111 | will store a reserved entry at the indicated index. Users of the |
| 112 | API will see this entry as containing ``NULL``. If you do not need to | 112 | normal API will see this entry as containing ``NULL``. If you do |
| 113 | use the reserved entry, you can call :c:func:`xa_release` to remove the | 113 | not need to use the reserved entry, you can call :c:func:`xa_release` |
| 114 | unused entry. If another user has stored to the entry in the meantime, | 114 | to remove the unused entry. If another user has stored to the entry |
| 115 | :c:func:`xa_release` will do nothing; if instead you want the entry to | 115 | in the meantime, :c:func:`xa_release` will do nothing; if instead you |
| 116 | become ``NULL``, you should use :c:func:`xa_erase`. | 116 | want the entry to become ``NULL``, you should use :c:func:`xa_erase`. |
| 117 | Using :c:func:`xa_insert` on a reserved entry will fail. | ||
| 117 | 118 | ||
| 118 | If all entries in the array are ``NULL``, the :c:func:`xa_empty` function | 119 | If all entries in the array are ``NULL``, the :c:func:`xa_empty` function |
| 119 | will return ``true``. | 120 | will return ``true``. |
| @@ -183,6 +184,8 @@ Takes xa_lock internally: | |||
| 183 | * :c:func:`xa_store_bh` | 184 | * :c:func:`xa_store_bh` |
| 184 | * :c:func:`xa_store_irq` | 185 | * :c:func:`xa_store_irq` |
| 185 | * :c:func:`xa_insert` | 186 | * :c:func:`xa_insert` |
| 187 | * :c:func:`xa_insert_bh` | ||
| 188 | * :c:func:`xa_insert_irq` | ||
| 186 | * :c:func:`xa_erase` | 189 | * :c:func:`xa_erase` |
| 187 | * :c:func:`xa_erase_bh` | 190 | * :c:func:`xa_erase_bh` |
| 188 | * :c:func:`xa_erase_irq` | 191 | * :c:func:`xa_erase_irq` |
diff --git a/include/linux/xarray.h b/include/linux/xarray.h index f492e21c4aa2..5d9d318bcf7a 100644 --- a/include/linux/xarray.h +++ b/include/linux/xarray.h | |||
| @@ -176,7 +176,8 @@ static inline bool xa_is_internal(const void *entry) | |||
| 176 | */ | 176 | */ |
| 177 | static inline bool xa_is_err(const void *entry) | 177 | static inline bool xa_is_err(const void *entry) |
| 178 | { | 178 | { |
| 179 | return unlikely(xa_is_internal(entry)); | 179 | return unlikely(xa_is_internal(entry) && |
| 180 | entry >= xa_mk_internal(-MAX_ERRNO)); | ||
| 180 | } | 181 | } |
| 181 | 182 | ||
| 182 | /** | 183 | /** |
| @@ -286,7 +287,6 @@ struct xarray { | |||
| 286 | */ | 287 | */ |
| 287 | #define DEFINE_XARRAY_ALLOC(name) DEFINE_XARRAY_FLAGS(name, XA_FLAGS_ALLOC) | 288 | #define DEFINE_XARRAY_ALLOC(name) DEFINE_XARRAY_FLAGS(name, XA_FLAGS_ALLOC) |
| 288 | 289 | ||
| 289 | void xa_init_flags(struct xarray *, gfp_t flags); | ||
| 290 | void *xa_load(struct xarray *, unsigned long index); | 290 | void *xa_load(struct xarray *, unsigned long index); |
| 291 | void *xa_store(struct xarray *, unsigned long index, void *entry, gfp_t); | 291 | void *xa_store(struct xarray *, unsigned long index, void *entry, gfp_t); |
| 292 | void *xa_erase(struct xarray *, unsigned long index); | 292 | void *xa_erase(struct xarray *, unsigned long index); |
| @@ -304,6 +304,24 @@ unsigned int xa_extract(struct xarray *, void **dst, unsigned long start, | |||
| 304 | void xa_destroy(struct xarray *); | 304 | void xa_destroy(struct xarray *); |
| 305 | 305 | ||
| 306 | /** | 306 | /** |
| 307 | * xa_init_flags() - Initialise an empty XArray with flags. | ||
| 308 | * @xa: XArray. | ||
| 309 | * @flags: XA_FLAG values. | ||
| 310 | * | ||
| 311 | * If you need to initialise an XArray with special flags (eg you need | ||
| 312 | * to take the lock from interrupt context), use this function instead | ||
| 313 | * of xa_init(). | ||
| 314 | * | ||
| 315 | * Context: Any context. | ||
| 316 | */ | ||
| 317 | static inline void xa_init_flags(struct xarray *xa, gfp_t flags) | ||
| 318 | { | ||
| 319 | spin_lock_init(&xa->xa_lock); | ||
| 320 | xa->xa_flags = flags; | ||
| 321 | xa->xa_head = NULL; | ||
| 322 | } | ||
| 323 | |||
| 324 | /** | ||
| 307 | * xa_init() - Initialise an empty XArray. | 325 | * xa_init() - Initialise an empty XArray. |
| 308 | * @xa: XArray. | 326 | * @xa: XArray. |
| 309 | * | 327 | * |
| @@ -342,20 +360,45 @@ static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark) | |||
| 342 | } | 360 | } |
| 343 | 361 | ||
| 344 | /** | 362 | /** |
| 345 | * xa_for_each() - Iterate over a portion of an XArray. | 363 | * xa_for_each_start() - Iterate over a portion of an XArray. |
| 346 | * @xa: XArray. | 364 | * @xa: XArray. |
| 365 | * @index: Index of @entry. | ||
| 347 | * @entry: Entry retrieved from array. | 366 | * @entry: Entry retrieved from array. |
| 367 | * @start: First index to retrieve from array. | ||
| 368 | * | ||
| 369 | * During the iteration, @entry will have the value of the entry stored | ||
| 370 | * in @xa at @index. You may modify @index during the iteration if you | ||
| 371 | * want to skip or reprocess indices. It is safe to modify the array | ||
| 372 | * during the iteration. At the end of the iteration, @entry will be set | ||
| 373 | * to NULL and @index will have a value less than or equal to max. | ||
| 374 | * | ||
| 375 | * xa_for_each_start() is O(n.log(n)) while xas_for_each() is O(n). You have | ||
| 376 | * to handle your own locking with xas_for_each(), and if you have to unlock | ||
| 377 | * after each iteration, it will also end up being O(n.log(n)). | ||
| 378 | * xa_for_each_start() will spin if it hits a retry entry; if you intend to | ||
| 379 | * see retry entries, you should use the xas_for_each() iterator instead. | ||
| 380 | * The xas_for_each() iterator will expand into more inline code than | ||
| 381 | * xa_for_each_start(). | ||
| 382 | * | ||
| 383 | * Context: Any context. Takes and releases the RCU lock. | ||
| 384 | */ | ||
| 385 | #define xa_for_each_start(xa, index, entry, start) \ | ||
| 386 | for (index = start, \ | ||
| 387 | entry = xa_find(xa, &index, ULONG_MAX, XA_PRESENT); \ | ||
| 388 | entry; \ | ||
| 389 | entry = xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT)) | ||
| 390 | |||
| 391 | /** | ||
| 392 | * xa_for_each() - Iterate over present entries in an XArray. | ||
| 393 | * @xa: XArray. | ||
| 348 | * @index: Index of @entry. | 394 | * @index: Index of @entry. |
| 349 | * @max: Maximum index to retrieve from array. | 395 | * @entry: Entry retrieved from array. |
| 350 | * @filter: Selection criterion. | ||
| 351 | * | 396 | * |
| 352 | * Initialise @index to the lowest index you want to retrieve from the | 397 | * During the iteration, @entry will have the value of the entry stored |
| 353 | * array. During the iteration, @entry will have the value of the entry | 398 | * in @xa at @index. You may modify @index during the iteration if you want |
| 354 | * stored in @xa at @index. The iteration will skip all entries in the | 399 | * to skip or reprocess indices. It is safe to modify the array during the |
| 355 | * array which do not match @filter. You may modify @index during the | 400 | * iteration. At the end of the iteration, @entry will be set to NULL and |
| 356 | * iteration if you want to skip or reprocess indices. It is safe to modify | 401 | * @index will have a value less than or equal to max. |
| 357 | * the array during the iteration. At the end of the iteration, @entry will | ||
| 358 | * be set to NULL and @index will have a value less than or equal to max. | ||
| 359 | * | 402 | * |
| 360 | * xa_for_each() is O(n.log(n)) while xas_for_each() is O(n). You have | 403 | * xa_for_each() is O(n.log(n)) while xas_for_each() is O(n). You have |
| 361 | * to handle your own locking with xas_for_each(), and if you have to unlock | 404 | * to handle your own locking with xas_for_each(), and if you have to unlock |
| @@ -366,9 +409,36 @@ static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark) | |||
| 366 | * | 409 | * |
| 367 | * Context: Any context. Takes and releases the RCU lock. | 410 | * Context: Any context. Takes and releases the RCU lock. |
| 368 | */ | 411 | */ |
| 369 | #define xa_for_each(xa, entry, index, max, filter) \ | 412 | #define xa_for_each(xa, index, entry) \ |
| 370 | for (entry = xa_find(xa, &index, max, filter); entry; \ | 413 | xa_for_each_start(xa, index, entry, 0) |
| 371 | entry = xa_find_after(xa, &index, max, filter)) | 414 | |
| 415 | /** | ||
| 416 | * xa_for_each_marked() - Iterate over marked entries in an XArray. | ||
| 417 | * @xa: XArray. | ||
| 418 | * @index: Index of @entry. | ||
| 419 | * @entry: Entry retrieved from array. | ||
| 420 | * @filter: Selection criterion. | ||
| 421 | * | ||
| 422 | * During the iteration, @entry will have the value of the entry stored | ||
| 423 | * in @xa at @index. The iteration will skip all entries in the array | ||
| 424 | * which do not match @filter. You may modify @index during the iteration | ||
| 425 | * if you want to skip or reprocess indices. It is safe to modify the array | ||
| 426 | * during the iteration. At the end of the iteration, @entry will be set to | ||
| 427 | * NULL and @index will have a value less than or equal to max. | ||
| 428 | * | ||
| 429 | * xa_for_each_marked() is O(n.log(n)) while xas_for_each_marked() is O(n). | ||
| 430 | * You have to handle your own locking with xas_for_each(), and if you have | ||
| 431 | * to unlock after each iteration, it will also end up being O(n.log(n)). | ||
| 432 | * xa_for_each_marked() will spin if it hits a retry entry; if you intend to | ||
| 433 | * see retry entries, you should use the xas_for_each_marked() iterator | ||
| 434 | * instead. The xas_for_each_marked() iterator will expand into more inline | ||
| 435 | * code than xa_for_each_marked(). | ||
| 436 | * | ||
| 437 | * Context: Any context. Takes and releases the RCU lock. | ||
| 438 | */ | ||
| 439 | #define xa_for_each_marked(xa, index, entry, filter) \ | ||
| 440 | for (index = 0, entry = xa_find(xa, &index, ULONG_MAX, filter); \ | ||
| 441 | entry; entry = xa_find_after(xa, &index, ULONG_MAX, filter)) | ||
| 372 | 442 | ||
| 373 | #define xa_trylock(xa) spin_trylock(&(xa)->xa_lock) | 443 | #define xa_trylock(xa) spin_trylock(&(xa)->xa_lock) |
| 374 | #define xa_lock(xa) spin_lock(&(xa)->xa_lock) | 444 | #define xa_lock(xa) spin_lock(&(xa)->xa_lock) |
| @@ -393,40 +463,13 @@ void *__xa_erase(struct xarray *, unsigned long index); | |||
| 393 | void *__xa_store(struct xarray *, unsigned long index, void *entry, gfp_t); | 463 | void *__xa_store(struct xarray *, unsigned long index, void *entry, gfp_t); |
| 394 | void *__xa_cmpxchg(struct xarray *, unsigned long index, void *old, | 464 | void *__xa_cmpxchg(struct xarray *, unsigned long index, void *old, |
| 395 | void *entry, gfp_t); | 465 | void *entry, gfp_t); |
| 466 | int __xa_insert(struct xarray *, unsigned long index, void *entry, gfp_t); | ||
| 396 | int __xa_alloc(struct xarray *, u32 *id, u32 max, void *entry, gfp_t); | 467 | int __xa_alloc(struct xarray *, u32 *id, u32 max, void *entry, gfp_t); |
| 397 | int __xa_reserve(struct xarray *, unsigned long index, gfp_t); | 468 | int __xa_reserve(struct xarray *, unsigned long index, gfp_t); |
| 398 | void __xa_set_mark(struct xarray *, unsigned long index, xa_mark_t); | 469 | void __xa_set_mark(struct xarray *, unsigned long index, xa_mark_t); |
| 399 | void __xa_clear_mark(struct xarray *, unsigned long index, xa_mark_t); | 470 | void __xa_clear_mark(struct xarray *, unsigned long index, xa_mark_t); |
| 400 | 471 | ||
| 401 | /** | 472 | /** |
| 402 | * __xa_insert() - Store this entry in the XArray unless another entry is | ||
| 403 | * already present. | ||
| 404 | * @xa: XArray. | ||
| 405 | * @index: Index into array. | ||
