Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xarray: Add XArray marks

XArray marks are like the radix tree tags, only slightly more strongly
typed. They are renamed in order to distinguish them from tagged
pointers. This commit adds the basic get/set/clear operations.

Signed-off-by: Matthew Wilcox <willy@infradead.org>

+444 -12
+63
include/linux/xarray.h
··· 11 11 12 12 #include <linux/bug.h> 13 13 #include <linux/compiler.h> 14 + #include <linux/gfp.h> 14 15 #include <linux/kconfig.h> 15 16 #include <linux/kernel.h> 16 17 #include <linux/rcupdate.h> ··· 198 197 return 0; 199 198 } 200 199 200 + typedef unsigned __bitwise xa_mark_t; 201 + #define XA_MARK_0 ((__force xa_mark_t)0U) 202 + #define XA_MARK_1 ((__force xa_mark_t)1U) 203 + #define XA_MARK_2 ((__force xa_mark_t)2U) 204 + #define XA_PRESENT ((__force xa_mark_t)8U) 205 + #define XA_MARK_MAX XA_MARK_2 206 + 207 + /* 208 + * Values for xa_flags. The radix tree stores its GFP flags in the xa_flags, 209 + * and we remain compatible with that. 210 + */ 211 + #define XA_FLAGS_MARK(mark) ((__force gfp_t)((1U << __GFP_BITS_SHIFT) << \ 212 + (__force unsigned)(mark))) 213 + 201 214 /** 202 215 * struct xarray - The anchor of the XArray. 203 216 * @xa_lock: Lock that protects the contents of the XArray. ··· 267 252 268 253 void xa_init_flags(struct xarray *, gfp_t flags); 269 254 void *xa_load(struct xarray *, unsigned long index); 255 + bool xa_get_mark(struct xarray *, unsigned long index, xa_mark_t); 256 + void xa_set_mark(struct xarray *, unsigned long index, xa_mark_t); 257 + void xa_clear_mark(struct xarray *, unsigned long index, xa_mark_t); 270 258 271 259 /** 272 260 * xa_init() - Initialise an empty XArray. ··· 296 278 return xa->xa_head == NULL; 297 279 } 298 280 281 + /** 282 + * xa_marked() - Inquire whether any entry in this array has a mark set 283 + * @xa: Array 284 + * @mark: Mark value 285 + * 286 + * Context: Any context. 287 + * Return: %true if any entry has this mark set. 288 + */ 289 + static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark) 290 + { 291 + return xa->xa_flags & XA_FLAGS_MARK(mark); 292 + } 293 + 299 294 #define xa_trylock(xa) spin_trylock(&(xa)->xa_lock) 300 295 #define xa_lock(xa) spin_lock(&(xa)->xa_lock) 301 296 #define xa_unlock(xa) spin_unlock(&(xa)->xa_lock) ··· 320 289 spin_lock_irqsave(&(xa)->xa_lock, flags) 321 290 #define xa_unlock_irqrestore(xa, flags) \ 322 291 spin_unlock_irqrestore(&(xa)->xa_lock, flags) 292 + 293 + /* 294 + * Versions of the normal API which require the caller to hold the xa_lock. 295 + */ 296 + void __xa_set_mark(struct xarray *, unsigned long index, xa_mark_t); 297 + void __xa_clear_mark(struct xarray *, unsigned long index, xa_mark_t); 323 298 324 299 /* Everything below here is the Advanced API. Proceed with caution. */ 325 300 ··· 422 385 { 423 386 XA_NODE_BUG_ON(node, offset >= XA_CHUNK_SIZE); 424 387 return rcu_dereference_protected(node->slots[offset], 388 + lockdep_is_held(&xa->xa_lock)); 389 + } 390 + 391 + /* Private */ 392 + static inline struct xa_node *xa_parent(const struct xarray *xa, 393 + const struct xa_node *node) 394 + { 395 + return rcu_dereference_check(node->parent, 396 + lockdep_is_held(&xa->xa_lock)); 397 + } 398 + 399 + /* Private */ 400 + static inline struct xa_node *xa_parent_locked(const struct xarray *xa, 401 + const struct xa_node *node) 402 + { 403 + return rcu_dereference_protected(node->parent, 425 404 lockdep_is_held(&xa->xa_lock)); 426 405 } 427 406 ··· 641 588 return !xas_invalid(xas); 642 589 } 643 590 591 + /* True if the pointer is something other than a node */ 592 + static inline bool xas_not_node(struct xa_node *node) 593 + { 594 + return ((unsigned long)node & 3) || !node; 595 + } 596 + 644 597 /** 645 598 * xas_reset() - Reset an XArray operation state. 646 599 * @xas: XArray operation state. ··· 683 624 } 684 625 685 626 void *xas_load(struct xa_state *); 627 + 628 + bool xas_get_mark(const struct xa_state *, xa_mark_t); 629 + void xas_set_mark(const struct xa_state *, xa_mark_t); 630 + void xas_clear_mark(const struct xa_state *, xa_mark_t); 686 631 687 632 /** 688 633 * xas_reload() - Refetch an entry from the xarray.
+34
lib/test_xarray.c
··· 67 67 XA_BUG_ON(xa, !xa_empty(xa)); 68 68 } 69 69 70 + static noinline void check_xa_mark_1(struct xarray *xa, unsigned long index) 71 + { 72 + /* NULL elements have no marks set */ 73 + XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 74 + xa_set_mark(xa, index, XA_MARK_0); 75 + XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 76 + 77 + /* Storing a pointer will not make a mark appear */ 78 + XA_BUG_ON(xa, xa_store_index(xa, index, GFP_KERNEL) != NULL); 79 + XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 80 + xa_set_mark(xa, index, XA_MARK_0); 81 + XA_BUG_ON(xa, !xa_get_mark(xa, index, XA_MARK_0)); 82 + 83 + /* Setting one mark will not set another mark */ 84 + XA_BUG_ON(xa, xa_get_mark(xa, index + 1, XA_MARK_0)); 85 + XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_1)); 86 + 87 + /* Storing NULL clears marks, and they can't be set again */ 88 + xa_erase_index(xa, index); 89 + XA_BUG_ON(xa, !xa_empty(xa)); 90 + XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 91 + xa_set_mark(xa, index, XA_MARK_0); 92 + XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 93 + } 94 + 95 + static noinline void check_xa_mark(struct xarray *xa) 96 + { 97 + unsigned long index; 98 + 99 + for (index = 0; index < 16384; index += 4) 100 + check_xa_mark_1(xa, index); 101 + } 102 + 70 103 static RADIX_TREE(array, GFP_KERNEL); 71 104 72 105 static int xarray_checks(void) 73 106 { 74 107 check_xa_load(&array); 108 + check_xa_mark(&array); 75 109 76 110 printk("XArray: %u of %u tests passed\n", tests_passed, tests_run); 77 111 return (tests_run == tests_passed) ? 0 : -EINVAL;
+230 -2
lib/xarray.c
··· 5 5 * Author: Matthew Wilcox <willy@infradead.org> 6 6 */ 7 7 8 + #include <linux/bitmap.h> 8 9 #include <linux/export.h> 9 10 #include <linux/xarray.h> 10 11 ··· 24 23 * @parent refers to the @xa_node closer to the head than @node. 25 24 * @entry refers to something stored in a slot in the xarray 26 25 */ 26 + 27 + static inline void xa_mark_set(struct xarray *xa, xa_mark_t mark) 28 + { 29 + if (!(xa->xa_flags & XA_FLAGS_MARK(mark))) 30 + xa->xa_flags |= XA_FLAGS_MARK(mark); 31 + } 32 + 33 + static inline void xa_mark_clear(struct xarray *xa, xa_mark_t mark) 34 + { 35 + if (xa->xa_flags & XA_FLAGS_MARK(mark)) 36 + xa->xa_flags &= ~(XA_FLAGS_MARK(mark)); 37 + } 38 + 39 + static inline unsigned long *node_marks(struct xa_node *node, xa_mark_t mark) 40 + { 41 + return node->marks[(__force unsigned)mark]; 42 + } 43 + 44 + static inline bool node_get_mark(struct xa_node *node, 45 + unsigned int offset, xa_mark_t mark) 46 + { 47 + return test_bit(offset, node_marks(node, mark)); 48 + } 49 + 50 + /* returns true if the bit was set */ 51 + static inline bool node_set_mark(struct xa_node *node, unsigned int offset, 52 + xa_mark_t mark) 53 + { 54 + return __test_and_set_bit(offset, node_marks(node, mark)); 55 + } 56 + 57 + /* returns true if the bit was set */ 58 + static inline bool node_clear_mark(struct xa_node *node, unsigned int offset, 59 + xa_mark_t mark) 60 + { 61 + return __test_and_clear_bit(offset, node_marks(node, mark)); 62 + } 63 + 64 + static inline bool node_any_mark(struct xa_node *node, xa_mark_t mark) 65 + { 66 + return !bitmap_empty(node_marks(node, mark), XA_CHUNK_SIZE); 67 + } 27 68 28 69 /* extracts the offset within this node from the index */ 29 70 static unsigned int get_offset(unsigned long index, struct xa_node *node) ··· 162 119 EXPORT_SYMBOL_GPL(xas_load); 163 120 164 121 /** 122 + * xas_get_mark() - Returns the state of this mark. 123 + * @xas: XArray operation state. 124 + * @mark: Mark number. 125 + * 126 + * Return: true if the mark is set, false if the mark is clear or @xas 127 + * is in an error state. 128 + */ 129 + bool xas_get_mark(const struct xa_state *xas, xa_mark_t mark) 130 + { 131 + if (xas_invalid(xas)) 132 + return false; 133 + if (!xas->xa_node) 134 + return xa_marked(xas->xa, mark); 135 + return node_get_mark(xas->xa_node, xas->xa_offset, mark); 136 + } 137 + EXPORT_SYMBOL_GPL(xas_get_mark); 138 + 139 + /** 140 + * xas_set_mark() - Sets the mark on this entry and its parents. 141 + * @xas: XArray operation state. 142 + * @mark: Mark number. 143 + * 144 + * Sets the specified mark on this entry, and walks up the tree setting it 145 + * on all the ancestor entries. Does nothing if @xas has not been walked to 146 + * an entry, or is in an error state. 147 + */ 148 + void xas_set_mark(const struct xa_state *xas, xa_mark_t mark) 149 + { 150 + struct xa_node *node = xas->xa_node; 151 + unsigned int offset = xas->xa_offset; 152 + 153 + if (xas_invalid(xas)) 154 + return; 155 + 156 + while (node) { 157 + if (node_set_mark(node, offset, mark)) 158 + return; 159 + offset = node->offset; 160 + node = xa_parent_locked(xas->xa, node); 161 + } 162 + 163 + if (!xa_marked(xas->xa, mark)) 164 + xa_mark_set(xas->xa, mark); 165 + } 166 + EXPORT_SYMBOL_GPL(xas_set_mark); 167 + 168 + /** 169 + * xas_clear_mark() - Clears the mark on this entry and its parents. 170 + * @xas: XArray operation state. 171 + * @mark: Mark number. 172 + * 173 + * Clears the specified mark on this entry, and walks back to the head 174 + * attempting to clear it on all the ancestor entries. Does nothing if 175 + * @xas has not been walked to an entry, or is in an error state. 176 + */ 177 + void xas_clear_mark(const struct xa_state *xas, xa_mark_t mark) 178 + { 179 + struct xa_node *node = xas->xa_node; 180 + unsigned int offset = xas->xa_offset; 181 + 182 + if (xas_invalid(xas)) 183 + return; 184 + 185 + while (node) { 186 + if (!node_clear_mark(node, offset, mark)) 187 + return; 188 + if (node_any_mark(node, mark)) 189 + return; 190 + 191 + offset = node->offset; 192 + node = xa_parent_locked(xas->xa, node); 193 + } 194 + 195 + if (xa_marked(xas->xa, mark)) 196 + xa_mark_clear(xas->xa, mark); 197 + } 198 + EXPORT_SYMBOL_GPL(xas_clear_mark); 199 + 200 + /** 165 201 * xa_init_flags() - Initialise an empty XArray with flags. 166 202 * @xa: XArray. 167 203 * @flags: XA_FLAG values. ··· 281 159 return entry; 282 160 } 283 161 EXPORT_SYMBOL(xa_load); 162 + 163 + /** 164 + * __xa_set_mark() - Set this mark on this entry while locked. 165 + * @xa: XArray. 166 + * @index: Index of entry. 167 + * @mark: Mark number. 168 + * 169 + * Attempting to set a mark on a NULL entry does not succeed. 170 + * 171 + * Context: Any context. Expects xa_lock to be held on entry. 172 + */ 173 + void __xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 174 + { 175 + XA_STATE(xas, xa, index); 176 + void *entry = xas_load(&xas); 177 + 178 + if (entry) 179 + xas_set_mark(&xas, mark); 180 + } 181 + EXPORT_SYMBOL_GPL(__xa_set_mark); 182 + 183 + /** 184 + * __xa_clear_mark() - Clear this mark on this entry while locked. 185 + * @xa: XArray. 186 + * @index: Index of entry. 187 + * @mark: Mark number. 188 + * 189 + * Context: Any context. Expects xa_lock to be held on entry. 190 + */ 191 + void __xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 192 + { 193 + XA_STATE(xas, xa, index); 194 + void *entry = xas_load(&xas); 195 + 196 + if (entry) 197 + xas_clear_mark(&xas, mark); 198 + } 199 + EXPORT_SYMBOL_GPL(__xa_clear_mark); 200 + 201 + /** 202 + * xa_get_mark() - Inquire whether this mark is set on this entry. 203 + * @xa: XArray. 204 + * @index: Index of entry. 205 + * @mark: Mark number. 206 + * 207 + * This function uses the RCU read lock, so the result may be out of date 208 + * by the time it returns. If you need the result to be stable, use a lock. 209 + * 210 + * Context: Any context. Takes and releases the RCU lock. 211 + * Return: True if the entry at @index has this mark set, false if it doesn't. 212 + */ 213 + bool xa_get_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 214 + { 215 + XA_STATE(xas, xa, index); 216 + void *entry; 217 + 218 + rcu_read_lock(); 219 + entry = xas_start(&xas); 220 + while (xas_get_mark(&xas, mark)) { 221 + if (!xa_is_node(entry)) 222 + goto found; 223 + entry = xas_descend(&xas, xa_to_node(entry)); 224 + } 225 + rcu_read_unlock(); 226 + return false; 227 + found: 228 + rcu_read_unlock(); 229 + return true; 230 + } 231 + EXPORT_SYMBOL(xa_get_mark); 232 + 233 + /** 234 + * xa_set_mark() - Set this mark on this entry. 235 + * @xa: XArray. 236 + * @index: Index of entry. 237 + * @mark: Mark number. 238 + * 239 + * Attempting to set a mark on a NULL entry does not succeed. 240 + * 241 + * Context: Process context. Takes and releases the xa_lock. 242 + */ 243 + void xa_set_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 244 + { 245 + xa_lock(xa); 246 + __xa_set_mark(xa, index, mark); 247 + xa_unlock(xa); 248 + } 249 + EXPORT_SYMBOL(xa_set_mark); 250 + 251 + /** 252 + * xa_clear_mark() - Clear this mark on this entry. 253 + * @xa: XArray. 254 + * @index: Index of entry. 255 + * @mark: Mark number. 256 + * 257 + * Clearing a mark always succeeds. 258 + * 259 + * Context: Process context. Takes and releases the xa_lock. 260 + */ 261 + void xa_clear_mark(struct xarray *xa, unsigned long index, xa_mark_t mark) 262 + { 263 + xa_lock(xa); 264 + __xa_clear_mark(xa, index, mark); 265 + xa_unlock(xa); 266 + } 267 + EXPORT_SYMBOL(xa_clear_mark); 284 268 285 269 #ifdef XA_DEBUG 286 270 void xa_dump_node(const struct xa_node *node) ··· 458 230 unsigned int shift = 0; 459 231 460 232 pr_info("xarray: %px head %px flags %x marks %d %d %d\n", xa, entry, 461 - xa->xa_flags, radix_tree_tagged(xa, 0), 462 - radix_tree_tagged(xa, 1), radix_tree_tagged(xa, 2)); 233 + xa->xa_flags, xa_marked(xa, XA_MARK_0), 234 + xa_marked(xa, XA_MARK_1), xa_marked(xa, XA_MARK_2)); 463 235 if (xa_is_node(entry)) 464 236 shift = xa_to_node(entry)->shift + XA_CHUNK_SHIFT; 465 237 xa_dump_entry(entry, 0, shift);
+1
tools/include/asm-generic/bitops.h
··· 27 27 #include <asm-generic/bitops/hweight.h> 28 28 29 29 #include <asm-generic/bitops/atomic.h> 30 + #include <asm-generic/bitops/non-atomic.h> 30 31 31 32 #endif /* __TOOLS_ASM_GENERIC_BITOPS_H */
-9
tools/include/asm-generic/bitops/atomic.h
··· 15 15 addr[nr / __BITS_PER_LONG] &= ~(1UL << (nr % __BITS_PER_LONG)); 16 16 } 17 17 18 - static __always_inline int test_bit(unsigned int nr, const unsigned long *addr) 19 - { 20 - return ((1UL << (nr % __BITS_PER_LONG)) & 21 - (((unsigned long *)addr)[nr / __BITS_PER_LONG])) != 0; 22 - } 23 - 24 - #define __set_bit(nr, addr) set_bit(nr, addr) 25 - #define __clear_bit(nr, addr) clear_bit(nr, addr) 26 - 27 18 #endif /* _TOOLS_LINUX_ASM_GENERIC_BITOPS_ATOMIC_H_ */
+109
tools/include/asm-generic/bitops/non-atomic.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ 3 + #define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ 4 + 5 + #include <asm/types.h> 6 + 7 + /** 8 + * __set_bit - Set a bit in memory 9 + * @nr: the bit to set 10 + * @addr: the address to start counting from 11 + * 12 + * Unlike set_bit(), this function is non-atomic and may be reordered. 13 + * If it's called on the same region of memory simultaneously, the effect 14 + * may be that only one operation succeeds. 15 + */ 16 + static inline void __set_bit(int nr, volatile unsigned long *addr) 17 + { 18 + unsigned long mask = BIT_MASK(nr); 19 + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 20 + 21 + *p |= mask; 22 + } 23 + 24 + static inline void __clear_bit(int nr, volatile unsigned long *addr) 25 + { 26 + unsigned long mask = BIT_MASK(nr); 27 + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 28 + 29 + *p &= ~mask; 30 + } 31 + 32 + /** 33 + * __change_bit - Toggle a bit in memory 34 + * @nr: the bit to change 35 + * @addr: the address to start counting from 36 + * 37 + * Unlike change_bit(), this function is non-atomic and may be reordered. 38 + * If it's called on the same region of memory simultaneously, the effect 39 + * may be that only one operation succeeds. 40 + */ 41 + static inline void __change_bit(int nr, volatile unsigned long *addr) 42 + { 43 + unsigned long mask = BIT_MASK(nr); 44 + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 45 + 46 + *p ^= mask; 47 + } 48 + 49 + /** 50 + * __test_and_set_bit - Set a bit and return its old value 51 + * @nr: Bit to set 52 + * @addr: Address to count from 53 + * 54 + * This operation is non-atomic and can be reordered. 55 + * If two examples of this operation race, one can appear to succeed 56 + * but actually fail. You must protect multiple accesses with a lock. 57 + */ 58 + static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) 59 + { 60 + unsigned long mask = BIT_MASK(nr); 61 + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 62 + unsigned long old = *p; 63 + 64 + *p = old | mask; 65 + return (old & mask) != 0; 66 + } 67 + 68 + /** 69 + * __test_and_clear_bit - Clear a bit and return its old value 70 + * @nr: Bit to clear 71 + * @addr: Address to count from 72 + * 73 + * This operation is non-atomic and can be reordered. 74 + * If two examples of this operation race, one can appear to succeed 75 + * but actually fail. You must protect multiple accesses with a lock. 76 + */ 77 + static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) 78 + { 79 + unsigned long mask = BIT_MASK(nr); 80 + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 81 + unsigned long old = *p; 82 + 83 + *p = old & ~mask; 84 + return (old & mask) != 0; 85 + } 86 + 87 + /* WARNING: non atomic and it can be reordered! */ 88 + static inline int __test_and_change_bit(int nr, 89 + volatile unsigned long *addr) 90 + { 91 + unsigned long mask = BIT_MASK(nr); 92 + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 93 + unsigned long old = *p; 94 + 95 + *p = old ^ mask; 96 + return (old & mask) != 0; 97 + } 98 + 99 + /** 100 + * test_bit - Determine whether a bit is set 101 + * @nr: bit number to test 102 + * @addr: Address to start counting from 103 + */ 104 + static inline int test_bit(int nr, const volatile unsigned long *addr) 105 + { 106 + return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); 107 + } 108 + 109 + #endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */
+7 -1
tools/include/linux/spinlock.h
··· 8 8 #define spinlock_t pthread_mutex_t 9 9 #define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER 10 10 #define __SPIN_LOCK_UNLOCKED(x) (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER 11 - #define spin_lock_init(x) pthread_mutex_init(x, NULL) 11 + #define spin_lock_init(x) pthread_mutex_init(x, NULL) 12 12 13 + #define spin_lock(x) pthread_mutex_lock(x) 14 + #define spin_unlock(x) pthread_mutex_unlock(x) 15 + #define spin_lock_bh(x) pthread_mutex_lock(x) 16 + #define spin_unlock_bh(x) pthread_mutex_unlock(x) 17 + #define spin_lock_irq(x) pthread_mutex_lock(x) 18 + #define spin_unlock_irq(x) pthread_mutex_unlock(x) 13 19 #define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) 14 20 #define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) 15 21