18c2ecf20Sopenharmony_ci 28c2ecf20Sopenharmony_ci#include <linux/export.h> 38c2ecf20Sopenharmony_ci#include <linux/generic-radix-tree.h> 48c2ecf20Sopenharmony_ci#include <linux/gfp.h> 58c2ecf20Sopenharmony_ci#include <linux/kmemleak.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define GENRADIX_ARY (PAGE_SIZE / sizeof(struct genradix_node *)) 88c2ecf20Sopenharmony_ci#define GENRADIX_ARY_SHIFT ilog2(GENRADIX_ARY) 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistruct genradix_node { 118c2ecf20Sopenharmony_ci union { 128c2ecf20Sopenharmony_ci /* Interior node: */ 138c2ecf20Sopenharmony_ci struct genradix_node *children[GENRADIX_ARY]; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci /* Leaf: */ 168c2ecf20Sopenharmony_ci u8 data[PAGE_SIZE]; 178c2ecf20Sopenharmony_ci }; 188c2ecf20Sopenharmony_ci}; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic inline int genradix_depth_shift(unsigned depth) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci return PAGE_SHIFT + GENRADIX_ARY_SHIFT * depth; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * Returns size (of data, in bytes) that a tree of a given depth holds: 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_cistatic inline size_t genradix_depth_size(unsigned depth) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci return 1UL << genradix_depth_shift(depth); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* depth that's needed for a genradix that can address up to ULONG_MAX: */ 348c2ecf20Sopenharmony_ci#define GENRADIX_MAX_DEPTH \ 358c2ecf20Sopenharmony_ci DIV_ROUND_UP(BITS_PER_LONG - PAGE_SHIFT, GENRADIX_ARY_SHIFT) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define GENRADIX_DEPTH_MASK \ 388c2ecf20Sopenharmony_ci ((unsigned long) (roundup_pow_of_two(GENRADIX_MAX_DEPTH + 1) - 1)) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic inline unsigned genradix_root_to_depth(struct genradix_root *r) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci return (unsigned long) r & GENRADIX_DEPTH_MASK; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline struct genradix_node *genradix_root_to_node(struct genradix_root *r) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return (void *) ((unsigned long) r & ~GENRADIX_DEPTH_MASK); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * Returns pointer to the specified byte @offset within @radix, or NULL if not 528c2ecf20Sopenharmony_ci * allocated 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_civoid *__genradix_ptr(struct __genradix *radix, size_t offset) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct genradix_root *r = READ_ONCE(radix->root); 578c2ecf20Sopenharmony_ci struct genradix_node *n = genradix_root_to_node(r); 588c2ecf20Sopenharmony_ci unsigned level = genradix_root_to_depth(r); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (ilog2(offset) >= genradix_depth_shift(level)) 618c2ecf20Sopenharmony_ci return NULL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci while (1) { 648c2ecf20Sopenharmony_ci if (!n) 658c2ecf20Sopenharmony_ci return NULL; 668c2ecf20Sopenharmony_ci if (!level) 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci level--; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci n = n->children[offset >> genradix_depth_shift(level)]; 728c2ecf20Sopenharmony_ci offset &= genradix_depth_size(level) - 1; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return &n->data[offset]; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__genradix_ptr); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline struct genradix_node *genradix_alloc_node(gfp_t gfp_mask) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct genradix_node *node; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci node = (struct genradix_node *)__get_free_page(gfp_mask|__GFP_ZERO); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* 868c2ecf20Sopenharmony_ci * We're using pages (not slab allocations) directly for kernel data 878c2ecf20Sopenharmony_ci * structures, so we need to explicitly inform kmemleak of them in order 888c2ecf20Sopenharmony_ci * to avoid false positive memory leak reports. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci kmemleak_alloc(node, PAGE_SIZE, 1, gfp_mask); 918c2ecf20Sopenharmony_ci return node; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic inline void genradix_free_node(struct genradix_node *node) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci kmemleak_free(node); 978c2ecf20Sopenharmony_ci free_page((unsigned long)node); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * Returns pointer to the specified byte @offset within @radix, allocating it if 1028c2ecf20Sopenharmony_ci * necessary - newly allocated slots are always zeroed out: 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_civoid *__genradix_ptr_alloc(struct __genradix *radix, size_t offset, 1058c2ecf20Sopenharmony_ci gfp_t gfp_mask) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct genradix_root *v = READ_ONCE(radix->root); 1088c2ecf20Sopenharmony_ci struct genradix_node *n, *new_node = NULL; 1098c2ecf20Sopenharmony_ci unsigned level; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Increase tree depth if necessary: */ 1128c2ecf20Sopenharmony_ci while (1) { 1138c2ecf20Sopenharmony_ci struct genradix_root *r = v, *new_root; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci n = genradix_root_to_node(r); 1168c2ecf20Sopenharmony_ci level = genradix_root_to_depth(r); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (n && ilog2(offset) < genradix_depth_shift(level)) 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (!new_node) { 1228c2ecf20Sopenharmony_ci new_node = genradix_alloc_node(gfp_mask); 1238c2ecf20Sopenharmony_ci if (!new_node) 1248c2ecf20Sopenharmony_ci return NULL; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci new_node->children[0] = n; 1288c2ecf20Sopenharmony_ci new_root = ((struct genradix_root *) 1298c2ecf20Sopenharmony_ci ((unsigned long) new_node | (n ? level + 1 : 0))); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if ((v = cmpxchg_release(&radix->root, r, new_root)) == r) { 1328c2ecf20Sopenharmony_ci v = new_root; 1338c2ecf20Sopenharmony_ci new_node = NULL; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci while (level--) { 1388c2ecf20Sopenharmony_ci struct genradix_node **p = 1398c2ecf20Sopenharmony_ci &n->children[offset >> genradix_depth_shift(level)]; 1408c2ecf20Sopenharmony_ci offset &= genradix_depth_size(level) - 1; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci n = READ_ONCE(*p); 1438c2ecf20Sopenharmony_ci if (!n) { 1448c2ecf20Sopenharmony_ci if (!new_node) { 1458c2ecf20Sopenharmony_ci new_node = genradix_alloc_node(gfp_mask); 1468c2ecf20Sopenharmony_ci if (!new_node) 1478c2ecf20Sopenharmony_ci return NULL; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (!(n = cmpxchg_release(p, NULL, new_node))) 1518c2ecf20Sopenharmony_ci swap(n, new_node); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (new_node) 1568c2ecf20Sopenharmony_ci genradix_free_node(new_node); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return &n->data[offset]; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__genradix_ptr_alloc); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_civoid *__genradix_iter_peek(struct genradix_iter *iter, 1638c2ecf20Sopenharmony_ci struct __genradix *radix, 1648c2ecf20Sopenharmony_ci size_t objs_per_page) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct genradix_root *r; 1678c2ecf20Sopenharmony_ci struct genradix_node *n; 1688c2ecf20Sopenharmony_ci unsigned level, i; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (iter->offset == SIZE_MAX) 1718c2ecf20Sopenharmony_ci return NULL; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cirestart: 1748c2ecf20Sopenharmony_ci r = READ_ONCE(radix->root); 1758c2ecf20Sopenharmony_ci if (!r) 1768c2ecf20Sopenharmony_ci return NULL; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci n = genradix_root_to_node(r); 1798c2ecf20Sopenharmony_ci level = genradix_root_to_depth(r); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (ilog2(iter->offset) >= genradix_depth_shift(level)) 1828c2ecf20Sopenharmony_ci return NULL; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci while (level) { 1858c2ecf20Sopenharmony_ci level--; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci i = (iter->offset >> genradix_depth_shift(level)) & 1888c2ecf20Sopenharmony_ci (GENRADIX_ARY - 1); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci while (!n->children[i]) { 1918c2ecf20Sopenharmony_ci size_t objs_per_ptr = genradix_depth_size(level); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (iter->offset + objs_per_ptr < iter->offset) { 1948c2ecf20Sopenharmony_ci iter->offset = SIZE_MAX; 1958c2ecf20Sopenharmony_ci iter->pos = SIZE_MAX; 1968c2ecf20Sopenharmony_ci return NULL; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci i++; 2008c2ecf20Sopenharmony_ci iter->offset = round_down(iter->offset + objs_per_ptr, 2018c2ecf20Sopenharmony_ci objs_per_ptr); 2028c2ecf20Sopenharmony_ci iter->pos = (iter->offset >> PAGE_SHIFT) * 2038c2ecf20Sopenharmony_ci objs_per_page; 2048c2ecf20Sopenharmony_ci if (i == GENRADIX_ARY) 2058c2ecf20Sopenharmony_ci goto restart; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci n = n->children[i]; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return &n->data[iter->offset & (PAGE_SIZE - 1)]; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__genradix_iter_peek); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void genradix_free_recurse(struct genradix_node *n, unsigned level) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci if (level) { 2188c2ecf20Sopenharmony_ci unsigned i; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci for (i = 0; i < GENRADIX_ARY; i++) 2218c2ecf20Sopenharmony_ci if (n->children[i]) 2228c2ecf20Sopenharmony_ci genradix_free_recurse(n->children[i], level - 1); 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci genradix_free_node(n); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciint __genradix_prealloc(struct __genradix *radix, size_t size, 2298c2ecf20Sopenharmony_ci gfp_t gfp_mask) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci size_t offset; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci for (offset = 0; offset < size; offset += PAGE_SIZE) 2348c2ecf20Sopenharmony_ci if (!__genradix_ptr_alloc(radix, offset, gfp_mask)) 2358c2ecf20Sopenharmony_ci return -ENOMEM; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__genradix_prealloc); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_civoid __genradix_free(struct __genradix *radix) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct genradix_root *r = xchg(&radix->root, NULL); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci genradix_free_recurse(genradix_root_to_node(r), 2468c2ecf20Sopenharmony_ci genradix_root_to_depth(r)); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__genradix_free); 249