aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/idr.h5
-rw-r--r--lib/idr.c39
-rw-r--r--lib/radix-tree.c45
-rw-r--r--tools/testing/radix-tree/linux/kernel.h2
-rw-r--r--tools/testing/radix-tree/linux/percpu.h5
5 files changed, 51 insertions, 45 deletions
diff --git a/include/linux/idr.h b/include/linux/idr.h
index f58c0a3addc3..2027c7aba50d 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -14,6 +14,7 @@
14 14
15#include <linux/radix-tree.h> 15#include <linux/radix-tree.h>
16#include <linux/gfp.h> 16#include <linux/gfp.h>
17#include <linux/percpu.h>
17 18
18struct idr { 19struct idr {
19 struct radix_tree_root idr_rt; 20 struct radix_tree_root idr_rt;
@@ -171,9 +172,10 @@ struct ida_bitmap {
171 unsigned long bitmap[IDA_BITMAP_LONGS]; 172 unsigned long bitmap[IDA_BITMAP_LONGS];
172}; 173};
173 174
175DECLARE_PER_CPU(struct ida_bitmap *, ida_bitmap);
176
174struct ida { 177struct ida {
175 struct radix_tree_root ida_rt; 178 struct radix_tree_root ida_rt;
176 struct ida_bitmap *free_bitmap;
177}; 179};
178 180
179#define IDA_INIT { \ 181#define IDA_INIT { \
@@ -193,7 +195,6 @@ void ida_simple_remove(struct ida *ida, unsigned int id);
193static inline void ida_init(struct ida *ida) 195static inline void ida_init(struct ida *ida)
194{ 196{
195 INIT_RADIX_TREE(&ida->ida_rt, IDR_RT_MARKER | GFP_NOWAIT); 197 INIT_RADIX_TREE(&ida->ida_rt, IDR_RT_MARKER | GFP_NOWAIT);
196 ida->free_bitmap = NULL;
197} 198}
198 199
199/** 200/**
diff --git a/lib/idr.c b/lib/idr.c
index b87056e2cc4c..2abd7769c430 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -4,6 +4,7 @@
4#include <linux/slab.h> 4#include <linux/slab.h>
5#include <linux/spinlock.h> 5#include <linux/spinlock.h>
6 6
7DEFINE_PER_CPU(struct ida_bitmap *, ida_bitmap);
7static DEFINE_SPINLOCK(simple_ida_lock); 8static DEFINE_SPINLOCK(simple_ida_lock);
8 9
9/** 10/**
@@ -193,38 +194,6 @@ EXPORT_SYMBOL(idr_replace);
193 * limitation, it should be quite straightforward to raise the maximum. 194 * limitation, it should be quite straightforward to raise the maximum.
194 */ 195 */
195 196
196/**
197 * ida_pre_get - reserve resources for ida allocation
198 * @ida: ida handle
199 * @gfp: memory allocation flags
200 *
201 * This function should be called before calling ida_get_new_above(). If it
202 * is unable to allocate memory, it will return %0. On success, it returns %1.
203 */
204int ida_pre_get(struct ida *ida, gfp_t gfp)
205{
206 struct ida_bitmap *bitmap;
207
208 /*
209 * This looks weird, but the IDA API has no preload_end() equivalent.
210 * Instead, ida_get_new() can return -EAGAIN, prompting the caller
211 * to return to the ida_pre_get() step.
212 */
213 idr_preload(gfp);
214 idr_preload_end();
215
216 if (!ida->free_bitmap) {
217 bitmap = kmalloc(sizeof(struct ida_bitmap), gfp);
218 if (!bitmap)
219 return 0;
220 bitmap = xchg(&ida->free_bitmap, bitmap);
221 kfree(bitmap);
222 }
223
224 return 1;
225}
226EXPORT_SYMBOL(ida_pre_get);
227
228#define IDA_MAX (0x80000000U / IDA_BITMAP_BITS) 197#define IDA_MAX (0x80000000U / IDA_BITMAP_BITS)
229 198
230/** 199/**
@@ -292,10 +261,9 @@ int ida_get_new_above(struct ida *ida, int start, int *id)
292 new += bit; 261 new += bit;
293 if (new < 0) 262 if (new < 0)
294 return -ENOSPC; 263 return -ENOSPC;
295 bitmap = ida->free_bitmap; 264 bitmap = this_cpu_xchg(ida_bitmap, NULL);
296 if (!bitmap) 265 if (!bitmap)
297 return -EAGAIN; 266 return -EAGAIN;
298 ida->free_bitmap = NULL;
299 memset(bitmap, 0, sizeof(*bitmap)); 267 memset(bitmap, 0, sizeof(*bitmap));
300 __set_bit(bit, bitmap->bitmap); 268 __set_bit(bit, bitmap->bitmap);
301 radix_tree_iter_replace(root, &iter, slot, bitmap); 269 radix_tree_iter_replace(root, &iter, slot, bitmap);
@@ -361,9 +329,6 @@ void ida_destroy(struct ida *ida)
361 kfree(bitmap); 329 kfree(bitmap);
362 radix_tree_iter_delete(&ida->ida_rt, &iter, slot); 330 radix_tree_iter_delete(&ida->ida_rt, &iter, slot);
363 } 331 }
364
365 kfree(ida->free_bitmap);
366 ida->free_bitmap = NULL;
367} 332}
368EXPORT_SYMBOL(ida_destroy); 333EXPORT_SYMBOL(ida_destroy);
369 334
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index eaea14b8f2ca..7b9f8515033e 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -70,6 +70,14 @@ static struct kmem_cache *radix_tree_node_cachep;
70#define IDR_PRELOAD_SIZE (IDR_MAX_PATH * 2 - 1) 70#define IDR_PRELOAD_SIZE (IDR_MAX_PATH * 2 - 1)
71 71
72/* 72/*
73 * The IDA is even shorter since it uses a bitmap at the last level.
74 */
75#define IDA_INDEX_BITS (8 * sizeof(int) - 1 - ilog2(IDA_BITMAP_BITS))
76#define IDA_MAX_PATH (DIV_ROUND_UP(IDA_INDEX_BITS, \
77 RADIX_TREE_MAP_SHIFT))
78#define IDA_PRELOAD_SIZE (IDA_MAX_PATH * 2 - 1)
79
80/*
73 * Per-cpu pool of preloaded nodes 81 * Per-cpu pool of preloaded nodes
74 */ 82 */
75struct radix_tree_preload { 83struct radix_tree_preload {
@@ -346,9 +354,8 @@ static void dump_ida_node(void *entry, unsigned long index)
346static void ida_dump(struct ida *ida) 354static void ida_dump(struct ida *ida)
347{ 355{
348 struct radix_tree_root *root = &ida->ida_rt; 356 struct radix_tree_root *root = &ida->ida_rt;
349 pr_debug("ida: %p %p free %d bitmap %p\n", ida, root->rnode, 357 pr_debug("ida: %p node %p free %d\n", ida, root->rnode,
350 root->gfp_mask >> ROOT_TAG_SHIFT, 358 root->gfp_mask >> ROOT_TAG_SHIFT);
351 ida->free_bitmap);
352 dump_ida_node(root->rnode, 0); 359 dump_ida_node(root->rnode, 0);
353} 360}
354#endif 361#endif
@@ -2080,6 +2087,36 @@ void idr_preload(gfp_t gfp_mask)
2080} 2087}
2081EXPORT_SYMBOL(idr_preload); 2088EXPORT_SYMBOL(idr_preload);
2082 2089
2090/**
2091 * ida_pre_get - reserve resources for ida allocation
2092 * @ida: ida handle
2093 * @gfp: memory allocation flags
2094 *
2095 * This function should be called before calling ida_get_new_above(). If it
2096 * is unable to allocate memory, it will return %0. On success, it returns %1.
2097 */
2098int ida_pre_get(struct ida *ida, gfp_t gfp)
2099{
2100 __radix_tree_preload(gfp, IDA_PRELOAD_SIZE);
2101 /*
2102 * The IDA API has no preload_end() equivalent. Instead,
2103 * ida_get_new() can return -EAGAIN, prompting the caller
2104 * to return to the ida_pre_get() step.
2105 */
2106 preempt_enable();
2107
2108 if (!this_cpu_read(ida_bitmap)) {
2109 struct ida_bitmap *bitmap = kmalloc(sizeof(*bitmap), gfp);
2110 if (!bitmap)
2111 return 0;
2112 bitmap = this_cpu_cmpxchg(ida_bitmap, NULL, bitmap);
2113 kfree(bitmap);
2114 }
2115
2116 return 1;
2117}
2118EXPORT_SYMBOL(ida_pre_get);
2119
2083void **idr_get_free(struct radix_tree_root *root, 2120void **idr_get_free(struct radix_tree_root *root,
2084 struct radix_tree_iter *iter, gfp_t gfp, int end) 2121 struct radix_tree_iter *iter, gfp_t gfp, int end)
2085{ 2122{
@@ -2219,6 +2256,8 @@ static int radix_tree_cpu_dead(unsigned int cpu)
2219 kmem_cache_free(radix_tree_node_cachep, node); 2256 kmem_cache_free(radix_tree_node_cachep, node);
2220 rtp->nr--; 2257 rtp->nr--;
2221 } 2258 }
2259 kfree(per_cpu(ida_bitmap, cpu));
2260 per_cpu(ida_bitmap, cpu) = NULL;
2222 return 0; 2261 return 0;
2223} 2262}
2224 2263
diff --git a/tools/testing/radix-tree/linux/kernel.h b/tools/testing/radix-tree/linux/kernel.h
index 63fce553781a..677b8c0f60f9 100644
--- a/tools/testing/radix-tree/linux/kernel.h
+++ b/tools/testing/radix-tree/linux/kernel.h
@@ -24,6 +24,4 @@
24 24
25#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 25#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
26 26
27#define xchg(ptr, x) uatomic_xchg(ptr, x)
28
29#endif /* _KERNEL_H */ 27#endif /* _KERNEL_H */
diff --git a/tools/testing/radix-tree/linux/percpu.h b/tools/testing/radix-tree/linux/percpu.h
index 5837f1d56f17..3ea01a1a88c2 100644
--- a/tools/testing/radix-tree/linux/percpu.h
+++ b/tools/testing/radix-tree/linux/percpu.h
@@ -1,7 +1,10 @@
1 1#define DECLARE_PER_CPU(type, val) extern type val
2#define DEFINE_PER_CPU(type, val) type val 2#define DEFINE_PER_CPU(type, val) type val
3 3
4#define __get_cpu_var(var) var 4#define __get_cpu_var(var) var
5#define this_cpu_ptr(var) var 5#define this_cpu_ptr(var) var
6#define this_cpu_read(var) var
7#define this_cpu_xchg(var, val) uatomic_xchg(&var, val)
8#define this_cpu_cmpxchg(var, old, new) uatomic_cmpxchg(&var, old, new)
6#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); }) 9#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
7#define per_cpu(var, cpu) (*per_cpu_ptr(&(var), cpu)) 10#define per_cpu(var, cpu) (*per_cpu_ptr(&(var), cpu))