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