1*b4d0d230SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */ 23cb98950SDavid Howells /* Private definitions for the generic associative array implementation. 33cb98950SDavid Howells * 45fb94e9cSMauro Carvalho Chehab * See Documentation/core-api/assoc_array.rst for information. 53cb98950SDavid Howells * 63cb98950SDavid Howells * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. 73cb98950SDavid Howells * Written by David Howells (dhowells@redhat.com) 83cb98950SDavid Howells */ 93cb98950SDavid Howells 103cb98950SDavid Howells #ifndef _LINUX_ASSOC_ARRAY_PRIV_H 113cb98950SDavid Howells #define _LINUX_ASSOC_ARRAY_PRIV_H 123cb98950SDavid Howells 133cb98950SDavid Howells #ifdef CONFIG_ASSOCIATIVE_ARRAY 143cb98950SDavid Howells 153cb98950SDavid Howells #include <linux/assoc_array.h> 163cb98950SDavid Howells 173cb98950SDavid Howells #define ASSOC_ARRAY_FAN_OUT 16 /* Number of slots per node */ 183cb98950SDavid Howells #define ASSOC_ARRAY_FAN_MASK (ASSOC_ARRAY_FAN_OUT - 1) 193cb98950SDavid Howells #define ASSOC_ARRAY_LEVEL_STEP (ilog2(ASSOC_ARRAY_FAN_OUT)) 203cb98950SDavid Howells #define ASSOC_ARRAY_LEVEL_STEP_MASK (ASSOC_ARRAY_LEVEL_STEP - 1) 213cb98950SDavid Howells #define ASSOC_ARRAY_KEY_CHUNK_MASK (ASSOC_ARRAY_KEY_CHUNK_SIZE - 1) 223cb98950SDavid Howells #define ASSOC_ARRAY_KEY_CHUNK_SHIFT (ilog2(BITS_PER_LONG)) 233cb98950SDavid Howells 243cb98950SDavid Howells /* 253cb98950SDavid Howells * Undefined type representing a pointer with type information in the bottom 263cb98950SDavid Howells * two bits. 273cb98950SDavid Howells */ 283cb98950SDavid Howells struct assoc_array_ptr; 293cb98950SDavid Howells 303cb98950SDavid Howells /* 313cb98950SDavid Howells * An N-way node in the tree. 323cb98950SDavid Howells * 333cb98950SDavid Howells * Each slot contains one of four things: 343cb98950SDavid Howells * 353cb98950SDavid Howells * (1) Nothing (NULL). 363cb98950SDavid Howells * 373cb98950SDavid Howells * (2) A leaf object (pointer types 0). 383cb98950SDavid Howells * 393cb98950SDavid Howells * (3) A next-level node (pointer type 1, subtype 0). 403cb98950SDavid Howells * 413cb98950SDavid Howells * (4) A shortcut (pointer type 1, subtype 1). 423cb98950SDavid Howells * 433cb98950SDavid Howells * The tree is optimised for search-by-ID, but permits reasonable iteration 443cb98950SDavid Howells * also. 453cb98950SDavid Howells * 463cb98950SDavid Howells * The tree is navigated by constructing an index key consisting of an array of 473cb98950SDavid Howells * segments, where each segment is ilog2(ASSOC_ARRAY_FAN_OUT) bits in size. 483cb98950SDavid Howells * 493cb98950SDavid Howells * The segments correspond to levels of the tree (the first segment is used at 503cb98950SDavid Howells * level 0, the second at level 1, etc.). 513cb98950SDavid Howells */ 523cb98950SDavid Howells struct assoc_array_node { 533cb98950SDavid Howells struct assoc_array_ptr *back_pointer; 543cb98950SDavid Howells u8 parent_slot; 553cb98950SDavid Howells struct assoc_array_ptr *slots[ASSOC_ARRAY_FAN_OUT]; 563cb98950SDavid Howells unsigned long nr_leaves_on_branch; 573cb98950SDavid Howells }; 583cb98950SDavid Howells 593cb98950SDavid Howells /* 603cb98950SDavid Howells * A shortcut through the index space out to where a collection of nodes/leaves 613cb98950SDavid Howells * with the same IDs live. 623cb98950SDavid Howells */ 633cb98950SDavid Howells struct assoc_array_shortcut { 643cb98950SDavid Howells struct assoc_array_ptr *back_pointer; 653cb98950SDavid Howells int parent_slot; 663cb98950SDavid Howells int skip_to_level; 673cb98950SDavid Howells struct assoc_array_ptr *next_node; 683cb98950SDavid Howells unsigned long index_key[]; 693cb98950SDavid Howells }; 703cb98950SDavid Howells 713cb98950SDavid Howells /* 723cb98950SDavid Howells * Preallocation cache. 733cb98950SDavid Howells */ 743cb98950SDavid Howells struct assoc_array_edit { 753cb98950SDavid Howells struct rcu_head rcu; 763cb98950SDavid Howells struct assoc_array *array; 773cb98950SDavid Howells const struct assoc_array_ops *ops; 783cb98950SDavid Howells const struct assoc_array_ops *ops_for_excised_subtree; 793cb98950SDavid Howells struct assoc_array_ptr *leaf; 803cb98950SDavid Howells struct assoc_array_ptr **leaf_p; 813cb98950SDavid Howells struct assoc_array_ptr *dead_leaf; 823cb98950SDavid Howells struct assoc_array_ptr *new_meta[3]; 833cb98950SDavid Howells struct assoc_array_ptr *excised_meta[1]; 843cb98950SDavid Howells struct assoc_array_ptr *excised_subtree; 853cb98950SDavid Howells struct assoc_array_ptr **set_backpointers[ASSOC_ARRAY_FAN_OUT]; 863cb98950SDavid Howells struct assoc_array_ptr *set_backpointers_to; 873cb98950SDavid Howells struct assoc_array_node *adjust_count_on; 883cb98950SDavid Howells long adjust_count_by; 893cb98950SDavid Howells struct { 903cb98950SDavid Howells struct assoc_array_ptr **ptr; 913cb98950SDavid Howells struct assoc_array_ptr *to; 923cb98950SDavid Howells } set[2]; 933cb98950SDavid Howells struct { 943cb98950SDavid Howells u8 *p; 953cb98950SDavid Howells u8 to; 963cb98950SDavid Howells } set_parent_slot[1]; 973cb98950SDavid Howells u8 segment_cache[ASSOC_ARRAY_FAN_OUT + 1]; 983cb98950SDavid Howells }; 993cb98950SDavid Howells 1003cb98950SDavid Howells /* 1013cb98950SDavid Howells * Internal tree member pointers are marked in the bottom one or two bits to 1023cb98950SDavid Howells * indicate what type they are so that we don't have to look behind every 1033cb98950SDavid Howells * pointer to see what it points to. 1043cb98950SDavid Howells * 1053cb98950SDavid Howells * We provide functions to test type annotations and to create and translate 1063cb98950SDavid Howells * the annotated pointers. 1073cb98950SDavid Howells */ 1083cb98950SDavid Howells #define ASSOC_ARRAY_PTR_TYPE_MASK 0x1UL 1093cb98950SDavid Howells #define ASSOC_ARRAY_PTR_LEAF_TYPE 0x0UL /* Points to leaf (or nowhere) */ 1103cb98950SDavid Howells #define ASSOC_ARRAY_PTR_META_TYPE 0x1UL /* Points to node or shortcut */ 1113cb98950SDavid Howells #define ASSOC_ARRAY_PTR_SUBTYPE_MASK 0x2UL 1123cb98950SDavid Howells #define ASSOC_ARRAY_PTR_NODE_SUBTYPE 0x0UL 1133cb98950SDavid Howells #define ASSOC_ARRAY_PTR_SHORTCUT_SUBTYPE 0x2UL 1143cb98950SDavid Howells 1153cb98950SDavid Howells static inline bool assoc_array_ptr_is_meta(const struct assoc_array_ptr *x) 1163cb98950SDavid Howells { 1173cb98950SDavid Howells return (unsigned long)x & ASSOC_ARRAY_PTR_TYPE_MASK; 1183cb98950SDavid Howells } 1193cb98950SDavid Howells static inline bool assoc_array_ptr_is_leaf(const struct assoc_array_ptr *x) 1203cb98950SDavid Howells { 1213cb98950SDavid Howells return !assoc_array_ptr_is_meta(x); 1223cb98950SDavid Howells } 1233cb98950SDavid Howells static inline bool assoc_array_ptr_is_shortcut(const struct assoc_array_ptr *x) 1243cb98950SDavid Howells { 1253cb98950SDavid Howells return (unsigned long)x & ASSOC_ARRAY_PTR_SUBTYPE_MASK; 1263cb98950SDavid Howells } 1273cb98950SDavid Howells static inline bool assoc_array_ptr_is_node(const struct assoc_array_ptr *x) 1283cb98950SDavid Howells { 1293cb98950SDavid Howells return !assoc_array_ptr_is_shortcut(x); 1303cb98950SDavid Howells } 1313cb98950SDavid Howells 1323cb98950SDavid Howells static inline void *assoc_array_ptr_to_leaf(const struct assoc_array_ptr *x) 1333cb98950SDavid Howells { 1343cb98950SDavid Howells return (void *)((unsigned long)x & ~ASSOC_ARRAY_PTR_TYPE_MASK); 1353cb98950SDavid Howells } 1363cb98950SDavid Howells 1373cb98950SDavid Howells static inline 1383cb98950SDavid Howells unsigned long __assoc_array_ptr_to_meta(const struct assoc_array_ptr *x) 1393cb98950SDavid Howells { 1403cb98950SDavid Howells return (unsigned long)x & 1413cb98950SDavid Howells ~(ASSOC_ARRAY_PTR_SUBTYPE_MASK | ASSOC_ARRAY_PTR_TYPE_MASK); 1423cb98950SDavid Howells } 1433cb98950SDavid Howells static inline 1443cb98950SDavid Howells struct assoc_array_node *assoc_array_ptr_to_node(const struct assoc_array_ptr *x) 1453cb98950SDavid Howells { 1463cb98950SDavid Howells return (struct assoc_array_node *)__assoc_array_ptr_to_meta(x); 1473cb98950SDavid Howells } 1483cb98950SDavid Howells static inline 1493cb98950SDavid Howells struct assoc_array_shortcut *assoc_array_ptr_to_shortcut(const struct assoc_array_ptr *x) 1503cb98950SDavid Howells { 1513cb98950SDavid Howells return (struct assoc_array_shortcut *)__assoc_array_ptr_to_meta(x); 1523cb98950SDavid Howells } 1533cb98950SDavid Howells 1543cb98950SDavid Howells static inline 1553cb98950SDavid Howells struct assoc_array_ptr *__assoc_array_x_to_ptr(const void *p, unsigned long t) 1563cb98950SDavid Howells { 1573cb98950SDavid Howells return (struct assoc_array_ptr *)((unsigned long)p | t); 1583cb98950SDavid Howells } 1593cb98950SDavid Howells static inline 1603cb98950SDavid Howells struct assoc_array_ptr *assoc_array_leaf_to_ptr(const void *p) 1613cb98950SDavid Howells { 1623cb98950SDavid Howells return __assoc_array_x_to_ptr(p, ASSOC_ARRAY_PTR_LEAF_TYPE); 1633cb98950SDavid Howells } 1643cb98950SDavid Howells static inline 1653cb98950SDavid Howells struct assoc_array_ptr *assoc_array_node_to_ptr(const struct assoc_array_node *p) 1663cb98950SDavid Howells { 1673cb98950SDavid Howells return __assoc_array_x_to_ptr( 1683cb98950SDavid Howells p, ASSOC_ARRAY_PTR_META_TYPE | ASSOC_ARRAY_PTR_NODE_SUBTYPE); 1693cb98950SDavid Howells } 1703cb98950SDavid Howells static inline 1713cb98950SDavid Howells struct assoc_array_ptr *assoc_array_shortcut_to_ptr(const struct assoc_array_shortcut *p) 1723cb98950SDavid Howells { 1733cb98950SDavid Howells return __assoc_array_x_to_ptr( 1743cb98950SDavid Howells p, ASSOC_ARRAY_PTR_META_TYPE | ASSOC_ARRAY_PTR_SHORTCUT_SUBTYPE); 1753cb98950SDavid Howells } 1763cb98950SDavid Howells 1773cb98950SDavid Howells #endif /* CONFIG_ASSOCIATIVE_ARRAY */ 1783cb98950SDavid Howells #endif /* _LINUX_ASSOC_ARRAY_PRIV_H */ 179