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