2 #include <linux/export.h>
3 #include <linux/generic-radix-tree.h>
6 #define GENRADIX_ARY (PAGE_SIZE / sizeof(struct genradix_node *))
7 #define GENRADIX_ARY_SHIFT ilog2(GENRADIX_ARY)
12 struct genradix_node
*children
[GENRADIX_ARY
];
19 static inline int genradix_depth_shift(unsigned depth
)
21 return PAGE_SHIFT
+ GENRADIX_ARY_SHIFT
* depth
;
25 * Returns size (of data, in bytes) that a tree of a given depth holds:
27 static inline size_t genradix_depth_size(unsigned depth
)
29 return 1UL << genradix_depth_shift(depth
);
32 /* depth that's needed for a genradix that can address up to ULONG_MAX: */
33 #define GENRADIX_MAX_DEPTH \
34 DIV_ROUND_UP(BITS_PER_LONG - PAGE_SHIFT, GENRADIX_ARY_SHIFT)
36 #define GENRADIX_DEPTH_MASK \
37 ((unsigned long) (roundup_pow_of_two(GENRADIX_MAX_DEPTH + 1) - 1))
39 unsigned genradix_root_to_depth(struct genradix_root
*r
)
41 return (unsigned long) r
& GENRADIX_DEPTH_MASK
;
44 struct genradix_node
*genradix_root_to_node(struct genradix_root
*r
)
46 return (void *) ((unsigned long) r
& ~GENRADIX_DEPTH_MASK
);
50 * Returns pointer to the specified byte @offset within @radix, or NULL if not
53 void *__genradix_ptr(struct __genradix
*radix
, size_t offset
)
55 struct genradix_root
*r
= READ_ONCE(radix
->root
);
56 struct genradix_node
*n
= genradix_root_to_node(r
);
57 unsigned level
= genradix_root_to_depth(r
);
59 if (ilog2(offset
) >= genradix_depth_shift(level
))
70 n
= n
->children
[offset
>> genradix_depth_shift(level
)];
71 offset
&= genradix_depth_size(level
) - 1;
74 return &n
->data
[offset
];
76 EXPORT_SYMBOL(__genradix_ptr
);
79 * Returns pointer to the specified byte @offset within @radix, allocating it if
80 * necessary - newly allocated slots are always zeroed out:
82 void *__genradix_ptr_alloc(struct __genradix
*radix
, size_t offset
,
85 struct genradix_root
*v
= READ_ONCE(radix
->root
);
86 struct genradix_node
*n
, *new_node
= NULL
;
89 /* Increase tree depth if necessary: */
91 struct genradix_root
*r
= v
, *new_root
;
93 n
= genradix_root_to_node(r
);
94 level
= genradix_root_to_depth(r
);
96 if (n
&& ilog2(offset
) < genradix_depth_shift(level
))
101 __get_free_page(gfp_mask
|__GFP_ZERO
);
106 new_node
->children
[0] = n
;
107 new_root
= ((struct genradix_root
*)
108 ((unsigned long) new_node
| (n
? level
+ 1 : 0)));
110 if ((v
= cmpxchg_release(&radix
->root
, r
, new_root
)) == r
) {
117 struct genradix_node
**p
=
118 &n
->children
[offset
>> genradix_depth_shift(level
)];
119 offset
&= genradix_depth_size(level
) - 1;
125 __get_free_page(gfp_mask
|__GFP_ZERO
);
130 if (!(n
= cmpxchg_release(p
, NULL
, new_node
)))
136 free_page((unsigned long) new_node
);
138 return &n
->data
[offset
];
140 EXPORT_SYMBOL(__genradix_ptr_alloc
);
142 void *__genradix_iter_peek(struct genradix_iter
*iter
,
143 struct __genradix
*radix
,
144 size_t objs_per_page
)
146 struct genradix_root
*r
;
147 struct genradix_node
*n
;
150 r
= READ_ONCE(radix
->root
);
154 n
= genradix_root_to_node(r
);
155 level
= genradix_root_to_depth(r
);
157 if (ilog2(iter
->offset
) >= genradix_depth_shift(level
))
163 i
= (iter
->offset
>> genradix_depth_shift(level
)) &
166 while (!n
->children
[i
]) {
168 iter
->offset
= round_down(iter
->offset
+
169 genradix_depth_size(level
),
170 genradix_depth_size(level
));
171 iter
->pos
= (iter
->offset
>> PAGE_SHIFT
) *
173 if (i
== GENRADIX_ARY
)
180 return &n
->data
[iter
->offset
& (PAGE_SIZE
- 1)];
182 EXPORT_SYMBOL(__genradix_iter_peek
);
184 static void genradix_free_recurse(struct genradix_node
*n
, unsigned level
)
189 for (i
= 0; i
< GENRADIX_ARY
; i
++)
191 genradix_free_recurse(n
->children
[i
], level
- 1);
194 free_page((unsigned long) n
);
197 int __genradix_prealloc(struct __genradix
*radix
, size_t size
,
202 for (offset
= 0; offset
< size
; offset
+= PAGE_SIZE
)
203 if (!__genradix_ptr_alloc(radix
, offset
, gfp_mask
))
208 EXPORT_SYMBOL(__genradix_prealloc
);
210 void __genradix_free(struct __genradix
*radix
)
212 struct genradix_root
*r
= xchg(&radix
->root
, NULL
);
214 genradix_free_recurse(genradix_root_to_node(r
),
215 genradix_root_to_depth(r
));
217 EXPORT_SYMBOL(__genradix_free
);