1f8d5d0ccSMatthew Wilcox // SPDX-License-Identifier: GPL-2.0+ 2f8d5d0ccSMatthew Wilcox /* 3f8d5d0ccSMatthew Wilcox * XArray implementation 4f8d5d0ccSMatthew Wilcox * Copyright (c) 2017 Microsoft Corporation 5f8d5d0ccSMatthew Wilcox * Author: Matthew Wilcox <[email protected]> 6f8d5d0ccSMatthew Wilcox */ 7f8d5d0ccSMatthew Wilcox 89b89a035SMatthew Wilcox #include <linux/bitmap.h> 9f8d5d0ccSMatthew Wilcox #include <linux/export.h> 1058d6ea30SMatthew Wilcox #include <linux/list.h> 1158d6ea30SMatthew Wilcox #include <linux/slab.h> 12f8d5d0ccSMatthew Wilcox #include <linux/xarray.h> 13f8d5d0ccSMatthew Wilcox 14f8d5d0ccSMatthew Wilcox /* 15f8d5d0ccSMatthew Wilcox * Coding conventions in this file: 16f8d5d0ccSMatthew Wilcox * 17f8d5d0ccSMatthew Wilcox * @xa is used to refer to the entire xarray. 18f8d5d0ccSMatthew Wilcox * @xas is the 'xarray operation state'. It may be either a pointer to 19f8d5d0ccSMatthew Wilcox * an xa_state, or an xa_state stored on the stack. This is an unfortunate 20f8d5d0ccSMatthew Wilcox * ambiguity. 21f8d5d0ccSMatthew Wilcox * @index is the index of the entry being operated on 22f8d5d0ccSMatthew Wilcox * @mark is an xa_mark_t; a small number indicating one of the mark bits. 23f8d5d0ccSMatthew Wilcox * @node refers to an xa_node; usually the primary one being operated on by 24f8d5d0ccSMatthew Wilcox * this function. 25f8d5d0ccSMatthew Wilcox * @offset is the index into the slots array inside an xa_node. 26f8d5d0ccSMatthew Wilcox * @parent refers to the @xa_node closer to the head than @node. 27f8d5d0ccSMatthew Wilcox * @entry refers to something stored in a slot in the xarray 28f8d5d0ccSMatthew Wilcox */ 29f8d5d0ccSMatthew Wilcox 3058d6ea30SMatthew Wilcox static inline unsigned int xa_lock_type(const struct xarray *xa) 3158d6ea30SMatthew Wilcox { 3258d6ea30SMatthew Wilcox return (__force unsigned int)xa->xa_flags & 3; 3358d6ea30SMatthew Wilcox } 3458d6ea30SMatthew Wilcox 3558d6ea30SMatthew Wilcox static inline void xas_lock_type(struct xa_state *xas, unsigned int lock_type) 3658d6ea30SMatthew Wilcox { 3758d6ea30SMatthew Wilcox if (lock_type == XA_LOCK_IRQ) 3858d6ea30SMatthew Wilcox xas_lock_irq(xas); 3958d6ea30SMatthew Wilcox else if (lock_type == XA_LOCK_BH) 4058d6ea30SMatthew Wilcox xas_lock_bh(xas); 4158d6ea30SMatthew Wilcox else 4258d6ea30SMatthew Wilcox xas_lock(xas); 4358d6ea30SMatthew Wilcox } 4458d6ea30SMatthew Wilcox 4558d6ea30SMatthew Wilcox static inline void xas_unlock_type(struct xa_state *xas, unsigned int lock_type) 4658d6ea30SMatthew Wilcox { 4758d6ea30SMatthew Wilcox if (lock_type == XA_LOCK_IRQ) 4858d6ea30SMatthew Wilcox xas_unlock_irq(xas); 4958d6ea30SMatthew Wilcox else if (lock_type == XA_LOCK_BH) 5058d6ea30SMatthew Wilcox xas_unlock_bh(xas); 5158d6ea30SMatthew Wilcox else 5258d6ea30SMatthew Wilcox xas_unlock(xas); 5358d6ea30SMatthew Wilcox } 5458d6ea30SMatthew Wilcox 55*371c752dSMatthew Wilcox static inline bool xa_track_free(const struct xarray *xa) 56*371c752dSMatthew Wilcox { 57*371c752dSMatthew Wilcox return xa->xa_flags & XA_FLAGS_TRACK_FREE; 58*371c752dSMatthew Wilcox } 59*371c752dSMatthew Wilcox 609b89a035SMatthew Wilcox static inline void xa_mark_set(struct xarray *xa, xa_mark_t mark) 619b89a035SMatthew Wilcox { 629b89a035SMatthew Wilcox if (!(xa->xa_flags & XA_FLAGS_MARK(mark))) 639b89a035SMatthew Wilcox xa->xa_flags |= XA_FLAGS_MARK(mark); 649b89a035SMatthew Wilcox } 659b89a035SMatthew Wilcox 669b89a035SMatthew Wilcox static inline void xa_mark_clear(struct xarray *xa, xa_mark_t mark) 679b89a035SMatthew Wilcox { 689b89a035SMatthew Wilcox if (xa->xa_flags & XA_FLAGS_MARK(mark)) 699b89a035SMatthew Wilcox xa->xa_flags &= ~(XA_FLAGS_MARK(mark)); 709b89a035SMatthew Wilcox } 719b89a035SMatthew Wilcox 729b89a035SMatthew Wilcox static inline unsigned long *node_marks(struct xa_node *node, xa_mark_t mark) 739b89a035SMatthew Wilcox { 749b89a035SMatthew Wilcox return node->marks[(__force unsigned)mark]; 759b89a035SMatthew Wilcox } 769b89a035SMatthew Wilcox 779b89a035SMatthew Wilcox static inline bool node_get_mark(struct xa_node *node, 789b89a035SMatthew Wilcox unsigned int offset, xa_mark_t mark) 799b89a035SMatthew Wilcox { 809b89a035SMatthew Wilcox return test_bit(offset, node_marks(node, mark)); 819b89a035SMatthew Wilcox } 829b89a035SMatthew Wilcox 839b89a035SMatthew Wilcox /* returns true if the bit was set */ 849b89a035SMatthew Wilcox static inline bool node_set_mark(struct xa_node *node, unsigned int offset, 859b89a035SMatthew Wilcox xa_mark_t mark) 869b89a035SMatthew Wilcox { 879b89a035SMatthew Wilcox return __test_and_set_bit(offset, node_marks(node, mark)); 889b89a035SMatthew Wilcox } 899b89a035SMatthew Wilcox 909b89a035SMatthew Wilcox /* returns true if the bit was set */ 919b89a035SMatthew Wilcox static inline bool node_clear_mark(struct xa_node *node, unsigned int offset, 929b89a035SMatthew Wilcox xa_mark_t mark) 939b89a035SMatthew Wilcox { 949b89a035SMatthew Wilcox return __test_and_clear_bit(offset, node_marks(node, mark)); 959b89a035SMatthew Wilcox } 969b89a035SMatthew Wilcox 979b89a035SMatthew Wilcox static inline bool node_any_mark(struct xa_node *node, xa_mark_t mark) 989b89a035SMatthew Wilcox { 999b89a035SMatthew Wilcox return !bitmap_empty(node_marks(node, mark), XA_CHUNK_SIZE); 1009b89a035SMatthew Wilcox } 1019b89a035SMatthew Wilcox 102*371c752dSMatthew Wilcox static inline void node_mark_all(struct xa_node *node, xa_mark_t mark) 103*371c752dSMatthew Wilcox { 104*371c752dSMatthew Wilcox bitmap_fill(node_marks(node, mark), XA_CHUNK_SIZE); 105*371c752dSMatthew Wilcox } 106*371c752dSMatthew Wilcox 10758d6ea30SMatthew Wilcox #define mark_inc(mark) do { \ 10858d6ea30SMatthew Wilcox mark = (__force xa_mark_t)((__force unsigned)(mark) + 1); \ 10958d6ea30SMatthew Wilcox } while (0) 11058d6ea30SMatthew Wilcox 11158d6ea30SMatthew Wilcox /* 11258d6ea30SMatthew Wilcox * xas_squash_marks() - Merge all marks to the first entry 11358d6ea30SMatthew Wilcox * @xas: Array operation state. 11458d6ea30SMatthew Wilcox * 11558d6ea30SMatthew Wilcox * Set a mark on the first entry if any entry has it set. Clear marks on 11658d6ea30SMatthew Wilcox * all sibling entries. 11758d6ea30SMatthew Wilcox */ 11858d6ea30SMatthew Wilcox static void xas_squash_marks(const struct xa_state *xas) 11958d6ea30SMatthew Wilcox { 12058d6ea30SMatthew Wilcox unsigned int mark = 0; 12158d6ea30SMatthew Wilcox unsigned int limit = xas->xa_offset + xas->xa_sibs + 1; 12258d6ea30SMatthew Wilcox 12358d6ea30SMatthew Wilcox if (!xas->xa_sibs) 12458d6ea30SMatthew Wilcox return; 12558d6ea30SMatthew Wilcox 12658d6ea30SMatthew Wilcox do { 12758d6ea30SMatthew Wilcox unsigned long *marks = xas->xa_node->marks[mark]; 12858d6ea30SMatthew Wilcox if (find_next_bit(marks, limit, xas->xa_offset + 1) == limit) 12958d6ea30SMatthew Wilcox continue; 13058d6ea30SMatthew Wilcox __set_bit(xas->xa_offset, marks); 13158d6ea30SMatthew Wilcox bitmap_clear(marks, xas->xa_offset + 1, xas->xa_sibs); 13258d6ea30SMatthew Wilcox } while (mark++ != (__force unsigned)XA_MARK_MAX); 13358d6ea30SMatthew Wilcox } 13458d6ea30SMatthew Wilcox 135ad3d6c72SMatthew Wilcox /* extracts the offset within this node from the index */ 136ad3d6c72SMatthew Wilcox static unsigned int get_offset(unsigned long index, struct xa_node *node) 137ad3d6c72SMatthew Wilcox { 138ad3d6c72SMatthew Wilcox return (index >> node->shift) & XA_CHUNK_MASK; 139ad3d6c72SMatthew Wilcox } 140ad3d6c72SMatthew Wilcox 141b803b428SMatthew Wilcox static void xas_set_offset(struct xa_state *xas) 142b803b428SMatthew Wilcox { 143b803b428SMatthew Wilcox xas->xa_offset = get_offset(xas->xa_index, xas->xa_node); 144b803b428SMatthew Wilcox } 145b803b428SMatthew Wilcox 146ad3d6c72SMatthew Wilcox /* move the index either forwards (find) or backwards (sibling slot) */ 147ad3d6c72SMatthew Wilcox static void xas_move_index(struct xa_state *xas, unsigned long offset) 148ad3d6c72SMatthew Wilcox { 149ad3d6c72SMatthew Wilcox unsigned int shift = xas->xa_node->shift; 150ad3d6c72SMatthew Wilcox xas->xa_index &= ~XA_CHUNK_MASK << shift; 151ad3d6c72SMatthew Wilcox xas->xa_index += offset << shift; 152ad3d6c72SMatthew Wilcox } 153ad3d6c72SMatthew Wilcox 154b803b428SMatthew Wilcox static void xas_advance(struct xa_state *xas) 155b803b428SMatthew Wilcox { 156b803b428SMatthew Wilcox xas->xa_offset++; 157b803b428SMatthew Wilcox xas_move_index(xas, xas->xa_offset); 158b803b428SMatthew Wilcox } 159b803b428SMatthew Wilcox 160ad3d6c72SMatthew Wilcox static void *set_bounds(struct xa_state *xas) 161ad3d6c72SMatthew Wilcox { 162ad3d6c72SMatthew Wilcox xas->xa_node = XAS_BOUNDS; 163ad3d6c72SMatthew Wilcox return NULL; 164ad3d6c72SMatthew Wilcox } 165ad3d6c72SMatthew Wilcox 166ad3d6c72SMatthew Wilcox /* 167ad3d6c72SMatthew Wilcox * Starts a walk. If the @xas is already valid, we assume that it's on 168ad3d6c72SMatthew Wilcox * the right path and just return where we've got to. If we're in an 169ad3d6c72SMatthew Wilcox * error state, return NULL. If the index is outside the current scope 170ad3d6c72SMatthew Wilcox * of the xarray, return NULL without changing @xas->xa_node. Otherwise 171ad3d6c72SMatthew Wilcox * set @xas->xa_node to NULL and return the current head of the array. 172ad3d6c72SMatthew Wilcox */ 173ad3d6c72SMatthew Wilcox static void *xas_start(struct xa_state *xas) 174ad3d6c72SMatthew Wilcox { 175ad3d6c72SMatthew Wilcox void *entry; 176ad3d6c72SMatthew Wilcox 177ad3d6c72SMatthew Wilcox if (xas_valid(xas)) 178ad3d6c72SMatthew Wilcox return xas_reload(xas); 179ad3d6c72SMatthew Wilcox if (xas_error(xas)) 180ad3d6c72SMatthew Wilcox return NULL; 181ad3d6c72SMatthew Wilcox 182ad3d6c72SMatthew Wilcox entry = xa_head(xas->xa); 183ad3d6c72SMatthew Wilcox if (!xa_is_node(entry)) { 184ad3d6c72SMatthew Wilcox if (xas->xa_index) 185ad3d6c72SMatthew Wilcox return set_bounds(xas); 186ad3d6c72SMatthew Wilcox } else { 187ad3d6c72SMatthew Wilcox if ((xas->xa_index >> xa_to_node(entry)->shift) > XA_CHUNK_MASK) 188ad3d6c72SMatthew Wilcox return set_bounds(xas); 189ad3d6c72SMatthew Wilcox } 190ad3d6c72SMatthew Wilcox 191ad3d6c72SMatthew Wilcox xas->xa_node = NULL; 192ad3d6c72SMatthew Wilcox return entry; 193ad3d6c72SMatthew Wilcox } 194ad3d6c72SMatthew Wilcox 195ad3d6c72SMatthew Wilcox static void *xas_descend(struct xa_state *xas, struct xa_node *node) 196ad3d6c72SMatthew Wilcox { 197ad3d6c72SMatthew Wilcox unsigned int offset = get_offset(xas->xa_index, node); 198ad3d6c72SMatthew Wilcox void *entry = xa_entry(xas->xa, node, offset); 199ad3d6c72SMatthew Wilcox 200ad3d6c72SMatthew Wilcox xas->xa_node = node; 201ad3d6c72SMatthew Wilcox if (xa_is_sibling(entry)) { 202ad3d6c72SMatthew Wilcox offset = xa_to_sibling(entry); 203ad3d6c72SMatthew Wilcox entry = xa_entry(xas->xa, node, offset); 204ad3d6c72SMatthew Wilcox } 205ad3d6c72SMatthew Wilcox 206ad3d6c72SMatthew Wilcox xas->xa_offset = offset; 207ad3d6c72SMatthew Wilcox return entry; 208ad3d6c72SMatthew Wilcox } 209ad3d6c72SMatthew Wilcox 210ad3d6c72SMatthew Wilcox /** 211ad3d6c72SMatthew Wilcox * xas_load() - Load an entry from the XArray (advanced). 212ad3d6c72SMatthew Wilcox * @xas: XArray operation state. 213ad3d6c72SMatthew Wilcox * 214ad3d6c72SMatthew Wilcox * Usually walks the @xas to the appropriate state to load the entry 215ad3d6c72SMatthew Wilcox * stored at xa_index. However, it will do nothing and return %NULL if 216ad3d6c72SMatthew Wilcox * @xas is in an error state. xas_load() will never expand the tree. 217ad3d6c72SMatthew Wilcox * 218ad3d6c72SMatthew Wilcox * If the xa_state is set up to operate on a multi-index entry, xas_load() 219ad3d6c72SMatthew Wilcox * may return %NULL or an internal entry, even if there are entries 220ad3d6c72SMatthew Wilcox * present within the range specified by @xas. 221ad3d6c72SMatthew Wilcox * 222ad3d6c72SMatthew Wilcox * Context: Any context. The caller should hold the xa_lock or the RCU lock. 223ad3d6c72SMatthew Wilcox * Return: Usually an entry in the XArray, but see description for exceptions. 224ad3d6c72SMatthew Wilcox */ 225ad3d6c72SMatthew Wilcox void *xas_load(struct xa_state *xas) 226ad3d6c72SMatthew Wilcox { 227ad3d6c72SMatthew Wilcox void *entry = xas_start(xas); 228ad3d6c72SMatthew Wilcox 229ad3d6c72SMatthew Wilcox while (xa_is_node(entry)) { 230ad3d6c72SMatthew Wilcox struct xa_node *node = xa_to_node(entry); 231ad3d6c72SMatthew Wilcox 232ad3d6c72SMatthew Wilcox if (xas->xa_shift > node->shift) 233ad3d6c72SMatthew Wilcox break; 234ad3d6c72SMatthew Wilcox entry = xas_descend(xas, node); 235ad3d6c72SMatthew Wilcox } 236ad3d6c72SMatthew Wilcox return entry; 237ad3d6c72SMatthew Wilcox } 238ad3d6c72SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_load); 239ad3d6c72SMatthew Wilcox 24058d6ea30SMatthew Wilcox /* Move the radix tree node cache here */ 24158d6ea30SMatthew Wilcox extern struct kmem_cache *radix_tree_node_cachep; 24258d6ea30SMatthew Wilcox extern void radix_tree_node_rcu_free(struct rcu_head *head); 24358d6ea30SMatthew Wilcox 24458d6ea30SMatthew Wilcox #define XA_RCU_FREE ((struct xarray *)1) 24558d6ea30SMatthew Wilcox 24658d6ea30SMatthew Wilcox static void xa_node_free(struct xa_node *node) 24758d6ea30SMatthew Wilcox { 24858d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, !list_empty(&node->private_list)); 24958d6ea30SMatthew Wilcox node->array = XA_RCU_FREE; 25058d6ea30SMatthew Wilcox call_rcu(&node->rcu_head, radix_tree_node_rcu_free); 25158d6ea30SMatthew Wilcox } 25258d6ea30SMatthew Wilcox 25358d6ea30SMatthew Wilcox /* 25458d6ea30SMatthew Wilcox * xas_destroy() - Free any resources allocated during the XArray operation. 25558d6ea30SMatthew Wilcox * @xas: XArray operation state. 25658d6ea30SMatthew Wilcox * 25758d6ea30SMatthew Wilcox * This function is now internal-only. 25858d6ea30SMatthew Wilcox */ 25958d6ea30SMatthew Wilcox static void xas_destroy(struct xa_state *xas) 26058d6ea30SMatthew Wilcox { 26158d6ea30SMatthew Wilcox struct xa_node *node = xas->xa_alloc; 26258d6ea30SMatthew Wilcox 26358d6ea30SMatthew Wilcox if (!node) 26458d6ea30SMatthew Wilcox return; 26558d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, !list_empty(&node->private_list)); 26658d6ea30SMatthew Wilcox kmem_cache_free(radix_tree_node_cachep, node); 26758d6ea30SMatthew Wilcox xas->xa_alloc = NULL; 26858d6ea30SMatthew Wilcox } 26958d6ea30SMatthew Wilcox 27058d6ea30SMatthew Wilcox /** 27158d6ea30SMatthew Wilcox * xas_nomem() - Allocate memory if needed. 27258d6ea30SMatthew Wilcox * @xas: XArray operation state. 27358d6ea30SMatthew Wilcox * @gfp: Memory allocation flags. 27458d6ea30SMatthew Wilcox * 27558d6ea30SMatthew Wilcox * If we need to add new nodes to the XArray, we try to allocate memory 27658d6ea30SMatthew Wilcox * with GFP_NOWAIT while holding the lock, which will usually succeed. 27758d6ea30SMatthew Wilcox * If it fails, @xas is flagged as needing memory to continue. The caller 27858d6ea30SMatthew Wilcox * should drop the lock and call xas_nomem(). If xas_nomem() succeeds, 27958d6ea30SMatthew Wilcox * the caller should retry the operation. 28058d6ea30SMatthew Wilcox * 28158d6ea30SMatthew Wilcox * Forward progress is guaranteed as one node is allocated here and 28258d6ea30SMatthew Wilcox * stored in the xa_state where it will be found by xas_alloc(). More 28358d6ea30SMatthew Wilcox * nodes will likely be found in the slab allocator, but we do not tie 28458d6ea30SMatthew Wilcox * them up here. 28558d6ea30SMatthew Wilcox * 28658d6ea30SMatthew Wilcox * Return: true if memory was needed, and was successfully allocated. 28758d6ea30SMatthew Wilcox */ 28858d6ea30SMatthew Wilcox bool xas_nomem(struct xa_state *xas, gfp_t gfp) 28958d6ea30SMatthew Wilcox { 29058d6ea30SMatthew Wilcox if (xas->xa_node != XA_ERROR(-ENOMEM)) { 29158d6ea30SMatthew Wilcox xas_destroy(xas); 29258d6ea30SMatthew Wilcox return false; 29358d6ea30SMatthew Wilcox } 29458d6ea30SMatthew Wilcox xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp); 29558d6ea30SMatthew Wilcox if (!xas->xa_alloc) 29658d6ea30SMatthew Wilcox return false; 29758d6ea30SMatthew Wilcox XA_NODE_BUG_ON(xas->xa_alloc, !list_empty(&xas->xa_alloc->private_list)); 29858d6ea30SMatthew Wilcox xas->xa_node = XAS_RESTART; 29958d6ea30SMatthew Wilcox return true; 30058d6ea30SMatthew Wilcox } 30158d6ea30SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_nomem); 30258d6ea30SMatthew Wilcox 30358d6ea30SMatthew Wilcox /* 30458d6ea30SMatthew Wilcox * __xas_nomem() - Drop locks and allocate memory if needed. 30558d6ea30SMatthew Wilcox * @xas: XArray operation state. 30658d6ea30SMatthew Wilcox * @gfp: Memory allocation flags. 30758d6ea30SMatthew Wilcox * 30858d6ea30SMatthew Wilcox * Internal variant of xas_nomem(). 30958d6ea30SMatthew Wilcox * 31058d6ea30SMatthew Wilcox * Return: true if memory was needed, and was successfully allocated. 31158d6ea30SMatthew Wilcox */ 31258d6ea30SMatthew Wilcox static bool __xas_nomem(struct xa_state *xas, gfp_t gfp) 31358d6ea30SMatthew Wilcox __must_hold(xas->xa->xa_lock) 31458d6ea30SMatthew Wilcox { 31558d6ea30SMatthew Wilcox unsigned int lock_type = xa_lock_type(xas->xa); 31658d6ea30SMatthew Wilcox 31758d6ea30SMatthew Wilcox if (xas->xa_node != XA_ERROR(-ENOMEM)) { 31858d6ea30SMatthew Wilcox xas_destroy(xas); 31958d6ea30SMatthew Wilcox return false; 32058d6ea30SMatthew Wilcox } 32158d6ea30SMatthew Wilcox if (gfpflags_allow_blocking(gfp)) { 32258d6ea30SMatthew Wilcox xas_unlock_type(xas, lock_type); 32358d6ea30SMatthew Wilcox xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp); 32458d6ea30SMatthew Wilcox xas_lock_type(xas, lock_type); 32558d6ea30SMatthew Wilcox } else { 32658d6ea30SMatthew Wilcox xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp); 32758d6ea30SMatthew Wilcox } 32858d6ea30SMatthew Wilcox if (!xas->xa_alloc) 32958d6ea30SMatthew Wilcox return false; 33058d6ea30SMatthew Wilcox XA_NODE_BUG_ON(xas->xa_alloc, !list_empty(&xas->xa_alloc->private_list)); 33158d6ea30SMatthew Wilcox xas->xa_node = XAS_RESTART; 33258d6ea30SMatthew Wilcox return true; 33358d6ea30SMatthew Wilcox } 33458d6ea30SMatthew Wilcox 33558d6ea30SMatthew Wilcox static void xas_update(struct xa_state *xas, struct xa_node *node) 33658d6ea30SMatthew Wilcox { 33758d6ea30SMatthew Wilcox if (xas->xa_update) 33858d6ea30SMatthew Wilcox xas->xa_update(node); 33958d6ea30SMatthew Wilcox else 34058d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, !list_empty(&node->private_list)); 34158d6ea30SMatthew Wilcox } 34258d6ea30SMatthew Wilcox 34358d6ea30SMatthew Wilcox static void *xas_alloc(struct xa_state *xas, unsigned int shift) 34458d6ea30SMatthew Wilcox { 34558d6ea30SMatthew Wilcox struct xa_node *parent = xas->xa_node; 34658d6ea30SMatthew Wilcox struct xa_node *node = xas->xa_alloc; 34758d6ea30SMatthew Wilcox 34858d6ea30SMatthew Wilcox if (xas_invalid(xas)) 34958d6ea30SMatthew Wilcox return NULL; 35058d6ea30SMatthew Wilcox 35158d6ea30SMatthew Wilcox if (node) { 35258d6ea30SMatthew Wilcox xas->xa_alloc = NULL; 35358d6ea30SMatthew Wilcox } else { 35458d6ea30SMatthew Wilcox node = kmem_cache_alloc(radix_tree_node_cachep, 35558d6ea30SMatthew Wilcox GFP_NOWAIT | __GFP_NOWARN); 35658d6ea30SMatthew Wilcox if (!node) { 35758d6ea30SMatthew Wilcox xas_set_err(xas, -ENOMEM); 35858d6ea30SMatthew Wilcox return NULL; 35958d6ea30SMatthew Wilcox } 36058d6ea30SMatthew Wilcox } 36158d6ea30SMatthew Wilcox 36258d6ea30SMatthew Wilcox if (parent) { 36358d6ea30SMatthew Wilcox node->offset = xas->xa_offset; 36458d6ea30SMatthew Wilcox parent->count++; 36558d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, parent->count > XA_CHUNK_SIZE); 36658d6ea30SMatthew Wilcox xas_update(xas, parent); 36758d6ea30SMatthew Wilcox } 36858d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, shift > BITS_PER_LONG); 36958d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, !list_empty(&node->private_list)); 37058d6ea30SMatthew Wilcox node->shift = shift; 37158d6ea30SMatthew Wilcox node->count = 0; 37258d6ea30SMatthew Wilcox node->nr_values = 0; 37358d6ea30SMatthew Wilcox RCU_INIT_POINTER(node->parent, xas->xa_node); 37458d6ea30SMatthew Wilcox node->array = xas->xa; 37558d6ea30SMatthew Wilcox 37658d6ea30SMatthew Wilcox return node; 37758d6ea30SMatthew Wilcox } 37858d6ea30SMatthew Wilcox 37958d6ea30SMatthew Wilcox /* 38058d6ea30SMatthew Wilcox * Use this to calculate the maximum index that will need to be created 38158d6ea30SMatthew Wilcox * in order to add the entry described by @xas. Because we cannot store a 38258d6ea30SMatthew Wilcox * multiple-index entry at index 0, the calculation is a little more complex 38358d6ea30SMatthew Wilcox * than you might expect. 38458d6ea30SMatthew Wilcox */ 38558d6ea30SMatthew Wilcox static unsigned long xas_max(struct xa_state *xas) 38658d6ea30SMatthew Wilcox { 38758d6ea30SMatthew Wilcox unsigned long max = xas->xa_index; 38858d6ea30SMatthew Wilcox 38958d6ea30SMatthew Wilcox #ifdef CONFIG_XARRAY_MULTI 39058d6ea30SMatthew Wilcox if (xas->xa_shift || xas->xa_sibs) { 39158d6ea30SMatthew Wilcox unsigned long mask; 39258d6ea30SMatthew Wilcox mask = (((xas->xa_sibs + 1UL) << xas->xa_shift) - 1); 39358d6ea30SMatthew Wilcox max |= mask; 39458d6ea30SMatthew Wilcox if (mask == max) 39558d6ea30SMatthew Wilcox max++; 39658d6ea30SMatthew Wilcox } 39758d6ea30SMatthew Wilcox #endif 39858d6ea30SMatthew Wilcox 39958d6ea30SMatthew Wilcox return max; 40058d6ea30SMatthew Wilcox } 40158d6ea30SMatthew Wilcox 40258d6ea30SMatthew Wilcox /* The maximum index that can be contained in the array without expanding it */ 40358d6ea30SMatthew Wilcox static unsigned long max_index(void *entry) 40458d6ea30SMatthew Wilcox { 40558d6ea30SMatthew Wilcox if (!xa_is_node(entry)) 40658d6ea30SMatthew Wilcox return 0; 40758d6ea30SMatthew Wilcox return (XA_CHUNK_SIZE << xa_to_node(entry)->shift) - 1; 40858d6ea30SMatthew Wilcox } 40958d6ea30SMatthew Wilcox 41058d6ea30SMatthew Wilcox static void xas_shrink(struct xa_state *xas) 41158d6ea30SMatthew Wilcox { 41258d6ea30SMatthew Wilcox struct xarray *xa = xas->xa; 41358d6ea30SMatthew Wilcox struct xa_node *node = xas->xa_node; 41458d6ea30SMatthew Wilcox 41558d6ea30SMatthew Wilcox for (;;) { 41658d6ea30SMatthew Wilcox void *entry; 41758d6ea30SMatthew Wilcox 41858d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, node->count > XA_CHUNK_SIZE); 41958d6ea30SMatthew Wilcox if (node->count != 1) 42058d6ea30SMatthew Wilcox break; 42158d6ea30SMatthew Wilcox entry = xa_entry_locked(xa, node, 0); 42258d6ea30SMatthew Wilcox if (!entry) 42358d6ea30SMatthew Wilcox break; 42458d6ea30SMatthew Wilcox if (!xa_is_node(entry) && node->shift) 42558d6ea30SMatthew Wilcox break; 42658d6ea30SMatthew Wilcox xas->xa_node = XAS_BOUNDS; 42758d6ea30SMatthew Wilcox 42858d6ea30SMatthew Wilcox RCU_INIT_POINTER(xa->xa_head, entry); 429*371c752dSMatthew Wilcox if (xa_track_free(xa) && !node_get_mark(node, 0, XA_FREE_MARK)) 430*371c752dSMatthew Wilcox xa_mark_clear(xa, XA_FREE_MARK); 43158d6ea30SMatthew Wilcox 43258d6ea30SMatthew Wilcox node->count = 0; 43358d6ea30SMatthew Wilcox node->nr_values = 0; 43458d6ea30SMatthew Wilcox if (!xa_is_node(entry)) 43558d6ea30SMatthew Wilcox RCU_INIT_POINTER(node->slots[0], XA_RETRY_ENTRY); 43658d6ea30SMatthew Wilcox xas_update(xas, node); 43758d6ea30SMatthew Wilcox xa_node_free(node); 43858d6ea30SMatthew Wilcox if (!xa_is_node(entry)) 43958d6ea30SMatthew Wilcox break; 44058d6ea30SMatthew Wilcox node = xa_to_node(entry); 44158d6ea30SMatthew Wilcox node->parent = NULL; 44258d6ea30SMatthew Wilcox } 44358d6ea30SMatthew Wilcox } 44458d6ea30SMatthew Wilcox 44558d6ea30SMatthew Wilcox /* 44658d6ea30SMatthew Wilcox * xas_delete_node() - Attempt to delete an xa_node 44758d6ea30SMatthew Wilcox * @xas: Array operation state. 44858d6ea30SMatthew Wilcox * 44958d6ea30SMatthew Wilcox * Attempts to delete the @xas->xa_node. This will fail if xa->node has 45058d6ea30SMatthew Wilcox * a non-zero reference count. 45158d6ea30SMatthew Wilcox */ 45258d6ea30SMatthew Wilcox static void xas_delete_node(struct xa_state *xas) 45358d6ea30SMatthew Wilcox { 45458d6ea30SMatthew Wilcox struct xa_node *node = xas->xa_node; 45558d6ea30SMatthew Wilcox 45658d6ea30SMatthew Wilcox for (;;) { 45758d6ea30SMatthew Wilcox struct xa_node *parent; 45858d6ea30SMatthew Wilcox 45958d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, node->count > XA_CHUNK_SIZE); 46058d6ea30SMatthew Wilcox if (node->count) 46158d6ea30SMatthew Wilcox break; 46258d6ea30SMatthew Wilcox 46358d6ea30SMatthew Wilcox parent = xa_parent_locked(xas->xa, node); 46458d6ea30SMatthew Wilcox xas->xa_node = parent; 46558d6ea30SMatthew Wilcox xas->xa_offset = node->offset; 46658d6ea30SMatthew Wilcox xa_node_free(node); 46758d6ea30SMatthew Wilcox 46858d6ea30SMatthew Wilcox if (!parent) { 46958d6ea30SMatthew Wilcox xas->xa->xa_head = NULL; 47058d6ea30SMatthew Wilcox xas->xa_node = XAS_BOUNDS; 47158d6ea30SMatthew Wilcox return; 47258d6ea30SMatthew Wilcox } 47358d6ea30SMatthew Wilcox 47458d6ea30SMatthew Wilcox parent->slots[xas->xa_offset] = NULL; 47558d6ea30SMatthew Wilcox parent->count--; 47658d6ea30SMatthew Wilcox XA_NODE_BUG_ON(parent, parent->count > XA_CHUNK_SIZE); 47758d6ea30SMatthew Wilcox node = parent; 47858d6ea30SMatthew Wilcox xas_update(xas, node); 47958d6ea30SMatthew Wilcox } 48058d6ea30SMatthew Wilcox 48158d6ea30SMatthew Wilcox if (!node->parent) 48258d6ea30SMatthew Wilcox xas_shrink(xas); 48358d6ea30SMatthew Wilcox } 48458d6ea30SMatthew Wilcox 48558d6ea30SMatthew Wilcox /** 48658d6ea30SMatthew Wilcox * xas_free_nodes() - Free this node and all nodes that it references 48758d6ea30SMatthew Wilcox * @xas: Array operation state. 48858d6ea30SMatthew Wilcox * @top: Node to free 48958d6ea30SMatthew Wilcox * 49058d6ea30SMatthew Wilcox * This node has been removed from the tree. We must now free it and all 49158d6ea30SMatthew Wilcox * of its subnodes. There may be RCU walkers with references into the tree, 49258d6ea30SMatthew Wilcox * so we must replace all entries with retry markers. 49358d6ea30SMatthew Wilcox */ 49458d6ea30SMatthew Wilcox static void xas_free_nodes(struct xa_state *xas, struct xa_node *top) 49558d6ea30SMatthew Wilcox { 49658d6ea30SMatthew Wilcox unsigned int offset = 0; 49758d6ea30SMatthew Wilcox struct xa_node *node = top; 49858d6ea30SMatthew Wilcox 49958d6ea30SMatthew Wilcox for (;;) { 50058d6ea30SMatthew Wilcox void *entry = xa_entry_locked(xas->xa, node, offset); 50158d6ea30SMatthew Wilcox 50258d6ea30SMatthew Wilcox if (xa_is_node(entry)) { 50358d6ea30SMatthew Wilcox node = xa_to_node(entry); 50458d6ea30SMatthew Wilcox offset = 0; 50558d6ea30SMatthew Wilcox continue; 50658d6ea30SMatthew Wilcox } 50758d6ea30SMatthew Wilcox if (entry) 50858d6ea30SMatthew Wilcox RCU_INIT_POINTER(node->slots[offset], XA_RETRY_ENTRY); 50958d6ea30SMatthew Wilcox offset++; 51058d6ea30SMatthew Wilcox while (offset == XA_CHUNK_SIZE) { 51158d6ea30SMatthew Wilcox struct xa_node *parent; 51258d6ea30SMatthew Wilcox 51358d6ea30SMatthew Wilcox parent = xa_parent_locked(xas->xa, node); 51458d6ea30SMatthew Wilcox offset = node->offset + 1; 51558d6ea30SMatthew Wilcox node->count = 0; 51658d6ea30SMatthew Wilcox node->nr_values = 0; 51758d6ea30SMatthew Wilcox xas_update(xas, node); 51858d6ea30SMatthew Wilcox xa_node_free(node); 51958d6ea30SMatthew Wilcox if (node == top) 52058d6ea30SMatthew Wilcox return; 52158d6ea30SMatthew Wilcox node = parent; 52258d6ea30SMatthew Wilcox } 52358d6ea30SMatthew Wilcox } 52458d6ea30SMatthew Wilcox } 52558d6ea30SMatthew Wilcox 52658d6ea30SMatthew Wilcox /* 52758d6ea30SMatthew Wilcox * xas_expand adds nodes to the head of the tree until it has reached 52858d6ea30SMatthew Wilcox * sufficient height to be able to contain @xas->xa_index 52958d6ea30SMatthew Wilcox */ 53058d6ea30SMatthew Wilcox static int xas_expand(struct xa_state *xas, void *head) 53158d6ea30SMatthew Wilcox { 53258d6ea30SMatthew Wilcox struct xarray *xa = xas->xa; 53358d6ea30SMatthew Wilcox struct xa_node *node = NULL; 53458d6ea30SMatthew Wilcox unsigned int shift = 0; 53558d6ea30SMatthew Wilcox unsigned long max = xas_max(xas); 53658d6ea30SMatthew Wilcox 53758d6ea30SMatthew Wilcox if (!head) { 53858d6ea30SMatthew Wilcox if (max == 0) 53958d6ea30SMatthew Wilcox return 0; 54058d6ea30SMatthew Wilcox while ((max >> shift) >= XA_CHUNK_SIZE) 54158d6ea30SMatthew Wilcox shift += XA_CHUNK_SHIFT; 54258d6ea30SMatthew Wilcox return shift + XA_CHUNK_SHIFT; 54358d6ea30SMatthew Wilcox } else if (xa_is_node(head)) { 54458d6ea30SMatthew Wilcox node = xa_to_node(head); 54558d6ea30SMatthew Wilcox shift = node->shift + XA_CHUNK_SHIFT; 54658d6ea30SMatthew Wilcox } 54758d6ea30SMatthew Wilcox xas->xa_node = NULL; 54858d6ea30SMatthew Wilcox 54958d6ea30SMatthew Wilcox while (max > max_index(head)) { 55058d6ea30SMatthew Wilcox xa_mark_t mark = 0; 55158d6ea30SMatthew Wilcox 55258d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, shift > BITS_PER_LONG); 55358d6ea30SMatthew Wilcox node = xas_alloc(xas, shift); 55458d6ea30SMatthew Wilcox if (!node) 55558d6ea30SMatthew Wilcox return -ENOMEM; 55658d6ea30SMatthew Wilcox 55758d6ea30SMatthew Wilcox node->count = 1; 55858d6ea30SMatthew Wilcox if (xa_is_value(head)) 55958d6ea30SMatthew Wilcox node->nr_values = 1; 56058d6ea30SMatthew Wilcox RCU_INIT_POINTER(node->slots[0], head); 56158d6ea30SMatthew Wilcox 56258d6ea30SMatthew Wilcox /* Propagate the aggregated mark info to the new child */ 56358d6ea30SMatthew Wilcox for (;;) { 564*371c752dSMatthew Wilcox if (xa_track_free(xa) && mark == XA_FREE_MARK) { 565*371c752dSMatthew Wilcox node_mark_all(node, XA_FREE_MARK); 566*371c752dSMatthew Wilcox if (!xa_marked(xa, XA_FREE_MARK)) { 567*371c752dSMatthew Wilcox node_clear_mark(node, 0, XA_FREE_MARK); 568*371c752dSMatthew Wilcox xa_mark_set(xa, XA_FREE_MARK); 569*371c752dSMatthew Wilcox } 570*371c752dSMatthew Wilcox } else if (xa_marked(xa, mark)) { 57158d6ea30SMatthew Wilcox node_set_mark(node, 0, mark); 572*371c752dSMatthew Wilcox } 57358d6ea30SMatthew Wilcox if (mark == XA_MARK_MAX) 57458d6ea30SMatthew Wilcox break; 57558d6ea30SMatthew Wilcox mark_inc(mark); 57658d6ea30SMatthew Wilcox } 57758d6ea30SMatthew Wilcox 57858d6ea30SMatthew Wilcox /* 57958d6ea30SMatthew Wilcox * Now that the new node is fully initialised, we can add 58058d6ea30SMatthew Wilcox * it to the tree 58158d6ea30SMatthew Wilcox */ 58258d6ea30SMatthew Wilcox if (xa_is_node(head)) { 58358d6ea30SMatthew Wilcox xa_to_node(head)->offset = 0; 58458d6ea30SMatthew Wilcox rcu_assign_pointer(xa_to_node(head)->parent, node); 58558d6ea30SMatthew Wilcox } 58658d6ea30SMatthew Wilcox head = xa_mk_node(node); 58758d6ea30SMatthew Wilcox rcu_assign_pointer(xa->xa_head, head); 58858d6ea30SMatthew Wilcox xas_update(xas, node); 58958d6ea30SMatthew Wilcox 59058d6ea30SMatthew Wilcox shift += XA_CHUNK_SHIFT; 59158d6ea30SMatthew Wilcox } 59258d6ea30SMatthew Wilcox 59358d6ea30SMatthew Wilcox xas->xa_node = node; 59458d6ea30SMatthew Wilcox return shift; 59558d6ea30SMatthew Wilcox } 59658d6ea30SMatthew Wilcox 59758d6ea30SMatthew Wilcox /* 59858d6ea30SMatthew Wilcox * xas_create() - Create a slot to store an entry in. 59958d6ea30SMatthew Wilcox * @xas: XArray operation state. 60058d6ea30SMatthew Wilcox * 60158d6ea30SMatthew Wilcox * Most users will not need to call this function directly, as it is called 60258d6ea30SMatthew Wilcox * by xas_store(). It is useful for doing conditional store operations 60358d6ea30SMatthew Wilcox * (see the xa_cmpxchg() implementation for an example). 60458d6ea30SMatthew Wilcox * 60558d6ea30SMatthew Wilcox * Return: If the slot already existed, returns the contents of this slot. 60658d6ea30SMatthew Wilcox * If the slot was newly created, returns NULL. If it failed to create the 60758d6ea30SMatthew Wilcox * slot, returns NULL and indicates the error in @xas. 60858d6ea30SMatthew Wilcox */ 60958d6ea30SMatthew Wilcox static void *xas_create(struct xa_state *xas) 61058d6ea30SMatthew Wilcox { 61158d6ea30SMatthew Wilcox struct xarray *xa = xas->xa; 61258d6ea30SMatthew Wilcox void *entry; 61358d6ea30SMatthew Wilcox void __rcu **slot; 61458d6ea30SMatthew Wilcox struct xa_node *node = xas->xa_node; 61558d6ea30SMatthew Wilcox int shift; 61658d6ea30SMatthew Wilcox unsigned int order = xas->xa_shift; 61758d6ea30SMatthew Wilcox 61858d6ea30SMatthew Wilcox if (xas_top(node)) { 61958d6ea30SMatthew Wilcox entry = xa_head_locked(xa); 62058d6ea30SMatthew Wilcox xas->xa_node = NULL; 62158d6ea30SMatthew Wilcox shift = xas_expand(xas, entry); 62258d6ea30SMatthew Wilcox if (shift < 0) 62358d6ea30SMatthew Wilcox return NULL; 62458d6ea30SMatthew Wilcox entry = xa_head_locked(xa); 62558d6ea30SMatthew Wilcox slot = &xa->xa_head; 62658d6ea30SMatthew Wilcox } else if (xas_error(xas)) { 62758d6ea30SMatthew Wilcox return NULL; 62858d6ea30SMatthew Wilcox } else if (node) { 62958d6ea30SMatthew Wilcox unsigned int offset = xas->xa_offset; 63058d6ea30SMatthew Wilcox 63158d6ea30SMatthew Wilcox shift = node->shift; 63258d6ea30SMatthew Wilcox entry = xa_entry_locked(xa, node, offset); 63358d6ea30SMatthew Wilcox slot = &node->slots[offset]; 63458d6ea30SMatthew Wilcox } else { 63558d6ea30SMatthew Wilcox shift = 0; 63658d6ea30SMatthew Wilcox entry = xa_head_locked(xa); 63758d6ea30SMatthew Wilcox slot = &xa->xa_head; 63858d6ea30SMatthew Wilcox } 63958d6ea30SMatthew Wilcox 64058d6ea30SMatthew Wilcox while (shift > order) { 64158d6ea30SMatthew Wilcox shift -= XA_CHUNK_SHIFT; 64258d6ea30SMatthew Wilcox if (!entry) { 64358d6ea30SMatthew Wilcox node = xas_alloc(xas, shift); 64458d6ea30SMatthew Wilcox if (!node) 64558d6ea30SMatthew Wilcox break; 646*371c752dSMatthew Wilcox if (xa_track_free(xa)) 647*371c752dSMatthew Wilcox node_mark_all(node, XA_FREE_MARK); 64858d6ea30SMatthew Wilcox rcu_assign_pointer(*slot, xa_mk_node(node)); 64958d6ea30SMatthew Wilcox } else if (xa_is_node(entry)) { 65058d6ea30SMatthew Wilcox node = xa_to_node(entry); 65158d6ea30SMatthew Wilcox } else { 65258d6ea30SMatthew Wilcox break; 65358d6ea30SMatthew Wilcox } 65458d6ea30SMatthew Wilcox entry = xas_descend(xas, node); 65558d6ea30SMatthew Wilcox slot = &node->slots[xas->xa_offset]; 65658d6ea30SMatthew Wilcox } 65758d6ea30SMatthew Wilcox 65858d6ea30SMatthew Wilcox return entry; 65958d6ea30SMatthew Wilcox } 66058d6ea30SMatthew Wilcox 6612264f513SMatthew Wilcox /** 6622264f513SMatthew Wilcox * xas_create_range() - Ensure that stores to this range will succeed 6632264f513SMatthew Wilcox * @xas: XArray operation state. 6642264f513SMatthew Wilcox * 6652264f513SMatthew Wilcox * Creates all of the slots in the range covered by @xas. Sets @xas to 6662264f513SMatthew Wilcox * create single-index entries and positions it at the beginning of the 6672264f513SMatthew Wilcox * range. This is for the benefit of users which have not yet been 6682264f513SMatthew Wilcox * converted to use multi-index entries. 6692264f513SMatthew Wilcox */ 6702264f513SMatthew Wilcox void xas_create_range(struct xa_state *xas) 6712264f513SMatthew Wilcox { 6722264f513SMatthew Wilcox unsigned long index = xas->xa_index; 6732264f513SMatthew Wilcox unsigned char shift = xas->xa_shift; 6742264f513SMatthew Wilcox unsigned char sibs = xas->xa_sibs; 6752264f513SMatthew Wilcox 6762264f513SMatthew Wilcox xas->xa_index |= ((sibs + 1) << shift) - 1; 6772264f513SMatthew Wilcox if (xas_is_node(xas) && xas->xa_node->shift == xas->xa_shift) 6782264f513SMatthew Wilcox xas->xa_offset |= sibs; 6792264f513SMatthew Wilcox xas->xa_shift = 0; 6802264f513SMatthew Wilcox xas->xa_sibs = 0; 6812264f513SMatthew Wilcox 6822264f513SMatthew Wilcox for (;;) { 6832264f513SMatthew Wilcox xas_create(xas); 6842264f513SMatthew Wilcox if (xas_error(xas)) 6852264f513SMatthew Wilcox goto restore; 6862264f513SMatthew Wilcox if (xas->xa_index <= (index | XA_CHUNK_MASK)) 6872264f513SMatthew Wilcox goto success; 6882264f513SMatthew Wilcox xas->xa_index -= XA_CHUNK_SIZE; 6892264f513SMatthew Wilcox 6902264f513SMatthew Wilcox for (;;) { 6912264f513SMatthew Wilcox struct xa_node *node = xas->xa_node; 6922264f513SMatthew Wilcox xas->xa_node = xa_parent_locked(xas->xa, node); 6932264f513SMatthew Wilcox xas->xa_offset = node->offset - 1; 6942264f513SMatthew Wilcox if (node->offset != 0) 6952264f513SMatthew Wilcox break; 6962264f513SMatthew Wilcox } 6972264f513SMatthew Wilcox } 6982264f513SMatthew Wilcox 6992264f513SMatthew Wilcox restore: 7002264f513SMatthew Wilcox xas->xa_shift = shift; 7012264f513SMatthew Wilcox xas->xa_sibs = sibs; 7022264f513SMatthew Wilcox xas->xa_index = index; 7032264f513SMatthew Wilcox return; 7042264f513SMatthew Wilcox success: 7052264f513SMatthew Wilcox xas->xa_index = index; 7062264f513SMatthew Wilcox if (xas->xa_node) 7072264f513SMatthew Wilcox xas_set_offset(xas); 7082264f513SMatthew Wilcox } 7092264f513SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_create_range); 7102264f513SMatthew Wilcox 71158d6ea30SMatthew Wilcox static void update_node(struct xa_state *xas, struct xa_node *node, 71258d6ea30SMatthew Wilcox int count, int values) 71358d6ea30SMatthew Wilcox { 71458d6ea30SMatthew Wilcox if (!node || (!count && !values)) 71558d6ea30SMatthew Wilcox return; 71658d6ea30SMatthew Wilcox 71758d6ea30SMatthew Wilcox node->count += count; 71858d6ea30SMatthew Wilcox node->nr_values += values; 71958d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, node->count > XA_CHUNK_SIZE); 72058d6ea30SMatthew Wilcox XA_NODE_BUG_ON(node, node->nr_values > XA_CHUNK_SIZE); 72158d6ea30SMatthew Wilcox xas_update(xas, node); 72258d6ea30SMatthew Wilcox if (count < 0) 72358d6ea30SMatthew Wilcox xas_delete_node(xas); 72458d6ea30SMatthew Wilcox } 72558d6ea30SMatthew Wilcox 72658d6ea30SMatthew Wilcox /** 72758d6ea30SMatthew Wilcox * xas_store() - Store this entry in the XArray. 72858d6ea30SMatthew Wilcox * @xas: XArray operation state. 72958d6ea30SMatthew Wilcox * @entry: New entry. 73058d6ea30SMatthew Wilcox * 73158d6ea30SMatthew Wilcox * If @xas is operating on a multi-index entry, the entry returned by this 73258d6ea30SMatthew Wilcox * function is essentially meaningless (it may be an internal entry or it 73358d6ea30SMatthew Wilcox * may be %NULL, even if there are non-NULL entries at some of the indices 73458d6ea30SMatthew Wilcox * covered by the range). This is not a problem for any current users, 73558d6ea30SMatthew Wilcox * and can be changed if needed. 73658d6ea30SMatthew Wilcox * 73758d6ea30SMatthew Wilcox * Return: The old entry at this index. 73858d6ea30SMatthew Wilcox */ 73958d6ea30SMatthew Wilcox void *xas_store(struct xa_state *xas, void *entry) 74058d6ea30SMatthew Wilcox { 74158d6ea30SMatthew Wilcox struct xa_node *node; 74258d6ea30SMatthew Wilcox void __rcu **slot = &xas->xa->xa_head; 74358d6ea30SMatthew Wilcox unsigned int offset, max; 74458d6ea30SMatthew Wilcox int count = 0; 74558d6ea30SMatthew Wilcox int values = 0; 74658d6ea30SMatthew Wilcox void *first, *next; 74758d6ea30SMatthew Wilcox bool value = xa_is_value(entry); 74858d6ea30SMatthew Wilcox 74958d6ea30SMatthew Wilcox if (entry) 75058d6ea30SMatthew Wilcox first = xas_create(xas); 75158d6ea30SMatthew Wilcox else 75258d6ea30SMatthew Wilcox first = xas_load(xas); 75358d6ea30SMatthew Wilcox 75458d6ea30SMatthew Wilcox if (xas_invalid(xas)) 75558d6ea30SMatthew Wilcox return first; 75658d6ea30SMatthew Wilcox node = xas->xa_node; 75758d6ea30SMatthew Wilcox if (node && (xas->xa_shift < node->shift)) 75858d6ea30SMatthew Wilcox xas->xa_sibs = 0; 75958d6ea30SMatthew Wilcox if ((first == entry) && !xas->xa_sibs) 76058d6ea30SMatthew Wilcox return first; 76158d6ea30SMatthew Wilcox 76258d6ea30SMatthew Wilcox next = first; 76358d6ea30SMatthew Wilcox offset = xas->xa_offset; 76458d6ea30SMatthew Wilcox max = xas->xa_offset + xas->xa_sibs; 76558d6ea30SMatthew Wilcox if (node) { 76658d6ea30SMatthew Wilcox slot = &node->slots[offset]; 76758d6ea30SMatthew Wilcox if (xas->xa_sibs) 76858d6ea30SMatthew Wilcox xas_squash_marks(xas); 76958d6ea30SMatthew Wilcox } 77058d6ea30SMatthew Wilcox if (!entry) 77158d6ea30SMatthew Wilcox xas_init_marks(xas); 77258d6ea30SMatthew Wilcox 77358d6ea30SMatthew Wilcox for (;;) { 77458d6ea30SMatthew Wilcox /* 77558d6ea30SMatthew Wilcox * Must clear the marks before setting the entry to NULL, 77658d6ea30SMatthew Wilcox * otherwise xas_for_each_marked may find a NULL entry and 77758d6ea30SMatthew Wilcox * stop early. rcu_assign_pointer contains a release barrier 77858d6ea30SMatthew Wilcox * so the mark clearing will appear to happen before the 77958d6ea30SMatthew Wilcox * entry is set to NULL. 78058d6ea30SMatthew Wilcox */ 78158d6ea30SMatthew Wilcox rcu_assign_pointer(*slot, entry); 78258d6ea30SMatthew Wilcox if (xa_is_node(next)) 78358d6ea30SMatthew Wilcox xas_free_nodes(xas, xa_to_node(next)); 78458d6ea30SMatthew Wilcox if (!node) 78558d6ea30SMatthew Wilcox break; 78658d6ea30SMatthew Wilcox count += !next - !entry; 78758d6ea30SMatthew Wilcox values += !xa_is_value(first) - !value; 78858d6ea30SMatthew Wilcox if (entry) { 78958d6ea30SMatthew Wilcox if (offset == max) 79058d6ea30SMatthew Wilcox break; 79158d6ea30SMatthew Wilcox if (!xa_is_sibling(entry)) 79258d6ea30SMatthew Wilcox entry = xa_mk_sibling(xas->xa_offset); 79358d6ea30SMatthew Wilcox } else { 79458d6ea30SMatthew Wilcox if (offset == XA_CHUNK_MASK) 79558d6ea30SMatthew Wilcox break; 79658d6ea30SMatthew Wilcox } 79758d6ea30SMatthew Wilcox next = xa_entry_locked(xas->xa, node, ++offset); 79858d6ea30SMatthew Wilcox if (!xa_is_sibling(next)) { 79958d6ea30SMatthew Wilcox if (!entry && (offset > max)) 80058d6ea30SMatthew Wilcox break; 80158d6ea30SMatthew Wilcox first = next; 80258d6ea30SMatthew Wilcox } 80358d6ea30SMatthew Wilcox slot++; 80458d6ea30SMatthew Wilcox } 80558d6ea30SMatthew Wilcox 80658d6ea30SMatthew Wilcox update_node(xas, node, count, values); 80758d6ea30SMatthew Wilcox return first; 80858d6ea30SMatthew Wilcox } 80958d6ea30SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_store); 81058d6ea30SMatthew Wilcox 811f8d5d0ccSMatthew Wilcox /** 8129b89a035SMatthew Wilcox * xas_get_mark() - Returns the state of this mark. 8139b89a035SMatthew Wilcox * @xas: XArray operation state. 8149b89a035SMatthew Wilcox * @mark: Mark number. 8159b89a035SMatthew Wilcox * 8169b89a035SMatthew Wilcox * Return: true if the mark is set, false if the mark is clear or @xas 8179b89a035SMatthew Wilcox * is in an error state. 8189b89a035SMatthew Wilcox */ 8199b89a035SMatthew Wilcox bool xas_get_mark(const struct xa_state *xas, xa_mark_t mark) 8209b89a035SMatthew Wilcox { 8219b89a035SMatthew Wilcox if (xas_invalid(xas)) 8229b89a035SMatthew Wilcox return false; 8239b89a035SMatthew Wilcox if (!xas->xa_node) 8249b89a035SMatthew Wilcox return xa_marked(xas->xa, mark); 8259b89a035SMatthew Wilcox return node_get_mark(xas->xa_node, xas->xa_offset, mark); 8269b89a035SMatthew Wilcox } 8279b89a035SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_get_mark); 8289b89a035SMatthew Wilcox 8299b89a035SMatthew Wilcox /** 8309b89a035SMatthew Wilcox * xas_set_mark() - Sets the mark on this entry and its parents. 8319b89a035SMatthew Wilcox * @xas: XArray operation state. 8329b89a035SMatthew Wilcox * @mark: Mark number. 8339b89a035SMatthew Wilcox * 8349b89a035SMatthew Wilcox * Sets the specified mark on this entry, and walks up the tree setting it 8359b89a035SMatthew Wilcox * on all the ancestor entries. Does nothing if @xas has not been walked to 8369b89a035SMatthew Wilcox * an entry, or is in an error state. 8379b89a035SMatthew Wilcox */ 8389b89a035SMatthew Wilcox void xas_set_mark(const struct xa_state *xas, xa_mark_t mark) 8399b89a035SMatthew Wilcox { 8409b89a035SMatthew Wilcox struct xa_node *node = xas->xa_node; 8419b89a035SMatthew Wilcox unsigned int offset = xas->xa_offset; 8429b89a035SMatthew Wilcox 8439b89a035SMatthew Wilcox if (xas_invalid(xas)) 8449b89a035SMatthew Wilcox return; 8459b89a035SMatthew Wilcox 8469b89a035SMatthew Wilcox while (node) { 8479b89a035SMatthew Wilcox if (node_set_mark(node, offset, mark)) 8489b89a035SMatthew Wilcox return; 8499b89a035SMatthew Wilcox offset = node->offset; 8509b89a035SMatthew Wilcox node = xa_parent_locked(xas->xa, node); 8519b89a035SMatthew Wilcox } 8529b89a035SMatthew Wilcox 8539b89a035SMatthew Wilcox if (!xa_marked(xas->xa, mark)) 8549b89a035SMatthew Wilcox xa_mark_set(xas->xa, mark); 8559b89a035SMatthew Wilcox } 8569b89a035SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_set_mark); 8579b89a035SMatthew Wilcox 8589b89a035SMatthew Wilcox /** 8599b89a035SMatthew Wilcox * xas_clear_mark() - Clears the mark on this entry and its parents. 8609b89a035SMatthew Wilcox * @xas: XArray operation state. 8619b89a035SMatthew Wilcox * @mark: Mark number. 8629b89a035SMatthew Wilcox * 8639b89a035SMatthew Wilcox * Clears the specified mark on this entry, and walks back to the head 8649b89a035SMatthew Wilcox * attempting to clear it on all the ancestor entries. Does nothing if 8659b89a035SMatthew Wilcox * @xas has not been walked to an entry, or is in an error state. 8669b89a035SMatthew Wilcox */ 8679b89a035SMatthew Wilcox void xas_clear_mark(const struct xa_state *xas, xa_mark_t mark) 8689b89a035SMatthew Wilcox { 8699b89a035SMatthew Wilcox struct xa_node *node = xas->xa_node; 8709b89a035SMatthew Wilcox unsigned int offset = xas->xa_offset; 8719b89a035SMatthew Wilcox 8729b89a035SMatthew Wilcox if (xas_invalid(xas)) 8739b89a035SMatthew Wilcox return; 8749b89a035SMatthew Wilcox 8759b89a035SMatthew Wilcox while (node) { 8769b89a035SMatthew Wilcox if (!node_clear_mark(node, offset, mark)) 8779b89a035SMatthew Wilcox return; 8789b89a035SMatthew Wilcox if (node_any_mark(node, mark)) 8799b89a035SMatthew Wilcox return; 8809b89a035SMatthew Wilcox 8819b89a035SMatthew Wilcox offset = node->offset; 8829b89a035SMatthew Wilcox node = xa_parent_locked(xas->xa, node); 8839b89a035SMatthew Wilcox } 8849b89a035SMatthew Wilcox 8859b89a035SMatthew Wilcox if (xa_marked(xas->xa, mark)) 8869b89a035SMatthew Wilcox xa_mark_clear(xas->xa, mark); 8879b89a035SMatthew Wilcox } 8889b89a035SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_clear_mark); 8899b89a035SMatthew Wilcox 8909b89a035SMatthew Wilcox /** 89158d6ea30SMatthew Wilcox * xas_init_marks() - Initialise all marks for the entry 89258d6ea30SMatthew Wilcox * @xas: Array operations state. 89358d6ea30SMatthew Wilcox * 89458d6ea30SMatthew Wilcox * Initialise all marks for the entry specified by @xas. If we're tracking 89558d6ea30SMatthew Wilcox * free entries with a mark, we need to set it on all entries. All other 89658d6ea30SMatthew Wilcox * marks are cleared. 89758d6ea30SMatthew Wilcox * 89858d6ea30SMatthew Wilcox * This implementation is not as efficient as it could be; we may walk 89958d6ea30SMatthew Wilcox * up the tree multiple times. 90058d6ea30SMatthew Wilcox */ 90158d6ea30SMatthew Wilcox void xas_init_marks(const struct xa_state *xas) 90258d6ea30SMatthew Wilcox { 90358d6ea30SMatthew Wilcox xa_mark_t mark = 0; 90458d6ea30SMatthew Wilcox 90558d6ea30SMatthew Wilcox for (;;) { 906*371c752dSMatthew Wilcox if (xa_track_free(xas->xa) && mark == XA_FREE_MARK) 907*371c752dSMatthew Wilcox xas_set_mark(xas, mark); 908*371c752dSMatthew Wilcox else 90958d6ea30SMatthew Wilcox xas_clear_mark(xas, mark); 91058d6ea30SMatthew Wilcox if (mark == XA_MARK_MAX) 91158d6ea30SMatthew Wilcox break; 91258d6ea30SMatthew Wilcox mark_inc(mark); 91358d6ea30SMatthew Wilcox } 91458d6ea30SMatthew Wilcox } 91558d6ea30SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_init_marks); 91658d6ea30SMatthew Wilcox 91758d6ea30SMatthew Wilcox /** 918b803b428SMatthew Wilcox * xas_pause() - Pause a walk to drop a lock. 919b803b428SMatthew Wilcox * @xas: XArray operation state. 920b803b428SMatthew Wilcox * 921b803b428SMatthew Wilcox * Some users need to pause a walk and drop the lock they're holding in 922b803b428SMatthew Wilcox * order to yield to a higher priority thread or carry out an operation 923b803b428SMatthew Wilcox * on an entry. Those users should call this function before they drop 924b803b428SMatthew Wilcox * the lock. It resets the @xas to be suitable for the next iteration 925b803b428SMatthew Wilcox * of the loop after the user has reacquired the lock. If most entries 926b803b428SMatthew Wilcox * found during a walk require you to call xas_pause(), the xa_for_each() 927b803b428SMatthew Wilcox * iterator may be more appropriate. 928b803b428SMatthew Wilcox * 929b803b428SMatthew Wilcox * Note that xas_pause() only works for forward iteration. If a user needs 930b803b428SMatthew Wilcox * to pause a reverse iteration, we will need a xas_pause_rev(). 931b803b428SMatthew Wilcox */ 932b803b428SMatthew Wilcox void xas_pause(struct xa_state *xas) 933b803b428SMatthew Wilcox { 934b803b428SMatthew Wilcox struct xa_node *node = xas->xa_node; 935b803b428SMatthew Wilcox 936b803b428SMatthew Wilcox if (xas_invalid(xas)) 937b803b428SMatthew Wilcox return; 938b803b428SMatthew Wilcox 939b803b428SMatthew Wilcox if (node) { 940b803b428SMatthew Wilcox unsigned int offset = xas->xa_offset; 941b803b428SMatthew Wilcox while (++offset < XA_CHUNK_SIZE) { 942b803b428SMatthew Wilcox if (!xa_is_sibling(xa_entry(xas->xa, node, offset))) 943b803b428SMatthew Wilcox break; 944b803b428SMatthew Wilcox } 945b803b428SMatthew Wilcox xas->xa_index += (offset - xas->xa_offset) << node->shift; 946b803b428SMatthew Wilcox } else { 947b803b428SMatthew Wilcox xas->xa_index++; 948b803b428SMatthew Wilcox } 949b803b428SMatthew Wilcox xas->xa_node = XAS_RESTART; 950b803b428SMatthew Wilcox } 951b803b428SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_pause); 952b803b428SMatthew Wilcox 95364d3e9a9SMatthew Wilcox /* 95464d3e9a9SMatthew Wilcox * __xas_prev() - Find the previous entry in the XArray. 95564d3e9a9SMatthew Wilcox * @xas: XArray operation state. 95664d3e9a9SMatthew Wilcox * 95764d3e9a9SMatthew Wilcox * Helper function for xas_prev() which handles all the complex cases 95864d3e9a9SMatthew Wilcox * out of line. 95964d3e9a9SMatthew Wilcox */ 96064d3e9a9SMatthew Wilcox void *__xas_prev(struct xa_state *xas) 96164d3e9a9SMatthew Wilcox { 96264d3e9a9SMatthew Wilcox void *entry; 96364d3e9a9SMatthew Wilcox 96464d3e9a9SMatthew Wilcox if (!xas_frozen(xas->xa_node)) 96564d3e9a9SMatthew Wilcox xas->xa_index--; 96664d3e9a9SMatthew Wilcox if (xas_not_node(xas->xa_node)) 96764d3e9a9SMatthew Wilcox return xas_load(xas); 96864d3e9a9SMatthew Wilcox 96964d3e9a9SMatthew Wilcox if (xas->xa_offset != get_offset(xas->xa_index, xas->xa_node)) 97064d3e9a9SMatthew Wilcox xas->xa_offset--; 97164d3e9a9SMatthew Wilcox 97264d3e9a9SMatthew Wilcox while (xas->xa_offset == 255) { 97364d3e9a9SMatthew Wilcox xas->xa_offset = xas->xa_node->offset - 1; 97464d3e9a9SMatthew Wilcox xas->xa_node = xa_parent(xas->xa, xas->xa_node); 97564d3e9a9SMatthew Wilcox if (!xas->xa_node) 97664d3e9a9SMatthew Wilcox return set_bounds(xas); 97764d3e9a9SMatthew Wilcox } 97864d3e9a9SMatthew Wilcox 97964d3e9a9SMatthew Wilcox for (;;) { 98064d3e9a9SMatthew Wilcox entry = xa_entry(xas->xa, xas->xa_node, xas->xa_offset); 98164d3e9a9SMatthew Wilcox if (!xa_is_node(entry)) 98264d3e9a9SMatthew Wilcox return entry; 98364d3e9a9SMatthew Wilcox 98464d3e9a9SMatthew Wilcox xas->xa_node = xa_to_node(entry); 98564d3e9a9SMatthew Wilcox xas_set_offset(xas); 98664d3e9a9SMatthew Wilcox } 98764d3e9a9SMatthew Wilcox } 98864d3e9a9SMatthew Wilcox EXPORT_SYMBOL_GPL(__xas_prev); 98964d3e9a9SMatthew Wilcox 99064d3e9a9SMatthew Wilcox /* 99164d3e9a9SMatthew Wilcox * __xas_next() - Find the next entry in the XArray. 99264d3e9a9SMatthew Wilcox * @xas: XArray operation state. 99364d3e9a9SMatthew Wilcox * 99464d3e9a9SMatthew Wilcox * Helper function for xas_next() which handles all the complex cases 99564d3e9a9SMatthew Wilcox * out of line. 99664d3e9a9SMatthew Wilcox */ 99764d3e9a9SMatthew Wilcox void *__xas_next(struct xa_state *xas) 99864d3e9a9SMatthew Wilcox { 99964d3e9a9SMatthew Wilcox void *entry; 100064d3e9a9SMatthew Wilcox 100164d3e9a9SMatthew Wilcox if (!xas_frozen(xas->xa_node)) 100264d3e9a9SMatthew Wilcox xas->xa_index++; 100364d3e9a9SMatthew Wilcox if (xas_not_node(xas->xa_node)) 100464d3e9a9SMatthew Wilcox return xas_load(xas); 100564d3e9a9SMatthew Wilcox 100664d3e9a9SMatthew Wilcox if (xas->xa_offset != get_offset(xas->xa_index, xas->xa_node)) 100764d3e9a9SMatthew Wilcox xas->xa_offset++; 100864d3e9a9SMatthew Wilcox 100964d3e9a9SMatthew Wilcox while (xas->xa_offset == XA_CHUNK_SIZE) { 101064d3e9a9SMatthew Wilcox xas->xa_offset = xas->xa_node->offset + 1; 101164d3e9a9SMatthew Wilcox xas->xa_node = xa_parent(xas->xa, xas->xa_node); 101264d3e9a9SMatthew Wilcox if (!xas->xa_node) 101364d3e9a9SMatthew Wilcox return set_bounds(xas); 101464d3e9a9SMatthew Wilcox } 101564d3e9a9SMatthew Wilcox 101664d3e9a9SMatthew Wilcox for (;;) { 101764d3e9a9SMatthew Wilcox entry = xa_entry(xas->xa, xas->xa_node, xas->xa_offset); 101864d3e9a9SMatthew Wilcox if (!xa_is_node(entry)) 101964d3e9a9SMatthew Wilcox return entry; 102064d3e9a9SMatthew Wilcox 102164d3e9a9SMatthew Wilcox xas->xa_node = xa_to_node(entry); 102264d3e9a9SMatthew Wilcox xas_set_offset(xas); 102364d3e9a9SMatthew Wilcox } 102464d3e9a9SMatthew Wilcox } 102564d3e9a9SMatthew Wilcox EXPORT_SYMBOL_GPL(__xas_next); 102664d3e9a9SMatthew Wilcox 1027b803b428SMatthew Wilcox /** 1028b803b428SMatthew Wilcox * xas_find() - Find the next present entry in the XArray. 1029b803b428SMatthew Wilcox * @xas: XArray operation state. 1030b803b428SMatthew Wilcox * @max: Highest index to return. 1031b803b428SMatthew Wilcox * 1032b803b428SMatthew Wilcox * If the @xas has not yet been walked to an entry, return the entry 1033b803b428SMatthew Wilcox * which has an index >= xas.xa_index. If it has been walked, the entry 1034b803b428SMatthew Wilcox * currently being pointed at has been processed, and so we move to the 1035b803b428SMatthew Wilcox * next entry. 1036b803b428SMatthew Wilcox * 1037b803b428SMatthew Wilcox * If no entry is found and the array is smaller than @max, the iterator 1038b803b428SMatthew Wilcox * is set to the smallest index not yet in the array. This allows @xas 1039b803b428SMatthew Wilcox * to be immediately passed to xas_store(). 1040b803b428SMatthew Wilcox * 1041b803b428SMatthew Wilcox * Return: The entry, if found, otherwise %NULL. 1042b803b428SMatthew Wilcox */ 1043b803b428SMatthew Wilcox void *xas_find(struct xa_state *xas, unsigned long max) 1044b803b428SMatthew Wilcox { 1045b803b428SMatthew Wilcox void *entry; 1046b803b428SMatthew Wilcox 1047b803b428SMatthew Wilcox if (xas_error(xas)) 1048b803b428SMatthew Wilcox return NULL; 1049b803b428SMatthew Wilcox 1050b803b428SMatthew Wilcox if (!xas->xa_node) { 1051b803b428SMatthew Wilcox xas->xa_index = 1; 1052b803b428SMatthew Wilcox return set_bounds(xas); 1053b803b428SMatthew Wilcox } else if (xas_top(xas->xa_node)) { 1054b803b428SMatthew Wilcox entry = xas_load(xas); 1055b803b428SMatthew Wilcox if (entry || xas_not_node(xas->xa_node)) 1056b803b428SMatthew Wilcox return entry; 1057b803b428SMatthew Wilcox } else if (!xas->xa_node->shift && 1058b803b428SMatthew Wilcox xas->xa_offset != (xas->xa_index & XA_CHUNK_MASK)) { 1059b803b428SMatthew Wilcox xas->xa_offset = ((xas->xa_index - 1) & XA_CHUNK_MASK) + 1; 1060b803b428SMatthew Wilcox } 1061b803b428SMatthew Wilcox 1062b803b428SMatthew Wilcox xas_advance(xas); 1063b803b428SMatthew Wilcox 1064b803b428SMatthew Wilcox while (xas->xa_node && (xas->xa_index <= max)) { 1065b803b428SMatthew Wilcox if (unlikely(xas->xa_offset == XA_CHUNK_SIZE)) { 1066b803b428SMatthew Wilcox xas->xa_offset = xas->xa_node->offset + 1; 1067b803b428SMatthew Wilcox xas->xa_node = xa_parent(xas->xa, xas->xa_node); 1068b803b428SMatthew Wilcox continue; 1069b803b428SMatthew Wilcox } 1070b803b428SMatthew Wilcox 1071b803b428SMatthew Wilcox entry = xa_entry(xas->xa, xas->xa_node, xas->xa_offset); 1072b803b428SMatthew Wilcox if (xa_is_node(entry)) { 1073b803b428SMatthew Wilcox xas->xa_node = xa_to_node(entry); 1074b803b428SMatthew Wilcox xas->xa_offset = 0; 1075b803b428SMatthew Wilcox continue; 1076b803b428SMatthew Wilcox } 1077b803b428SMatthew Wilcox if (entry && !xa_is_sibling(entry)) 1078b803b428SMatthew Wilcox return entry; 1079b803b428SMatthew Wilcox 1080b803b428SMatthew Wilcox xas_advance(xas); 1081b803b428SMatthew Wilcox } 1082b803b428SMatthew Wilcox 1083b803b428SMatthew Wilcox if (!xas->xa_node) 1084b803b428SMatthew Wilcox xas->xa_node = XAS_BOUNDS; 1085b803b428SMatthew Wilcox return NULL; 1086b803b428SMatthew Wilcox } 1087b803b428SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_find); 1088b803b428SMatthew Wilcox 1089b803b428SMatthew Wilcox /** 1090b803b428SMatthew Wilcox * xas_find_marked() - Find the next marked entry in the XArray. 1091b803b428SMatthew Wilcox * @xas: XArray operation state. 1092b803b428SMatthew Wilcox * @max: Highest index to return. 1093b803b428SMatthew Wilcox * @mark: Mark number to search for. 1094b803b428SMatthew Wilcox * 1095b803b428SMatthew Wilcox * If the @xas has not yet been walked to an entry, return the marked entry 1096b803b428SMatthew Wilcox * which has an index >= xas.xa_index. If it has been walked, the entry 1097b803b428SMatthew Wilcox * currently being pointed at has been processed, and so we return the 1098b803b428SMatthew Wilcox * first marked entry with an index > xas.xa_index. 1099b803b428SMatthew Wilcox * 1100b803b428SMatthew Wilcox * If no marked entry is found and the array is smaller than @max, @xas is 1101b803b428SMatthew Wilcox * set to the bounds state and xas->xa_index is set to the smallest index 1102b803b428SMatthew Wilcox * not yet in the array. This allows @xas to be immediately passed to 1103b803b428SMatthew Wilcox * xas_store(). 1104b803b428SMatthew Wilcox * 1105b803b428SMatthew Wilcox * If no entry is found before @max is reached, @xas is set to the restart 1106b803b428SMatthew Wilcox * state. 1107b803b428SMatthew Wilcox * 1108b803b428SMatthew Wilcox * Return: The entry, if found, otherwise %NULL. 1109b803b428SMatthew Wilcox */ 1110b803b428SMatthew Wilcox void *xas_find_marked(struct xa_state *xas, unsigned long max, xa_mark_t mark) 1111b803b428SMatthew Wilcox { 1112b803b428SMatthew Wilcox bool advance = true; 1113b803b428SMatthew Wilcox unsigned int offset; 1114b803b428SMatthew Wilcox void *entry; 1115b803b428SMatthew Wilcox 1116b803b428SMatthew Wilcox if (xas_error(xas)) 1117b803b428SMatthew Wilcox return NULL; 1118b803b428SMatthew Wilcox 1119b803b428SMatthew Wilcox if (!xas->xa_node) { 1120b803b428SMatthew Wilcox xas->xa_index = 1; 1121b803b428SMatthew Wilcox goto out; 1122b803b428SMatthew Wilcox } else if (xas_top(xas->xa_node)) { 1123b803b428SMatthew Wilcox advance = false; 1124b803b428SMatthew Wilcox entry = xa_head(xas->xa); 1125b803b428SMatthew Wilcox xas->xa_node = NULL; 1126b803b428SMatthew Wilcox if (xas->xa_index > max_index(entry)) 1127b803b428SMatthew Wilcox goto bounds; 1128b803b428SMatthew Wilcox if (!xa_is_node(entry)) { 1129b803b428SMatthew Wilcox if (xa_marked(xas->xa, mark)) 1130b803b428SMatthew Wilcox return entry; 1131b803b428SMatthew Wilcox xas->xa_index = 1; 1132b803b428SMatthew Wilcox goto out; 1133b803b428SMatthew Wilcox } 1134b803b428SMatthew Wilcox xas->xa_node = xa_to_node(entry); 1135b803b428SMatthew Wilcox xas->xa_offset = xas->xa_index >> xas->xa_node->shift; 1136b803b428SMatthew Wilcox } 1137b803b428SMatthew Wilcox 1138b803b428SMatthew Wilcox while (xas->xa_index <= max) { 1139b803b428SMatthew Wilcox if (unlikely(xas->xa_offset == XA_CHUNK_SIZE)) { 1140b803b428SMatthew Wilcox xas->xa_offset = xas->xa_node->offset + 1; 1141b803b428SMatthew Wilcox xas->xa_node = xa_parent(xas->xa, xas->xa_node); 1142b803b428SMatthew Wilcox if (!xas->xa_node) 1143b803b428SMatthew Wilcox break; 1144b803b428SMatthew Wilcox advance = false; 1145b803b428SMatthew Wilcox continue; 1146b803b428SMatthew Wilcox } 1147b803b428SMatthew Wilcox 1148b803b428SMatthew Wilcox if (!advance) { 1149b803b428SMatthew Wilcox entry = xa_entry(xas->xa, xas->xa_node, xas->xa_offset); 1150b803b428SMatthew Wilcox if (xa_is_sibling(entry)) { 1151b803b428SMatthew Wilcox xas->xa_offset = xa_to_sibling(entry); 1152b803b428SMatthew Wilcox xas_move_index(xas, xas->xa_offset); 1153b803b428SMatthew Wilcox } 1154b803b428SMatthew Wilcox } 1155b803b428SMatthew Wilcox 1156b803b428SMatthew Wilcox offset = xas_find_chunk(xas, advance, mark); 1157b803b428SMatthew Wilcox if (offset > xas->xa_offset) { 1158b803b428SMatthew Wilcox advance = false; 1159b803b428SMatthew Wilcox xas_move_index(xas, offset); 1160b803b428SMatthew Wilcox /* Mind the wrap */ 1161b803b428SMatthew Wilcox if ((xas->xa_index - 1) >= max) 1162b803b428SMatthew Wilcox goto max; 1163b803b428SMatthew Wilcox xas->xa_offset = offset; 1164b803b428SMatthew Wilcox if (offset == XA_CHUNK_SIZE) 1165b803b428SMatthew Wilcox continue; 1166b803b428SMatthew Wilcox } 1167b803b428SMatthew Wilcox 1168b803b428SMatthew Wilcox entry = xa_entry(xas->xa, xas->xa_node, xas->xa_offset); 1169b803b428SMatthew Wilcox if (!xa_is_node(entry)) 1170b803b428SMatthew Wilcox return entry; 1171b803b428SMatthew Wilcox xas->xa_node = xa_to_node(entry); 1172b803b428SMatthew Wilcox xas_set_offset(xas); 1173b803b428SMatthew Wilcox } 1174b803b428SMatthew Wilcox 1175b803b428SMatthew Wilcox out: 1176b803b428SMatthew Wilcox if (!max) 1177b803b428SMatthew Wilcox goto max; 1178b803b428SMatthew Wilcox bounds: 1179b803b428SMatthew Wilcox xas->xa_node = XAS_BOUNDS; 1180b803b428SMatthew Wilcox return NULL; 1181b803b428SMatthew Wilcox max: 1182b803b428SMatthew Wilcox xas->xa_node = XAS_RESTART; 1183b803b428SMatthew Wilcox return NULL; 1184b803b428SMatthew Wilcox } 1185b803b428SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_find_marked); 1186b803b428SMatthew Wilcox 1187b803b428SMatthew Wilcox /** 11884e99d4e9SMatthew Wilcox * xas_find_conflict() - Find the next present entry in a range. 11894e99d4e9SMatthew Wilcox * @xas: XArray operation state. 11904e99d4e9SMatthew Wilcox * 11914e99d4e9SMatthew Wilcox * The @xas describes both a range and a position within that range. 11924e99d4e9SMatthew Wilcox * 11934e99d4e9SMatthew Wilcox * Context: Any context. Expects xa_lock to be held. 11944e99d4e9SMatthew Wilcox * Return: The next entry in the range covered by @xas or %NULL. 11954e99d4e9SMatthew Wilcox */ 11964e99d4e9SMatthew Wilcox void *xas_find_conflict(struct xa_state *xas) 11974e99d4e9SMatthew Wilcox { 11984e99d4e9SMatthew Wilcox void *curr; 11994e99d4e9SMatthew Wilcox 12004e99d4e9SMatthew Wilcox if (xas_error(xas)) 12014e99d4e9SMatthew Wilcox return NULL; 12024e99d4e9SMatthew Wilcox 12034e99d4e9SMatthew Wilcox if (!xas->xa_node) 12044e99d4e9SMatthew Wilcox return NULL; 12054e99d4e9SMatthew Wilcox 12064e99d4e9SMatthew Wilcox if (xas_top(xas->xa_node)) { 12074e99d4e9SMatthew Wilcox curr = xas_start(xas); 12084e99d4e9SMatthew Wilcox if (!curr) 12094e99d4e9SMatthew Wilcox return NULL; 12104e99d4e9SMatthew Wilcox while (xa_is_node(curr)) { 12114e99d4e9SMatthew Wilcox struct xa_node *node = xa_to_node(curr); 12124e99d4e9SMatthew Wilcox curr = xas_descend(xas, node); 12134e99d4e9SMatthew Wilcox } 12144e99d4e9SMatthew Wilcox if (curr) 12154e99d4e9SMatthew Wilcox return curr; 12164e99d4e9SMatthew Wilcox } 12174e99d4e9SMatthew Wilcox 12184e99d4e9SMatthew Wilcox if (xas->xa_node->shift > xas->xa_shift) 12194e99d4e9SMatthew Wilcox return NULL; 12204e99d4e9SMatthew Wilcox 12214e99d4e9SMatthew Wilcox for (;;) { 12224e99d4e9SMatthew Wilcox if (xas->xa_node->shift == xas->xa_shift) { 12234e99d4e9SMatthew Wilcox if ((xas->xa_offset & xas->xa_sibs) == xas->xa_sibs) 12244e99d4e9SMatthew Wilcox break; 12254e99d4e9SMatthew Wilcox } else if (xas->xa_offset == XA_CHUNK_MASK) { 12264e99d4e9SMatthew Wilcox xas->xa_offset = xas->xa_node->offset; 12274e99d4e9SMatthew Wilcox xas->xa_node = xa_parent_locked(xas->xa, xas->xa_node); 12284e99d4e9SMatthew Wilcox if (!xas->xa_node) 12294e99d4e9SMatthew Wilcox break; 12304e99d4e9SMatthew Wilcox continue; 12314e99d4e9SMatthew Wilcox } 12324e99d4e9SMatthew Wilcox curr = xa_entry_locked(xas->xa, xas->xa_node, ++xas->xa_offset); 12334e99d4e9SMatthew Wilcox if (xa_is_sibling(curr)) 12344e99d4e9SMatthew Wilcox continue; 12354e99d4e9SMatthew Wilcox while (xa_is_node(curr)) { 12364e99d4e9SMatthew Wilcox xas->xa_node = xa_to_node(curr); 12374e99d4e9SMatthew Wilcox xas->xa_offset = 0; 12384e99d4e9SMatthew Wilcox curr = xa_entry_locked(xas->xa, xas->xa_node, 0); 12394e99d4e9SMatthew Wilcox } 12404e99d4e9SMatthew Wilcox if (curr) 12414e99d4e9SMatthew Wilcox return curr; 12424e99d4e9SMatthew Wilcox } 12434e99d4e9SMatthew Wilcox xas->xa_offset -= xas->xa_sibs; 12444e99d4e9SMatthew Wilcox return NULL; 12454e99d4e9SMatthew Wilcox } 12464e99d4e9SMatthew Wilcox EXPORT_SYMBOL_GPL(xas_find_conflict); 12474e99d4e9SMatthew Wilcox 12484e99d4e9SMatthew Wilcox /** 1249f8d5d0ccSMatthew Wilcox * xa_init_flags() - Initialise an empty XArray with flags. 1250f8d5d0ccSMatthew Wilcox * @xa: XArray. 1251f8d5d0ccSMatthew Wilcox * @flags: XA_FLAG values. 1252f8d5d0ccSMatthew Wilcox * 1253f8d5d0ccSMatthew Wilcox * If you need to initialise an XArray with special flags (eg you need 1254f8d5d0ccSMatthew Wilcox * to take the lock from interrupt context), use this function instead 1255f8d5d0ccSMatthew Wilcox * of xa_init(). 1256f8d5d0ccSMatthew Wilcox * 1257f8d5d0ccSMatthew Wilcox * Context: Any context. 1258f8d5d0ccSMatthew Wilcox */ 1259f8d5d0ccSMatthew Wilcox void xa_init_flags(struct xarray *xa, gfp_t flags) 1260f8d5d0ccSMatthew Wilcox { 126158d6ea30SMatthew Wilcox unsigned int lock_type; 126258d6ea30SMatthew Wilcox static struct lock_class_key xa_lock_irq; 126358d6ea30SMatthew Wilcox static struct lock_class_key xa_lock_bh; 126458d6ea30SMatthew Wilcox 1265f8d5d0ccSMatthew Wilcox spin_lock_init(&xa->xa_lock); 1266f8d5d0ccSMatthew Wilcox xa->xa_flags = flags; 1267f8d5d0ccSMatthew Wilcox xa->xa_head = NULL; 126858d6ea30SMatthew Wilcox 126958d6ea30SMatthew Wilcox lock_type = xa_lock_type(xa); 127058d6ea30SMatthew Wilcox if (lock_type == XA_LOCK_IRQ) 127158d6ea30SMatthew Wilcox lockdep_set_class(&xa->xa_lock, &xa_lock_irq); 127258d6ea30SMatthew Wilcox else if (lock_type == XA_LOCK_BH) 127358d6ea30SMatthew Wilcox lockdep_set_class(&xa->xa_lock, &xa_lock_bh); 1274f8d5d0ccSMatthew Wilcox } 1275f8d5d0ccSMatthew Wilcox EXPORT_SYMBOL(xa_init_flags); 1276ad3d6c72SMatthew Wilcox 1277ad3d6c72SMatthew Wilcox /** 1278ad3d6c72SMatthew Wilcox * xa_load() - Load an entry from an XArray. 1279ad3d6c72SMatthew Wilcox * @xa: XArray. 1280ad3d6c72SMatthew Wilcox * @index: index into array. 1281ad3d6c72SMatthew Wilcox * 1282ad3d6c72SMatthew Wilcox * Context: Any context. Takes and releases the RCU lock. 1283ad3d6c72SMatthew Wilcox * Return: The entry at @index in @xa. 1284ad3d6c72SMatthew Wilcox */ 1285ad3d6c72SMatthew Wilcox void *xa_load(struct xarray *xa, unsigned long index) 1286ad3d6c72SMatthew Wilcox { 1287ad3d6c72SMatthew Wilcox XA_STATE(xas, xa, index); 1288ad3d6c72SMatthew Wilcox void *entry; 1289ad3d6c72SMatthew Wilcox 1290ad3d6c72SMatthew Wilcox rcu_read_lock(); 1291ad3d6c72SMatthew Wilcox do { 1292ad3d6c72SMatthew Wilcox entry = xas_load(&xas); 12939f14d4f1SMatthew Wilcox if (xa_is_zero(entry)) 12949f14d4f1SMatthew Wilcox entry = NULL; 1295ad3d6c72SMatthew Wilcox } while (xas_retry(&xas, entry)); 1296ad3d6c72SMatthew Wilcox rcu_read_unlock(); 1297ad3d6c72SMatthew Wilcox 1298ad3d6c72SMatthew Wilcox return entry; 1299ad3d6c72SMatthew Wilcox } 1300ad3d6c72SMatthew Wilcox EXPORT_SYMBOL(xa_load); 1301ad3d6c72SMatthew Wilcox 130258d6ea30SMatthew Wilcox static void *xas_result(struct xa_state *xas, void *curr) 130358d6ea30SMatthew Wilcox { 13049f14d4f1SMatthew Wilcox if (xa_is_zero(curr)) 13059f14d4f1SMatthew Wilcox return NULL; 130658d6ea30SMatthew Wilcox XA_NODE_BUG_ON(xas->xa_node, xa_is_internal(curr)); 130758d6ea30SMatthew Wilcox if (xas_error(xas)) 130858d6ea30SMatthew Wilcox curr = xas->xa_node; 130958d6ea30SMatthew Wilcox return curr; 131058d6ea30SMatthew Wilcox } 131158d6ea30SMatthew Wilcox 131258d6ea30SMatthew Wilcox /** 131358d6ea30SMatthew Wilcox * __xa_erase() - Erase this entry from the XArray while locked. 131458d6ea30SMatthew Wilcox * @xa: XArray. 131558d6ea30SMatthew Wilcox * @index: Index into array. 131658d6ea30SMatthew Wilcox * 131758d6ea30SMatthew Wilcox * If the entry at this index is a multi-index entry then all indices will 131858d6ea30SMatthew Wilcox * be erased, and the entry will no longer be a multi-index entry. 131958d6ea30SMatthew Wilcox * This function expects the xa_lock to be held on entry. 132058d6ea30SMatthew Wilcox * 132158d6ea30SMatthew Wilcox * Context: Any context. Expects xa_lock to be held on entry. May 132258d6ea30SMatthew Wilcox * release and reacquire xa_lock if @gfp flags permit. 132358d6ea30SMatthew Wilcox * Return: The old entry at this index. 132458d6ea30SMatthew Wilcox */ 132558d6ea30SMatthew Wilcox void *__xa_erase(struct xarray *xa, unsigned long index) 132658d6ea30SMatthew Wilcox { 132758d6ea30SMatthew Wilcox XA_STATE(xas, xa, index); 132858d6ea30SMatthew Wilcox return xas_result(&xas, xas_store(&xas, NULL)); 132958d6ea30SMatthew Wilcox } 133058d6ea30SMatthew Wilcox EXPORT_SYMBOL_GPL(__xa_erase); 133158d6ea30SMatthew Wilcox 133258d6ea30SMatthew Wilcox /** 133358d6ea30SMatthew Wilcox * xa_store() - Store this entry in the XArray. 133458d6ea30SMatthew Wilcox * @xa: XArray. 133558d6ea30SMatthew Wilcox * @index: Index into array. 133658d6ea30SMatthew Wilcox * @entry: New entry. 133758d6ea30SMatthew Wilcox * @gfp: Memory allocation flags. 133858d6ea30SMatthew Wilcox * 133958d6ea30SMatthew Wilcox * After this function returns, loads from this index will return @entry. 134058d6ea30SMatthew Wilcox * Storing into an existing multislot entry updates the entry of every index. 134158d6ea30SMatthew Wilcox * The marks associated with @index are unaffected unless @entry is %NULL. 134258d6ea30SMatthew Wilcox * 134358d6ea30SMatthew Wilcox * Context: Process context. Takes and releases the xa_lock. May sleep 134458d6ea30SMatthew Wilcox * if the @gfp flags permit. 134558d6ea30SMatthew Wilcox * Return: The old entry at this index on success, xa_err(-EINVAL) if @entry 134658d6ea30SMatthew Wilcox * cannot be stored in an XArray, or xa_err(-ENOMEM) if memory allocation 134758d6ea30SMatthew Wilcox * failed. 134858d6ea30SMatthew Wilcox */ 134958d6ea30SMatthew Wilcox void *xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) 135058d6ea30SMatthew Wilcox { 135158d6ea30SMatthew Wilcox XA_STATE(xas, xa, index); 135258d6ea30SMatthew Wilcox void *curr; 135358d6ea30SMatthew Wilcox 135458d6ea30SMatthew Wilcox if (WARN_ON_ONCE(xa_is_internal(entry))) 135558d6ea30SMatthew Wilcox return XA_ERROR(-EINVAL); 135658d6ea30SMatthew Wilcox 135758d6ea30SMatthew Wilcox do { 135858d6ea30SMatthew Wilcox xas_lock(&xas); 135958d6ea30SMatthew Wilcox curr = xas_store(&xas, entry); 1360*371c752dSMatthew Wilcox if (xa_track_free(xa) && entry) 1361*371c752dSMatthew Wilcox xas_clear_mark(&xas, XA_FREE_MARK); 136258d6ea30SMatthew Wilcox xas_unlock(&xas); 136358d6ea30SMatthew Wilcox } while (xas_nomem(&xas, gfp)); 136458d6ea30SMatthew Wilcox 136558d6ea30SMatthew Wilcox return xas_result(&xas, curr); 136658d6ea30SMatthew Wilcox } 136758d6ea30SMatthew Wilcox EXPORT_SYMBOL(xa_store); 136858d6ea30SMatthew Wilcox 136958d6ea30SMatthew Wilcox /** 137058d6ea30SMatthew Wilcox * __xa_store() - Store this entry in the XArray. 137158d6ea30SMatthew Wilcox * @xa: XArray. 137258d6ea30SMatthew Wilcox * @index: Index into array. 137358d6ea30SMatthew Wilcox * @entry: New entry. 137458d6ea30SMatthew Wilcox * @gfp: Memory allocation flags. 137558d6ea30SMatthew Wilcox * 137658d6ea30SMatthew Wilcox * You must already be holding the xa_lock when calling this function. 137758d6ea30SMatthew Wilcox * It will drop the lock if needed to allocate memory, and then reacquire 137858d6ea30SMatthew Wilcox * it afterwards. 137958d6ea30SMatthew Wilcox * 138058d6ea30SMatthew Wilcox * Context: Any context. Expects xa_lock to be held on entry. May 138158d6ea30SMatthew Wilcox * release and reacquire xa_lock if @gfp flags permit. 138258d6ea30SMatthew Wilcox * Return: The old entry at this index or xa_err() if an error happened. 138358d6ea30SMatthew Wilcox */ 138458d6ea30SMatthew Wilcox void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) 138558d6ea30SMatthew Wilcox { 138658d6ea30SMatthew Wilcox XA_STATE(xas, xa, index); 138758d6ea30SMatthew Wilcox void *curr; 138858d6ea30SMatthew Wilcox 138958d6ea30SMatthew Wilcox if (WARN_ON_ONCE(xa_is_internal(entry))) 139058d6ea30SMatthew Wilcox return XA_ERROR(-EINVAL); 139158d6ea30SMatthew Wilcox 139258d6ea30SMatthew Wilcox do { 139358d6ea30SMatthew Wilcox curr = xas_store(&xas, entry); 1394*371c752dSMatthew Wilcox if (xa_track_free(xa) && entry) 1395*371c752dSMatthew Wilcox xas_clear_mark(&xas, XA_FREE_MARK); 139658d6ea30SMatthew Wilcox } while (__xas_nomem(&xas, gfp)); 139758d6ea30SMatthew Wilcox 139858d6ea30SMatthew Wilcox return xas_result(&xas, curr); 139958d6ea30SMatthew Wilcox } 140058d6ea30SMatthew Wilcox EXPORT_SYMBOL(__xa_store); 140158d6ea30SMatthew Wilcox 14029b89a035SMatthew Wilcox /** 140341aec91fSMatthew Wilcox * xa_cmpxchg() - Conditionally replace an entry in the XArray. 140441aec91fSMatthew Wilcox * @xa: XArray. 140541aec91fSMatthew Wilcox * @index: Index into array. 140641aec91fSMatthew Wilcox * @old: Old value to test against. 140741aec91fSMatthew Wilcox * @entry: New value to place in array. 140841aec91fSMatthew Wilcox * @gfp: Memory allocation flags. 140941aec91fSMatthew Wilcox * 141041aec91fSMatthew Wilcox * If the entry at @index is the same as @old, replace it with @entry. 141141aec91fSMatthew Wilcox * If the return value is equal to @old, then the exchange was successful. 141241aec91fSMatthew Wilcox * 141341aec91fSMatthew Wilcox * Context: Process context. Takes and releases the xa_lock. May sleep 141441aec91fSMatthew Wilcox * if the @gfp flags permit. 141541aec91fSMatthew Wilcox * Return: The old value at this index or xa_err() if an error happened. 141641aec91fSMatthew Wilcox */ 141741aec91fSMatthew Wilcox void *xa_cmpxchg(struct xarray *xa, unsigned long index, 141841aec91fSMatthew Wilcox void *old, void *entry, gfp_t gfp) 141941aec91fSMatthew Wilcox { 142041aec91fSMatthew Wilcox XA_STATE(xas, xa, index); 142141aec91fSMatthew Wilcox void *curr; 142241aec91fSMatthew Wilcox 142341aec91fSMatthew Wilcox if (WARN_ON_ONCE(xa_is_internal(entry))) 142441aec91fSMatthew Wilcox return XA_ERROR(-EINVAL); 142541aec91fSMatthew Wilcox 142641aec91fSMatthew Wilcox do { 142741aec91fSMatthew Wilcox xas_lock(&xas); 142841aec91fSMatthew Wilcox curr = xas_load(&xas); 14299f14d4f1SMatthew Wilcox if (curr == XA_ZERO_ENTRY) 14309f14d4f1SMatthew Wilcox curr = NULL; 1431*371c752dSMatthew Wilcox if (curr == old) { 143241aec91fSMatthew Wilcox xas_store(&xas, entry); 1433*371c752dSMatthew Wilcox if (xa_track_free(xa) && entry) 1434*371c752dSMatthew Wilcox xas_clear_mark(&xas, XA_FREE_MARK); 1435*371c752dSMatthew Wilcox } 143641aec91fSMatthew Wilcox xas_unlock(&xas); 143741aec91fSMatthew Wilcox } while (xas_nomem(&xas, gfp)); 143841aec91fSMatthew Wilcox 143941aec91fSMatthew Wilcox return xas_result(&xas, curr); 144041aec91fSMatthew Wilcox } 144141aec91fSMatthew Wilcox EXPORT_SYMBOL(xa_cmpxchg); 144241aec91fSMatthew Wilcox 144341aec91fSMatthew Wilcox /** 144441aec91fSMatthew Wilcox * __xa_cmpxchg() - Store this entry in the XArray. 144541aec91fSMatthew Wilcox * @xa: XArray. 144641aec91fSMatthew Wilcox * @index: Index into array. 144741aec91fSMatthew Wilcox * @old: Old value to test against. 144841aec91fSMatthew Wilcox * @entry: New entry. 144941aec91fSMatthew Wilcox * @gfp: Memory allocation flags. 145041aec91fSMatthew Wilcox * 145141aec91fSMatthew Wilcox * You must already be holding the xa_lock when calling this function. 145241aec91fSMatthew Wilcox * It will drop the lock if needed to allocate memory, and then reacquire 145341aec91fSMatthew Wilcox * it afterwards. 145441aec91fSMatthew Wilcox * 145541aec91fSMatthew Wilcox * Context: Any context. Expects xa_lock to be held on entry. May 145641aec91fSMatthew Wilcox * release and reacquire xa_lock if @gfp flags permit. 145741aec91fSMatthew Wilcox * Return: The old entry at this index or xa_err() if an error happened. 145841aec91fSMatthew Wilcox */ 145941aec91fSMatthew Wilcox void *__xa_cmpxchg(struct xarray *xa, unsigned long index, 146041aec91fSMatthew Wilcox void *old, void *entry, gfp_t gfp) 146141aec91fSMatthew Wilcox { 146241aec91fSMatthew Wilcox XA_STATE(xas, xa, index); 146341aec91fSMatthew Wilcox void *curr; 146441aec91fSMatthew Wilcox 146541aec91fSMatthew Wilcox if (WARN_ON_ONCE(xa_is_internal(entry))) 146641aec91fSMatthew Wilcox return XA_ERROR(-EINVAL); 146741aec91fSMatthew Wilcox 146841aec91fSMatthew Wilcox do { 146941aec91fSMatthew Wilcox curr = xas_load(&xas); 14709f14d4f1SMatthew Wilcox if (curr == XA_ZERO_ENTRY) 14719f14d4f1SMatthew Wilcox curr = NULL; 1472*371c752dSMatthew Wilcox if (curr == old) { 147341aec91fSMatthew Wilcox xas_store(&xas, entry); 1474*371c752dSMatthew Wilcox if (xa_track_free(xa) && entry) 1475*371c752dSMatthew Wilcox xas_clear_mark(&xas, XA_FREE_MARK); 1476*371c752dSMatthew Wilcox } 147741aec91fSMatthew Wilcox } while (__xas_nomem(&xas, gfp)); 147841aec91fSMatthew Wilcox 147941aec91fSMatthew Wilcox return xas_result(&xas, curr); 148041aec91fSMatthew Wilcox } 148141aec91fSMatthew Wilcox EXPORT_SYMBOL(__xa_cmpxchg); 148241aec91fSMatthew Wilcox 148341aec91fSMatthew Wilcox /** 14849f14d4f1SMatthew Wilcox * xa_reserve() - Reserve this index in the XArray. 14859f14d4f1SMatthew Wilcox * @xa: XArray. 14869f14d4f1SMatthew Wilcox * @index: Index into array. 14879f14d4f1SMatthew Wilcox * @gfp: Memory allocation flags. 14889f14d4f1SMatthew Wilcox * 14899f14d4f1SMatthew Wilcox * Ensures there is somewhere to store an entry at @index in the array. 14909f14d4f1SMatthew Wilcox * If there is already something stored at @index, this function does 14919f14d4f1SMatthew Wilcox * nothing. If there was nothing there, the entry is marked as reserved. 14929f14d4f1SMatthew Wilcox * Loads from @index will continue to see a %NULL pointer until a 14939f14d4f1SMatthew Wilcox * subsequent store to @index. 14949f14d4f1SMatthew Wilcox * 14959f14d4f1SMatthew Wilcox * If you do not use the entry that you have reserved, call xa_release() 14969f14d4f1SMatthew Wilcox * or xa_erase() to free any unnecessary memory. 14979f14d4f1SMatthew Wilcox * 14989f14d4f1SMatthew Wilcox * Context: Process context. Takes and releases the xa_lock, IRQ or BH safe 14999f14d4f1SMatthew Wilcox * if specified in XArray flags. May sleep if the @gfp flags permit. 15009f14d4f1SMatthew Wilcox * Return: 0 if the reservation succeeded or -ENOMEM if it failed. 15019f14d4f1SMatthew Wilcox */ 15029f14d4f1SMatthew Wilcox int xa_reserve(struct xarray *xa, unsigned long index, gfp_t gfp) 15039f14d4f1SMatthew Wilcox { 15049f14d4f1SMatthew Wilcox XA_STATE(xas, xa, index); 15059f14d4f1SMatthew Wilcox unsigned int lock_type = xa_lock_type(xa); 15069f14d4f1SMatthew Wilcox void *curr; 15079f14d4f1SMatthew Wilcox 15089f14d4f1SMatthew Wilcox do { 15099f14d4f1SMatthew Wilcox xas_lock_type(&xas, lock_type); 15109f14d4f1SMatthew Wilcox curr = xas_load(&xas); 15119f14d4f1SMatthew Wilcox if (!curr) 15129f14d4f1SMatthew Wilcox xas_store(&xas, XA_ZERO_ENTRY); 15139f14d4f1SMatthew Wilcox xas_unlock_type(&xas, lock_type); 15149f14d4f1SMatthew Wilcox } while (xas_nomem(&xas, gfp)); 15159f14d4f1SMatthew Wilcox 15169f14d4f1SMatthew Wilcox return xas_error(&xas); 15179f14d4f1SMatthew Wilcox } 15189f14d4f1SMatthew Wilcox EXPORT_SYMBOL(xa_reserve); 15199f14d4f1SMatthew Wilcox 15209f14d4f1SMatthew Wilcox /** 1521*371c752dSMatthew Wilcox * __xa_alloc() - Find somewhere to store this entry in the XArray. 1522*371c752dSMatthew Wilcox * @xa: XArray. 1523*371c752dSMatthew Wilcox * @id: Pointer to ID. 1524*371c752dSMatthew Wilcox * @max: Maximum ID to allocate (inclusive). 1525*371c752dSMatthew Wilcox * @entry: New entry. 1526*371c752dSMatthew Wilcox * @gfp: Memory allocation flags. 1527*371c752dSMatthew Wilcox * 1528*371c752dSMatthew Wilcox * Allocates an unused ID in the range specified by @id and @max. 1529*371c752dSMatthew Wilcox * Updates the @id pointer with the index, then stores the entry at that 1530*371c752dSMatthew Wilcox * index. A concurrent lookup will not see an uninitialised @id. 1531*371c752dSMatthew Wilcox * 1532*371c752dSMatthew Wilcox * Context: Any context. Expects xa_lock to be held on entry. May 1533*371c752dSMatthew Wilcox * release and reacquire xa_lock if @gfp flags permit. 1534*371c752dSMatthew Wilcox * Return: 0 on success, -ENOMEM if memory allocation fails or -ENOSPC if 1535*371c752dSMatthew Wilcox * there is no more space in the XArray. 1536*371c752dSMatthew Wilcox */ 1537*371c752dSMatthew Wilcox int __xa_alloc(struct xarray *xa, u32 *id, u32 max, void *entry, gfp_t gfp) 1538*371c752dSMatthew Wilcox { 1539*371c752dSMatthew Wilcox XA_STATE(xas, xa, 0); 1540*371c752dSMatthew Wilcox int err; 1541*371c752dSMatthew Wilcox 1542*371c752dSMatthew Wilcox if (WARN_ON_ONCE(xa_is_internal(entry))) 1543*371c752dSMatthew Wilcox return -EINVAL; 1544*371c752dSMatthew Wilcox if (WARN_ON_ONCE(!xa_track_free(xa))) 1545*371c752dSMatthew Wilcox return -EINVAL; 1546*371c752dSMatthew Wilcox 1547*371c752dSMatthew Wilcox if (!entry) 1548*371c752dSMatthew Wilcox entry = XA_ZERO_ENTRY; 1549*371c752dSMatthew Wilcox 1550*371c752dSMatthew Wilcox do { 1551*371c752dSMatthew Wilcox xas.xa_index = *id; 1552*371c752dSMatthew Wilcox xas_find_marked(&xas, max, XA_FREE_MARK); 1553*371c752dSMatthew Wilcox if (xas.xa_node == XAS_RESTART) 1554*371c752dSMatthew Wilcox xas_set_err(&xas, -ENOSPC); 1555*371c752dSMatthew Wilcox xas_store(&xas, entry); 1556*371c752dSMatthew Wilcox xas_clear_mark(&xas, XA_FREE_MARK); 1557*371c752dSMatthew Wilcox } while (__xas_nomem(&xas, gfp)); 1558*371c752dSMatthew Wilcox 1559*371c752dSMatthew Wilcox err = xas_error(&xas); 1560*371c752dSMatthew Wilcox if (!err) 1561*371c752dSMatthew Wilcox *id = xas.xa_index; 1562*371c752dSMatthew Wilcox return err; 1563*371c752dSMatthew Wilcox } 1564*371c752dSMatthew Wilcox EXPORT_SYMBOL(__xa_alloc); 1565*371c752dSMatthew Wilcox 1566*371c752dSMatthew Wilcox /** 15679b89a035SMatthew Wilcox * __xa_set_mark() - Set this mark on this entry while locked. 15689b89a035SMatthew Wilcox * @xa: XArray. 15699b89a035SMatthew Wilcox * @index: Index of entry. 15709b89a035SMatthew Wilcox * @mark: Mark number. 15719b89a035SMatthew Wilcox * 15729b89a035SMatthew Wilcox * Attempting to set a mark on a NULL entry does not succeed. 15739b89a035SMatthew Wilcox * 15749b89a035SMatthew Wilcox * Context: Any context. Expects xa_lock to be held on entry. 15759b89a035SMatthew Wilcox */ 15769b89a035SMatthew Wilcox void __xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 15779b89a035SMatthew Wilcox { 15789b89a035SMatthew Wilcox XA_STATE(xas, xa, index); 15799b89a035SMatthew Wilcox void *entry = xas_load(&xas); 15809b89a035SMatthew Wilcox 15819b89a035SMatthew Wilcox if (entry) 15829b89a035SMatthew Wilcox xas_set_mark(&xas, mark); 15839b89a035SMatthew Wilcox } 15849b89a035SMatthew Wilcox EXPORT_SYMBOL_GPL(__xa_set_mark); 15859b89a035SMatthew Wilcox 15869b89a035SMatthew Wilcox /** 15879b89a035SMatthew Wilcox * __xa_clear_mark() - Clear this mark on this entry while locked. 15889b89a035SMatthew Wilcox * @xa: XArray. 15899b89a035SMatthew Wilcox * @index: Index of entry. 15909b89a035SMatthew Wilcox * @mark: Mark number. 15919b89a035SMatthew Wilcox * 15929b89a035SMatthew Wilcox * Context: Any context. Expects xa_lock to be held on entry. 15939b89a035SMatthew Wilcox */ 15949b89a035SMatthew Wilcox void __xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 15959b89a035SMatthew Wilcox { 15969b89a035SMatthew Wilcox XA_STATE(xas, xa, index); 15979b89a035SMatthew Wilcox void *entry = xas_load(&xas); 15989b89a035SMatthew Wilcox 15999b89a035SMatthew Wilcox if (entry) 16009b89a035SMatthew Wilcox xas_clear_mark(&xas, mark); 16019b89a035SMatthew Wilcox } 16029b89a035SMatthew Wilcox EXPORT_SYMBOL_GPL(__xa_clear_mark); 16039b89a035SMatthew Wilcox 16049b89a035SMatthew Wilcox /** 16059b89a035SMatthew Wilcox * xa_get_mark() - Inquire whether this mark is set on this entry. 16069b89a035SMatthew Wilcox * @xa: XArray. 16079b89a035SMatthew Wilcox * @index: Index of entry. 16089b89a035SMatthew Wilcox * @mark: Mark number. 16099b89a035SMatthew Wilcox * 16109b89a035SMatthew Wilcox * This function uses the RCU read lock, so the result may be out of date 16119b89a035SMatthew Wilcox * by the time it returns. If you need the result to be stable, use a lock. 16129b89a035SMatthew Wilcox * 16139b89a035SMatthew Wilcox * Context: Any context. Takes and releases the RCU lock. 16149b89a035SMatthew Wilcox * Return: True if the entry at @index has this mark set, false if it doesn't. 16159b89a035SMatthew Wilcox */ 16169b89a035SMatthew Wilcox bool xa_get_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 16179b89a035SMatthew Wilcox { 16189b89a035SMatthew Wilcox XA_STATE(xas, xa, index); 16199b89a035SMatthew Wilcox void *entry; 16209b89a035SMatthew Wilcox 16219b89a035SMatthew Wilcox rcu_read_lock(); 16229b89a035SMatthew Wilcox entry = xas_start(&xas); 16239b89a035SMatthew Wilcox while (xas_get_mark(&xas, mark)) { 16249b89a035SMatthew Wilcox if (!xa_is_node(entry)) 16259b89a035SMatthew Wilcox goto found; 16269b89a035SMatthew Wilcox entry = xas_descend(&xas, xa_to_node(entry)); 16279b89a035SMatthew Wilcox } 16289b89a035SMatthew Wilcox rcu_read_unlock(); 16299b89a035SMatthew Wilcox return false; 16309b89a035SMatthew Wilcox found: 16319b89a035SMatthew Wilcox rcu_read_unlock(); 16329b89a035SMatthew Wilcox return true; 16339b89a035SMatthew Wilcox } 16349b89a035SMatthew Wilcox EXPORT_SYMBOL(xa_get_mark); 16359b89a035SMatthew Wilcox 16369b89a035SMatthew Wilcox /** 16379b89a035SMatthew Wilcox * xa_set_mark() - Set this mark on this entry. 16389b89a035SMatthew Wilcox * @xa: XArray. 16399b89a035SMatthew Wilcox * @index: Index of entry. 16409b89a035SMatthew Wilcox * @mark: Mark number. 16419b89a035SMatthew Wilcox * 16429b89a035SMatthew Wilcox * Attempting to set a mark on a NULL entry does not succeed. 16439b89a035SMatthew Wilcox * 16449b89a035SMatthew Wilcox * Context: Process context. Takes and releases the xa_lock. 16459b89a035SMatthew Wilcox */ 16469b89a035SMatthew Wilcox void xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 16479b89a035SMatthew Wilcox { 16489b89a035SMatthew Wilcox xa_lock(xa); 16499b89a035SMatthew Wilcox __xa_set_mark(xa, index, mark); 16509b89a035SMatthew Wilcox xa_unlock(xa); 16519b89a035SMatthew Wilcox } 16529b89a035SMatthew Wilcox EXPORT_SYMBOL(xa_set_mark); 16539b89a035SMatthew Wilcox 16549b89a035SMatthew Wilcox /** 16559b89a035SMatthew Wilcox * xa_clear_mark() - Clear this mark on this entry. 16569b89a035SMatthew Wilcox * @xa: XArray. 16579b89a035SMatthew Wilcox * @index: Index of entry. 16589b89a035SMatthew Wilcox * @mark: Mark number. 16599b89a035SMatthew Wilcox * 16609b89a035SMatthew Wilcox * Clearing a mark always succeeds. 16619b89a035SMatthew Wilcox * 16629b89a035SMatthew Wilcox * Context: Process context. Takes and releases the xa_lock. 16639b89a035SMatthew Wilcox */ 16649b89a035SMatthew Wilcox void xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 16659b89a035SMatthew Wilcox { 16669b89a035SMatthew Wilcox xa_lock(xa); 16679b89a035SMatthew Wilcox __xa_clear_mark(xa, index, mark); 16689b89a035SMatthew Wilcox xa_unlock(xa); 16699b89a035SMatthew Wilcox } 16709b89a035SMatthew Wilcox EXPORT_SYMBOL(xa_clear_mark); 16719b89a035SMatthew Wilcox 1672b803b428SMatthew Wilcox /** 1673b803b428SMatthew Wilcox * xa_find() - Search the XArray for an entry. 1674b803b428SMatthew Wilcox * @xa: XArray. 1675b803b428SMatthew Wilcox * @indexp: Pointer to an index. 1676b803b428SMatthew Wilcox * @max: Maximum index to search to. 1677b803b428SMatthew Wilcox * @filter: Selection criterion. 1678b803b428SMatthew Wilcox * 1679b803b428SMatthew Wilcox * Finds the entry in @xa which matches the @filter, and has the lowest 1680b803b428SMatthew Wilcox * index that is at least @indexp and no more than @max. 1681b803b428SMatthew Wilcox * If an entry is found, @indexp is updated to be the index of the entry. 1682b803b428SMatthew Wilcox * This function is protected by the RCU read lock, so it may not find 1683b803b428SMatthew Wilcox * entries which are being simultaneously added. It will not return an 1684b803b428SMatthew Wilcox * %XA_RETRY_ENTRY; if you need to see retry entries, use xas_find(). 1685b803b428SMatthew Wilcox * 1686b803b428SMatthew Wilcox * Context: Any context. Takes and releases the RCU lock. 1687b803b428SMatthew Wilcox * Return: The entry, if found, otherwise %NULL. 1688b803b428SMatthew Wilcox */ 1689b803b428SMatthew Wilcox void *xa_find(struct xarray *xa, unsigned long *indexp, 1690b803b428SMatthew Wilcox unsigned long max, xa_mark_t filter) 1691b803b428SMatthew Wilcox { 1692b803b428SMatthew Wilcox XA_STATE(xas, xa, *indexp); 1693b803b428SMatthew Wilcox void *entry; 1694b803b428SMatthew Wilcox 1695b803b428SMatthew Wilcox rcu_read_lock(); 1696b803b428SMatthew Wilcox do { 1697b803b428SMatthew Wilcox if ((__force unsigned int)filter < XA_MAX_MARKS) 1698b803b428SMatthew Wilcox entry = xas_find_marked(&xas, max, filter); 1699b803b428SMatthew Wilcox else 1700b803b428SMatthew Wilcox entry = xas_find(&xas, max); 1701b803b428SMatthew Wilcox } while (xas_retry(&xas, entry)); 1702b803b428SMatthew Wilcox rcu_read_unlock(); 1703b803b428SMatthew Wilcox 1704b803b428SMatthew Wilcox if (entry) 1705b803b428SMatthew Wilcox *indexp = xas.xa_index; 1706b803b428SMatthew Wilcox return entry; 1707b803b428SMatthew Wilcox } 1708b803b428SMatthew Wilcox EXPORT_SYMBOL(xa_find); 1709b803b428SMatthew Wilcox 1710b803b428SMatthew Wilcox /** 1711b803b428SMatthew Wilcox * xa_find_after() - Search the XArray for a present entry. 1712b803b428SMatthew Wilcox * @xa: XArray. 1713b803b428SMatthew Wilcox * @indexp: Pointer to an index. 1714b803b428SMatthew Wilcox * @max: Maximum index to search to. 1715b803b428SMatthew Wilcox * @filter: Selection criterion. 1716b803b428SMatthew Wilcox * 1717b803b428SMatthew Wilcox * Finds the entry in @xa which matches the @filter and has the lowest 1718b803b428SMatthew Wilcox * index that is above @indexp and no more than @max. 1719b803b428SMatthew Wilcox * If an entry is found, @indexp is updated to be the index of the entry. 1720b803b428SMatthew Wilcox * This function is protected by the RCU read lock, so it may miss entries 1721b803b428SMatthew Wilcox * which are being simultaneously added. It will not return an 1722b803b428SMatthew Wilcox * %XA_RETRY_ENTRY; if you need to see retry entries, use xas_find(). 1723b803b428SMatthew Wilcox * 1724b803b428SMatthew Wilcox * Context: Any context. Takes and releases the RCU lock. 1725b803b428SMatthew Wilcox * Return: The pointer, if found, otherwise %NULL. 1726b803b428SMatthew Wilcox */ 1727b803b428SMatthew Wilcox void *xa_find_after(struct xarray *xa, unsigned long *indexp, 1728b803b428SMatthew Wilcox unsigned long max, xa_mark_t filter) 1729b803b428SMatthew Wilcox { 1730b803b428SMatthew Wilcox XA_STATE(xas, xa, *indexp + 1); 1731b803b428SMatthew Wilcox void *entry; 1732b803b428SMatthew Wilcox 1733b803b428SMatthew Wilcox rcu_read_lock(); 1734b803b428SMatthew Wilcox for (;;) { 1735b803b428SMatthew Wilcox if ((__force unsigned int)filter < XA_MAX_MARKS) 1736b803b428SMatthew Wilcox entry = xas_find_marked(&xas, max, filter); 1737b803b428SMatthew Wilcox else 1738b803b428SMatthew Wilcox entry = xas_find(&xas, max); 1739b803b428SMatthew Wilcox if (xas.xa_shift) { 1740b803b428SMatthew Wilcox if (xas.xa_index & ((1UL << xas.xa_shift) - 1)) 1741b803b428SMatthew Wilcox continue; 1742b803b428SMatthew Wilcox } else { 1743b803b428SMatthew Wilcox if (xas.xa_offset < (xas.xa_index & XA_CHUNK_MASK)) 1744b803b428SMatthew Wilcox continue; 1745b803b428SMatthew Wilcox } 1746b803b428SMatthew Wilcox if (!xas_retry(&xas, entry)) 1747b803b428SMatthew Wilcox break; 1748b803b428SMatthew Wilcox } 1749b803b428SMatthew Wilcox rcu_read_unlock(); 1750b803b428SMatthew Wilcox 1751b803b428SMatthew Wilcox if (entry) 1752b803b428SMatthew Wilcox *indexp = xas.xa_index; 1753b803b428SMatthew Wilcox return entry; 1754b803b428SMatthew Wilcox } 1755b803b428SMatthew Wilcox EXPORT_SYMBOL(xa_find_after); 1756b803b428SMatthew Wilcox 175780a0a1a9SMatthew Wilcox static unsigned int xas_extract_present(struct xa_state *xas, void **dst, 175880a0a1a9SMatthew Wilcox unsigned long max, unsigned int n) 175980a0a1a9SMatthew Wilcox { 176080a0a1a9SMatthew Wilcox void *entry; 176180a0a1a9SMatthew Wilcox unsigned int i = 0; 176280a0a1a9SMatthew Wilcox 176380a0a1a9SMatthew Wilcox rcu_read_lock(); 176480a0a1a9SMatthew Wilcox xas_for_each(xas, entry, max) { 176580a0a1a9SMatthew Wilcox if (xas_retry(xas, entry)) 176680a0a1a9SMatthew Wilcox continue; 176780a0a1a9SMatthew Wilcox dst[i++] = entry; 176880a0a1a9SMatthew Wilcox if (i == n) 176980a0a1a9SMatthew Wilcox break; 177080a0a1a9SMatthew Wilcox } 177180a0a1a9SMatthew Wilcox rcu_read_unlock(); 177280a0a1a9SMatthew Wilcox 177380a0a1a9SMatthew Wilcox return i; 177480a0a1a9SMatthew Wilcox } 177580a0a1a9SMatthew Wilcox 177680a0a1a9SMatthew Wilcox static unsigned int xas_extract_marked(struct xa_state *xas, void **dst, 177780a0a1a9SMatthew Wilcox unsigned long max, unsigned int n, xa_mark_t mark) 177880a0a1a9SMatthew Wilcox { 177980a0a1a9SMatthew Wilcox void *entry; 178080a0a1a9SMatthew Wilcox unsigned int i = 0; 178180a0a1a9SMatthew Wilcox 178280a0a1a9SMatthew Wilcox rcu_read_lock(); 178380a0a1a9SMatthew Wilcox xas_for_each_marked(xas, entry, max, mark) { 178480a0a1a9SMatthew Wilcox if (xas_retry(xas, entry)) 178580a0a1a9SMatthew Wilcox continue; 178680a0a1a9SMatthew Wilcox dst[i++] = entry; 178780a0a1a9SMatthew Wilcox if (i == n) 178880a0a1a9SMatthew Wilcox break; 178980a0a1a9SMatthew Wilcox } 179080a0a1a9SMatthew Wilcox rcu_read_unlock(); 179180a0a1a9SMatthew Wilcox 179280a0a1a9SMatthew Wilcox return i; 179380a0a1a9SMatthew Wilcox } 179480a0a1a9SMatthew Wilcox 179580a0a1a9SMatthew Wilcox /** 179680a0a1a9SMatthew Wilcox * xa_extract() - Copy selected entries from the XArray into a normal array. 179780a0a1a9SMatthew Wilcox * @xa: The source XArray to copy from. 179880a0a1a9SMatthew Wilcox * @dst: The buffer to copy entries into. 179980a0a1a9SMatthew Wilcox * @start: The first index in the XArray eligible to be selected. 180080a0a1a9SMatthew Wilcox * @max: The last index in the XArray eligible to be selected. 180180a0a1a9SMatthew Wilcox * @n: The maximum number of entries to copy. 180280a0a1a9SMatthew Wilcox * @filter: Selection criterion. 180380a0a1a9SMatthew Wilcox * 180480a0a1a9SMatthew Wilcox * Copies up to @n entries that match @filter from the XArray. The 180580a0a1a9SMatthew Wilcox * copied entries will have indices between @start and @max, inclusive. 180680a0a1a9SMatthew Wilcox * 180780a0a1a9SMatthew Wilcox * The @filter may be an XArray mark value, in which case entries which are 180880a0a1a9SMatthew Wilcox * marked with that mark will be copied. It may also be %XA_PRESENT, in 180980a0a1a9SMatthew Wilcox * which case all entries which are not NULL will be copied. 181080a0a1a9SMatthew Wilcox * 181180a0a1a9SMatthew Wilcox * The entries returned may not represent a snapshot of the XArray at a 181280a0a1a9SMatthew Wilcox * moment in time. For example, if another thread stores to index 5, then 181380a0a1a9SMatthew Wilcox * index 10, calling xa_extract() may return the old contents of index 5 181480a0a1a9SMatthew Wilcox * and the new contents of index 10. Indices not modified while this 181580a0a1a9SMatthew Wilcox * function is running will not be skipped. 181680a0a1a9SMatthew Wilcox * 181780a0a1a9SMatthew Wilcox * If you need stronger guarantees, holding the xa_lock across calls to this 181880a0a1a9SMatthew Wilcox * function will prevent concurrent modification. 181980a0a1a9SMatthew Wilcox * 182080a0a1a9SMatthew Wilcox * Context: Any context. Takes and releases the RCU lock. 182180a0a1a9SMatthew Wilcox * Return: The number of entries copied. 182280a0a1a9SMatthew Wilcox */ 182380a0a1a9SMatthew Wilcox unsigned int xa_extract(struct xarray *xa, void **dst, unsigned long start, 182480a0a1a9SMatthew Wilcox unsigned long max, unsigned int n, xa_mark_t filter) 182580a0a1a9SMatthew Wilcox { 182680a0a1a9SMatthew Wilcox XA_STATE(xas, xa, start); 182780a0a1a9SMatthew Wilcox 182880a0a1a9SMatthew Wilcox if (!n) 182980a0a1a9SMatthew Wilcox return 0; 183080a0a1a9SMatthew Wilcox 183180a0a1a9SMatthew Wilcox if ((__force unsigned int)filter < XA_MAX_MARKS) 183280a0a1a9SMatthew Wilcox return xas_extract_marked(&xas, dst, max, n, filter); 183380a0a1a9SMatthew Wilcox return xas_extract_present(&xas, dst, max, n); 183480a0a1a9SMatthew Wilcox } 183580a0a1a9SMatthew Wilcox EXPORT_SYMBOL(xa_extract); 183680a0a1a9SMatthew Wilcox 1837687149fcSMatthew Wilcox /** 1838687149fcSMatthew Wilcox * xa_destroy() - Free all internal data structures. 1839687149fcSMatthew Wilcox * @xa: XArray. 1840687149fcSMatthew Wilcox * 1841687149fcSMatthew Wilcox * After calling this function, the XArray is empty and has freed all memory 1842687149fcSMatthew Wilcox * allocated for its internal data structures. You are responsible for 1843687149fcSMatthew Wilcox * freeing the objects referenced by the XArray. 1844687149fcSMatthew Wilcox * 1845687149fcSMatthew Wilcox * Context: Any context. Takes and releases the xa_lock, interrupt-safe. 1846687149fcSMatthew Wilcox */ 1847687149fcSMatthew Wilcox void xa_destroy(struct xarray *xa) 1848687149fcSMatthew Wilcox { 1849687149fcSMatthew Wilcox XA_STATE(xas, xa, 0); 1850687149fcSMatthew Wilcox unsigned long flags; 1851687149fcSMatthew Wilcox void *entry; 1852687149fcSMatthew Wilcox 1853687149fcSMatthew Wilcox xas.xa_node = NULL; 1854687149fcSMatthew Wilcox xas_lock_irqsave(&xas, flags); 1855687149fcSMatthew Wilcox entry = xa_head_locked(xa); 1856687149fcSMatthew Wilcox RCU_INIT_POINTER(xa->xa_head, NULL); 1857687149fcSMatthew Wilcox xas_init_marks(&xas); 1858687149fcSMatthew Wilcox /* lockdep checks we're still holding the lock in xas_free_nodes() */ 1859687149fcSMatthew Wilcox if (xa_is_node(entry)) 1860687149fcSMatthew Wilcox xas_free_nodes(&xas, xa_to_node(entry)); 1861687149fcSMatthew Wilcox xas_unlock_irqrestore(&xas, flags); 1862687149fcSMatthew Wilcox } 1863687149fcSMatthew Wilcox EXPORT_SYMBOL(xa_destroy); 1864687149fcSMatthew Wilcox 1865ad3d6c72SMatthew Wilcox #ifdef XA_DEBUG 1866ad3d6c72SMatthew Wilcox void xa_dump_node(const struct xa_node *node) 1867ad3d6c72SMatthew Wilcox { 1868ad3d6c72SMatthew Wilcox unsigned i, j; 1869ad3d6c72SMatthew Wilcox 1870ad3d6c72SMatthew Wilcox if (!node) 1871ad3d6c72SMatthew Wilcox return; 1872ad3d6c72SMatthew Wilcox if ((unsigned long)node & 3) { 1873ad3d6c72SMatthew Wilcox pr_cont("node %px\n", node); 1874ad3d6c72SMatthew Wilcox return; 1875ad3d6c72SMatthew Wilcox } 1876ad3d6c72SMatthew Wilcox 1877ad3d6c72SMatthew Wilcox pr_cont("node %px %s %d parent %px shift %d count %d values %d " 1878ad3d6c72SMatthew Wilcox "array %px list %px %px marks", 1879ad3d6c72SMatthew Wilcox node, node->parent ? "offset" : "max", node->offset, 1880ad3d6c72SMatthew Wilcox node->parent, node->shift, node->count, node->nr_values, 1881ad3d6c72SMatthew Wilcox node->array, node->private_list.prev, node->private_list.next); 1882ad3d6c72SMatthew Wilcox for (i = 0; i < XA_MAX_MARKS; i++) 1883ad3d6c72SMatthew Wilcox for (j = 0; j < XA_MARK_LONGS; j++) 1884ad3d6c72SMatthew Wilcox pr_cont(" %lx", node->marks[i][j]); 1885ad3d6c72SMatthew Wilcox pr_cont("\n"); 1886ad3d6c72SMatthew Wilcox } 1887ad3d6c72SMatthew Wilcox 1888ad3d6c72SMatthew Wilcox void xa_dump_index(unsigned long index, unsigned int shift) 1889ad3d6c72SMatthew Wilcox { 1890ad3d6c72SMatthew Wilcox if (!shift) 1891ad3d6c72SMatthew Wilcox pr_info("%lu: ", index); 1892ad3d6c72SMatthew Wilcox else if (shift >= BITS_PER_LONG) 1893ad3d6c72SMatthew Wilcox pr_info("0-%lu: ", ~0UL); 1894ad3d6c72SMatthew Wilcox else 1895ad3d6c72SMatthew Wilcox pr_info("%lu-%lu: ", index, index | ((1UL << shift) - 1)); 1896ad3d6c72SMatthew Wilcox } 1897ad3d6c72SMatthew Wilcox 1898ad3d6c72SMatthew Wilcox void xa_dump_entry(const void *entry, unsigned long index, unsigned long shift) 1899ad3d6c72SMatthew Wilcox { 1900ad3d6c72SMatthew Wilcox if (!entry) 1901ad3d6c72SMatthew Wilcox return; 1902ad3d6c72SMatthew Wilcox 1903ad3d6c72SMatthew Wilcox xa_dump_index(index, shift); 1904ad3d6c72SMatthew Wilcox 1905ad3d6c72SMatthew Wilcox if (xa_is_node(entry)) { 1906ad3d6c72SMatthew Wilcox if (shift == 0) { 1907ad3d6c72SMatthew Wilcox pr_cont("%px\n", entry); 1908ad3d6c72SMatthew Wilcox } else { 1909ad3d6c72SMatthew Wilcox unsigned long i; 1910ad3d6c72SMatthew Wilcox struct xa_node *node = xa_to_node(entry); 1911ad3d6c72SMatthew Wilcox xa_dump_node(node); 1912ad3d6c72SMatthew Wilcox for (i = 0; i < XA_CHUNK_SIZE; i++) 1913ad3d6c72SMatthew Wilcox xa_dump_entry(node->slots[i], 1914ad3d6c72SMatthew Wilcox index + (i << node->shift), node->shift); 1915ad3d6c72SMatthew Wilcox } 1916ad3d6c72SMatthew Wilcox } else if (xa_is_value(entry)) 1917ad3d6c72SMatthew Wilcox pr_cont("value %ld (0x%lx) [%px]\n", xa_to_value(entry), 1918ad3d6c72SMatthew Wilcox xa_to_value(entry), entry); 1919ad3d6c72SMatthew Wilcox else if (!xa_is_internal(entry)) 1920ad3d6c72SMatthew Wilcox pr_cont("%px\n", entry); 1921ad3d6c72SMatthew Wilcox else if (xa_is_retry(entry)) 1922ad3d6c72SMatthew Wilcox pr_cont("retry (%ld)\n", xa_to_internal(entry)); 1923ad3d6c72SMatthew Wilcox else if (xa_is_sibling(entry)) 1924ad3d6c72SMatthew Wilcox pr_cont("sibling (slot %ld)\n", xa_to_sibling(entry)); 19259f14d4f1SMatthew Wilcox else if (xa_is_zero(entry)) 19269f14d4f1SMatthew Wilcox pr_cont("zero (%ld)\n", xa_to_internal(entry)); 1927ad3d6c72SMatthew Wilcox else 1928ad3d6c72SMatthew Wilcox pr_cont("UNKNOWN ENTRY (%px)\n", entry); 1929ad3d6c72SMatthew Wilcox } 1930ad3d6c72SMatthew Wilcox 1931ad3d6c72SMatthew Wilcox void xa_dump(const struct xarray *xa) 1932ad3d6c72SMatthew Wilcox { 1933ad3d6c72SMatthew Wilcox void *entry = xa->xa_head; 1934ad3d6c72SMatthew Wilcox unsigned int shift = 0; 1935ad3d6c72SMatthew Wilcox 1936ad3d6c72SMatthew Wilcox pr_info("xarray: %px head %px flags %x marks %d %d %d\n", xa, entry, 19379b89a035SMatthew Wilcox xa->xa_flags, xa_marked(xa, XA_MARK_0), 19389b89a035SMatthew Wilcox xa_marked(xa, XA_MARK_1), xa_marked(xa, XA_MARK_2)); 1939ad3d6c72SMatthew Wilcox if (xa_is_node(entry)) 1940ad3d6c72SMatthew Wilcox shift = xa_to_node(entry)->shift + XA_CHUNK_SHIFT; 1941ad3d6c72SMatthew Wilcox xa_dump_entry(entry, 0, shift); 1942ad3d6c72SMatthew Wilcox } 1943ad3d6c72SMatthew Wilcox #endif 1944