vm_radix.c revision 228079
1/*
2 * Copyright (c) 2011 Jeffrey Roberson <jeff@freebsd.org>
3 * Copyright (c) 2008 Mayur Shardul <mayur.shardul@gmail.com>
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:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29
30/*
31 * Radix tree implementation.
32 */
33
34#include <sys/cdefs.h>
35
36#include <sys/param.h>
37#include <sys/conf.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
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>
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
61#ifndef UMA_MD_SMALL_ALLOC
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. */
70	*flags = UMA_SLAB_KERNEL;
71
72	pflags = VM_ALLOC_WIRED | VM_ALLOC_NOOBJ;
73
74	/*
75	 * As kmem_alloc_nofault() can however fail, let just assume that
76	 * M_NOWAIT is on and act accordingly.
77	 */
78	pflags |= ((wait & M_USE_RESERVE) != 0) ? VM_ALLOC_INTERRUPT :
79	    VM_ALLOC_SYSTEM;
80	if ((wait & M_ZERO) != 0)
81		pflags |= VM_ALLOC_ZERO;
82	addr = kmem_alloc_nofault(kernel_map, size);
83	if (addr == 0)
84		return (NULL);
85
86	/* Just one page allocation is assumed here. */
87	m = vm_page_alloc(NULL, OFF_TO_IDX(addr - VM_MIN_KERNEL_ADDRESS),
88	    pflags);
89	if (m == NULL) {
90		kmem_free(kernel_map, addr, size);
91		return (NULL);
92	}
93	if ((wait & M_ZERO) != 0 && (m->flags & PG_ZERO) == 0)
94		pmap_zero_page(m);
95	pmap_qenter(addr, &m, 1);
96	return ((void *)addr);
97}
98
99static void
100vm_radix_node_zone_freef(void *item, int size, uint8_t flags)
101{
102	vm_page_t m;
103	vm_offset_t voitem;
104
105	MPASS((flags & UMA_SLAB_KERNEL) != 0);
106
107	/* Just one page allocation is assumed here. */
108	voitem = (vm_offset_t)item;
109	m = PHYS_TO_VM_PAGE(pmap_kextract(voitem));
110	pmap_qremove(voitem, 1);
111	vm_page_free(m);
112	kmem_free(kernel_map, voitem, size);
113}
114
115static void
116init_vm_radix_alloc(void *dummy __unused)
117{
118
119	uma_zone_set_allocf(vm_radix_node_zone, vm_radix_node_zone_allocf);
120	uma_zone_set_freef(vm_radix_node_zone, vm_radix_node_zone_freef);
121}
122SYSINIT(vm_radix, SI_SUB_KMEM, SI_ORDER_SECOND, init_vm_radix_alloc, NULL);
123#endif
124
125/*
126 * Radix node zone destructor.
127 */
128#ifdef INVARIANTS
129static void
130vm_radix_node_zone_dtor(void *mem, int size, void *arg)
131{
132	struct vm_radix_node *rnode;
133
134	rnode = mem;
135	KASSERT(rnode->rn_count == 0,
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 */
144static __inline struct vm_radix_node *
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 */
154static __inline void
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 */
164static __inline int
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
182	    NULL, NULL, VM_RADIX_HEIGHT, UMA_ZONE_VM);
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
214static inline void *
215vm_radix_match(void *child, int color)
216{
217	uintptr_t c;
218
219	c = (uintptr_t)child;
220
221	if ((c & color) == 0)
222		return (NULL);
223	return ((void *)(c & ~VM_RADIX_FLAGS));
224}
225
226static void
227vm_radix_reclaim_allnodes_internal(struct vm_radix_node *rnode, int level)
228{
229	int slot;
230
231	MPASS(rnode != NULL && level >= 0);
232
233	/*
234	 * Level 0 just contains pages as children, thus make it a special
235	 * case, free the node and return.
236	 */
237	if (level == 0) {
238		CTR2(KTR_VM, "reclaiming: node %p, level %d", rnode, level);
239		rnode->rn_count = 0;
240		vm_radix_node_put(rnode);
241		return;
242	}
243	for (slot = 0; slot < VM_RADIX_COUNT && rnode->rn_count != 0; slot++) {
244		if (rnode->rn_child[slot] == NULL)
245			continue;
246		CTR3(KTR_VM,
247		    "reclaiming: node %p, level %d recursing in slot %d",
248		    rnode, level, slot);
249		vm_radix_reclaim_allnodes_internal(rnode->rn_child[slot],
250		    level - 1);
251		rnode->rn_count--;
252	}
253	MPASS(rnode->rn_count == 0);
254	CTR2(KTR_VM, "reclaiming: node %p, level %d", rnode, level);
255	vm_radix_node_put(rnode);
256}
257
258/*
259 * Inserts the key-value pair in to the radix tree.  Returns errno.
260 * Panics if the key already exists.
261 */
262int
263vm_radix_insert(struct vm_radix *rtree, vm_pindex_t index, void *val)
264{
265	struct vm_radix_node *rnode;
266	struct vm_radix_node *root;
267	int level;
268	int slot;
269
270	CTR3(KTR_VM,
271	    "insert: tree %p, index %p, val %p", rtree, (void *)index, val);
272	if (index == -1)
273		panic("vm_radix_insert: -1 is not a valid index.\n");
274	level = vm_radix_height(rtree, &root);
275	/*
276	 * Increase the height by adding nodes at the root until
277	 * there is sufficient space.
278	 */
279	while (level == 0 || index > VM_RADIX_MAX(level)) {
280		CTR3(KTR_VM, "insert: expanding %jd > %jd height %d",
281		    index, VM_RADIX_MAX(level), level);
282		level++;
283		KASSERT(level <= VM_RADIX_LIMIT,
284		    ("vm_radix_insert: Tree %p height %d too tall",
285		    rtree, level));
286		/*
287		 * Only allocate tree nodes if they are needed.
288		 */
289		if (root == NULL || root->rn_count != 0) {
290			rnode = vm_radix_node_get();
291			if (rnode == NULL) {
292				CTR4(KTR_VM,
293			"insert: tree %p, root %p, index: %d, level: %d ENOMEM",
294				    rtree, root, index, level);
295				return (ENOMEM);
296			}
297			/*
298			 * Store the new pointer with a memory barrier so
299			 * that it is visible before the new root.
300			 */
301			if (root) {
302				atomic_store_rel_ptr((volatile uintptr_t *)
303				    &rnode->rn_child[0], (uintptr_t)root);
304				rnode->rn_count = 1;
305			}
306			root = rnode;
307		}
308		vm_radix_setroot(rtree, root, level);
309	}
310
311	/* Now that the tree is tall enough, fill in the path to the index. */
312	rnode = root;
313	for (level = level - 1; level > 0; level--) {
314		slot = vm_radix_slot(index, level);
315		/* Add the required intermidiate nodes. */
316		if (rnode->rn_child[slot] == NULL) {
317			rnode->rn_child[slot] = vm_radix_node_get();
318    			if (rnode->rn_child[slot] == NULL) {
319				CTR6(KTR_VM,
320"insert: tree %p, index %jd, level %d, slot %d, rnode %p, child %p ENOMEM",
321		    		    rtree, index, level, slot, rnode,
322				    (rnode != NULL) ? rnode->rn_child[slot] :
323				    NULL);
324		    		return (ENOMEM);
325			}
326			rnode->rn_count++;
327	    	}
328		CTR6(KTR_VM,
329	"insert: tree %p, index %p, level %d, slot %d, rnode %p, child %p",
330		    rtree, (void *)index, level, slot, rnode,
331		    (rnode != NULL) ?  rnode->rn_child[slot] : NULL);
332		rnode = rnode->rn_child[slot];
333	}
334
335	slot = vm_radix_slot(index, 0);
336	CTR6(KTR_VM,
337	    "insert: tree %p, index %p, level %d, slot %d, rnode %p, child %p",
338	    rtree, (void *)index, level, slot, rnode,
339	    (rnode != NULL) ? rnode->rn_child[slot] : NULL);
340	KASSERT(rnode->rn_child[slot] == NULL,
341	    ("vm_radix_insert: Duplicate value %p at index: %lu\n",
342	    rnode->rn_child[slot], (u_long)index));
343	val = (void *)((uintptr_t)val | VM_RADIX_BLACK);
344	rnode->rn_child[slot] = val;
345	atomic_add_int((volatile int *)&rnode->rn_count, 1);
346
347	return 0;
348}
349
350/*
351 * Returns the value stored at the index.  If the index is not present
352 * NULL is returned.
353 */
354void *
355vm_radix_lookup(struct vm_radix *rtree, vm_pindex_t index, int color)
356{
357	struct vm_radix_node *rnode;
358	int slot;
359	int level;
360
361	level = vm_radix_height(rtree, &rnode);
362	if (index > VM_RADIX_MAX(level))
363		return NULL;
364	level--;
365	while (rnode) {
366		slot = vm_radix_slot(index, level);
367		CTR6(KTR_VM,
368	"lookup: tree %p, index %p, level %d, slot %d, rnode %p, child %p",
369		    rtree, (void *)index, level, slot, rnode,
370		    (rnode != NULL) ? rnode->rn_child[slot] : NULL);
371		if (level == 0)
372			return vm_radix_match(rnode->rn_child[slot], color);
373		rnode = rnode->rn_child[slot];
374		level--;
375	}
376	CTR2(KTR_VM, "lookup: tree %p, index %p failed", rtree, (void *)index);
377
378	return NULL;
379}
380
381void *
382vm_radix_color(struct vm_radix *rtree, vm_pindex_t index, int color)
383{
384	struct vm_radix_node *rnode;
385	uintptr_t child;
386	int slot;
387	int level;
388
389	level = vm_radix_height(rtree, &rnode);
390	if (index > VM_RADIX_MAX(level))
391		return NULL;
392	level--;
393	while (rnode) {
394		slot = vm_radix_slot(index, level);
395		CTR6(KTR_VM,
396	"color: tree %p, index %p, level %d, slot %d, rnode %p, child %p",
397		    rtree, (void *)index, level, slot, rnode,
398		    (rnode != NULL) ? rnode->rn_child[slot] : NULL);
399		if (level == 0)
400			break;
401		rnode = rnode->rn_child[slot];
402		level--;
403	}
404	if (rnode == NULL || rnode->rn_child[slot] == NULL)
405		return (NULL);
406	child = (uintptr_t)rnode->rn_child[slot];
407	child &= ~VM_RADIX_FLAGS;
408	rnode->rn_child[slot] = (void *)(child | color);
409
410	return (void *)child;
411}
412
413/*
414 * Find the first leaf with a valid node between *startp and end.  Return
415 * the index of the first valid item in the leaf in *startp.
416 */
417static struct vm_radix_node *
418vm_radix_leaf(struct vm_radix *rtree, vm_pindex_t *startp, vm_pindex_t end)
419{
420	struct vm_radix_node *rnode;
421	vm_pindex_t start;
422	vm_pindex_t inc;
423	int slot;
424	int level;
425
426	start = *startp;
427restart:
428	level = vm_radix_height(rtree, &rnode);
429	if (start > VM_RADIX_MAX(level) || (end && start >= end)) {
430		rnode = NULL;
431		goto out;
432	}
433	/*
434	 * Search the tree from the top for any leaf node holding an index
435	 * between start and end.
436	 */
437	for (level--; level; level--) {
438		slot = vm_radix_slot(start, level);
439		CTR6(KTR_VM,
440	"leaf: tree %p, index %p, level %d, slot %d, rnode %p, child %p",
441		    rtree, (void *)start, level, slot, rnode,
442		    (rnode != NULL) ? rnode->rn_child[slot] : NULL);
443		if (rnode->rn_child[slot] != NULL) {
444			rnode = rnode->rn_child[slot];
445			continue;
446		}
447		/*
448		 * Calculate how much to increment our index by
449		 * based on the tree level.  We must truncate the
450		 * lower bits to start from the begnning of the
451		 * next leaf.
452	 	 */
453		inc = 1LL << (level * VM_RADIX_WIDTH);
454		start &= ~VM_RADIX_MAX(level);
455		start += inc;
456		slot++;
457		CTR5(KTR_VM,
458		    "leaf: start %p end %p inc %d mask 0x%lX slot %d",
459		    (void *)start, (void *)end, inc,
460		    ~VM_RADIX_MAX(level), slot);
461		for (; slot < VM_RADIX_COUNT; slot++, start += inc) {
462			if (end != 0 && start >= end) {
463				rnode = NULL;
464				goto out;
465			}
466			if (rnode->rn_child[slot]) {
467				rnode = rnode->rn_child[slot];
468				break;
469			}
470		}
471		if (slot == VM_RADIX_COUNT)
472			goto restart;
473	}
474
475out:
476	*startp = start;
477	return (rnode);
478}
479
480
481
482/*
483 * Looks up as many as cnt values between start and end, and stores
484 * them in the caller allocated array out.  The next index can be used
485 * to restart the scan.  This optimizes forward scans in the tree.
486 */
487int
488vm_radix_lookupn(struct vm_radix *rtree, vm_pindex_t start,
489    vm_pindex_t end, int color, void **out, int cnt, vm_pindex_t *next)
490{
491	struct vm_radix_node *rnode;
492	void *val;
493	int slot;
494	int outidx;
495
496	CTR3(KTR_VM, "lookupn: tree %p, start %p, end %p",
497	    rtree, (void *)start, (void *)end);
498	if (rtree->rt_root == 0)
499		return (0);
500	outidx = 0;
501	while ((rnode = vm_radix_leaf(rtree, &start, end)) != NULL) {
502		slot = vm_radix_slot(start, 0);
503		for (; slot < VM_RADIX_COUNT; slot++, start++) {
504			if (end != 0 && start >= end)
505				goto out;
506			val = vm_radix_match(rnode->rn_child[slot], color);
507			if (val == NULL)
508				continue;
509			CTR4(KTR_VM,
510			    "lookupn: tree %p index %p slot %d found child %p",
511			    rtree, (void *)start, slot, val);
512			out[outidx] = val;
513			if (++outidx == cnt)
514				goto out;
515		}
516		if (end != 0 && start >= end)
517			break;
518	}
519out:
520	*next = start;
521	return (outidx);
522}
523
524void
525vm_radix_foreach(struct vm_radix *rtree, vm_pindex_t start, vm_pindex_t end,
526    int color, void (*iter)(void *))
527{
528	struct vm_radix_node *rnode;
529	void *val;
530	int slot;
531
532	if (rtree->rt_root == 0)
533		return;
534	while ((rnode = vm_radix_leaf(rtree, &start, end)) != NULL) {
535		slot = vm_radix_slot(start, 0);
536		for (; slot < VM_RADIX_COUNT; slot++, start++) {
537			if (end != 0 && start >= end)
538				return;
539			val = vm_radix_match(rnode->rn_child[slot], color);
540			if (val)
541				iter(val);
542		}
543		if (end != 0 && start >= end)
544			return;
545	}
546}
547
548
549/*
550 * Look up any entry at a position less than or equal to index.
551 */
552void *
553vm_radix_lookup_le(struct vm_radix *rtree, vm_pindex_t index, int color)
554{
555	struct vm_radix_node *rnode;
556	struct vm_radix_node *child;
557	vm_pindex_t max;
558	vm_pindex_t inc;
559	void *val;
560	int slot;
561	int level;
562
563	CTR2(KTR_VM,
564	    "lookup_le: tree %p, index %p", rtree, (void *)index);
565restart:
566	level = vm_radix_height(rtree, &rnode);
567	if (rnode == NULL)
568		return (NULL);
569	max = VM_RADIX_MAX(level);
570	if (index > max || index == 0)
571		index = max;
572	/*
573	 * Search the tree from the top for any leaf node holding an index
574	 * lower than 'index'.
575	 */
576	level--;
577	while (rnode) {
578		slot = vm_radix_slot(index, level);
579		CTR6(KTR_VM,
580	"lookup_le: tree %p, index %p, level %d, slot %d, rnode %p, child %p",
581		    rtree, (void *)index, level, slot, rnode,
582		    (rnode != NULL) ? rnode->rn_child[slot] : NULL);
583		if (level == 0)
584			break;
585		/*
586		 * If we don't have an exact match we must start our search
587		 * from the next leaf and adjust our index appropriately.
588		 */
589		if ((child = rnode->rn_child[slot]) == NULL) {
590			/*
591			 * Calculate how much to decrement our index by
592			 * based on the tree level.  We must set the
593			 * lower bits to start from the end of the next
594			 * leaf.
595		 	 */
596			inc = 1LL << (level * VM_RADIX_WIDTH);
597			index |= VM_RADIX_MAX(level);
598			index -= inc;
599			slot--;
600			CTR4(KTR_VM,
601			    "lookup_le: start %p inc %ld mask 0x%lX slot %d",
602			    (void *)index, inc, VM_RADIX_MAX(level), slot);
603			for (; slot >= 0; slot--, index -= inc) {
604				child = rnode->rn_child[slot];
605				if (child)
606					break;
607			}
608		}
609		rnode = child;
610		level--;
611	}
612	if (rnode) {
613		for (; slot >= 0; slot--, index--) {
614			val = vm_radix_match(rnode->rn_child[slot], color);
615			if (val)
616				return (val);
617		}
618	}
619	if (index != -1)
620		goto restart;
621	return (NULL);
622}
623
624/*
625 * Remove the specified index from the tree.  If possible the height of the
626 * tree is adjusted after deletion.  The value stored at index is returned
627 * panics if the key is not present.
628 */
629void *
630vm_radix_remove(struct vm_radix *rtree, vm_pindex_t index, int color)
631{
632	struct vm_radix_node *stack[VM_RADIX_LIMIT];
633	struct vm_radix_node *rnode, *root;
634	void *val;
635	int level;
636	int slot;
637
638	level = vm_radix_height(rtree, &root);
639	KASSERT(index <= VM_RADIX_MAX(level),
640	    ("vm_radix_remove: %p index %jd out of range %jd.",
641	    rtree, index, VM_RADIX_MAX(level)));
642	rnode = root;
643	val = NULL;
644	level--;
645	/*
646	 * Find the node and record the path in stack.
647	 */
648	while (level && rnode) {
649		stack[level] = rnode;
650		slot = vm_radix_slot(index, level);
651		CTR6(KTR_VM,
652	"remove: tree %p, index %p, level %d, slot %d, rnode %p, child %p",
653		    rtree, (void *)index, level, slot, rnode,
654		    (rnode != NULL) ? rnode->rn_child[slot] : NULL);
655		rnode = rnode->rn_child[slot];
656		level--;
657	}
658	KASSERT(rnode != NULL,
659	    ("vm_radix_remove: index %jd not present in the tree.\n", index));
660	slot = vm_radix_slot(index, 0);
661	val = vm_radix_match(rnode->rn_child[slot], color);
662	KASSERT(val != NULL,
663	    ("vm_radix_remove: index %jd not present in the tree.\n", index));
664
665	for (;;) {
666		CTR6(KTR_VM,
667"remove: resetting tree %p, index %p, level %d, slot %d, rnode %p, child %p",
668		    rtree, (void *)index, level, slot, rnode,
669		    (rnode != NULL) ? rnode->rn_child[slot] : NULL);
670		CTR3(KTR_VM, "remove: rnode %p, count %p, color %d",
671		    rnode, (rnode != NULL) ? rnode->rn_count : NULL, color);
672		rnode->rn_child[slot] = NULL;
673		/*
674		 * Use atomics for the last level since red and black
675		 * will both adjust it.
676		 */
677		if (level == 0)
678			atomic_add_int((volatile int *)&rnode->rn_count, -1);
679		else
680			rnode->rn_count--;
681		/*
682		 * Only allow black removes to prune the tree.
683		 */
684		if ((color & VM_RADIX_BLACK) == 0 || rnode->rn_count > 0)
685			break;
686		vm_radix_node_put(rnode);
687		if (rnode == root) {
688			vm_radix_setroot(rtree, NULL, 0);
689			break;
690		}
691		rnode = stack[++level];
692		slot = vm_radix_slot(index, level);
693
694	}
695	return (val);
696}
697
698/*
699 * Remove and free all the nodes from the radix tree.
700 * This function is recrusive but there is a tight control on it as the
701 * maximum depth of the tree is fixed.
702 */
703void
704vm_radix_reclaim_allnodes(struct vm_radix *rtree)
705{
706	struct vm_radix_node *root;
707	int level;
708
709	if (rtree->rt_root == 0)
710		return;
711	level = vm_radix_height(rtree, &root);
712	vm_radix_reclaim_allnodes_internal(root, level - 1);
713	rtree->rt_root = 0;
714}
715
716/*
717 * Attempts to reduce the height of the tree.
718 */
719void
720vm_radix_shrink(struct vm_radix *rtree)
721{
722	struct vm_radix_node *tmp, *root;
723	int level;
724
725	if (rtree->rt_root == 0)
726		return;
727	level = vm_radix_height(rtree, &root);
728
729	/* Adjust the height of the tree. */
730	while (root->rn_count == 1 && root->rn_child[0] != NULL) {
731		tmp = root;
732		root->rn_count--;
733		root = root->rn_child[0];
734		level--;
735		vm_radix_node_put(tmp);
736	}
737	/* Finally see if we have an empty tree. */
738	if (root->rn_count == 0) {
739		vm_radix_node_put(root);
740		root = NULL;
741		level--;
742	}
743	vm_radix_setroot(rtree, root, level);
744}
745