rbtree: Make swap resistant to nodes outside the tree

Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
Robert Baldyga 2020-11-09 17:28:27 +01:00
parent 694224971c
commit 50c4de0495

View File

@ -12,24 +12,19 @@ void ocf_rb_tree_init(struct ocf_rb_tree *tree, ocf_rb_tree_node_cmp_cb cmp)
} }
static void ocf_rb_tree_update_parent(struct ocf_rb_tree *tree, static void ocf_rb_tree_update_parent(struct ocf_rb_tree *tree,
struct ocf_rb_node *node, struct ocf_rb_node *old_node, struct ocf_rb_node *parent, struct ocf_rb_node *old_node,
struct ocf_rb_node *new_node) struct ocf_rb_node *new_node)
{ {
if (!node->parent) if (!parent) {
tree->root = new_node; if (tree->root == old_node)
else if (old_node == node->parent->left) tree->root = new_node;
node->parent->left = new_node; return;
else if (old_node == node->parent->right) }
node->parent->right = new_node;
}
static void ocf_rb_tree_update_children(struct ocf_rb_node *node) if (parent->left == old_node)
{ parent->left = new_node;
if (node->left) else if (parent->right == old_node)
node->left->parent = node; parent->right = new_node;
if (node->right)
node->right->parent = node;
} }
static void ocf_rb_tree_rotate_left(struct ocf_rb_tree *tree, static void ocf_rb_tree_rotate_left(struct ocf_rb_tree *tree,
@ -44,7 +39,7 @@ static void ocf_rb_tree_rotate_left(struct ocf_rb_tree *tree,
right->parent = node->parent; right->parent = node->parent;
ocf_rb_tree_update_parent(tree, node, node, right); ocf_rb_tree_update_parent(tree, node->parent, node, right);
right->left = node; right->left = node;
node->parent = right; node->parent = right;
@ -62,7 +57,7 @@ static void ocf_rb_tree_rotate_right(struct ocf_rb_tree *tree,
left->parent = node->parent; left->parent = node->parent;
ocf_rb_tree_update_parent(tree, node, node, left); ocf_rb_tree_update_parent(tree, node->parent, node, left);
left->right = node; left->right = node;
node->parent = left; node->parent = left;
@ -165,34 +160,51 @@ void ocf_rb_tree_insert(struct ocf_rb_tree *tree, struct ocf_rb_node *node)
ocf_rb_tree_fix_violation(tree, node); ocf_rb_tree_fix_violation(tree, node);
} }
static void ocf_rb_copy_node(struct ocf_rb_node *dst, struct ocf_rb_node *src)
{
dst->red = src->red;
dst->left = src->left;
dst->right = src->right;
dst->parent = src->parent;
}
static void ocf_rb_tree_update_children(struct ocf_rb_node *node)
{
if (node->left)
node->left->parent = node;
if (node->right)
node->right->parent = node;
}
static void ocf_rb_tree_swap(struct ocf_rb_tree *tree, static void ocf_rb_tree_swap(struct ocf_rb_tree *tree,
struct ocf_rb_node *node1, struct ocf_rb_node *node2) struct ocf_rb_node *node1, struct ocf_rb_node *node2)
{ {
struct ocf_rb_node tmp; struct ocf_rb_node tmp;
if (node1->left == node2) ocf_rb_copy_node(&tmp, node1);
node1->left = node1; ocf_rb_copy_node(node1, node2);
else if (node1->right == node2) ocf_rb_copy_node(node2, &tmp);
node1->right = node1;
else if (node1->parent == node2)
node1->parent = node1;
if (node2->left == node1) if (node1->parent == node1)
node2->left = node2; node1->parent = node2;
else if (node2->right == node1) else if (node1->left == node1)
node2->right = node2; node1->left = node2;
else if (node2->parent == node1) else if (node1->right == node1)
node2->parent = node2; node1->right = node2;
tmp = *node1; if (node2->parent == node2)
*node1 = *node2; node2->parent = node1;
*node2 = tmp; else if (node2->left == node2)
node2->left = node1;
ocf_rb_tree_update_parent(tree, node1, node2, node1); else if (node2->right == node2)
ocf_rb_tree_update_parent(tree, node2, node1, node2); node2->right = node1;
ocf_rb_tree_update_children(node1); ocf_rb_tree_update_children(node1);
ocf_rb_tree_update_children(node2); ocf_rb_tree_update_children(node2);
ocf_rb_tree_update_parent(tree, node2->parent, node1, node2);
ocf_rb_tree_update_parent(tree, node1->parent, node2, node1);
} }
static struct ocf_rb_node *ocf_rb_tree_successor(struct ocf_rb_node *node) static struct ocf_rb_node *ocf_rb_tree_successor(struct ocf_rb_node *node)
@ -334,7 +346,8 @@ void ocf_rb_tree_remove(struct ocf_rb_tree *tree, struct ocf_rb_node *node)
else if (sibling) else if (sibling)
sibling->red = true; sibling->red = true;
ocf_rb_tree_update_parent(tree, node, node, NULL); ocf_rb_tree_update_parent(tree, node->parent,
node, NULL);
} }
break; break;
} }
@ -346,7 +359,8 @@ void ocf_rb_tree_remove(struct ocf_rb_tree *tree, struct ocf_rb_node *node)
if (!node->red) if (!node->red)
ocf_rb_tree_fix_double_black(tree, node); ocf_rb_tree_fix_double_black(tree, node);
ocf_rb_tree_update_parent(tree, node, node, NULL); ocf_rb_tree_update_parent(tree, node->parent,
node, NULL);
break; break;
} }