Blame view

lib/radix-tree.c 34.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * Copyright (C) 2001 Momchil Velikov
   * Portions Copyright (C) 2001 Christoph Hellwig
cde535359   Christoph Lameter   Christoph has moved
4
   * Copyright (C) 2005 SGI, Christoph Lameter
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
5
   * Copyright (C) 2006 Nick Piggin
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation; either version 2, or (at
   * your option) any later version.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
  
  #include <linux/errno.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/radix-tree.h>
  #include <linux/percpu.h>
  #include <linux/slab.h>
  #include <linux/notifier.h>
  #include <linux/cpu.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include <linux/string.h>
  #include <linux/bitops.h>
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
33
  #include <linux/rcupdate.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
  
  
  #ifdef __KERNEL__
cfd9b7df4   Nick Piggin   [PATCH] radix-tre...
37
  #define RADIX_TREE_MAP_SHIFT	(CONFIG_BASE_SMALL ? 4 : 6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
  #else
  #define RADIX_TREE_MAP_SHIFT	3	/* For more stressful testing */
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
47
48
  
  #define RADIX_TREE_MAP_SIZE	(1UL << RADIX_TREE_MAP_SHIFT)
  #define RADIX_TREE_MAP_MASK	(RADIX_TREE_MAP_SIZE-1)
  
  #define RADIX_TREE_TAG_LONGS	\
  	((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG)
  
  struct radix_tree_node {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
49
  	unsigned int	height;		/* Height from the bottom */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  	unsigned int	count;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
51
  	struct rcu_head	rcu_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  	void		*slots[RADIX_TREE_MAP_SIZE];
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
53
  	unsigned long	tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
  };
  
  struct radix_tree_path {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
57
  	struct radix_tree_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
  	int offset;
  };
  
  #define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
26fb1589c   Jeff Moyer   fix the max path ...
62
63
  #define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \
  					  RADIX_TREE_MAP_SHIFT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

26fb1589c   Jeff Moyer   fix the max path ...
65
66
67
68
69
  /*
   * The height_to_maxindex array needs to be one deeper than the maximum
   * path as height 0 holds only 1 entry.
   */
  static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH + 1] __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
  
  /*
   * Radix tree node cache.
   */
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
74
  static struct kmem_cache *radix_tree_node_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
  
  /*
   * Per-cpu pool of preloaded nodes
   */
  struct radix_tree_preload {
  	int nr;
  	struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH];
  };
8cef7d57a   Harvey Harrison   lib: radix_tree.c...
83
  static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

612d6c19d   Nick Piggin   [PATCH] radix-tre...
85
86
87
88
  static inline gfp_t root_gfp_mask(struct radix_tree_root *root)
  {
  	return root->gfp_mask & __GFP_BITS_MASK;
  }
643b52b9c   Nick Piggin   radix-tree: fix s...
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  static inline void tag_set(struct radix_tree_node *node, unsigned int tag,
  		int offset)
  {
  	__set_bit(offset, node->tags[tag]);
  }
  
  static inline void tag_clear(struct radix_tree_node *node, unsigned int tag,
  		int offset)
  {
  	__clear_bit(offset, node->tags[tag]);
  }
  
  static inline int tag_get(struct radix_tree_node *node, unsigned int tag,
  		int offset)
  {
  	return test_bit(offset, node->tags[tag]);
  }
  
  static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag)
  {
  	root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT));
  }
  
  static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag)
  {
  	root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT));
  }
  
  static inline void root_tag_clear_all(struct radix_tree_root *root)
  {
  	root->gfp_mask &= __GFP_BITS_MASK;
  }
  
  static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag)
  {
  	return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
  }
  
  /*
   * Returns 1 if any slot in the node has this tag set.
   * Otherwise returns 0.
   */
  static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag)
  {
  	int idx;
  	for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
  		if (node->tags[tag][idx])
  			return 1;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
145
146
  /*
   * This assumes that the caller has performed appropriate preallocation, and
   * that the caller has pinned this thread of control to the current CPU.
   */
  static struct radix_tree_node *
  radix_tree_node_alloc(struct radix_tree_root *root)
  {
e2848a0ef   Nick Piggin   radix-tree: avoid...
147
  	struct radix_tree_node *ret = NULL;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
148
  	gfp_t gfp_mask = root_gfp_mask(root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

e2848a0ef   Nick Piggin   radix-tree: avoid...
150
  	if (!(gfp_mask & __GFP_WAIT)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  		struct radix_tree_preload *rtp;
e2848a0ef   Nick Piggin   radix-tree: avoid...
152
153
154
155
156
  		/*
  		 * Provided the caller has preloaded here, we will always
  		 * succeed in getting a node here (and never reach
  		 * kmem_cache_alloc)
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
  		rtp = &__get_cpu_var(radix_tree_preloads);
  		if (rtp->nr) {
  			ret = rtp->nodes[rtp->nr - 1];
  			rtp->nodes[rtp->nr - 1] = NULL;
  			rtp->nr--;
  		}
  	}
e2848a0ef   Nick Piggin   radix-tree: avoid...
164
  	if (ret == NULL)
488514d17   Christoph Lameter   Remove set_migrat...
165
  		ret = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
e2848a0ef   Nick Piggin   radix-tree: avoid...
166

c0bc9875b   Nick Piggin   radix-tree: use i...
167
  	BUG_ON(radix_tree_is_indirect_ptr(ret));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
  	return ret;
  }
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
170
171
172
173
  static void radix_tree_node_rcu_free(struct rcu_head *head)
  {
  	struct radix_tree_node *node =
  			container_of(head, struct radix_tree_node, rcu_head);
643b52b9c   Nick Piggin   radix-tree: fix s...
174
175
176
177
178
179
180
181
182
183
  
  	/*
  	 * must only free zeroed nodes into the slab. radix_tree_shrink
  	 * can leave us with a non-NULL entry in the first slot, so clear
  	 * that here to make sure.
  	 */
  	tag_clear(node, 0, 0);
  	tag_clear(node, 1, 0);
  	node->slots[0] = NULL;
  	node->count = 0;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
184
185
  	kmem_cache_free(radix_tree_node_cachep, node);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
  static inline void
  radix_tree_node_free(struct radix_tree_node *node)
  {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
189
  	call_rcu(&node->rcu_head, radix_tree_node_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
195
196
  }
  
  /*
   * Load up this CPU's radix_tree_node buffer with sufficient objects to
   * ensure that the addition of a single element in the tree cannot fail.  On
   * success, return zero, with preemption disabled.  On error, return -ENOMEM
   * with preemption not disabled.
b34df792b   David Howells   FS-Cache: Use rad...
197
198
199
   *
   * To make use of this facility, the radix tree must be initialised without
   * __GFP_WAIT being passed to INIT_RADIX_TREE().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
   */
dd0fc66fb   Al Viro   [PATCH] gfp flags...
201
  int radix_tree_preload(gfp_t gfp_mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
209
210
  {
  	struct radix_tree_preload *rtp;
  	struct radix_tree_node *node;
  	int ret = -ENOMEM;
  
  	preempt_disable();
  	rtp = &__get_cpu_var(radix_tree_preloads);
  	while (rtp->nr < ARRAY_SIZE(rtp->nodes)) {
  		preempt_enable();
488514d17   Christoph Lameter   Remove set_migrat...
211
  		node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
221
222
223
224
  		if (node == NULL)
  			goto out;
  		preempt_disable();
  		rtp = &__get_cpu_var(radix_tree_preloads);
  		if (rtp->nr < ARRAY_SIZE(rtp->nodes))
  			rtp->nodes[rtp->nr++] = node;
  		else
  			kmem_cache_free(radix_tree_node_cachep, node);
  	}
  	ret = 0;
  out:
  	return ret;
  }
d7f0923d8   David Chinner   [LIB]: export rad...
225
  EXPORT_SYMBOL(radix_tree_preload);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226

6e954b9e9   Nick Piggin   [PATCH] radix tre...
227
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
   *	Return the maximum key which can be store into a
   *	radix tree with height HEIGHT.
   */
  static inline unsigned long radix_tree_maxindex(unsigned int height)
  {
  	return height_to_maxindex[height];
  }
  
  /*
   *	Extend a radix tree so it can store key @index.
   */
  static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
  {
  	struct radix_tree_node *node;
  	unsigned int height;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
248
249
250
251
252
253
  	int tag;
  
  	/* Figure out what the height should be.  */
  	height = root->height + 1;
  	while (index > radix_tree_maxindex(height))
  		height++;
  
  	if (root->rnode == NULL) {
  		root->height = height;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  	do {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
255
  		unsigned int newheight;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
  		if (!(node = radix_tree_node_alloc(root)))
  			return -ENOMEM;
  
  		/* Increase the height.  */
c0bc9875b   Nick Piggin   radix-tree: use i...
260
  		node->slots[0] = radix_tree_indirect_to_ptr(root->rnode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
  
  		/* Propagate the aggregated tag info into the new root */
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
263
  		for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
612d6c19d   Nick Piggin   [PATCH] radix-tre...
264
  			if (root_tag_get(root, tag))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
  				tag_set(node, tag, 0);
  		}
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
267
268
  		newheight = root->height+1;
  		node->height = newheight;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  		node->count = 1;
c0bc9875b   Nick Piggin   radix-tree: use i...
270
  		node = radix_tree_ptr_to_indirect(node);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
271
272
  		rcu_assign_pointer(root->rnode, node);
  		root->height = newheight;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  	} while (height > root->height);
  out:
  	return 0;
  }
  
  /**
   *	radix_tree_insert    -    insert into a radix tree
   *	@root:		radix tree root
   *	@index:		index key
   *	@item:		item to insert
   *
   *	Insert an item into the radix tree at position @index.
   */
  int radix_tree_insert(struct radix_tree_root *root,
  			unsigned long index, void *item)
  {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
289
  	struct radix_tree_node *node = NULL, *slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
  	unsigned int height, shift;
  	int offset;
  	int error;
c0bc9875b   Nick Piggin   radix-tree: use i...
293
  	BUG_ON(radix_tree_is_indirect_ptr(item));
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
294

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  	/* Make sure the tree is high enough.  */
612d6c19d   Nick Piggin   [PATCH] radix-tre...
296
  	if (index > radix_tree_maxindex(root->height)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
  		error = radix_tree_extend(root, index);
  		if (error)
  			return error;
  	}
c0bc9875b   Nick Piggin   radix-tree: use i...
301
  	slot = radix_tree_indirect_to_ptr(root->rnode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
  	height = root->height;
  	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
  
  	offset = 0;			/* uninitialised var warning */
612d6c19d   Nick Piggin   [PATCH] radix-tre...
306
  	while (height > 0) {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
307
  		if (slot == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  			/* Have to add a child node.  */
201b6264f   Christoph Lameter   [PATCH] radix-tre...
309
  			if (!(slot = radix_tree_node_alloc(root)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  				return -ENOMEM;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
311
  			slot->height = height;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
312
  			if (node) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
313
  				rcu_assign_pointer(node->slots[offset], slot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  				node->count++;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
315
  			} else
c0bc9875b   Nick Piggin   radix-tree: use i...
316
317
  				rcu_assign_pointer(root->rnode,
  					radix_tree_ptr_to_indirect(slot));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
  		}
  
  		/* Go a level down */
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
322
323
  		node = slot;
  		slot = node->slots[offset];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
326
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327

201b6264f   Christoph Lameter   [PATCH] radix-tre...
328
  	if (slot != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  		return -EEXIST;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
330

612d6c19d   Nick Piggin   [PATCH] radix-tre...
331
332
  	if (node) {
  		node->count++;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
333
  		rcu_assign_pointer(node->slots[offset], item);
612d6c19d   Nick Piggin   [PATCH] radix-tre...
334
335
336
  		BUG_ON(tag_get(node, 0, offset));
  		BUG_ON(tag_get(node, 1, offset));
  	} else {
c0bc9875b   Nick Piggin   radix-tree: use i...
337
  		rcu_assign_pointer(root->rnode, item);
612d6c19d   Nick Piggin   [PATCH] radix-tre...
338
339
340
  		BUG_ON(root_tag_get(root, 0));
  		BUG_ON(root_tag_get(root, 1));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
  	return 0;
  }
  EXPORT_SYMBOL(radix_tree_insert);
b72b71c6c   Huang Shijie   lib: do code opti...
345
346
347
  /*
   * is_slot == 1 : search for the slot.
   * is_slot == 0 : search for the node.
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
348
   */
b72b71c6c   Huang Shijie   lib: do code opti...
349
350
  static void *radix_tree_lookup_element(struct radix_tree_root *root,
  				unsigned long index, int is_slot)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  {
  	unsigned int height, shift;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
353
  	struct radix_tree_node *node, **slot;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
354

2676a58c9   Paul E. McKenney   radix-tree: Disab...
355
  	node = rcu_dereference_raw(root->rnode);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
356
  	if (node == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  		return NULL;
c0bc9875b   Nick Piggin   radix-tree: use i...
358
  	if (!radix_tree_is_indirect_ptr(node)) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
359
360
  		if (index > 0)
  			return NULL;
b72b71c6c   Huang Shijie   lib: do code opti...
361
  		return is_slot ? (void *)&root->rnode : node;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
362
  	}
c0bc9875b   Nick Piggin   radix-tree: use i...
363
  	node = radix_tree_indirect_to_ptr(node);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
364
365
366
367
  
  	height = node->height;
  	if (index > radix_tree_maxindex(height))
  		return NULL;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
368

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
371
372
373
  	do {
  		slot = (struct radix_tree_node **)
  			(node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
2676a58c9   Paul E. McKenney   radix-tree: Disab...
374
  		node = rcu_dereference_raw(*slot);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
375
  		if (node == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  			return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
379
  	} while (height > 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380

b72b71c6c   Huang Shijie   lib: do code opti...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  	return is_slot ? (void *)slot:node;
  }
  
  /**
   *	radix_tree_lookup_slot    -    lookup a slot in a radix tree
   *	@root:		radix tree root
   *	@index:		index key
   *
   *	Returns:  the slot corresponding to the position @index in the
   *	radix tree @root. This is useful for update-if-exists operations.
   *
   *	This function can be called under rcu_read_lock iff the slot is not
   *	modified by radix_tree_replace_slot, otherwise it must be called
   *	exclusive from other writers. Any dereference of the slot must be done
   *	using radix_tree_deref_slot.
   */
  void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
  {
  	return (void **)radix_tree_lookup_element(root, index, 1);
a43313668   Hans Reiser   [PATCH] reiser4: ...
400
  }
a43313668   Hans Reiser   [PATCH] reiser4: ...
401
402
403
404
405
406
407
408
  EXPORT_SYMBOL(radix_tree_lookup_slot);
  
  /**
   *	radix_tree_lookup    -    perform lookup operation on a radix tree
   *	@root:		radix tree root
   *	@index:		index key
   *
   *	Lookup the item at the position @index in the radix tree @root.
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
409
410
411
412
413
   *
   *	This function can be called under rcu_read_lock, however the caller
   *	must manage lifetimes of leaf nodes (eg. RCU may also be used to free
   *	them safely). No RCU barriers are required to access or modify the
   *	returned item, however.
a43313668   Hans Reiser   [PATCH] reiser4: ...
414
415
416
   */
  void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
  {
b72b71c6c   Huang Shijie   lib: do code opti...
417
  	return radix_tree_lookup_element(root, index, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
422
423
424
425
426
  }
  EXPORT_SYMBOL(radix_tree_lookup);
  
  /**
   *	radix_tree_tag_set - set a tag on a radix tree node
   *	@root:		radix tree root
   *	@index:		index key
   *	@tag: 		tag index
   *
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
427
428
   *	Set the search tag (which must be < RADIX_TREE_MAX_TAGS)
   *	corresponding to @index in the radix tree.  From
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
   *	the root all the way down to the leaf node.
   *
   *	Returns the address of the tagged item.   Setting a tag on a not-present
   *	item is a bug.
   */
  void *radix_tree_tag_set(struct radix_tree_root *root,
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
435
  			unsigned long index, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
  {
  	unsigned int height, shift;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
438
  	struct radix_tree_node *slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  
  	height = root->height;
4c91c3648   Peter Zijlstra   [PATCH] buglet in...
441
  	BUG_ON(index > radix_tree_maxindex(height));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442

c0bc9875b   Nick Piggin   radix-tree: use i...
443
  	slot = radix_tree_indirect_to_ptr(root->rnode);
612d6c19d   Nick Piggin   [PATCH] radix-tre...
444
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
  
  	while (height > 0) {
  		int offset;
  
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
d5274261e   Nick Piggin   [PATCH] radix tre...
450
451
  		if (!tag_get(slot, tag, offset))
  			tag_set(slot, tag, offset);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
452
453
  		slot = slot->slots[offset];
  		BUG_ON(slot == NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
456
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
  	}
612d6c19d   Nick Piggin   [PATCH] radix-tre...
457
458
459
  	/* set the root's tag bit */
  	if (slot && !root_tag_get(root, tag))
  		root_tag_set(root, tag);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
460
  	return slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
467
468
469
  }
  EXPORT_SYMBOL(radix_tree_tag_set);
  
  /**
   *	radix_tree_tag_clear - clear a tag on a radix tree node
   *	@root:		radix tree root
   *	@index:		index key
   *	@tag: 		tag index
   *
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
470
471
   *	Clear the search tag (which must be < RADIX_TREE_MAX_TAGS)
   *	corresponding to @index in the radix tree.  If
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
477
478
   *	this causes the leaf node to have no tags set then clear the tag in the
   *	next-to-leaf node, etc.
   *
   *	Returns the address of the tagged item on success, else NULL.  ie:
   *	has the same return value and semantics as radix_tree_lookup().
   */
  void *radix_tree_tag_clear(struct radix_tree_root *root,
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
479
  			unsigned long index, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  {
26fb1589c   Jeff Moyer   fix the max path ...
481
482
483
484
485
  	/*
  	 * The radix tree path needs to be one longer than the maximum path
  	 * since the "list" is null terminated.
  	 */
  	struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
486
  	struct radix_tree_node *slot = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  	unsigned int height, shift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
493
494
  
  	height = root->height;
  	if (index > radix_tree_maxindex(height))
  		goto out;
  
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
  	pathp->node = NULL;
c0bc9875b   Nick Piggin   radix-tree: use i...
495
  	slot = radix_tree_indirect_to_ptr(root->rnode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
  
  	while (height > 0) {
  		int offset;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
499
  		if (slot == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
502
503
  			goto out;
  
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
  		pathp[1].offset = offset;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
504
505
  		pathp[1].node = slot;
  		slot = slot->slots[offset];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
  		pathp++;
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
  	}
612d6c19d   Nick Piggin   [PATCH] radix-tre...
510
  	if (slot == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  		goto out;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
512
  	while (pathp->node) {
d5274261e   Nick Piggin   [PATCH] radix tre...
513
514
  		if (!tag_get(pathp->node, tag, pathp->offset))
  			goto out;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
515
  		tag_clear(pathp->node, tag, pathp->offset);
6e954b9e9   Nick Piggin   [PATCH] radix tre...
516
517
  		if (any_tag_set(pathp->node, tag))
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  		pathp--;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
519
520
521
522
523
  	}
  
  	/* clear the root's tag bit */
  	if (root_tag_get(root, tag))
  		root_tag_clear(root, tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  out:
612d6c19d   Nick Piggin   [PATCH] radix-tre...
525
  	return slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
  }
  EXPORT_SYMBOL(radix_tree_tag_clear);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  /**
32605a181   Marcelo Tosatti   [PATCH] radix_tag...
529
530
531
   * radix_tree_tag_get - get a tag on a radix tree node
   * @root:		radix tree root
   * @index:		index key
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
532
   * @tag: 		tag index (< RADIX_TREE_MAX_TAGS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
   *
32605a181   Marcelo Tosatti   [PATCH] radix_tag...
534
   * Return values:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
   *
612d6c19d   Nick Piggin   [PATCH] radix-tre...
536
537
   *  0: tag not present or not set
   *  1: tag set
ce82653d6   David Howells   radix_tree_tag_ge...
538
539
540
541
   *
   * Note that the return value of this function may not be relied on, even if
   * the RCU lock is held, unless tag modification and node deletion are excluded
   * from concurrency.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
   */
  int radix_tree_tag_get(struct radix_tree_root *root,
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
544
  			unsigned long index, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
  {
  	unsigned int height, shift;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
547
  	struct radix_tree_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  	int saw_unset_tag = 0;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
549
550
551
  	/* check the root's tag bit */
  	if (!root_tag_get(root, tag))
  		return 0;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
552
  	node = rcu_dereference_raw(root->rnode);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
553
554
  	if (node == NULL)
  		return 0;
c0bc9875b   Nick Piggin   radix-tree: use i...
555
  	if (!radix_tree_is_indirect_ptr(node))
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
556
  		return (index == 0);
c0bc9875b   Nick Piggin   radix-tree: use i...
557
  	node = radix_tree_indirect_to_ptr(node);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
558
559
560
561
  
  	height = node->height;
  	if (index > radix_tree_maxindex(height))
  		return 0;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
562

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
  
  	for ( ; ; ) {
  		int offset;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
567
  		if (node == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
570
571
572
573
574
575
  			return 0;
  
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
  
  		/*
  		 * This is just a debug check.  Later, we can bale as soon as
  		 * we see an unset tag.
  		 */
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
576
  		if (!tag_get(node, tag, offset))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  			saw_unset_tag = 1;
ce82653d6   David Howells   radix_tree_tag_ge...
578
579
  		if (height == 1)
  			return !!tag_get(node, tag, offset);
2676a58c9   Paul E. McKenney   radix-tree: Disab...
580
  		node = rcu_dereference_raw(node->slots[offset]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
583
584
585
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
  	}
  }
  EXPORT_SYMBOL(radix_tree_tag_get);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586

6df8ba4f8   Fengguang Wu   radixtree: introd...
587
  /**
ebf8aa44b   Jan Kara   radix-tree: omple...
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
   * radix_tree_range_tag_if_tagged - for each item in given range set given
   *				   tag if item has another tag set
   * @root:		radix tree root
   * @first_indexp:	pointer to a starting index of a range to scan
   * @last_index:		last index of a range to scan
   * @nr_to_tag:		maximum number items to tag
   * @iftag:		tag index to test
   * @settag:		tag index to set if tested tag is set
   *
   * This function scans range of radix tree from first_index to last_index
   * (inclusive).  For each item in the range if iftag is set, the function sets
   * also settag. The function stops either after tagging nr_to_tag items or
   * after reaching last_index.
   *
   * The function returns number of leaves where the tag was set and sets
   * *first_indexp to the first unscanned index.
   */
  unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
  		unsigned long *first_indexp, unsigned long last_index,
  		unsigned long nr_to_tag,
  		unsigned int iftag, unsigned int settag)
  {
  	unsigned int height = root->height, shift;
  	unsigned long tagged = 0, index = *first_indexp;
  	struct radix_tree_node *open_slots[height], *slot;
  
  	last_index = min(last_index, radix_tree_maxindex(height));
  	if (index > last_index)
  		return 0;
  	if (!nr_to_tag)
  		return 0;
  	if (!root_tag_get(root, iftag)) {
  		*first_indexp = last_index + 1;
  		return 0;
  	}
  	if (height == 0) {
  		*first_indexp = last_index + 1;
  		root_tag_set(root, settag);
  		return 1;
  	}
  
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
  	slot = radix_tree_indirect_to_ptr(root->rnode);
  
  	for (;;) {
  		int offset;
  
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
  		if (!slot->slots[offset])
  			goto next;
  		if (!tag_get(slot, iftag, offset))
  			goto next;
  		tag_set(slot, settag, offset);
  		if (height == 1) {
  			tagged++;
  			goto next;
  		}
  		/* Go down one level */
  		height--;
  		shift -= RADIX_TREE_MAP_SHIFT;
  		open_slots[height] = slot;
  		slot = slot->slots[offset];
  		continue;
  next:
  		/* Go to next item at level determined by 'shift' */
  		index = ((index >> shift) + 1) << shift;
  		if (index > last_index)
  			break;
  		if (tagged >= nr_to_tag)
  			break;
  		while (((index >> shift) & RADIX_TREE_MAP_MASK) == 0) {
  			/*
  			 * We've fully scanned this node. Go up. Because
  			 * last_index is guaranteed to be in the tree, what
  			 * we do below cannot wander astray.
  			 */
  			slot = open_slots[height];
  			height++;
  			shift += RADIX_TREE_MAP_SHIFT;
  		}
  	}
  	/*
  	 * The iftag must have been set somewhere because otherwise
  	 * we would return immediated at the beginning of the function
  	 */
  	root_tag_set(root, settag);
  	*first_indexp = index;
  
  	return tagged;
  }
  EXPORT_SYMBOL(radix_tree_range_tag_if_tagged);
  
  
  /**
6df8ba4f8   Fengguang Wu   radixtree: introd...
682
683
684
685
686
687
688
689
690
691
   *	radix_tree_next_hole    -    find the next hole (not-present entry)
   *	@root:		tree root
   *	@index:		index key
   *	@max_scan:	maximum range to search
   *
   *	Search the set [index, min(index+max_scan-1, MAX_INDEX)] for the lowest
   *	indexed hole.
   *
   *	Returns: the index of the hole if found, otherwise returns an index
   *	outside of the set specified (in which case 'return - index >= max_scan'
8e6bdb7f8   Wu Fengguang   trivial: radix-tr...
692
   *	will be true). In rare cases of index wrap-around, 0 will be returned.
6df8ba4f8   Fengguang Wu   radixtree: introd...
693
694
   *
   *	radix_tree_next_hole may be called under rcu_read_lock. However, like
8e6bdb7f8   Wu Fengguang   trivial: radix-tr...
695
696
697
698
699
   *	radix_tree_gang_lookup, this will not atomically search a snapshot of
   *	the tree at a single point in time. For example, if a hole is created
   *	at index 5, then subsequently a hole is created at index 10,
   *	radix_tree_next_hole covering both indexes may return 10 if called
   *	under rcu_read_lock.
6df8ba4f8   Fengguang Wu   radixtree: introd...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
   */
  unsigned long radix_tree_next_hole(struct radix_tree_root *root,
  				unsigned long index, unsigned long max_scan)
  {
  	unsigned long i;
  
  	for (i = 0; i < max_scan; i++) {
  		if (!radix_tree_lookup(root, index))
  			break;
  		index++;
  		if (index == 0)
  			break;
  	}
  
  	return index;
  }
  EXPORT_SYMBOL(radix_tree_next_hole);
dc566127d   Wu Fengguang   radix-tree: add r...
717
718
719
720
721
722
723
724
725
726
727
  /**
   *	radix_tree_prev_hole    -    find the prev hole (not-present entry)
   *	@root:		tree root
   *	@index:		index key
   *	@max_scan:	maximum range to search
   *
   *	Search backwards in the range [max(index-max_scan+1, 0), index]
   *	for the first hole.
   *
   *	Returns: the index of the hole if found, otherwise returns an index
   *	outside of the set specified (in which case 'index - return >= max_scan'
edcd1d843   Cesar Eduardo Barros   radix-tree: fix r...
728
   *	will be true). In rare cases of wrap-around, ULONG_MAX will be returned.
dc566127d   Wu Fengguang   radix-tree: add r...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
   *
   *	radix_tree_next_hole may be called under rcu_read_lock. However, like
   *	radix_tree_gang_lookup, this will not atomically search a snapshot of
   *	the tree at a single point in time. For example, if a hole is created
   *	at index 10, then subsequently a hole is created at index 5,
   *	radix_tree_prev_hole covering both indexes may return 5 if called under
   *	rcu_read_lock.
   */
  unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
  				   unsigned long index, unsigned long max_scan)
  {
  	unsigned long i;
  
  	for (i = 0; i < max_scan; i++) {
  		if (!radix_tree_lookup(root, index))
  			break;
  		index--;
edcd1d843   Cesar Eduardo Barros   radix-tree: fix r...
746
  		if (index == ULONG_MAX)
dc566127d   Wu Fengguang   radix-tree: add r...
747
748
749
750
751
752
  			break;
  	}
  
  	return index;
  }
  EXPORT_SYMBOL(radix_tree_prev_hole);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  static unsigned int
47feff2c8   Nick Piggin   radix-tree: add g...
754
  __lookup(struct radix_tree_node *slot, void ***results, unsigned long index,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
757
  	unsigned int max_items, unsigned long *next_index)
  {
  	unsigned int nr_found = 0;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
758
  	unsigned int shift, height;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
759
  	unsigned long i;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
760
761
  	height = slot->height;
  	if (height == 0)
201b6264f   Christoph Lameter   [PATCH] radix-tre...
762
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764

201b6264f   Christoph Lameter   [PATCH] radix-tre...
765
  	for ( ; height > 1; height--) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
766
767
  		i = (index >> shift) & RADIX_TREE_MAP_MASK;
  		for (;;) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
771
772
773
  			if (slot->slots[i] != NULL)
  				break;
  			index &= ~((1UL << shift) - 1);
  			index += 1UL << shift;
  			if (index == 0)
  				goto out;	/* 32-bit wraparound */
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
774
775
776
  			i++;
  			if (i == RADIX_TREE_MAP_SIZE)
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  		shift -= RADIX_TREE_MAP_SHIFT;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
780
  		slot = rcu_dereference_raw(slot->slots[i]);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
781
782
  		if (slot == NULL)
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  	}
201b6264f   Christoph Lameter   [PATCH] radix-tre...
784
785
786
787
  
  	/* Bottom level: grab some items */
  	for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
  		index++;
47feff2c8   Nick Piggin   radix-tree: add g...
788
789
  		if (slot->slots[i]) {
  			results[nr_found++] = &(slot->slots[i]);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
790
791
792
793
  			if (nr_found == max_items)
  				goto out;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
  out:
  	*next_index = index;
  	return nr_found;
  }
  
  /**
   *	radix_tree_gang_lookup - perform multiple lookup on a radix tree
   *	@root:		radix tree root
   *	@results:	where the results of the lookup are placed
   *	@first_index:	start the lookup from this key
   *	@max_items:	place up to this many items at *results
   *
   *	Performs an index-ascending scan of the tree for present items.  Places
   *	them at *@results and returns the number of items which were placed at
   *	*@results.
   *
   *	The implementation is naive.
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
811
812
813
814
815
816
   *
   *	Like radix_tree_lookup, radix_tree_gang_lookup may be called under
   *	rcu_read_lock. In this case, rather than the returned results being
   *	an atomic snapshot of the tree at a single point in time, the semantics
   *	of an RCU protected gang lookup are as though multiple radix_tree_lookups
   *	have been issued in individual locks, and results stored in 'results'.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
819
820
821
   */
  unsigned int
  radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
  			unsigned long first_index, unsigned int max_items)
  {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
822
823
  	unsigned long max_index;
  	struct radix_tree_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  	unsigned long cur_index = first_index;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
825
  	unsigned int ret;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
826
  	node = rcu_dereference_raw(root->rnode);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
827
828
  	if (!node)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829

c0bc9875b   Nick Piggin   radix-tree: use i...
830
  	if (!radix_tree_is_indirect_ptr(node)) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
831
832
  		if (first_index > 0)
  			return 0;
c0bc9875b   Nick Piggin   radix-tree: use i...
833
  		results[0] = node;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
834
835
  		return 1;
  	}
c0bc9875b   Nick Piggin   radix-tree: use i...
836
  	node = radix_tree_indirect_to_ptr(node);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
837
838
839
840
  
  	max_index = radix_tree_maxindex(node->height);
  
  	ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  	while (ret < max_items) {
47feff2c8   Nick Piggin   radix-tree: add g...
842
  		unsigned int nr_found, slots_found, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
  		unsigned long next_index;	/* Index of next search */
  
  		if (cur_index > max_index)
  			break;
47feff2c8   Nick Piggin   radix-tree: add g...
847
  		slots_found = __lookup(node, (void ***)results + ret, cur_index,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  					max_items - ret, &next_index);
47feff2c8   Nick Piggin   radix-tree: add g...
849
850
851
852
853
854
  		nr_found = 0;
  		for (i = 0; i < slots_found; i++) {
  			struct radix_tree_node *slot;
  			slot = *(((void ***)results)[ret + i]);
  			if (!slot)
  				continue;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
855
  			results[ret + nr_found] = rcu_dereference_raw(slot);
47feff2c8   Nick Piggin   radix-tree: add g...
856
857
  			nr_found++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
860
861
862
  		ret += nr_found;
  		if (next_index == 0)
  			break;
  		cur_index = next_index;
  	}
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
863

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
865
866
  	return ret;
  }
  EXPORT_SYMBOL(radix_tree_gang_lookup);
47feff2c8   Nick Piggin   radix-tree: add g...
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
  /**
   *	radix_tree_gang_lookup_slot - perform multiple slot lookup on radix tree
   *	@root:		radix tree root
   *	@results:	where the results of the lookup are placed
   *	@first_index:	start the lookup from this key
   *	@max_items:	place up to this many items at *results
   *
   *	Performs an index-ascending scan of the tree for present items.  Places
   *	their slots at *@results and returns the number of items which were
   *	placed at *@results.
   *
   *	The implementation is naive.
   *
   *	Like radix_tree_gang_lookup as far as RCU and locking goes. Slots must
   *	be dereferenced with radix_tree_deref_slot, and if using only RCU
   *	protection, radix_tree_deref_slot may fail requiring a retry.
   */
  unsigned int
  radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
  			unsigned long first_index, unsigned int max_items)
  {
  	unsigned long max_index;
  	struct radix_tree_node *node;
  	unsigned long cur_index = first_index;
  	unsigned int ret;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
892
  	node = rcu_dereference_raw(root->rnode);
47feff2c8   Nick Piggin   radix-tree: add g...
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
  	if (!node)
  		return 0;
  
  	if (!radix_tree_is_indirect_ptr(node)) {
  		if (first_index > 0)
  			return 0;
  		results[0] = (void **)&root->rnode;
  		return 1;
  	}
  	node = radix_tree_indirect_to_ptr(node);
  
  	max_index = radix_tree_maxindex(node->height);
  
  	ret = 0;
  	while (ret < max_items) {
  		unsigned int slots_found;
  		unsigned long next_index;	/* Index of next search */
  
  		if (cur_index > max_index)
  			break;
  		slots_found = __lookup(node, results + ret, cur_index,
  					max_items - ret, &next_index);
  		ret += slots_found;
  		if (next_index == 0)
  			break;
  		cur_index = next_index;
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL(radix_tree_gang_lookup_slot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
926
927
928
  /*
   * FIXME: the two tag_get()s here should use find_next_bit() instead of
   * open-coding the search.
   */
  static unsigned int
47feff2c8   Nick Piggin   radix-tree: add g...
929
  __lookup_tag(struct radix_tree_node *slot, void ***results, unsigned long index,
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
930
  	unsigned int max_items, unsigned long *next_index, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
932
  {
  	unsigned int nr_found = 0;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
933
  	unsigned int shift, height;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
935
936
  	height = slot->height;
  	if (height == 0)
612d6c19d   Nick Piggin   [PATCH] radix-tre...
937
  		goto out;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
938
  	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
940
941
  	while (height > 0) {
  		unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
943
944
  		for (;;) {
  			if (tag_get(slot, tag, i))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
949
  			index &= ~((1UL << shift) - 1);
  			index += 1UL << shift;
  			if (index == 0)
  				goto out;	/* 32-bit wraparound */
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
950
951
952
  			i++;
  			if (i == RADIX_TREE_MAP_SIZE)
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
957
958
959
  		height--;
  		if (height == 0) {	/* Bottom level: grab some items */
  			unsigned long j = index & RADIX_TREE_MAP_MASK;
  
  			for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
  				index++;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
960
961
  				if (!tag_get(slot, tag, j))
  					continue;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
962
963
964
965
966
967
968
969
970
971
  				/*
  				 * Even though the tag was found set, we need to
  				 * recheck that we have a non-NULL node, because
  				 * if this lookup is lockless, it may have been
  				 * subsequently deleted.
  				 *
  				 * Similar care must be taken in any place that
  				 * lookup ->slots[x] without a lock (ie. can't
  				 * rely on its value remaining the same).
  				 */
47feff2c8   Nick Piggin   radix-tree: add g...
972
973
  				if (slot->slots[j]) {
  					results[nr_found++] = &(slot->slots[j]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
976
977
978
979
  					if (nr_found == max_items)
  						goto out;
  				}
  			}
  		}
  		shift -= RADIX_TREE_MAP_SHIFT;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
980
  		slot = rcu_dereference_raw(slot->slots[i]);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
981
982
983
  		if (slot == NULL)
  			break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
985
986
987
988
989
990
991
992
993
994
995
  out:
  	*next_index = index;
  	return nr_found;
  }
  
  /**
   *	radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree
   *	                             based on a tag
   *	@root:		radix tree root
   *	@results:	where the results of the lookup are placed
   *	@first_index:	start the lookup from this key
   *	@max_items:	place up to this many items at *results
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
996
   *	@tag:		the tag index (< RADIX_TREE_MAX_TAGS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
1000
1001
1002
1003
   *
   *	Performs an index-ascending scan of the tree for present items which
   *	have the tag indexed by @tag set.  Places the items at *@results and
   *	returns the number of items which were placed at *@results.
   */
  unsigned int
  radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
1004
1005
  		unsigned long first_index, unsigned int max_items,
  		unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1007
1008
  	struct radix_tree_node *node;
  	unsigned long max_index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
  	unsigned long cur_index = first_index;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1010
  	unsigned int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011

612d6c19d   Nick Piggin   [PATCH] radix-tre...
1012
1013
1014
  	/* check the root's tag bit */
  	if (!root_tag_get(root, tag))
  		return 0;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
1015
  	node = rcu_dereference_raw(root->rnode);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1016
1017
  	if (!node)
  		return 0;
c0bc9875b   Nick Piggin   radix-tree: use i...
1018
  	if (!radix_tree_is_indirect_ptr(node)) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1019
1020
  		if (first_index > 0)
  			return 0;
c0bc9875b   Nick Piggin   radix-tree: use i...
1021
  		results[0] = node;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1022
1023
  		return 1;
  	}
c0bc9875b   Nick Piggin   radix-tree: use i...
1024
  	node = radix_tree_indirect_to_ptr(node);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1025
1026
1027
1028
  
  	max_index = radix_tree_maxindex(node->height);
  
  	ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
  	while (ret < max_items) {
47feff2c8   Nick Piggin   radix-tree: add g...
1030
  		unsigned int nr_found, slots_found, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
1032
1033
1034
  		unsigned long next_index;	/* Index of next search */
  
  		if (cur_index > max_index)
  			break;
47feff2c8   Nick Piggin   radix-tree: add g...
1035
1036
1037
1038
1039
1040
1041
1042
  		slots_found = __lookup_tag(node, (void ***)results + ret,
  				cur_index, max_items - ret, &next_index, tag);
  		nr_found = 0;
  		for (i = 0; i < slots_found; i++) {
  			struct radix_tree_node *slot;
  			slot = *(((void ***)results)[ret + i]);
  			if (!slot)
  				continue;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
1043
  			results[ret + nr_found] = rcu_dereference_raw(slot);
47feff2c8   Nick Piggin   radix-tree: add g...
1044
1045
  			nr_found++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
1050
  		ret += nr_found;
  		if (next_index == 0)
  			break;
  		cur_index = next_index;
  	}
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1051

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
1054
1055
1056
  	return ret;
  }
  EXPORT_SYMBOL(radix_tree_gang_lookup_tag);
  
  /**
47feff2c8   Nick Piggin   radix-tree: add g...
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
   *	radix_tree_gang_lookup_tag_slot - perform multiple slot lookup on a
   *					  radix tree based on a tag
   *	@root:		radix tree root
   *	@results:	where the results of the lookup are placed
   *	@first_index:	start the lookup from this key
   *	@max_items:	place up to this many items at *results
   *	@tag:		the tag index (< RADIX_TREE_MAX_TAGS)
   *
   *	Performs an index-ascending scan of the tree for present items which
   *	have the tag indexed by @tag set.  Places the slots at *@results and
   *	returns the number of slots which were placed at *@results.
   */
  unsigned int
  radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
  		unsigned long first_index, unsigned int max_items,
  		unsigned int tag)
  {
  	struct radix_tree_node *node;
  	unsigned long max_index;
  	unsigned long cur_index = first_index;
  	unsigned int ret;
  
  	/* check the root's tag bit */
  	if (!root_tag_get(root, tag))
  		return 0;
2676a58c9   Paul E. McKenney   radix-tree: Disab...
1082
  	node = rcu_dereference_raw(root->rnode);
47feff2c8   Nick Piggin   radix-tree: add g...
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
  	if (!node)
  		return 0;
  
  	if (!radix_tree_is_indirect_ptr(node)) {
  		if (first_index > 0)
  			return 0;
  		results[0] = (void **)&root->rnode;
  		return 1;
  	}
  	node = radix_tree_indirect_to_ptr(node);
  
  	max_index = radix_tree_maxindex(node->height);
  
  	ret = 0;
  	while (ret < max_items) {
  		unsigned int slots_found;
  		unsigned long next_index;	/* Index of next search */
  
  		if (cur_index > max_index)
  			break;
  		slots_found = __lookup_tag(node, results + ret,
  				cur_index, max_items - ret, &next_index, tag);
  		ret += slots_found;
  		if (next_index == 0)
  			break;
  		cur_index = next_index;
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL(radix_tree_gang_lookup_tag_slot);
  
  
  /**
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1117
1118
1119
1120
1121
1122
   *	radix_tree_shrink    -    shrink height of a radix tree to minimal
   *	@root		radix tree root
   */
  static inline void radix_tree_shrink(struct radix_tree_root *root)
  {
  	/* try to shrink tree height */
c0bc9875b   Nick Piggin   radix-tree: use i...
1123
  	while (root->height > 0) {
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1124
  		struct radix_tree_node *to_free = root->rnode;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1125
  		void *newptr;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1126

c0bc9875b   Nick Piggin   radix-tree: use i...
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  		BUG_ON(!radix_tree_is_indirect_ptr(to_free));
  		to_free = radix_tree_indirect_to_ptr(to_free);
  
  		/*
  		 * The candidate node has more than one child, or its child
  		 * is not at the leftmost slot, we cannot shrink.
  		 */
  		if (to_free->count != 1)
  			break;
  		if (!to_free->slots[0])
  			break;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1138
1139
1140
1141
1142
1143
1144
1145
  		/*
  		 * We don't need rcu_assign_pointer(), since we are simply
  		 * moving the node from one part of the tree to another. If
  		 * it was safe to dereference the old pointer to it
  		 * (to_free->slots[0]), it will be safe to dereference the new
  		 * one (root->rnode).
  		 */
  		newptr = to_free->slots[0];
c0bc9875b   Nick Piggin   radix-tree: use i...
1146
1147
  		if (root->height > 1)
  			newptr = radix_tree_ptr_to_indirect(newptr);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1148
  		root->rnode = newptr;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1149
  		root->height--;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1150
1151
1152
1153
1154
  		radix_tree_node_free(to_free);
  	}
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
   *	radix_tree_delete    -    delete an item from a radix tree
   *	@root:		radix tree root
   *	@index:		index key
   *
   *	Remove the item at @index from the radix tree rooted at @root.
   *
   *	Returns the address of the deleted item, or NULL if it was not present.
   */
  void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
  {
26fb1589c   Jeff Moyer   fix the max path ...
1165
1166
1167
1168
1169
  	/*
  	 * The radix tree path needs to be one longer than the maximum path
  	 * since the "list" is null terminated.
  	 */
  	struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1170
  	struct radix_tree_node *slot = NULL;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1171
  	struct radix_tree_node *to_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
  	unsigned int height, shift;
d5274261e   Nick Piggin   [PATCH] radix tre...
1173
1174
  	int tag;
  	int offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
1176
1177
1178
  
  	height = root->height;
  	if (index > radix_tree_maxindex(height))
  		goto out;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1179
  	slot = root->rnode;
c0bc9875b   Nick Piggin   radix-tree: use i...
1180
  	if (height == 0) {
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1181
1182
1183
1184
  		root_tag_clear_all(root);
  		root->rnode = NULL;
  		goto out;
  	}
c0bc9875b   Nick Piggin   radix-tree: use i...
1185
  	slot = radix_tree_indirect_to_ptr(slot);
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1186

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
  	pathp->node = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189

612d6c19d   Nick Piggin   [PATCH] radix-tre...
1190
  	do {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
1191
  		if (slot == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
  			goto out;
d5274261e   Nick Piggin   [PATCH] radix tre...
1193
  		pathp++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
d5274261e   Nick Piggin   [PATCH] radix tre...
1195
1196
  		pathp->offset = offset;
  		pathp->node = slot;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
1197
  		slot = slot->slots[offset];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
  		shift -= RADIX_TREE_MAP_SHIFT;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1199
1200
  		height--;
  	} while (height > 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201

612d6c19d   Nick Piggin   [PATCH] radix-tre...
1202
  	if (slot == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
1206
  	/*
  	 * Clear all tags associated with the just-deleted item
  	 */
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
1207
  	for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1208
1209
  		if (tag_get(pathp->node, tag, pathp->offset))
  			radix_tree_tag_clear(root, index, tag);
d5274261e   Nick Piggin   [PATCH] radix tre...
1210
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1212
  	to_free = NULL;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
1213
  	/* Now free the nodes we do not need anymore */
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1214
  	while (pathp->node) {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
1215
  		pathp->node->slots[pathp->offset] = NULL;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1216
  		pathp->node->count--;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1217
1218
1219
1220
1221
1222
  		/*
  		 * Queue the node for deferred freeing after the
  		 * last reference to it disappears (set NULL, above).
  		 */
  		if (to_free)
  			radix_tree_node_free(to_free);
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1223
1224
  
  		if (pathp->node->count) {
c0bc9875b   Nick Piggin   radix-tree: use i...
1225
1226
  			if (pathp->node ==
  					radix_tree_indirect_to_ptr(root->rnode))
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1227
  				radix_tree_shrink(root);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
1228
  			goto out;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
1229
  		}
201b6264f   Christoph Lameter   [PATCH] radix-tre...
1230
1231
  
  		/* Node with zero slots in use so free it */
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1232
  		to_free = pathp->node;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1233
  		pathp--;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1234

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
  	}
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1236
  	root_tag_clear_all(root);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
1237
  	root->height = 0;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1238
  	root->rnode = NULL;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
1239
1240
  	if (to_free)
  		radix_tree_node_free(to_free);
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1241

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
  out:
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1243
  	return slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
1245
1246
1247
1248
1249
1250
1251
  }
  EXPORT_SYMBOL(radix_tree_delete);
  
  /**
   *	radix_tree_tagged - test whether any items in the tree are tagged
   *	@root:		radix tree root
   *	@tag:		tag to test
   */
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
1252
  int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253
  {
612d6c19d   Nick Piggin   [PATCH] radix-tre...
1254
  	return root_tag_get(root, tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255
1256
1257
1258
  }
  EXPORT_SYMBOL(radix_tree_tagged);
  
  static void
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
1259
  radix_tree_node_ctor(void *node)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260
1261
1262
1263
1264
1265
  {
  	memset(node, 0, sizeof(struct radix_tree_node));
  }
  
  static __init unsigned long __maxindex(unsigned int height)
  {
430d275a3   Peter Lund   avoid negative (a...
1266
1267
1268
1269
1270
1271
1272
1273
  	unsigned int width = height * RADIX_TREE_MAP_SHIFT;
  	int shift = RADIX_TREE_INDEX_BITS - width;
  
  	if (shift < 0)
  		return ~0UL;
  	if (shift >= BITS_PER_LONG)
  		return 0UL;
  	return ~0UL >> shift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
1275
1276
1277
1278
1279
1280
1281
1282
  }
  
  static __init void radix_tree_init_maxindex(void)
  {
  	unsigned int i;
  
  	for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++)
  		height_to_maxindex[i] = __maxindex(i);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
1284
1285
1286
1287
1288
1289
1290
  static int radix_tree_callback(struct notifier_block *nfb,
                              unsigned long action,
                              void *hcpu)
  {
         int cpu = (long)hcpu;
         struct radix_tree_preload *rtp;
  
         /* Free per-cpu pool of perloaded nodes */
8bb784428   Rafael J. Wysocki   Add suspend-relat...
1291
         if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
                 rtp = &per_cpu(radix_tree_preloads, cpu);
                 while (rtp->nr) {
                         kmem_cache_free(radix_tree_node_cachep,
                                         rtp->nodes[rtp->nr-1]);
                         rtp->nodes[rtp->nr-1] = NULL;
                         rtp->nr--;
                 }
         }
         return NOTIFY_OK;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
1303
1304
1305
1306
  
  void __init radix_tree_init(void)
  {
  	radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
  			sizeof(struct radix_tree_node), 0,
488514d17   Christoph Lameter   Remove set_migrat...
1307
1308
  			SLAB_PANIC | SLAB_RECLAIM_ACCOUNT,
  			radix_tree_node_ctor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
1310
1311
  	radix_tree_init_maxindex();
  	hotcpu_notifier(radix_tree_callback, 0);
  }