Blame view

lib/radix-tree.c 25.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * Copyright (C) 2001 Momchil Velikov
   * Portions Copyright (C) 2001 Christoph Hellwig
201b6264f   Christoph Lameter   [PATCH] radix-tre...
4
   * Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
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
31
32
33
   *
   * 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>
  #include <linux/gfp.h>
  #include <linux/string.h>
  #include <linux/bitops.h>
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
34
  #include <linux/rcupdate.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
  
  
  #ifdef __KERNEL__
cfd9b7df4   Nick Piggin   [PATCH] radix-tre...
38
  #define RADIX_TREE_MAP_SHIFT	(CONFIG_BASE_SMALL ? 4 : 6)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #else
  #define RADIX_TREE_MAP_SHIFT	3	/* For more stressful testing */
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
  
  #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...
50
  	unsigned int	height;		/* Height from the bottom */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  	unsigned int	count;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
52
  	struct rcu_head	rcu_head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  	void		*slots[RADIX_TREE_MAP_SIZE];
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
54
  	unsigned long	tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
  };
  
  struct radix_tree_path {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
58
  	struct radix_tree_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
  	int offset;
  };
  
  #define RADIX_TREE_INDEX_BITS  (8 /* CHAR_BIT */ * sizeof(unsigned long))
  #define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2)
6c036527a   Christoph Lameter   [PATCH] mostly_re...
64
  static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH] __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
  
  /*
   * Radix tree node cache.
   */
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
69
  static struct kmem_cache *radix_tree_node_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
77
78
  
  /*
   * Per-cpu pool of preloaded nodes
   */
  struct radix_tree_preload {
  	int nr;
  	struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH];
  };
  DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
612d6c19d   Nick Piggin   [PATCH] radix-tre...
79
80
81
82
  static inline gfp_t root_gfp_mask(struct radix_tree_root *root)
  {
  	return root->gfp_mask & __GFP_BITS_MASK;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
88
89
90
  /*
   * 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)
  {
  	struct radix_tree_node *ret;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
91
  	gfp_t gfp_mask = root_gfp_mask(root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

612d6c19d   Nick Piggin   [PATCH] radix-tre...
93
94
  	ret = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
  	if (ret == NULL && !(gfp_mask & __GFP_WAIT)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
99
100
101
102
103
  		struct radix_tree_preload *rtp;
  
  		rtp = &__get_cpu_var(radix_tree_preloads);
  		if (rtp->nr) {
  			ret = rtp->nodes[rtp->nr - 1];
  			rtp->nodes[rtp->nr - 1] = NULL;
  			rtp->nr--;
  		}
  	}
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
104
  	BUG_ON(radix_tree_is_direct_ptr(ret));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  	return ret;
  }
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
107
108
109
110
111
112
  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);
  	kmem_cache_free(radix_tree_node_cachep, node);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
  static inline void
  radix_tree_node_free(struct radix_tree_node *node)
  {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
116
  	call_rcu(&node->rcu_head, radix_tree_node_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
  }
  
  /*
   * 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.
   */
dd0fc66fb   Al Viro   [PATCH] gfp flags...
125
  int radix_tree_preload(gfp_t gfp_mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  {
  	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();
  		node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
  		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;
  }
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
149
150
  static inline void tag_set(struct radix_tree_node *node, unsigned int tag,
  		int offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  {
d5274261e   Nick Piggin   [PATCH] radix tre...
152
  	__set_bit(offset, node->tags[tag]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  }
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
154
155
  static inline void tag_clear(struct radix_tree_node *node, unsigned int tag,
  		int offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  {
d5274261e   Nick Piggin   [PATCH] radix tre...
157
  	__clear_bit(offset, node->tags[tag]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  }
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
159
160
  static inline int tag_get(struct radix_tree_node *node, unsigned int tag,
  		int offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  {
d5274261e   Nick Piggin   [PATCH] radix tre...
162
  	return test_bit(offset, node->tags[tag]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  }
612d6c19d   Nick Piggin   [PATCH] radix-tre...
164
165
  static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag)
  {
20241ad40   Al Viro   [PATCH] gfp annot...
166
  	root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT));
612d6c19d   Nick Piggin   [PATCH] radix-tre...
167
168
169
170
171
  }
  
  
  static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag)
  {
20241ad40   Al Viro   [PATCH] gfp annot...
172
  	root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT));
612d6c19d   Nick Piggin   [PATCH] radix-tre...
173
174
175
176
177
178
179
180
181
  }
  
  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)
  {
20241ad40   Al Viro   [PATCH] gfp annot...
182
  	return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
612d6c19d   Nick Piggin   [PATCH] radix-tre...
183
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  /*
6e954b9e9   Nick Piggin   [PATCH] radix tre...
185
186
187
   * Returns 1 if any slot in the node has this tag set.
   * Otherwise returns 0.
   */
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
188
  static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag)
6e954b9e9   Nick Piggin   [PATCH] radix tre...
189
190
191
192
193
194
195
196
197
198
  {
  	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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
   *	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
214
215
216
217
218
219
220
221
222
223
224
  	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
225
  	do {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
226
  		unsigned int newheight;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  		if (!(node = radix_tree_node_alloc(root)))
  			return -ENOMEM;
  
  		/* Increase the height.  */
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
231
  		node->slots[0] = radix_tree_direct_to_ptr(root->rnode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
  
  		/* Propagate the aggregated tag info into the new root */
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
234
  		for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
612d6c19d   Nick Piggin   [PATCH] radix-tre...
235
  			if (root_tag_get(root, tag))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
  				tag_set(node, tag, 0);
  		}
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
238
239
  		newheight = root->height+1;
  		node->height = newheight;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  		node->count = 1;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
241
242
  		rcu_assign_pointer(root->rnode, node);
  		root->height = newheight;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  	} 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...
259
  	struct radix_tree_node *node = NULL, *slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
  	unsigned int height, shift;
  	int offset;
  	int error;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
263
  	BUG_ON(radix_tree_is_direct_ptr(item));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  	/* Make sure the tree is high enough.  */
612d6c19d   Nick Piggin   [PATCH] radix-tre...
265
  	if (index > radix_tree_maxindex(root->height)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
  		error = radix_tree_extend(root, index);
  		if (error)
  			return error;
  	}
201b6264f   Christoph Lameter   [PATCH] radix-tre...
270
  	slot = root->rnode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
  	height = root->height;
  	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
  
  	offset = 0;			/* uninitialised var warning */
612d6c19d   Nick Piggin   [PATCH] radix-tre...
275
  	while (height > 0) {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
276
  		if (slot == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  			/* Have to add a child node.  */
201b6264f   Christoph Lameter   [PATCH] radix-tre...
278
  			if (!(slot = radix_tree_node_alloc(root)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  				return -ENOMEM;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
280
  			slot->height = height;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
281
  			if (node) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
282
  				rcu_assign_pointer(node->slots[offset], slot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  				node->count++;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
284
  			} else
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
285
  				rcu_assign_pointer(root->rnode, slot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
  		}
  
  		/* Go a level down */
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
290
291
  		node = slot;
  		slot = node->slots[offset];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
294
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295

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

612d6c19d   Nick Piggin   [PATCH] radix-tre...
299
300
  	if (node) {
  		node->count++;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
301
  		rcu_assign_pointer(node->slots[offset], item);
612d6c19d   Nick Piggin   [PATCH] radix-tre...
302
303
304
  		BUG_ON(tag_get(node, 0, offset));
  		BUG_ON(tag_get(node, 1, offset));
  	} else {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
305
  		rcu_assign_pointer(root->rnode, radix_tree_ptr_to_direct(item));
612d6c19d   Nick Piggin   [PATCH] radix-tre...
306
307
308
  		BUG_ON(root_tag_get(root, 0));
  		BUG_ON(root_tag_get(root, 1));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
  	return 0;
  }
  EXPORT_SYMBOL(radix_tree_insert);
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
  /**
   *	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 cannot be called under rcu_read_lock, it must be
   *	excluded from writers, as must the returned slot for subsequent
   *	use by radix_tree_deref_slot() and radix_tree_replace slot.
   *	Caller must hold tree write locked across slot lookup and
   *	replace.
   */
  void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
  {
  	unsigned int height, shift;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
330
  	struct radix_tree_node *node, **slot;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
331

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
332
333
  	node = root->rnode;
  	if (node == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  		return NULL;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
335
336
337
  	if (radix_tree_is_direct_ptr(node)) {
  		if (index > 0)
  			return NULL;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
338
  		return (void **)&root->rnode;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
339
340
341
342
343
  	}
  
  	height = node->height;
  	if (index > radix_tree_maxindex(height))
  		return NULL;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
344

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

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
347
348
349
350
351
  	do {
  		slot = (struct radix_tree_node **)
  			(node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
  		node = *slot;
  		if (node == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  			return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
355
  	} while (height > 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356

a43313668   Hans Reiser   [PATCH] reiser4: ...
357
358
  	return (void **)slot;
  }
a43313668   Hans Reiser   [PATCH] reiser4: ...
359
360
361
362
363
364
365
366
  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...
367
368
369
370
371
   *
   *	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: ...
372
373
374
   */
  void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
  {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  	unsigned int height, shift;
  	struct radix_tree_node *node, **slot;
  
  	node = rcu_dereference(root->rnode);
  	if (node == NULL)
  		return NULL;
  
  	if (radix_tree_is_direct_ptr(node)) {
  		if (index > 0)
  			return NULL;
  		return radix_tree_direct_to_ptr(node);
  	}
  
  	height = node->height;
  	if (index > radix_tree_maxindex(height))
  		return NULL;
  
  	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
a43313668   Hans Reiser   [PATCH] reiser4: ...
393

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
394
395
396
397
398
399
400
401
402
403
404
405
  	do {
  		slot = (struct radix_tree_node **)
  			(node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
  		node = rcu_dereference(*slot);
  		if (node == NULL)
  			return NULL;
  
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
  	} while (height > 0);
  
  	return node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
411
412
413
414
  }
  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...
415
416
   *	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
417
418
419
420
421
422
   *	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...
423
  			unsigned long index, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  {
  	unsigned int height, shift;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
426
  	struct radix_tree_node *slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
  
  	height = root->height;
4c91c3648   Peter Zijlstra   [PATCH] buglet in...
429
  	BUG_ON(index > radix_tree_maxindex(height));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430

201b6264f   Christoph Lameter   [PATCH] radix-tre...
431
  	slot = root->rnode;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
432
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
  
  	while (height > 0) {
  		int offset;
  
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
d5274261e   Nick Piggin   [PATCH] radix tre...
438
439
  		if (!tag_get(slot, tag, offset))
  			tag_set(slot, tag, offset);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
440
441
  		slot = slot->slots[offset];
  		BUG_ON(slot == NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
  	}
612d6c19d   Nick Piggin   [PATCH] radix-tre...
445
446
447
  	/* set the root's tag bit */
  	if (slot && !root_tag_get(root, tag))
  		root_tag_set(root, tag);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
448
  	return slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
452
453
454
455
456
457
  }
  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...
458
459
   *	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
460
461
462
463
464
465
466
   *	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...
467
  			unsigned long index, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
  {
  	struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
470
  	struct radix_tree_node *slot = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  	unsigned int height, shift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
477
478
  
  	height = root->height;
  	if (index > radix_tree_maxindex(height))
  		goto out;
  
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
  	pathp->node = NULL;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
479
  	slot = root->rnode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
  
  	while (height > 0) {
  		int offset;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
483
  		if (slot == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
  			goto out;
  
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
  		pathp[1].offset = offset;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
488
489
  		pathp[1].node = slot;
  		slot = slot->slots[offset];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
  		pathp++;
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
  	}
612d6c19d   Nick Piggin   [PATCH] radix-tre...
494
  	if (slot == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  		goto out;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
496
  	while (pathp->node) {
d5274261e   Nick Piggin   [PATCH] radix tre...
497
498
  		if (!tag_get(pathp->node, tag, pathp->offset))
  			goto out;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
499
  		tag_clear(pathp->node, tag, pathp->offset);
6e954b9e9   Nick Piggin   [PATCH] radix tre...
500
501
  		if (any_tag_set(pathp->node, tag))
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
  		pathp--;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
503
504
505
506
507
  	}
  
  	/* 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
508
  out:
612d6c19d   Nick Piggin   [PATCH] radix-tre...
509
  	return slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
514
  }
  EXPORT_SYMBOL(radix_tree_tag_clear);
  
  #ifndef __KERNEL__	/* Only the test harness uses this at present */
  /**
32605a181   Marcelo Tosatti   [PATCH] radix_tag...
515
516
517
   * 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...
518
   * @tag: 		tag index (< RADIX_TREE_MAX_TAGS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
   *
32605a181   Marcelo Tosatti   [PATCH] radix_tag...
520
   * Return values:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
   *
612d6c19d   Nick Piggin   [PATCH] radix-tre...
522
523
   *  0: tag not present or not set
   *  1: tag set
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
   */
  int radix_tree_tag_get(struct radix_tree_root *root,
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
526
  			unsigned long index, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
  {
  	unsigned int height, shift;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
529
  	struct radix_tree_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  	int saw_unset_tag = 0;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
531
532
533
  	/* check the root's tag bit */
  	if (!root_tag_get(root, tag))
  		return 0;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
534
535
536
537
538
539
540
541
542
543
  	node = rcu_dereference(root->rnode);
  	if (node == NULL)
  		return 0;
  
  	if (radix_tree_is_direct_ptr(node))
  		return (index == 0);
  
  	height = node->height;
  	if (index > radix_tree_maxindex(height))
  		return 0;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
544

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
  
  	for ( ; ; ) {
  		int offset;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
549
  		if (node == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
555
556
557
  			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...
558
  		if (!tag_get(node, tag, offset))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
  			saw_unset_tag = 1;
  		if (height == 1) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
561
  			int ret = tag_get(node, tag, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
  
  			BUG_ON(ret && saw_unset_tag);
e5dcd90b5   Wu Fengguang   [PATCH] radixtree...
564
  			return !!ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
  		}
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
566
  		node = rcu_dereference(node->slots[offset]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
570
571
572
573
574
  		shift -= RADIX_TREE_MAP_SHIFT;
  		height--;
  	}
  }
  EXPORT_SYMBOL(radix_tree_tag_get);
  #endif
  
  static unsigned int
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
575
  __lookup(struct radix_tree_node *slot, void **results, unsigned long index,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
578
  	unsigned int max_items, unsigned long *next_index)
  {
  	unsigned int nr_found = 0;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
579
  	unsigned int shift, height;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
580
  	unsigned long i;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
581
582
  	height = slot->height;
  	if (height == 0)
201b6264f   Christoph Lameter   [PATCH] radix-tre...
583
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
  	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585

201b6264f   Christoph Lameter   [PATCH] radix-tre...
586
  	for ( ; height > 1; height--) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
587
588
  		i = (index >> shift) & RADIX_TREE_MAP_MASK;
  		for (;;) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
  			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...
595
596
597
  			i++;
  			if (i == RADIX_TREE_MAP_SIZE)
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  		shift -= RADIX_TREE_MAP_SHIFT;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
601
602
603
  		slot = rcu_dereference(slot->slots[i]);
  		if (slot == NULL)
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  	}
201b6264f   Christoph Lameter   [PATCH] radix-tre...
605
606
607
  
  	/* Bottom level: grab some items */
  	for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
608
  		struct radix_tree_node *node;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
609
  		index++;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
610
611
612
  		node = slot->slots[i];
  		if (node) {
  			results[nr_found++] = rcu_dereference(node);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
613
614
615
616
  			if (nr_found == max_items)
  				goto out;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  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...
634
635
636
637
638
639
   *
   *	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
640
641
642
643
644
   */
  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...
645
646
  	unsigned long max_index;
  	struct radix_tree_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  	unsigned long cur_index = first_index;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
648
649
650
651
652
  	unsigned int ret;
  
  	node = rcu_dereference(root->rnode);
  	if (!node)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
654
655
656
657
658
659
660
661
662
663
664
  	if (radix_tree_is_direct_ptr(node)) {
  		if (first_index > 0)
  			return 0;
  		node = radix_tree_direct_to_ptr(node);
  		results[0] = rcu_dereference(node);
  		return 1;
  	}
  
  	max_index = radix_tree_maxindex(node->height);
  
  	ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
667
668
669
670
  	while (ret < max_items) {
  		unsigned int nr_found;
  		unsigned long next_index;	/* Index of next search */
  
  		if (cur_index > max_index)
  			break;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
671
  		nr_found = __lookup(node, results + ret, cur_index,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
674
675
676
677
  					max_items - ret, &next_index);
  		ret += nr_found;
  		if (next_index == 0)
  			break;
  		cur_index = next_index;
  	}
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
678

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
682
683
684
685
686
687
  	return ret;
  }
  EXPORT_SYMBOL(radix_tree_gang_lookup);
  
  /*
   * FIXME: the two tag_get()s here should use find_next_bit() instead of
   * open-coding the search.
   */
  static unsigned int
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
688
  __lookup_tag(struct radix_tree_node *slot, void **results, unsigned long index,
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
689
  	unsigned int max_items, unsigned long *next_index, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
  {
  	unsigned int nr_found = 0;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
692
  	unsigned int shift, height;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
694
695
  	height = slot->height;
  	if (height == 0)
612d6c19d   Nick Piggin   [PATCH] radix-tre...
696
  		goto out;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
697
  	shift = (height-1) * RADIX_TREE_MAP_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698

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

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
702
703
  		for (;;) {
  			if (tag_get(slot, tag, i))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
708
  			index &= ~((1UL << shift) - 1);
  			index += 1UL << shift;
  			if (index == 0)
  				goto out;	/* 32-bit wraparound */
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
709
710
711
  			i++;
  			if (i == RADIX_TREE_MAP_SIZE)
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
  		height--;
  		if (height == 0) {	/* Bottom level: grab some items */
  			unsigned long j = index & RADIX_TREE_MAP_MASK;
  
  			for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
718
  				struct radix_tree_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
  				index++;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
  				if (!tag_get(slot, tag, j))
  					continue;
  				node = slot->slots[j];
  				/*
  				 * 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).
  				 */
  				if (node) {
  					node = rcu_dereference(node);
  					results[nr_found++] = node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
740
741
  					if (nr_found == max_items)
  						goto out;
  				}
  			}
  		}
  		shift -= RADIX_TREE_MAP_SHIFT;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
742
743
744
745
  		slot = rcu_dereference(slot->slots[i]);
  		if (slot == NULL)
  			break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
749
750
751
752
753
754
755
756
757
  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...
758
   *	@tag:		the tag index (< RADIX_TREE_MAX_TAGS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
762
763
764
765
   *
   *	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...
766
767
  		unsigned long first_index, unsigned int max_items,
  		unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
769
770
  	struct radix_tree_node *node;
  	unsigned long max_index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	unsigned long cur_index = first_index;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
772
  	unsigned int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773

612d6c19d   Nick Piggin   [PATCH] radix-tre...
774
775
776
  	/* check the root's tag bit */
  	if (!root_tag_get(root, tag))
  		return 0;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
  	node = rcu_dereference(root->rnode);
  	if (!node)
  		return 0;
  
  	if (radix_tree_is_direct_ptr(node)) {
  		if (first_index > 0)
  			return 0;
  		node = radix_tree_direct_to_ptr(node);
  		results[0] = rcu_dereference(node);
  		return 1;
  	}
  
  	max_index = radix_tree_maxindex(node->height);
  
  	ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
  	while (ret < max_items) {
  		unsigned int nr_found;
  		unsigned long next_index;	/* Index of next search */
  
  		if (cur_index > max_index)
  			break;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
798
  		nr_found = __lookup_tag(node, results + ret, cur_index,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
801
802
803
804
  					max_items - ret, &next_index, tag);
  		ret += nr_found;
  		if (next_index == 0)
  			break;
  		cur_index = next_index;
  	}
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
805

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
809
810
  	return ret;
  }
  EXPORT_SYMBOL(radix_tree_gang_lookup_tag);
  
  /**
a5f51c966   Nick Piggin   [PATCH] radix-tre...
811
812
813
814
815
816
   *	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 */
612d6c19d   Nick Piggin   [PATCH] radix-tre...
817
  	while (root->height > 0 &&
a5f51c966   Nick Piggin   [PATCH] radix-tre...
818
819
820
  			root->rnode->count == 1 &&
  			root->rnode->slots[0]) {
  		struct radix_tree_node *to_free = root->rnode;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
821
  		void *newptr;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
822

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
823
824
825
826
827
828
829
830
831
832
833
  		/*
  		 * 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];
  		if (root->height == 1)
  			newptr = radix_tree_ptr_to_direct(newptr);
  		root->rnode = newptr;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
834
835
836
837
838
839
840
841
842
843
844
  		root->height--;
  		/* must only free zeroed nodes into the slab */
  		tag_clear(to_free, 0, 0);
  		tag_clear(to_free, 1, 0);
  		to_free->slots[0] = NULL;
  		to_free->count = 0;
  		radix_tree_node_free(to_free);
  	}
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
848
849
850
851
852
853
854
855
   *	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)
  {
  	struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
856
  	struct radix_tree_node *slot = NULL;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
857
  	struct radix_tree_node *to_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  	unsigned int height, shift;
d5274261e   Nick Piggin   [PATCH] radix tre...
859
860
  	int tag;
  	int offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
863
864
  
  	height = root->height;
  	if (index > radix_tree_maxindex(height))
  		goto out;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
865
866
  	slot = root->rnode;
  	if (height == 0 && root->rnode) {
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
867
  		slot = radix_tree_direct_to_ptr(slot);
612d6c19d   Nick Piggin   [PATCH] radix-tre...
868
869
870
871
  		root_tag_clear_all(root);
  		root->rnode = NULL;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
  	shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
  	pathp->node = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874

612d6c19d   Nick Piggin   [PATCH] radix-tre...
875
  	do {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
876
  		if (slot == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
  			goto out;
d5274261e   Nick Piggin   [PATCH] radix tre...
878
  		pathp++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
  		offset = (index >> shift) & RADIX_TREE_MAP_MASK;
d5274261e   Nick Piggin   [PATCH] radix tre...
880
881
  		pathp->offset = offset;
  		pathp->node = slot;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
882
  		slot = slot->slots[offset];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
  		shift -= RADIX_TREE_MAP_SHIFT;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
884
885
  		height--;
  	} while (height > 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886

612d6c19d   Nick Piggin   [PATCH] radix-tre...
887
  	if (slot == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
891
  	/*
  	 * Clear all tags associated with the just-deleted item
  	 */
daff89f32   Jonathan Corbet   [PATCH] radix-tre...
892
  	for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
612d6c19d   Nick Piggin   [PATCH] radix-tre...
893
894
  		if (tag_get(pathp->node, tag, pathp->offset))
  			radix_tree_tag_clear(root, index, tag);
d5274261e   Nick Piggin   [PATCH] radix tre...
895
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896

7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
897
  	to_free = NULL;
201b6264f   Christoph Lameter   [PATCH] radix-tre...
898
  	/* Now free the nodes we do not need anymore */
612d6c19d   Nick Piggin   [PATCH] radix-tre...
899
  	while (pathp->node) {
201b6264f   Christoph Lameter   [PATCH] radix-tre...
900
  		pathp->node->slots[pathp->offset] = NULL;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
901
  		pathp->node->count--;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
902
903
904
905
906
907
  		/*
  		 * 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...
908
909
910
911
  
  		if (pathp->node->count) {
  			if (pathp->node == root->rnode)
  				radix_tree_shrink(root);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
912
  			goto out;
a5f51c966   Nick Piggin   [PATCH] radix-tre...
913
  		}
201b6264f   Christoph Lameter   [PATCH] radix-tre...
914
915
  
  		/* Node with zero slots in use so free it */
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
916
  		to_free = pathp->node;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
917
  		pathp--;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
918

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
  	}
612d6c19d   Nick Piggin   [PATCH] radix-tre...
920
  	root_tag_clear_all(root);
201b6264f   Christoph Lameter   [PATCH] radix-tre...
921
  	root->height = 0;
612d6c19d   Nick Piggin   [PATCH] radix-tre...
922
  	root->rnode = NULL;
7cf9c2c76   Nick Piggin   [PATCH] radix-tre...
923
924
  	if (to_free)
  		radix_tree_node_free(to_free);
612d6c19d   Nick Piggin   [PATCH] radix-tre...
925

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  out:
612d6c19d   Nick Piggin   [PATCH] radix-tre...
927
  	return slot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
930
931
932
933
934
935
  }
  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...
936
  int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
  {
612d6c19d   Nick Piggin   [PATCH] radix-tre...
938
  	return root_tag_get(root, tag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
942
  }
  EXPORT_SYMBOL(radix_tree_tagged);
  
  static void
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
943
  radix_tree_node_ctor(void *node, struct kmem_cache *cachep, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
  {
  	memset(node, 0, sizeof(struct radix_tree_node));
  }
  
  static __init unsigned long __maxindex(unsigned int height)
  {
  	unsigned int tmp = height * RADIX_TREE_MAP_SHIFT;
  	unsigned long index = (~0UL >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1;
  
  	if (tmp >= RADIX_TREE_INDEX_BITS)
  		index = ~0UL;
  	return index;
  }
  
  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
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
  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 */
         if (action == CPU_DEAD) {
                 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
984
985
986
987
988
989
990
991
992
  
  void __init radix_tree_init(void)
  {
  	radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
  			sizeof(struct radix_tree_node), 0,
  			SLAB_PANIC, radix_tree_node_ctor, NULL);
  	radix_tree_init_maxindex();
  	hotcpu_notifier(radix_tree_callback, 0);
  }