kvm tools: Add interval red-black tree helper

Interval rb-tree allows to directly store interval ranges
and quickly lookup an overlap with a single point or a range.

The helper is based on the kernel rb-tree implementation
(located in <linux/rbtree.h>) which alows for the augmention
of the classical rb-tree to be used as an interval tree.

Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
Sasha Levin
2015-06-01 16:39:43 +01:00
committed by Will Deacon
parent 70b0d7b0d1
commit e358b4fbdb
4 changed files with 131 additions and 0 deletions
+1
View File
@@ -42,6 +42,7 @@ OBJS += mptable.o
OBJS += threadpool.o
OBJS += irq.o
OBJS += ../../lib/rbtree.o
OBJS += util/rbtree-interval.o
DEPS := $(patsubst %.o,%.d,$(OBJS))
+27
View File
@@ -0,0 +1,27 @@
#ifndef KVM__INTERVAL_RBTREE_H
#define KVM__INTERVAL_RBTREE_H
#include <linux/rbtree.h>
#include <linux/types.h>
#define RB_INT_INIT(l, h) (struct rb_int_node){.low = l, .high = h}
struct rb_int_node {
struct rb_node node;
u64 low;
u64 high;
/* max_high will store the highest high of it's 2 children. */
u64 max_high;
};
/* Return the rb_int_node interval in which 'point' is located. */
struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point);
/* Return the rb_int_node in which start:len is located. */
struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high);
int rb_int_insert(struct rb_root *root, struct rb_int_node *data);
void rb_int_erase(struct rb_root *root, struct rb_int_node *node);
#endif
+13
View File
@@ -1,3 +1,4 @@
#ifndef KVM__LINUX_KERNEL_H_
#define KVM__LINUX_KERNEL_H_
@@ -23,4 +24,16 @@
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
#define max(x, y) ({ \
typeof(x) _max1 = (x); \
typeof(y) _max2 = (y); \
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
#endif
+90
View File
@@ -0,0 +1,90 @@
#include <kvm/rbtree-interval.h>
#include <stddef.h>
#define rb_int(n) rb_entry(n, struct rb_int_node, node)
struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point)
{
struct rb_node *node = root->rb_node;
struct rb_node *lowest = NULL;
while (node) {
struct rb_int_node *cur = rb_int(node);
if (node->rb_left && (rb_int(node->rb_left)->max_high > point)) {
node = node->rb_left;
} else if (cur->low <= point && cur->high > point) {
lowest = node;
break;
} else if (point > cur->low) {
node = node->rb_right;
} else {
break;
}
}
if (lowest == NULL)
return NULL;
return rb_int(lowest);
}
struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high)
{
struct rb_int_node *range;
range = rb_int_search_single(root, low);
if (range == NULL)
return NULL;
/* We simply verify that 'high' is smaller than the end of the range where 'low' is located */
if (range->high < high)
return NULL;
return range;
}
static void update_node_max_high(struct rb_node *node, void *arg)
{
struct rb_int_node *i_node = rb_int(node);
i_node->max_high = i_node->high;
if (node->rb_left)
i_node->max_high = max(i_node->max_high, rb_int(node->rb_left)->high);
if (node->rb_right)
i_node->max_high = max(i_node->max_high, rb_int(node->rb_right)->high);
}
int rb_int_insert(struct rb_root *root, struct rb_int_node *i_node)
{
struct rb_node **node = &(root->rb_node), *parent = NULL;
while (*node) {
int result = i_node->low - rb_int(*node)->low;
parent = *node;
if (result < 0)
node = &((*node)->rb_left);
else if (result > 0)
node = &((*node)->rb_right);
else
return 0;
}
rb_link_node(&i_node->node, parent, node);
rb_insert_color(&i_node->node, root);
rb_augment_insert(*node, update_node_max_high, NULL);
return 1;
}
void rb_int_erase(struct rb_root *root, struct rb_int_node *node)
{
struct rb_node *deepest;
deepest = rb_augment_erase_begin(&node->node);
rb_erase(&node->node, root);
rb_augment_erase_end(deepest, update_node_max_high, NULL);
}