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

radix-tree: free up the bottom bit of exceptional entries for reuse

We are guaranteed that pointers to radix_tree_nodes always have the
bottom two bits clear (because they come from a slab cache, and slab
caches have a minimum alignment of sizeof(void *)), so we can redefine
'radix_tree_is_internal_node' to only return true if the bottom two bits
have value '01'. This frees up one quarter of the potential values for
use by the user.

Idea from Neil Brown.

Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Suggested-by: Neil Brown <neilb@suse.de>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Kirill Shutemov <kirill.shutemov@linux.intel.com>
Cc: Jan Kara <jack@suse.com>
Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Matthew Wilcox and committed by
Linus Torvalds
3bcadd6f 78a9be0a

+22 -14
+22 -14
include/linux/radix-tree.h
··· 29 29 #include <linux/rcupdate.h> 30 30 31 31 /* 32 - * Entries in the radix tree have the low bit set if they refer to a 33 - * radix_tree_node. If the low bit is clear then the entry is user data. 32 + * The bottom two bits of the slot determine how the remaining bits in the 33 + * slot are interpreted: 34 34 * 35 - * We also use the low bit to indicate that the slot will be freed in the 36 - * next RCU idle period, and users need to re-walk the tree to find the 37 - * new slot for the index that they were looking for. See the comment in 38 - * radix_tree_shrink() for details. 35 + * 00 - data pointer 36 + * 01 - internal entry 37 + * 10 - exceptional entry 38 + * 11 - locked exceptional entry 39 + * 40 + * The internal entry may be a pointer to the next level in the tree, a 41 + * sibling entry, or an indicator that the entry in this slot has been moved 42 + * to another location in the tree and the lookup should be restarted. While 43 + * NULL fits the 'data pointer' pattern, it means that there is no entry in 44 + * the tree for this index (no matter what level of the tree it is found at). 45 + * This means that you cannot store NULL in the tree as a value for the index. 39 46 */ 40 - #define RADIX_TREE_INTERNAL_NODE 1 47 + #define RADIX_TREE_ENTRY_MASK 3UL 48 + #define RADIX_TREE_INTERNAL_NODE 1UL 41 49 42 50 /* 43 - * A common use of the radix tree is to store pointers to struct pages; 44 - * but shmem/tmpfs needs also to store swap entries in the same tree: 45 - * those are marked as exceptional entries to distinguish them. 51 + * Most users of the radix tree store pointers but shmem/tmpfs stores swap 52 + * entries in the same tree. They are marked as exceptional entries to 53 + * distinguish them from pointers to struct page. 46 54 * EXCEPTIONAL_ENTRY tests the bit, EXCEPTIONAL_SHIFT shifts content past it. 47 55 */ 48 56 #define RADIX_TREE_EXCEPTIONAL_ENTRY 2 49 57 #define RADIX_TREE_EXCEPTIONAL_SHIFT 2 50 58 51 - static inline int radix_tree_is_internal_node(void *ptr) 59 + static inline bool radix_tree_is_internal_node(void *ptr) 52 60 { 53 - return (int)((unsigned long)ptr & RADIX_TREE_INTERNAL_NODE); 61 + return ((unsigned long)ptr & RADIX_TREE_ENTRY_MASK) == 62 + RADIX_TREE_INTERNAL_NODE; 54 63 } 55 64 56 65 /*** radix-tree API starts here ***/ ··· 245 236 */ 246 237 static inline int radix_tree_exception(void *arg) 247 238 { 248 - return unlikely((unsigned long)arg & 249 - (RADIX_TREE_INTERNAL_NODE | RADIX_TREE_EXCEPTIONAL_ENTRY)); 239 + return unlikely((unsigned long)arg & RADIX_TREE_ENTRY_MASK); 250 240 } 251 241 252 242 /**