summaryrefslogtreecommitdiffstats
path: root/module/zfs/range_tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/range_tree.c')
-rw-r--r--module/zfs/range_tree.c84
1 files changed, 80 insertions, 4 deletions
diff --git a/module/zfs/range_tree.c b/module/zfs/range_tree.c
index 391533b3f..5919236d9 100644
--- a/module/zfs/range_tree.c
+++ b/module/zfs/range_tree.c
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2013, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2019 by Delphix. All rights reserved.
*/
#include <sys/zfs_context.h>
@@ -578,10 +578,10 @@ range_tree_vacate(range_tree_t *rt, range_tree_func_t *func, void *arg)
void
range_tree_walk(range_tree_t *rt, range_tree_func_t *func, void *arg)
{
- range_seg_t *rs;
-
- for (rs = avl_first(&rt->rt_root); rs; rs = AVL_NEXT(&rt->rt_root, rs))
+ for (range_seg_t *rs = avl_first(&rt->rt_root); rs;
+ rs = AVL_NEXT(&rt->rt_root, rs)) {
func(arg, rs->rs_start, rs->rs_end - rs->rs_start);
+ }
}
range_seg_t *
@@ -596,6 +596,12 @@ range_tree_space(range_tree_t *rt)
return (rt->rt_space);
}
+uint64_t
+range_tree_numsegs(range_tree_t *rt)
+{
+ return ((rt == NULL) ? 0 : avl_numnodes(&rt->rt_root));
+}
+
boolean_t
range_tree_is_empty(range_tree_t *rt)
{
@@ -667,3 +673,73 @@ range_tree_span(range_tree_t *rt)
{
return (range_tree_max(rt) - range_tree_min(rt));
}
+
+/*
+ * Remove any overlapping ranges between the given segment [start, end)
+ * from removefrom. Add non-overlapping leftovers to addto.
+ */
+void
+range_tree_remove_xor_add_segment(uint64_t start, uint64_t end,
+ range_tree_t *removefrom, range_tree_t *addto)
+{
+ avl_index_t where;
+ range_seg_t starting_rs = {
+ .rs_start = start,
+ .rs_end = start + 1
+ };
+
+ range_seg_t *curr = avl_find(&removefrom->rt_root,
+ &starting_rs, &where);
+
+ if (curr == NULL)
+ curr = avl_nearest(&removefrom->rt_root, where, AVL_AFTER);
+
+ range_seg_t *next;
+ for (; curr != NULL; curr = next) {
+ next = AVL_NEXT(&removefrom->rt_root, curr);
+
+ if (start == end)
+ return;
+ VERIFY3U(start, <, end);
+
+ /* there is no overlap */
+ if (end <= curr->rs_start) {
+ range_tree_add(addto, start, end - start);
+ return;
+ }
+
+ uint64_t overlap_start = MAX(curr->rs_start, start);
+ uint64_t overlap_end = MIN(curr->rs_end, end);
+ uint64_t overlap_size = overlap_end - overlap_start;
+ ASSERT3S(overlap_size, >, 0);
+ range_tree_remove(removefrom, overlap_start, overlap_size);
+
+ if (start < overlap_start)
+ range_tree_add(addto, start, overlap_start - start);
+
+ start = overlap_end;
+ }
+ VERIFY3P(curr, ==, NULL);
+
+ if (start != end) {
+ VERIFY3U(start, <, end);
+ range_tree_add(addto, start, end - start);
+ } else {
+ VERIFY3U(start, ==, end);
+ }
+}
+
+/*
+ * For each entry in rt, if it exists in removefrom, remove it
+ * from removefrom. Otherwise, add it to addto.
+ */
+void
+range_tree_remove_xor_add(range_tree_t *rt, range_tree_t *removefrom,
+ range_tree_t *addto)
+{
+ for (range_seg_t *rs = avl_first(&rt->rt_root); rs;
+ rs = AVL_NEXT(&rt->rt_root, rs)) {
+ range_tree_remove_xor_add_segment(rs->rs_start, rs->rs_end,
+ removefrom, addto);
+ }
+}