1 /* Copyright (c) 2010 The Regents of the University of California
2 * Barret Rhoden <brho@cs.berkeley.edu>
3 * See LICENSE for details.
5 * Radix Trees! Just the basics, doesn't do tagging or anything fancy. */
13 struct kmem_cache *radix_kcache;
14 static struct radix_node *__radix_lookup_node(struct radix_tree *tree,
17 static void __radix_remove_slot(struct radix_node *r_node, struct radix_node **slot);
19 /* Initializes the radix tree system, mostly just builds the kcache */
22 radix_kcache = kmem_cache_create("radix_nodes",
23 sizeof(struct radix_node),
24 __alignof__(struct radix_node), 0,
28 /* Initializes a tree dynamically */
29 void radix_tree_init(struct radix_tree *tree)
33 tree->upper_bound = 0;
36 /* Will clean up all the memory associated with a tree. Shouldn't be necessary
37 * if you delete all of the items, which you should do anyways since they are
38 * usually void*. Might expand this to have a function to call on every leaf
40 void radix_tree_destroy(struct radix_tree *tree)
42 /* Currently, we may have a root node, even if all the elements were removed
44 panic("Not implemented");
47 /* Attempts to insert an item in the tree at the given key. ENOMEM if we ran
48 * out of memory, EEXIST if an item is already in the tree. On success, will
49 * also return the slot pointer, if requested. */
50 int radix_insert(struct radix_tree *tree, unsigned long key, void *item,
53 printd("RADIX: insert %p at %d\n", item, key);
54 struct radix_node *r_node;
56 /* Is the tree tall enough? if not, it needs to grow a level. This will
57 * also create the initial node (upper bound starts at 0). */
58 while (key >= tree->upper_bound) {
59 r_node = kmem_cache_alloc(radix_kcache, 0);
62 memset(r_node, 0, sizeof(struct radix_node));
64 /* tree->root is the old root, now a child of the future root */
65 r_node->items[0] = tree->root;
66 tree->root->parent = r_node;
67 tree->root->my_slot = (struct radix_node**)&r_node->items[0];
68 r_node->num_items = 1;
70 /* if there was no root before, we're both the root and a leaf */
75 r_node->my_slot = &tree->root;
77 tree->upper_bound = 1ULL << (LOG_RNODE_SLOTS * tree->depth);
80 /* the tree now thinks it is tall enough, so find the last node, insert in
82 r_node = __radix_lookup_node(tree, key, TRUE);
83 assert(r_node); /* we want an ENOMEM actually, but i want to see this */
84 slot = &r_node->items[key & (NR_RNODE_SLOTS - 1)];
94 /* Removes an item from it's parent's structure, freeing the parent if there is
95 * nothing left, potentially recursively. */
96 static void __radix_remove_slot(struct radix_node *r_node, struct radix_node **slot)
98 assert(*slot); /* make sure there is something there */
101 /* this check excludes the root, but the if else handles it. For now, once
102 * we have a root, we'll always keep it (will need some changing in
104 if (!r_node->num_items && r_node->parent) {
106 __radix_remove_slot(r_node->parent, r_node->my_slot);
107 else /* we're the last node, attached to the actual tree */
108 *(r_node->my_slot) = 0;
109 kmem_cache_free(radix_kcache, r_node);
113 /* Removes a key/item from the tree, returning that item (the void*). If it
114 * detects a radix_node is now unused, it will dealloc that node. Though the
115 * tree will still think it is tall enough to handle its old upper_bound. It
117 void *radix_delete(struct radix_tree *tree, unsigned long key)
119 printd("RADIX: delete %d\n", key);
122 struct radix_node *r_node = __radix_lookup_node(tree, key, 0);
125 slot = &r_node->items[key & (NR_RNODE_SLOTS - 1)];
128 __radix_remove_slot(r_node, (struct radix_node**)slot);
130 /* it's okay to delete an empty, but i want to know about it for now */
131 warn("Tried to remove a non-existant item from a radix tree!");
136 /* Returns the item for a given key. 0 means no item, etc. */
137 void *radix_lookup(struct radix_tree *tree, unsigned long key)
139 printd("RADIX: lookup %d\n", key);
140 void **slot = radix_lookup_slot(tree, key);
146 /* Returns a pointer to the radix_node holding a given key. 0 if there is no
147 * such node, due to the tree being too small or something.
149 * If the depth is greater than one, we need to walk down the tree a level. The
150 * key is 'partitioned' among the levels of the tree, like so:
151 * ......444444333333222222111111
153 * If an interior node of the tree is missing, this will add one if it was
154 * directed to extend the tree. */
155 static struct radix_node *__radix_lookup_node(struct radix_tree *tree,
156 unsigned long key, bool extend)
158 printd("RADIX: lookup_node %d, %d\n", key, extend);
160 struct radix_node *child_node, *r_node = tree->root;
161 if (key >= tree->upper_bound) {
163 warn("Bound (%d) not set for key %d!\n", tree->upper_bound, key);
166 for (int i = tree->depth; i > 1; i--) { /* i = ..., 4, 3, 2 */
167 idx = (key >> (LOG_RNODE_SLOTS * (i - 1))) & (NR_RNODE_SLOTS - 1);
168 /* There might not be a node at this part of the tree */
169 if (!r_node->items[idx]) {
173 /* so build one, possibly returning 0 if we couldn't */
174 child_node = kmem_cache_alloc(radix_kcache, 0);
177 r_node->items[idx] = child_node;
178 memset(child_node, 0, sizeof(struct radix_node));
179 /* when we are on the last iteration (i == 2), the child will be
181 child_node->leaf = (i == 2) ? TRUE : FALSE;
182 child_node->parent = r_node;
183 child_node->my_slot = (struct radix_node**)&r_node->items[idx];
185 r_node = (struct radix_node*)r_node->items[idx];
188 r_node = (struct radix_node*)r_node->items[idx];
194 /* Returns a pointer to the slot for the given key. 0 if there is no such slot,
196 void **radix_lookup_slot(struct radix_tree *tree, unsigned long key)
198 printd("RADIX: lookup slot %d\n", key);
199 struct radix_node *r_node = __radix_lookup_node(tree, key, FALSE);
202 key = key & (NR_RNODE_SLOTS - 1);
203 return &r_node->items[key];
206 int radix_gang_lookup(struct radix_tree *tree, void **results,
207 unsigned long first, unsigned int max_items)
209 panic("Not implemented");
210 return -1; /* TODO! */
214 int radix_grow(struct radix_tree *tree, unsigned long max)
216 panic("Not implemented");
217 return -1; /* TODO! */
220 int radix_preload(struct radix_tree *tree, int flags)
222 panic("Not implemented");
223 return -1; /* TODO! */
227 void *radix_tag_set(struct radix_tree *tree, unsigned long key, int tag)
229 panic("Tagging not implemented!");
230 return (void*)-1; /* TODO! */
233 void *radix_tag_clear(struct radix_tree *tree, unsigned long key, int tag)
235 panic("Tagging not implemented!");
236 return (void*)-1; /* TODO! */
239 int radix_tag_get(struct radix_tree *tree, unsigned long key, int tag)
241 panic("Tagging not implemented!");
242 return -1; /* TODO! */
245 int radix_tree_tagged(struct radix_tree *tree, int tag)
247 panic("Tagging not implemented!");
248 return -1; /* TODO! */
251 int radix_tag_gang_lookup(struct radix_tree *tree, void **results,
252 unsigned long first, unsigned int max_items, int tag)
254 panic("Tagging not implemented!");
255 return -1; /* TODO! */
258 void print_radix_tree(struct radix_tree *tree)
260 printk("Tree %p, Depth: %d, Bound: %d\n", tree, tree->depth,
263 void print_rnode(struct radix_node *r_node, int depth)
268 for (int i = 0; i < depth; i++)
270 printk("%sRnode %p, parent %p, myslot %p, %d items, leaf? %d\n",
271 buf, r_node, r_node->parent, r_node->my_slot, r_node->num_items,
273 for (int i = 0; i < NR_RNODE_SLOTS; i++) {
274 if (!r_node->items[i])
277 printk("\t%sRnode Item %d: %p\n", buf, i, r_node->items[i]);
279 print_rnode(r_node->items[i], depth + 1);
282 print_rnode(tree->root, 0);