xref: /titanic_41/usr/src/uts/common/fs/zfs/range_tree.c (revision bc721b90dd3890486ebe0293e0ec508fe6a016de)
10713e232SGeorge Wilson /*
20713e232SGeorge Wilson  * CDDL HEADER START
30713e232SGeorge Wilson  *
40713e232SGeorge Wilson  * The contents of this file are subject to the terms of the
50713e232SGeorge Wilson  * Common Development and Distribution License (the "License").
60713e232SGeorge Wilson  * You may not use this file except in compliance with the License.
70713e232SGeorge Wilson  *
80713e232SGeorge Wilson  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90713e232SGeorge Wilson  * or http://www.opensolaris.org/os/licensing.
100713e232SGeorge Wilson  * See the License for the specific language governing permissions
110713e232SGeorge Wilson  * and limitations under the License.
120713e232SGeorge Wilson  *
130713e232SGeorge Wilson  * When distributing Covered Code, include this CDDL HEADER in each
140713e232SGeorge Wilson  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150713e232SGeorge Wilson  * If applicable, add the following below this CDDL HEADER, with the
160713e232SGeorge Wilson  * fields enclosed by brackets "[]" replaced with your own identifying
170713e232SGeorge Wilson  * information: Portions Copyright [yyyy] [name of copyright owner]
180713e232SGeorge Wilson  *
190713e232SGeorge Wilson  * CDDL HEADER END
200713e232SGeorge Wilson  */
210713e232SGeorge Wilson /*
220713e232SGeorge Wilson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230713e232SGeorge Wilson  * Use is subject to license terms.
240713e232SGeorge Wilson  */
250713e232SGeorge Wilson /*
26887cdfc7SMatthew Ahrens  * Copyright (c) 2013, 2014 by Delphix. All rights reserved.
270713e232SGeorge Wilson  */
280713e232SGeorge Wilson 
290713e232SGeorge Wilson #include <sys/zfs_context.h>
300713e232SGeorge Wilson #include <sys/spa.h>
310713e232SGeorge Wilson #include <sys/dmu.h>
320713e232SGeorge Wilson #include <sys/dnode.h>
330713e232SGeorge Wilson #include <sys/zio.h>
340713e232SGeorge Wilson #include <sys/range_tree.h>
350713e232SGeorge Wilson 
36*bc721b90SGeorge Wilson kmem_cache_t *range_seg_cache;
370713e232SGeorge Wilson 
380713e232SGeorge Wilson void
range_tree_init(void)390713e232SGeorge Wilson range_tree_init(void)
400713e232SGeorge Wilson {
410713e232SGeorge Wilson 	ASSERT(range_seg_cache == NULL);
420713e232SGeorge Wilson 	range_seg_cache = kmem_cache_create("range_seg_cache",
430713e232SGeorge Wilson 	    sizeof (range_seg_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
440713e232SGeorge Wilson }
450713e232SGeorge Wilson 
460713e232SGeorge Wilson void
range_tree_fini(void)470713e232SGeorge Wilson range_tree_fini(void)
480713e232SGeorge Wilson {
490713e232SGeorge Wilson 	kmem_cache_destroy(range_seg_cache);
500713e232SGeorge Wilson 	range_seg_cache = NULL;
510713e232SGeorge Wilson }
520713e232SGeorge Wilson 
530713e232SGeorge Wilson void
range_tree_stat_verify(range_tree_t * rt)540713e232SGeorge Wilson range_tree_stat_verify(range_tree_t *rt)
550713e232SGeorge Wilson {
560713e232SGeorge Wilson 	range_seg_t *rs;
570713e232SGeorge Wilson 	uint64_t hist[RANGE_TREE_HISTOGRAM_SIZE] = { 0 };
580713e232SGeorge Wilson 	int i;
590713e232SGeorge Wilson 
600713e232SGeorge Wilson 	for (rs = avl_first(&rt->rt_root); rs != NULL;
610713e232SGeorge Wilson 	    rs = AVL_NEXT(&rt->rt_root, rs)) {
620713e232SGeorge Wilson 		uint64_t size = rs->rs_end - rs->rs_start;
63887cdfc7SMatthew Ahrens 		int idx	= highbit64(size) - 1;
640713e232SGeorge Wilson 
650713e232SGeorge Wilson 		hist[idx]++;
660713e232SGeorge Wilson 		ASSERT3U(hist[idx], !=, 0);
670713e232SGeorge Wilson 	}
680713e232SGeorge Wilson 
690713e232SGeorge Wilson 	for (i = 0; i < RANGE_TREE_HISTOGRAM_SIZE; i++) {
700713e232SGeorge Wilson 		if (hist[i] != rt->rt_histogram[i]) {
710713e232SGeorge Wilson 			zfs_dbgmsg("i=%d, hist=%p, hist=%llu, rt_hist=%llu",
720713e232SGeorge Wilson 			    i, hist, hist[i], rt->rt_histogram[i]);
730713e232SGeorge Wilson 		}
740713e232SGeorge Wilson 		VERIFY3U(hist[i], ==, rt->rt_histogram[i]);
750713e232SGeorge Wilson 	}
760713e232SGeorge Wilson }
770713e232SGeorge Wilson 
780713e232SGeorge Wilson static void
range_tree_stat_incr(range_tree_t * rt,range_seg_t * rs)790713e232SGeorge Wilson range_tree_stat_incr(range_tree_t *rt, range_seg_t *rs)
800713e232SGeorge Wilson {
810713e232SGeorge Wilson 	uint64_t size = rs->rs_end - rs->rs_start;
82887cdfc7SMatthew Ahrens 	int idx = highbit64(size) - 1;
830713e232SGeorge Wilson 
8402b647c5SGeorge Wilson 	ASSERT(size != 0);
850713e232SGeorge Wilson 	ASSERT3U(idx, <,
860713e232SGeorge Wilson 	    sizeof (rt->rt_histogram) / sizeof (*rt->rt_histogram));
870713e232SGeorge Wilson 
880713e232SGeorge Wilson 	ASSERT(MUTEX_HELD(rt->rt_lock));
890713e232SGeorge Wilson 	rt->rt_histogram[idx]++;
900713e232SGeorge Wilson 	ASSERT3U(rt->rt_histogram[idx], !=, 0);
910713e232SGeorge Wilson }
920713e232SGeorge Wilson 
930713e232SGeorge Wilson static void
range_tree_stat_decr(range_tree_t * rt,range_seg_t * rs)940713e232SGeorge Wilson range_tree_stat_decr(range_tree_t *rt, range_seg_t *rs)
950713e232SGeorge Wilson {
960713e232SGeorge Wilson 	uint64_t size = rs->rs_end - rs->rs_start;
97887cdfc7SMatthew Ahrens 	int idx = highbit64(size) - 1;
980713e232SGeorge Wilson 
9902b647c5SGeorge Wilson 	ASSERT(size != 0);
1000713e232SGeorge Wilson 	ASSERT3U(idx, <,
1010713e232SGeorge Wilson 	    sizeof (rt->rt_histogram) / sizeof (*rt->rt_histogram));
1020713e232SGeorge Wilson 
1030713e232SGeorge Wilson 	ASSERT(MUTEX_HELD(rt->rt_lock));
1040713e232SGeorge Wilson 	ASSERT3U(rt->rt_histogram[idx], !=, 0);
1050713e232SGeorge Wilson 	rt->rt_histogram[idx]--;
1060713e232SGeorge Wilson }
1070713e232SGeorge Wilson 
1080713e232SGeorge Wilson /*
1090713e232SGeorge Wilson  * NOTE: caller is responsible for all locking.
1100713e232SGeorge Wilson  */
1110713e232SGeorge Wilson static int
range_tree_seg_compare(const void * x1,const void * x2)1120713e232SGeorge Wilson range_tree_seg_compare(const void *x1, const void *x2)
1130713e232SGeorge Wilson {
1140713e232SGeorge Wilson 	const range_seg_t *r1 = x1;
1150713e232SGeorge Wilson 	const range_seg_t *r2 = x2;
1160713e232SGeorge Wilson 
1170713e232SGeorge Wilson 	if (r1->rs_start < r2->rs_start) {
1180713e232SGeorge Wilson 		if (r1->rs_end > r2->rs_start)
1190713e232SGeorge Wilson 			return (0);
1200713e232SGeorge Wilson 		return (-1);
1210713e232SGeorge Wilson 	}
1220713e232SGeorge Wilson 	if (r1->rs_start > r2->rs_start) {
1230713e232SGeorge Wilson 		if (r1->rs_start < r2->rs_end)
1240713e232SGeorge Wilson 			return (0);
1250713e232SGeorge Wilson 		return (1);
1260713e232SGeorge Wilson 	}
1270713e232SGeorge Wilson 	return (0);
1280713e232SGeorge Wilson }
1290713e232SGeorge Wilson 
1300713e232SGeorge Wilson range_tree_t *
range_tree_create(range_tree_ops_t * ops,void * arg,kmutex_t * lp)1310713e232SGeorge Wilson range_tree_create(range_tree_ops_t *ops, void *arg, kmutex_t *lp)
1320713e232SGeorge Wilson {
1330713e232SGeorge Wilson 	range_tree_t *rt;
1340713e232SGeorge Wilson 
1350713e232SGeorge Wilson 	rt = kmem_zalloc(sizeof (range_tree_t), KM_SLEEP);
1360713e232SGeorge Wilson 
1370713e232SGeorge Wilson 	avl_create(&rt->rt_root, range_tree_seg_compare,
1380713e232SGeorge Wilson 	    sizeof (range_seg_t), offsetof(range_seg_t, rs_node));
1390713e232SGeorge Wilson 
1400713e232SGeorge Wilson 	rt->rt_lock = lp;
1410713e232SGeorge Wilson 	rt->rt_ops = ops;
1420713e232SGeorge Wilson 	rt->rt_arg = arg;
1430713e232SGeorge Wilson 
1440713e232SGeorge Wilson 	if (rt->rt_ops != NULL)
1450713e232SGeorge Wilson 		rt->rt_ops->rtop_create(rt, rt->rt_arg);
1460713e232SGeorge Wilson 
1470713e232SGeorge Wilson 	return (rt);
1480713e232SGeorge Wilson }
1490713e232SGeorge Wilson 
1500713e232SGeorge Wilson void
range_tree_destroy(range_tree_t * rt)1510713e232SGeorge Wilson range_tree_destroy(range_tree_t *rt)
1520713e232SGeorge Wilson {
1530713e232SGeorge Wilson 	VERIFY0(rt->rt_space);
1540713e232SGeorge Wilson 
1550713e232SGeorge Wilson 	if (rt->rt_ops != NULL)
1560713e232SGeorge Wilson 		rt->rt_ops->rtop_destroy(rt, rt->rt_arg);
1570713e232SGeorge Wilson 
1580713e232SGeorge Wilson 	avl_destroy(&rt->rt_root);
1590713e232SGeorge Wilson 	kmem_free(rt, sizeof (*rt));
1600713e232SGeorge Wilson }
1610713e232SGeorge Wilson 
1620713e232SGeorge Wilson void
range_tree_add(void * arg,uint64_t start,uint64_t size)1630713e232SGeorge Wilson range_tree_add(void *arg, uint64_t start, uint64_t size)
1640713e232SGeorge Wilson {
1650713e232SGeorge Wilson 	range_tree_t *rt = arg;
1660713e232SGeorge Wilson 	avl_index_t where;
1670713e232SGeorge Wilson 	range_seg_t rsearch, *rs_before, *rs_after, *rs;
1680713e232SGeorge Wilson 	uint64_t end = start + size;
1690713e232SGeorge Wilson 	boolean_t merge_before, merge_after;
1700713e232SGeorge Wilson 
1710713e232SGeorge Wilson 	ASSERT(MUTEX_HELD(rt->rt_lock));
1720713e232SGeorge Wilson 	VERIFY(size != 0);
1730713e232SGeorge Wilson 
1740713e232SGeorge Wilson 	rsearch.rs_start = start;
1750713e232SGeorge Wilson 	rsearch.rs_end = end;
1760713e232SGeorge Wilson 	rs = avl_find(&rt->rt_root, &rsearch, &where);
1770713e232SGeorge Wilson 
1780713e232SGeorge Wilson 	if (rs != NULL && rs->rs_start <= start && rs->rs_end >= end) {
1790713e232SGeorge Wilson 		zfs_panic_recover("zfs: allocating allocated segment"
1800713e232SGeorge Wilson 		    "(offset=%llu size=%llu)\n",
1810713e232SGeorge Wilson 		    (longlong_t)start, (longlong_t)size);
1820713e232SGeorge Wilson 		return;
1830713e232SGeorge Wilson 	}
1840713e232SGeorge Wilson 
1850713e232SGeorge Wilson 	/* Make sure we don't overlap with either of our neighbors */
1860713e232SGeorge Wilson 	VERIFY(rs == NULL);
1870713e232SGeorge Wilson 
1880713e232SGeorge Wilson 	rs_before = avl_nearest(&rt->rt_root, where, AVL_BEFORE);
1890713e232SGeorge Wilson 	rs_after = avl_nearest(&rt->rt_root, where, AVL_AFTER);
1900713e232SGeorge Wilson 
1910713e232SGeorge Wilson 	merge_before = (rs_before != NULL && rs_before->rs_end == start);
1920713e232SGeorge Wilson 	merge_after = (rs_after != NULL && rs_after->rs_start == end);
1930713e232SGeorge Wilson 
1940713e232SGeorge Wilson 	if (merge_before && merge_after) {
1950713e232SGeorge Wilson 		avl_remove(&rt->rt_root, rs_before);
1960713e232SGeorge Wilson 		if (rt->rt_ops != NULL) {
1970713e232SGeorge Wilson 			rt->rt_ops->rtop_remove(rt, rs_before, rt->rt_arg);
1980713e232SGeorge Wilson 			rt->rt_ops->rtop_remove(rt, rs_after, rt->rt_arg);
1990713e232SGeorge Wilson 		}
2000713e232SGeorge Wilson 
2010713e232SGeorge Wilson 		range_tree_stat_decr(rt, rs_before);
2020713e232SGeorge Wilson 		range_tree_stat_decr(rt, rs_after);
2030713e232SGeorge Wilson 
2040713e232SGeorge Wilson 		rs_after->rs_start = rs_before->rs_start;
2050713e232SGeorge Wilson 		kmem_cache_free(range_seg_cache, rs_before);
2060713e232SGeorge Wilson 		rs = rs_after;
2070713e232SGeorge Wilson 	} else if (merge_before) {
2080713e232SGeorge Wilson 		if (rt->rt_ops != NULL)
2090713e232SGeorge Wilson 			rt->rt_ops->rtop_remove(rt, rs_before, rt->rt_arg);
2100713e232SGeorge Wilson 
2110713e232SGeorge Wilson 		range_tree_stat_decr(rt, rs_before);
2120713e232SGeorge Wilson 
2130713e232SGeorge Wilson 		rs_before->rs_end = end;
2140713e232SGeorge Wilson 		rs = rs_before;
2150713e232SGeorge Wilson 	} else if (merge_after) {
2160713e232SGeorge Wilson 		if (rt->rt_ops != NULL)
2170713e232SGeorge Wilson 			rt->rt_ops->rtop_remove(rt, rs_after, rt->rt_arg);
2180713e232SGeorge Wilson 
2190713e232SGeorge Wilson 		range_tree_stat_decr(rt, rs_after);
2200713e232SGeorge Wilson 
2210713e232SGeorge Wilson 		rs_after->rs_start = start;
2220713e232SGeorge Wilson 		rs = rs_after;
2230713e232SGeorge Wilson 	} else {
2240713e232SGeorge Wilson 		rs = kmem_cache_alloc(range_seg_cache, KM_SLEEP);
2250713e232SGeorge Wilson 		rs->rs_start = start;
2260713e232SGeorge Wilson 		rs->rs_end = end;
2270713e232SGeorge Wilson 		avl_insert(&rt->rt_root, rs, where);
2280713e232SGeorge Wilson 	}
2290713e232SGeorge Wilson 
2300713e232SGeorge Wilson 	if (rt->rt_ops != NULL)
2310713e232SGeorge Wilson 		rt->rt_ops->rtop_add(rt, rs, rt->rt_arg);
2320713e232SGeorge Wilson 
2330713e232SGeorge Wilson 	range_tree_stat_incr(rt, rs);
2340713e232SGeorge Wilson 	rt->rt_space += size;
2350713e232SGeorge Wilson }
2360713e232SGeorge Wilson 
2370713e232SGeorge Wilson void
range_tree_remove(void * arg,uint64_t start,uint64_t size)2380713e232SGeorge Wilson range_tree_remove(void *arg, uint64_t start, uint64_t size)
2390713e232SGeorge Wilson {
2400713e232SGeorge Wilson 	range_tree_t *rt = arg;
2410713e232SGeorge Wilson 	avl_index_t where;
2420713e232SGeorge Wilson 	range_seg_t rsearch, *rs, *newseg;
2430713e232SGeorge Wilson 	uint64_t end = start + size;
2440713e232SGeorge Wilson 	boolean_t left_over, right_over;
2450713e232SGeorge Wilson 
2460713e232SGeorge Wilson 	ASSERT(MUTEX_HELD(rt->rt_lock));
2470713e232SGeorge Wilson 	VERIFY3U(size, !=, 0);
2480713e232SGeorge Wilson 	VERIFY3U(size, <=, rt->rt_space);
2490713e232SGeorge Wilson 
2500713e232SGeorge Wilson 	rsearch.rs_start = start;
2510713e232SGeorge Wilson 	rsearch.rs_end = end;
2520713e232SGeorge Wilson 	rs = avl_find(&rt->rt_root, &rsearch, &where);
2530713e232SGeorge Wilson 
2540713e232SGeorge Wilson 	/* Make sure we completely overlap with someone */
2550713e232SGeorge Wilson 	if (rs == NULL) {
2560713e232SGeorge Wilson 		zfs_panic_recover("zfs: freeing free segment "
2570713e232SGeorge Wilson 		    "(offset=%llu size=%llu)",
2580713e232SGeorge Wilson 		    (longlong_t)start, (longlong_t)size);
2590713e232SGeorge Wilson 		return;
2600713e232SGeorge Wilson 	}
2610713e232SGeorge Wilson 	VERIFY3U(rs->rs_start, <=, start);
2620713e232SGeorge Wilson 	VERIFY3U(rs->rs_end, >=, end);
2630713e232SGeorge Wilson 
2640713e232SGeorge Wilson 	left_over = (rs->rs_start != start);
2650713e232SGeorge Wilson 	right_over = (rs->rs_end != end);
2660713e232SGeorge Wilson 
2670713e232SGeorge Wilson 	range_tree_stat_decr(rt, rs);
2680713e232SGeorge Wilson 
2690713e232SGeorge Wilson 	if (rt->rt_ops != NULL)
2700713e232SGeorge Wilson 		rt->rt_ops->rtop_remove(rt, rs, rt->rt_arg);
2710713e232SGeorge Wilson 
2720713e232SGeorge Wilson 	if (left_over && right_over) {
2730713e232SGeorge Wilson 		newseg = kmem_cache_alloc(range_seg_cache, KM_SLEEP);
2740713e232SGeorge Wilson 		newseg->rs_start = end;
2750713e232SGeorge Wilson 		newseg->rs_end = rs->rs_end;
2760713e232SGeorge Wilson 		range_tree_stat_incr(rt, newseg);
2770713e232SGeorge Wilson 
2780713e232SGeorge Wilson 		rs->rs_end = start;
2790713e232SGeorge Wilson 
2800713e232SGeorge Wilson 		avl_insert_here(&rt->rt_root, newseg, rs, AVL_AFTER);
2810713e232SGeorge Wilson 		if (rt->rt_ops != NULL)
2820713e232SGeorge Wilson 			rt->rt_ops->rtop_add(rt, newseg, rt->rt_arg);
2830713e232SGeorge Wilson 	} else if (left_over) {
2840713e232SGeorge Wilson 		rs->rs_end = start;
2850713e232SGeorge Wilson 	} else if (right_over) {
2860713e232SGeorge Wilson 		rs->rs_start = end;
2870713e232SGeorge Wilson 	} else {
2880713e232SGeorge Wilson 		avl_remove(&rt->rt_root, rs);
2890713e232SGeorge Wilson 		kmem_cache_free(range_seg_cache, rs);
2900713e232SGeorge Wilson 		rs = NULL;
2910713e232SGeorge Wilson 	}
2920713e232SGeorge Wilson 
2930713e232SGeorge Wilson 	if (rs != NULL) {
2940713e232SGeorge Wilson 		range_tree_stat_incr(rt, rs);
2950713e232SGeorge Wilson 
2960713e232SGeorge Wilson 		if (rt->rt_ops != NULL)
2970713e232SGeorge Wilson 			rt->rt_ops->rtop_add(rt, rs, rt->rt_arg);
2980713e232SGeorge Wilson 	}
2990713e232SGeorge Wilson 
3000713e232SGeorge Wilson 	rt->rt_space -= size;
3010713e232SGeorge Wilson }
3020713e232SGeorge Wilson 
3030713e232SGeorge Wilson static range_seg_t *
range_tree_find_impl(range_tree_t * rt,uint64_t start,uint64_t size)304887cdfc7SMatthew Ahrens range_tree_find_impl(range_tree_t *rt, uint64_t start, uint64_t size)
3050713e232SGeorge Wilson {
306887cdfc7SMatthew Ahrens 	avl_index_t where;
307887cdfc7SMatthew Ahrens 	range_seg_t rsearch;
3080713e232SGeorge Wilson 	uint64_t end = start + size;
3090713e232SGeorge Wilson 
3100713e232SGeorge Wilson 	ASSERT(MUTEX_HELD(rt->rt_lock));
3110713e232SGeorge Wilson 	VERIFY(size != 0);
3120713e232SGeorge Wilson 
3130713e232SGeorge Wilson 	rsearch.rs_start = start;
3140713e232SGeorge Wilson 	rsearch.rs_end = end;
315887cdfc7SMatthew Ahrens 	return (avl_find(&rt->rt_root, &rsearch, &where));
316887cdfc7SMatthew Ahrens }
3170713e232SGeorge Wilson 
318887cdfc7SMatthew Ahrens static range_seg_t *
range_tree_find(range_tree_t * rt,uint64_t start,uint64_t size)319887cdfc7SMatthew Ahrens range_tree_find(range_tree_t *rt, uint64_t start, uint64_t size)
320887cdfc7SMatthew Ahrens {
321887cdfc7SMatthew Ahrens 	range_seg_t *rs = range_tree_find_impl(rt, start, size);
322887cdfc7SMatthew Ahrens 	if (rs != NULL && rs->rs_start <= start && rs->rs_end >= start + size)
3230713e232SGeorge Wilson 		return (rs);
3240713e232SGeorge Wilson 	return (NULL);
3250713e232SGeorge Wilson }
3260713e232SGeorge Wilson 
3270713e232SGeorge Wilson void
range_tree_verify(range_tree_t * rt,uint64_t off,uint64_t size)3280713e232SGeorge Wilson range_tree_verify(range_tree_t *rt, uint64_t off, uint64_t size)
3290713e232SGeorge Wilson {
3300713e232SGeorge Wilson 	range_seg_t *rs;
3310713e232SGeorge Wilson 
3320713e232SGeorge Wilson 	mutex_enter(rt->rt_lock);
333887cdfc7SMatthew Ahrens 	rs = range_tree_find(rt, off, size);
3340713e232SGeorge Wilson 	if (rs != NULL)
3350713e232SGeorge Wilson 		panic("freeing free block; rs=%p", (void *)rs);
3360713e232SGeorge Wilson 	mutex_exit(rt->rt_lock);
3370713e232SGeorge Wilson }
3380713e232SGeorge Wilson 
3390713e232SGeorge Wilson boolean_t
range_tree_contains(range_tree_t * rt,uint64_t start,uint64_t size)3400713e232SGeorge Wilson range_tree_contains(range_tree_t *rt, uint64_t start, uint64_t size)
3410713e232SGeorge Wilson {
342887cdfc7SMatthew Ahrens 	return (range_tree_find(rt, start, size) != NULL);
343887cdfc7SMatthew Ahrens }
3440713e232SGeorge Wilson 
345887cdfc7SMatthew Ahrens /*
346887cdfc7SMatthew Ahrens  * Ensure that this range is not in the tree, regardless of whether
347887cdfc7SMatthew Ahrens  * it is currently in the tree.
348887cdfc7SMatthew Ahrens  */
349887cdfc7SMatthew Ahrens void
range_tree_clear(range_tree_t * rt,uint64_t start,uint64_t size)350887cdfc7SMatthew Ahrens range_tree_clear(range_tree_t *rt, uint64_t start, uint64_t size)
351887cdfc7SMatthew Ahrens {
352887cdfc7SMatthew Ahrens 	range_seg_t *rs;
353887cdfc7SMatthew Ahrens 
354887cdfc7SMatthew Ahrens 	while ((rs = range_tree_find_impl(rt, start, size)) != NULL) {
355887cdfc7SMatthew Ahrens 		uint64_t free_start = MAX(rs->rs_start, start);
356887cdfc7SMatthew Ahrens 		uint64_t free_end = MIN(rs->rs_end, start + size);
357887cdfc7SMatthew Ahrens 		range_tree_remove(rt, free_start, free_end - free_start);
358887cdfc7SMatthew Ahrens 	}
3590713e232SGeorge Wilson }
3600713e232SGeorge Wilson 
3610713e232SGeorge Wilson void
range_tree_swap(range_tree_t ** rtsrc,range_tree_t ** rtdst)3620713e232SGeorge Wilson range_tree_swap(range_tree_t **rtsrc, range_tree_t **rtdst)
3630713e232SGeorge Wilson {
3640713e232SGeorge Wilson 	range_tree_t *rt;
3650713e232SGeorge Wilson 
3660713e232SGeorge Wilson 	ASSERT(MUTEX_HELD((*rtsrc)->rt_lock));
3670713e232SGeorge Wilson 	ASSERT0(range_tree_space(*rtdst));
3680713e232SGeorge Wilson 	ASSERT0(avl_numnodes(&(*rtdst)->rt_root));
3690713e232SGeorge Wilson 
3700713e232SGeorge Wilson 	rt = *rtsrc;
3710713e232SGeorge Wilson 	*rtsrc = *rtdst;
3720713e232SGeorge Wilson 	*rtdst = rt;
3730713e232SGeorge Wilson }
3740713e232SGeorge Wilson 
3750713e232SGeorge Wilson void
range_tree_vacate(range_tree_t * rt,range_tree_func_t * func,void * arg)3760713e232SGeorge Wilson range_tree_vacate(range_tree_t *rt, range_tree_func_t *func, void *arg)
3770713e232SGeorge Wilson {
3780713e232SGeorge Wilson 	range_seg_t *rs;
3790713e232SGeorge Wilson 	void *cookie = NULL;
3800713e232SGeorge Wilson 
3810713e232SGeorge Wilson 	ASSERT(MUTEX_HELD(rt->rt_lock));
3820713e232SGeorge Wilson 
3830713e232SGeorge Wilson 	if (rt->rt_ops != NULL)
3840713e232SGeorge Wilson 		rt->rt_ops->rtop_vacate(rt, rt->rt_arg);
3850713e232SGeorge Wilson 
3860713e232SGeorge Wilson 	while ((rs = avl_destroy_nodes(&rt->rt_root, &cookie)) != NULL) {
3870713e232SGeorge Wilson 		if (func != NULL)
3880713e232SGeorge Wilson 			func(arg, rs->rs_start, rs->rs_end - rs->rs_start);
3890713e232SGeorge Wilson 		kmem_cache_free(range_seg_cache, rs);
3900713e232SGeorge Wilson 	}
3910713e232SGeorge Wilson 
3920713e232SGeorge Wilson 	bzero(rt->rt_histogram, sizeof (rt->rt_histogram));
3930713e232SGeorge Wilson 	rt->rt_space = 0;
3940713e232SGeorge Wilson }
3950713e232SGeorge Wilson 
3960713e232SGeorge Wilson void
range_tree_walk(range_tree_t * rt,range_tree_func_t * func,void * arg)3970713e232SGeorge Wilson range_tree_walk(range_tree_t *rt, range_tree_func_t *func, void *arg)
3980713e232SGeorge Wilson {
3990713e232SGeorge Wilson 	range_seg_t *rs;
4000713e232SGeorge Wilson 
4010713e232SGeorge Wilson 	ASSERT(MUTEX_HELD(rt->rt_lock));
4020713e232SGeorge Wilson 
4030713e232SGeorge Wilson 	for (rs = avl_first(&rt->rt_root); rs; rs = AVL_NEXT(&rt->rt_root, rs))
4040713e232SGeorge Wilson 		func(arg, rs->rs_start, rs->rs_end - rs->rs_start);
4050713e232SGeorge Wilson }
4060713e232SGeorge Wilson 
4070713e232SGeorge Wilson uint64_t
range_tree_space(range_tree_t * rt)4080713e232SGeorge Wilson range_tree_space(range_tree_t *rt)
4090713e232SGeorge Wilson {
4100713e232SGeorge Wilson 	return (rt->rt_space);
4110713e232SGeorge Wilson }
412