Deleted Added
full compact
vm_radix.c (226873) vm_radix.c (226876)
1/*
2 * Copyright (c) 2008 Mayur Shardul <mayur.shardul@gmail.com>
3 * Copyright (c) 2011 Jeffrey Roberson <jeff@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 31 unchanged lines hidden (view full) ---

40#include <sys/malloc.h>
41#include <sys/queue.h>
42#include <sys/param.h>
43#include <sys/lock.h>
44#include <sys/mutex.h>
45#include <sys/ktr.h>
46#include <vm/uma.h>
47#include <vm/vm.h>
1/*
2 * Copyright (c) 2008 Mayur Shardul <mayur.shardul@gmail.com>
3 * Copyright (c) 2011 Jeffrey Roberson <jeff@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 31 unchanged lines hidden (view full) ---

40#include <sys/malloc.h>
41#include <sys/queue.h>
42#include <sys/param.h>
43#include <sys/lock.h>
44#include <sys/mutex.h>
45#include <sys/ktr.h>
46#include <vm/uma.h>
47#include <vm/vm.h>
48#include <vm/vm_param.h>
48#include <vm/vm_extern.h>
49#include <vm/vm_kern.h>
50#include <vm/vm_page.h>
51#include <vm/vm_radix.h>
52#include <vm/vm_object.h>
53
54#include <sys/kdb.h>
55
56CTASSERT(sizeof(struct vm_radix_node) < PAGE_SIZE);
57
58static uma_zone_t vm_radix_node_zone;
59
49#include <vm/vm_extern.h>
50#include <vm/vm_kern.h>
51#include <vm/vm_page.h>
52#include <vm/vm_radix.h>
53#include <vm/vm_object.h>
54
55#include <sys/kdb.h>
56
57CTASSERT(sizeof(struct vm_radix_node) < PAGE_SIZE);
58
59static uma_zone_t vm_radix_node_zone;
60
60#if 0
61#ifndef UMA_MD_SMALL_ALLOC
61static void *
62vm_radix_node_zone_allocf(uma_zone_t zone, int size, uint8_t *flags, int wait)
63{
64 vm_offset_t addr;
65 vm_page_t m;
66 int pflags;
67
68 /* Inform UMA that this allocator uses kernel_map. */

--- 66 unchanged lines hidden (view full) ---

135 ("vm_radix_node_put: Freeing a node with %d children\n",
136 rnode->rn_count));
137}
138#endif
139
140/*
141 * Allocate a radix node. Initializes all elements to 0.
142 */
62static void *
63vm_radix_node_zone_allocf(uma_zone_t zone, int size, uint8_t *flags, int wait)
64{
65 vm_offset_t addr;
66 vm_page_t m;
67 int pflags;
68
69 /* Inform UMA that this allocator uses kernel_map. */

--- 66 unchanged lines hidden (view full) ---

136 ("vm_radix_node_put: Freeing a node with %d children\n",
137 rnode->rn_count));
138}
139#endif
140
141/*
142 * Allocate a radix node. Initializes all elements to 0.
143 */
143static struct vm_radix_node *
144static __inline struct vm_radix_node *
144vm_radix_node_get(void)
145{
146
147 return (uma_zalloc(vm_radix_node_zone, M_NOWAIT | M_ZERO));
148}
149
150/*
151 * Free radix node.
152 */
145vm_radix_node_get(void)
146{
147
148 return (uma_zalloc(vm_radix_node_zone, M_NOWAIT | M_ZERO));
149}
150
151/*
152 * Free radix node.
153 */
153static void
154static __inline void
154vm_radix_node_put(struct vm_radix_node *rnode)
155{
156
157 uma_zfree(vm_radix_node_zone, rnode);
158}
159
160/*
161 * Return the position in the array for a given level.
162 */
155vm_radix_node_put(struct vm_radix_node *rnode)
156{
157
158 uma_zfree(vm_radix_node_zone, rnode);
159}
160
161/*
162 * Return the position in the array for a given level.
163 */
163static inline int
164static __inline int
164vm_radix_slot(vm_pindex_t index, int level)
165{
166
167 return ((index >> (level * VM_RADIX_WIDTH)) & VM_RADIX_MASK);
168}
169
170void
171vm_radix_init(void)
172{
173
174 vm_radix_node_zone = uma_zcreate("RADIX NODE",
175 sizeof(struct vm_radix_node), NULL,
176#ifdef INVARIANTS
177 vm_radix_node_zone_dtor,
178#else
179 NULL,
180#endif
165vm_radix_slot(vm_pindex_t index, int level)
166{
167
168 return ((index >> (level * VM_RADIX_WIDTH)) & VM_RADIX_MASK);
169}
170
171void
172vm_radix_init(void)
173{
174
175 vm_radix_node_zone = uma_zcreate("RADIX NODE",
176 sizeof(struct vm_radix_node), NULL,
177#ifdef INVARIANTS
178 vm_radix_node_zone_dtor,
179#else
180 NULL,
181#endif
181 NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM);
182 NULL, NULL, VM_RADIX_HEIGHT, UMA_ZONE_VM);
182}
183
184/*
183}
184
185/*
186 * Extract the root node and height from a radix tree with a single load.
187 */
188static __inline int
189vm_radix_height(struct vm_radix *rtree, struct vm_radix_node **rnode)
190{
191 uintptr_t root;
192 int height;
193
194 root = rtree->rt_root;
195 height = root & VM_RADIX_HEIGHT;
196 *rnode = (struct vm_radix_node *)(root - height);
197 return (height);
198}
199
200
201/*
202 * Set the root node and height for a radix tree.
203 */
204static inline void
205vm_radix_setroot(struct vm_radix *rtree, struct vm_radix_node *rnode,
206 int height)
207{
208 uintptr_t root;
209
210 root = (uintptr_t)rnode | height;
211 rtree->rt_root = root;
212}
213
214/*
185 * Inserts the key-value pair in to the radix tree. Returns errno.
186 * Panics if the key already exists.
187 */
188int
189vm_radix_insert(struct vm_radix *rtree, vm_pindex_t index, void *val)
190{
191 struct vm_radix_node *rnode;
215 * Inserts the key-value pair in to the radix tree. Returns errno.
216 * Panics if the key already exists.
217 */
218int
219vm_radix_insert(struct vm_radix *rtree, vm_pindex_t index, void *val)
220{
221 struct vm_radix_node *rnode;
192 int slot;
222 struct vm_radix_node *root;
193 int level;
223 int level;
224 int slot;
194
195 CTR3(KTR_VM,
196 "insert: tree %p, index %p, val %p", rtree, (void *)index, val);
197 if (index == -1)
198 panic("vm_radix_insert: -1 is not a valid index.\n");
225
226 CTR3(KTR_VM,
227 "insert: tree %p, index %p, val %p", rtree, (void *)index, val);
228 if (index == -1)
229 panic("vm_radix_insert: -1 is not a valid index.\n");
230 level = vm_radix_height(rtree, &root);
199 /*
200 * Increase the height by adding nodes at the root until
201 * there is sufficient space.
202 */
231 /*
232 * Increase the height by adding nodes at the root until
233 * there is sufficient space.
234 */
203 while (rtree->rt_height == 0 ||
204 index > VM_RADIX_MAX(rtree->rt_height)) {
235 while (level == 0 || index > VM_RADIX_MAX(level)) {
205 CTR3(KTR_VM, "insert: expanding %jd > %jd height %d",
236 CTR3(KTR_VM, "insert: expanding %jd > %jd height %d",
206 index, VM_RADIX_MAX(rtree->rt_height), rtree->rt_height);
237 index, VM_RADIX_MAX(level), level);
238 level++;
239 KASSERT(level <= VM_RADIX_LIMIT,
240 ("vm_radix_insert: Tree %p height %d too tall",
241 rtree, level));
207 /*
208 * Only allocate tree nodes if they are needed.
209 */
242 /*
243 * Only allocate tree nodes if they are needed.
244 */
210 if (rtree->rt_root == NULL || rtree->rt_root->rn_count != 0) {
245 if (root == NULL || root->rn_count != 0) {
211 rnode = vm_radix_node_get();
212 if (rnode == NULL)
213 return (ENOMEM);
246 rnode = vm_radix_node_get();
247 if (rnode == NULL)
248 return (ENOMEM);
214 if (rtree->rt_root) {
215 rnode->rn_child[0] = rtree->rt_root;
249 /*
250 * Store the new pointer with a memory barrier so
251 * that it is visible before the new root.
252 */
253 if (root) {
254 atomic_store_rel_ptr((volatile uintptr_t *)
255 &rnode->rn_child[0], (uintptr_t)root);
216 rnode->rn_count = 1;
217 }
256 rnode->rn_count = 1;
257 }
218 rtree->rt_root = rnode;
258 root = rnode;
219 }
259 }
220 rtree->rt_height++;
221 KASSERT(rtree->rt_height <= VM_RADIX_LIMIT,
222 ("vm_radix_insert: Tree %p height %d too tall", rtree,
223 rtree->rt_height));
260 vm_radix_setroot(rtree, root, level);
224 }
225
226 /* Now that the tree is tall enough, fill in the path to the index. */
261 }
262
263 /* Now that the tree is tall enough, fill in the path to the index. */
227 rnode = rtree->rt_root;
228 for (level = rtree->rt_height - 1; level > 0; level--) {
264 rnode = root;
265 for (level = level - 1; level > 0; level--) {
229 slot = vm_radix_slot(index, level);
230 /* Add the required intermidiate nodes. */
231 if (rnode->rn_child[slot] == NULL) {
232 rnode->rn_child[slot] = vm_radix_node_get();
233 if (rnode->rn_child[slot] == NULL)
234 return (ENOMEM);
235 rnode->rn_count++;
236 }

--- 21 unchanged lines hidden (view full) ---

258 */
259void *
260vm_radix_lookup(struct vm_radix *rtree, vm_pindex_t index)
261{
262 struct vm_radix_node *rnode;
263 int slot;
264 int level;
265
266 slot = vm_radix_slot(index, level);
267 /* Add the required intermidiate nodes. */
268 if (rnode->rn_child[slot] == NULL) {
269 rnode->rn_child[slot] = vm_radix_node_get();
270 if (rnode->rn_child[slot] == NULL)
271 return (ENOMEM);
272 rnode->rn_count++;
273 }

--- 21 unchanged lines hidden (view full) ---

295 */
296void *
297vm_radix_lookup(struct vm_radix *rtree, vm_pindex_t index)
298{
299 struct vm_radix_node *rnode;
300 int slot;
301 int level;
302
266 if (index > VM_RADIX_MAX(rtree->rt_height))
303 level = vm_radix_height(rtree, &rnode);
304 if (index > VM_RADIX_MAX(level))
267 return NULL;
305 return NULL;
268 level = rtree->rt_height - 1;
269 rnode = rtree->rt_root;
306 level--;
270 while (rnode) {
271 slot = vm_radix_slot(index, level);
272 CTR5(KTR_VM,
273 "lookup: tree %p, index %p, level %d, slot %d, child %p",
274 rtree, (void *)index, level, slot, rnode->rn_child[slot]);
275 if (level == 0)
276 return rnode->rn_child[slot];
277 rnode = rnode->rn_child[slot];

--- 21 unchanged lines hidden (view full) ---

299 int level;
300 void *val;
301 int outidx;
302 int loops = 0;
303
304 CTR3(KTR_VM, "lookupn: tree %p, start %p, end %p",
305 rtree, (void *)start, (void *)end);
306 outidx = 0;
307 while (rnode) {
308 slot = vm_radix_slot(index, level);
309 CTR5(KTR_VM,
310 "lookup: tree %p, index %p, level %d, slot %d, child %p",
311 rtree, (void *)index, level, slot, rnode->rn_child[slot]);
312 if (level == 0)
313 return rnode->rn_child[slot];
314 rnode = rnode->rn_child[slot];

--- 21 unchanged lines hidden (view full) ---

336 int level;
337 void *val;
338 int outidx;
339 int loops = 0;
340
341 CTR3(KTR_VM, "lookupn: tree %p, start %p, end %p",
342 rtree, (void *)start, (void *)end);
343 outidx = 0;
307 max = VM_RADIX_MAX(rtree->rt_height);
344restart:
345 level = vm_radix_height(rtree, &rnode);
346 max = VM_RADIX_MAX(level);
308 if (start > max)
347 if (start > max)
309 return 0;
348 goto out;
310 if (end > max || end == 0)
311 end = max;
349 if (end > max || end == 0)
350 end = max;
312restart:
313 loops++;
314 if (loops > 1000)
315 panic("vm_radix_lookupn: looping %d\n", loops);
316 /*
317 * Search the tree from the top for any leaf node holding an index
318 * between start and end.
319 */
351 loops++;
352 if (loops > 1000)
353 panic("vm_radix_lookupn: looping %d\n", loops);
354 /*
355 * Search the tree from the top for any leaf node holding an index
356 * between start and end.
357 */
320 level = rtree->rt_height - 1;
321 rnode = rtree->rt_root;
358 level--;
322 while (rnode) {
323 slot = vm_radix_slot(start, level);
324 CTR5(KTR_VM,
325 "lookupn: tree %p, index %p, level %d, slot %d, child %p",
326 rtree, (void *)start, level, slot, rnode->rn_child[slot]);
327 if (level == 0)
328 break;
329 /*

--- 69 unchanged lines hidden (view full) ---

399 vm_pindex_t max;
400 vm_pindex_t inc;
401 int slot;
402 int level;
403 int loops = 0;
404
405 CTR2(KTR_VM,
406 "lookup_le: tree %p, index %p", rtree, (void *)index);
359 while (rnode) {
360 slot = vm_radix_slot(start, level);
361 CTR5(KTR_VM,
362 "lookupn: tree %p, index %p, level %d, slot %d, child %p",
363 rtree, (void *)start, level, slot, rnode->rn_child[slot]);
364 if (level == 0)
365 break;
366 /*

--- 69 unchanged lines hidden (view full) ---

436 vm_pindex_t max;
437 vm_pindex_t inc;
438 int slot;
439 int level;
440 int loops = 0;
441
442 CTR2(KTR_VM,
443 "lookup_le: tree %p, index %p", rtree, (void *)index);
407 if (rtree->rt_root == NULL)
444restart:
445 level = vm_radix_height(rtree, &rnode);
446 if (rnode == NULL)
408 return (NULL);
447 return (NULL);
409 max = VM_RADIX_MAX(rtree->rt_height);
448 max = VM_RADIX_MAX(level);
410 if (index > max || index == 0)
411 index = max;
449 if (index > max || index == 0)
450 index = max;
412restart:
413 loops++;
414 if (loops > 1000)
415 panic("vm_radix_looku_le: looping %d\n", loops);
416 /*
417 * Search the tree from the top for any leaf node holding an index
418 * lower than 'index'.
419 */
451 loops++;
452 if (loops > 1000)
453 panic("vm_radix_looku_le: looping %d\n", loops);
454 /*
455 * Search the tree from the top for any leaf node holding an index
456 * lower than 'index'.
457 */
420 level = rtree->rt_height - 1;
421 rnode = rtree->rt_root;
458 level--;
422 while (rnode) {
423 slot = vm_radix_slot(index, level);
424 CTR5(KTR_VM,
425 "lookup_le: tree %p, index %p, level %d, slot %d, child %p",
426 rtree, (void *)index, level, slot, rnode->rn_child[slot]);
427 if (level == 0)
428 break;
429 /*

--- 38 unchanged lines hidden (view full) ---

468 * Remove the specified index from the tree. If possible the height of the
469 * tree is adjusted after deletion. The value stored at index is returned
470 * panics if the key is not present.
471 */
472void *
473vm_radix_remove(struct vm_radix *rtree, vm_pindex_t index)
474{
475 struct vm_radix_node *stack[VM_RADIX_LIMIT];
459 while (rnode) {
460 slot = vm_radix_slot(index, level);
461 CTR5(KTR_VM,
462 "lookup_le: tree %p, index %p, level %d, slot %d, child %p",
463 rtree, (void *)index, level, slot, rnode->rn_child[slot]);
464 if (level == 0)
465 break;
466 /*

--- 38 unchanged lines hidden (view full) ---

505 * Remove the specified index from the tree. If possible the height of the
506 * tree is adjusted after deletion. The value stored at index is returned
507 * panics if the key is not present.
508 */
509void *
510vm_radix_remove(struct vm_radix *rtree, vm_pindex_t index)
511{
512 struct vm_radix_node *stack[VM_RADIX_LIMIT];
476 struct vm_radix_node *rnode;
513 struct vm_radix_node *rnode, *root;
477 void *val;
478 int level;
479 int slot;
480
514 void *val;
515 int level;
516 int slot;
517
481 KASSERT(index <= VM_RADIX_MAX(rtree->rt_height),
518 level = vm_radix_height(rtree, &root);
519 KASSERT(index <= VM_RADIX_MAX(level),
482 ("vm_radix_remove: %p index %jd out of range %jd.",
520 ("vm_radix_remove: %p index %jd out of range %jd.",
483 rtree, index, VM_RADIX_MAX(rtree->rt_height)));
521 rtree, index, VM_RADIX_MAX(level)));
522 rnode = root;
484 val = NULL;
523 val = NULL;
485 rnode = rtree->rt_root;
486 level = rtree->rt_height - 1;
524 level--;
487 /*
488 * Find the node and record the path in stack.
489 */
490 while (level && rnode) {
491 stack[level] = rnode;
492 slot = vm_radix_slot(index, level);
493 rnode = rnode->rn_child[slot];
494 CTR5(KTR_VM,

--- 7 unchanged lines hidden (view full) ---

502
503 val = rnode->rn_child[slot];
504 for (;;) {
505 rnode->rn_child[slot] = NULL;
506 rnode->rn_count--;
507 if (rnode->rn_count > 0)
508 break;
509 vm_radix_node_put(rnode);
525 /*
526 * Find the node and record the path in stack.
527 */
528 while (level && rnode) {
529 stack[level] = rnode;
530 slot = vm_radix_slot(index, level);
531 rnode = rnode->rn_child[slot];
532 CTR5(KTR_VM,

--- 7 unchanged lines hidden (view full) ---

540
541 val = rnode->rn_child[slot];
542 for (;;) {
543 rnode->rn_child[slot] = NULL;
544 rnode->rn_count--;
545 if (rnode->rn_count > 0)
546 break;
547 vm_radix_node_put(rnode);
510 if (rnode == rtree->rt_root) {
511 rtree->rt_root = NULL;
512 rtree->rt_height = 0;
548 if (rnode == root) {
549 vm_radix_setroot(rtree, NULL, 0);
513 break;
514 }
515 rnode = stack[++level];
516 slot = vm_radix_slot(index, level);
517
518 }
519 return (val);
520}
521
522/*
523 * Attempts to reduce the height of the tree.
524 */
525void
526vm_radix_shrink(struct vm_radix *rtree)
527{
550 break;
551 }
552 rnode = stack[++level];
553 slot = vm_radix_slot(index, level);
554
555 }
556 return (val);
557}
558
559/*
560 * Attempts to reduce the height of the tree.
561 */
562void
563vm_radix_shrink(struct vm_radix *rtree)
564{
528 struct vm_radix_node *tmp;
565 struct vm_radix_node *tmp, *root;
566 int level;
529
567
530 if (rtree->rt_root == NULL)
568 if (rtree->rt_root == 0)
531 return;
569 return;
570 level = vm_radix_height(rtree, &root);
532
533 /* Adjust the height of the tree. */
571
572 /* Adjust the height of the tree. */
534 while (rtree->rt_root->rn_count == 1 &&
535 rtree->rt_root->rn_child[0] != NULL) {
536 tmp = rtree->rt_root;
537 rtree->rt_root = tmp->rn_child[0];
538 rtree->rt_height--;
539 tmp->rn_count--;
573 while (root->rn_count == 1 && root->rn_child[0] != NULL) {
574 tmp = root;
575 root->rn_count--;
576 root = root->rn_child[0];
577 level--;
540 vm_radix_node_put(tmp);
541 }
542 /* Finally see if we have an empty tree. */
578 vm_radix_node_put(tmp);
579 }
580 /* Finally see if we have an empty tree. */
543 if (rtree->rt_root->rn_count == 0) {
544 vm_radix_node_put(rtree->rt_root);
545 rtree->rt_root = NULL;
546 rtree->rt_height = 0;
581 if (root->rn_count == 0) {
582 vm_radix_node_put(root);
583 root = NULL;
584 level--;
547 }
585 }
586 vm_radix_setroot(rtree, root, level);
548}
587}