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

lib/generic-radix-tree.c: add preallocation

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

+37 -17
+32 -6
include/linux/generic-radix-tree.h
··· 41 41 #include <linux/limits.h> 42 42 #include <linux/log2.h> 43 43 #include <linux/math.h> 44 + #include <linux/slab.h> 44 45 #include <linux/types.h> 45 46 46 47 struct genradix_root; ··· 82 81 return (void *) ((unsigned long) r & ~GENRADIX_DEPTH_MASK); 83 82 } 84 83 84 + struct __genradix { 85 + struct genradix_root *root; 86 + }; 87 + 85 88 struct genradix_node { 86 89 union { 87 90 /* Interior node: */ ··· 96 91 }; 97 92 }; 98 93 99 - struct __genradix { 100 - struct genradix_root *root; 101 - }; 94 + static inline struct genradix_node *genradix_alloc_node(gfp_t gfp_mask) 95 + { 96 + return kzalloc(GENRADIX_NODE_SIZE, gfp_mask); 97 + } 98 + 99 + static inline void genradix_free_node(struct genradix_node *node) 100 + { 101 + kfree(node); 102 + } 102 103 103 104 /* 104 105 * NOTE: currently, sizeof(_type) must not be larger than GENRADIX_NODE_SIZE: ··· 220 209 __genradix_ptr(&(_radix)->tree, \ 221 210 __genradix_idx_to_offset(_radix, _idx))) 222 211 223 - void *__genradix_ptr_alloc(struct __genradix *, size_t, gfp_t); 212 + void *__genradix_ptr_alloc(struct __genradix *, size_t, 213 + struct genradix_node **, gfp_t); 224 214 225 215 #define genradix_ptr_alloc_inlined(_radix, _idx, _gfp) \ 226 216 (__genradix_cast(_radix) \ ··· 229 217 __genradix_idx_to_offset(_radix, _idx)) ?: \ 230 218 __genradix_ptr_alloc(&(_radix)->tree, \ 231 219 __genradix_idx_to_offset(_radix, _idx), \ 232 - _gfp))) 220 + NULL, _gfp))) 221 + 222 + #define genradix_ptr_alloc_preallocated_inlined(_radix, _idx, _new_node, _gfp)\ 223 + (__genradix_cast(_radix) \ 224 + (__genradix_ptr_inlined(&(_radix)->tree, \ 225 + __genradix_idx_to_offset(_radix, _idx)) ?: \ 226 + __genradix_ptr_alloc(&(_radix)->tree, \ 227 + __genradix_idx_to_offset(_radix, _idx), \ 228 + _new_node, _gfp))) 233 229 234 230 /** 235 231 * genradix_ptr_alloc - get a pointer to a genradix entry, allocating it ··· 252 232 (__genradix_cast(_radix) \ 253 233 __genradix_ptr_alloc(&(_radix)->tree, \ 254 234 __genradix_idx_to_offset(_radix, _idx), \ 255 - _gfp)) 235 + NULL, _gfp)) 236 + 237 + #define genradix_ptr_alloc_preallocated(_radix, _idx, _new_node, _gfp)\ 238 + (__genradix_cast(_radix) \ 239 + __genradix_ptr_alloc(&(_radix)->tree, \ 240 + __genradix_idx_to_offset(_radix, _idx), \ 241 + _new_node, _gfp)) 256 242 257 243 struct genradix_iter { 258 244 size_t offset;
+5 -11
lib/generic-radix-tree.c
··· 15 15 } 16 16 EXPORT_SYMBOL(__genradix_ptr); 17 17 18 - static inline struct genradix_node *genradix_alloc_node(gfp_t gfp_mask) 19 - { 20 - return kzalloc(GENRADIX_NODE_SIZE, gfp_mask); 21 - } 22 - 23 - static inline void genradix_free_node(struct genradix_node *node) 24 - { 25 - kfree(node); 26 - } 27 - 28 18 /* 29 19 * Returns pointer to the specified byte @offset within @radix, allocating it if 30 20 * necessary - newly allocated slots are always zeroed out: 31 21 */ 32 22 void *__genradix_ptr_alloc(struct __genradix *radix, size_t offset, 23 + struct genradix_node **preallocated, 33 24 gfp_t gfp_mask) 34 25 { 35 26 struct genradix_root *v = READ_ONCE(radix->root); 36 27 struct genradix_node *n, *new_node = NULL; 37 28 unsigned level; 29 + 30 + if (preallocated) 31 + swap(new_node, *preallocated); 38 32 39 33 /* Increase tree depth if necessary: */ 40 34 while (1) { ··· 213 219 size_t offset; 214 220 215 221 for (offset = 0; offset < size; offset += GENRADIX_NODE_SIZE) 216 - if (!__genradix_ptr_alloc(radix, offset, gfp_mask)) 222 + if (!__genradix_ptr_alloc(radix, offset, NULL, gfp_mask)) 217 223 return -ENOMEM; 218 224 219 225 return 0;