ref: 753d3b470be3150f50d99fea84280424ae5c3eb2
parent: ce0087be0d06ad6efc332ba0c8146aa29d439b2d
author: ngkaho1234 <[email protected]>
date: Sun Oct 4 17:39:03 EDT 2015
1. Use rbtree implementation from Freebsd kernel instead of the one from Linux Kernel.2. FIX: ext4_xattr_item_alloc_data: data_size == 1 when copying the on-disk data to memory.
--- a/lwext4/ext4_rbtree.c
+++ /dev/null
@@ -1,462 +1,0 @@
-/*
- Red Black Trees
- (C) 1999 Andrea Arcangeli <[email protected]>
- (C) 2002 David Woodhouse <[email protected]>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- linux/lib/rbtree.c
-*/
-#include "ext4_rbtree.h"
-
-static void __ext4_rb_rotate_left(struct ext4_rb_node *node, struct ext4_rb_root *root)
-{
- struct ext4_rb_node *right = node->ext4_rb_right;
- struct ext4_rb_node *parent = ext4_rb_parent(node);
-
- if ((node->ext4_rb_right = right->ext4_rb_left))
- ext4_rb_set_parent(right->ext4_rb_left, node);
- right->ext4_rb_left = node;
-
- ext4_rb_set_parent(right, parent);
-
- if (parent) {
- if (node == parent->ext4_rb_left)
- parent->ext4_rb_left = right;
- else
- parent->ext4_rb_right = right;
- } else
- root->ext4_rb_node = right;
- ext4_rb_set_parent(node, right);
-}
-
-static void __ext4_rb_rotate_right(struct ext4_rb_node *node, struct ext4_rb_root *root)
-{
- struct ext4_rb_node *left = node->ext4_rb_left;
- struct ext4_rb_node *parent = ext4_rb_parent(node);
-
- if ((node->ext4_rb_left = left->ext4_rb_right))
- ext4_rb_set_parent(left->ext4_rb_right, node);
- left->ext4_rb_right = node;
-
- ext4_rb_set_parent(left, parent);
-
- if (parent) {
- if (node == parent->ext4_rb_right)
- parent->ext4_rb_right = left;
- else
- parent->ext4_rb_left = left;
- } else
- root->ext4_rb_node = left;
- ext4_rb_set_parent(node, left);
-}
-
-void ext4_rb_insert_color(struct ext4_rb_node *node, struct ext4_rb_root *root)
-{
- struct ext4_rb_node *parent, *gparent;
-
- while ((parent = ext4_rb_parent(node)) && ext4_rb_is_red(parent)) {
- gparent = ext4_rb_parent(parent);
-
- if (parent == gparent->ext4_rb_left) {
- {
- register struct ext4_rb_node *uncle =
- gparent->ext4_rb_right;
- if (uncle && ext4_rb_is_red(uncle)) {
- ext4_rb_set_black(uncle);
- ext4_rb_set_black(parent);
- ext4_rb_set_red(gparent);
- node = gparent;
- continue;
- }
- }
-
- if (parent->ext4_rb_right == node) {
- register struct ext4_rb_node *tmp;
- __ext4_rb_rotate_left(parent, root);
- tmp = parent;
- parent = node;
- node = tmp;
- }
-
- ext4_rb_set_black(parent);
- ext4_rb_set_red(gparent);
- __ext4_rb_rotate_right(gparent, root);
- } else {
- {
- register struct ext4_rb_node *uncle =
- gparent->ext4_rb_left;
- if (uncle && ext4_rb_is_red(uncle)) {
- ext4_rb_set_black(uncle);
- ext4_rb_set_black(parent);
- ext4_rb_set_red(gparent);
- node = gparent;
- continue;
- }
- }
-
- if (parent->ext4_rb_left == node) {
- register struct ext4_rb_node *tmp;
- __ext4_rb_rotate_right(parent, root);
- tmp = parent;
- parent = node;
- node = tmp;
- }
-
- ext4_rb_set_black(parent);
- ext4_rb_set_red(gparent);
- __ext4_rb_rotate_left(gparent, root);
- }
- }
-
- ext4_rb_set_black(root->ext4_rb_node);
-}
-
-static void __ext4_rb_erase_color(struct ext4_rb_node *node, struct ext4_rb_node *parent,
- struct ext4_rb_root *root)
-{
- struct ext4_rb_node *other;
-
- while ((!node || ext4_rb_is_black(node)) && node != root->ext4_rb_node) {
- if (parent->ext4_rb_left == node) {
- other = parent->ext4_rb_right;
- if (ext4_rb_is_red(other)) {
- ext4_rb_set_black(other);
- ext4_rb_set_red(parent);
- __ext4_rb_rotate_left(parent, root);
- other = parent->ext4_rb_right;
- }
- if ((!other->ext4_rb_left ||
- ext4_rb_is_black(other->ext4_rb_left)) &&
- (!other->ext4_rb_right ||
- ext4_rb_is_black(other->ext4_rb_right))) {
- ext4_rb_set_red(other);
- node = parent;
- parent = ext4_rb_parent(node);
- } else {
- if (!other->ext4_rb_right ||
- ext4_rb_is_black(other->ext4_rb_right)) {
- ext4_rb_set_black(other->ext4_rb_left);
- ext4_rb_set_red(other);
- __ext4_rb_rotate_right(other, root);
- other = parent->ext4_rb_right;
- }
- ext4_rb_set_color(other, ext4_rb_color(parent));
- ext4_rb_set_black(parent);
- ext4_rb_set_black(other->ext4_rb_right);
- __ext4_rb_rotate_left(parent, root);
- node = root->ext4_rb_node;
- break;
- }
- } else {
- other = parent->ext4_rb_left;
- if (ext4_rb_is_red(other)) {
- ext4_rb_set_black(other);
- ext4_rb_set_red(parent);
- __ext4_rb_rotate_right(parent, root);
- other = parent->ext4_rb_left;
- }
- if ((!other->ext4_rb_left ||
- ext4_rb_is_black(other->ext4_rb_left)) &&
- (!other->ext4_rb_right ||
- ext4_rb_is_black(other->ext4_rb_right))) {
- ext4_rb_set_red(other);
- node = parent;
- parent = ext4_rb_parent(node);
- } else {
- if (!other->ext4_rb_left ||
- ext4_rb_is_black(other->ext4_rb_left)) {
- ext4_rb_set_black(other->ext4_rb_right);
- ext4_rb_set_red(other);
- __ext4_rb_rotate_left(other, root);
- other = parent->ext4_rb_left;
- }
- ext4_rb_set_color(other, ext4_rb_color(parent));
- ext4_rb_set_black(parent);
- ext4_rb_set_black(other->ext4_rb_left);
- __ext4_rb_rotate_right(parent, root);
- node = root->ext4_rb_node;
- break;
- }
- }
- }
- if (node)
- ext4_rb_set_black(node);
-}
-
-void __ext4_rb_erase(struct ext4_rb_node *node, struct ext4_rb_root *root)
-{
- struct ext4_rb_node *child, *parent;
- int color;
-
- if (!node->ext4_rb_left)
- child = node->ext4_rb_right;
- else if (!node->ext4_rb_right)
- child = node->ext4_rb_left;
- else {
- struct ext4_rb_node *old = node, *left;
-
- node = node->ext4_rb_right;
- while ((left = node->ext4_rb_left) != NULL)
- node = left;
-
- if (ext4_rb_parent(old)) {
- if (ext4_rb_parent(old)->ext4_rb_left == old)
- ext4_rb_parent(old)->ext4_rb_left = node;
- else
- ext4_rb_parent(old)->ext4_rb_right = node;
- } else
- root->ext4_rb_node = node;
-
- child = node->ext4_rb_right;
- parent = ext4_rb_parent(node);
- color = ext4_rb_color(node);
-
- if (parent == old) {
- parent = node;
- } else {
- if (child)
- ext4_rb_set_parent(child, parent);
- parent->ext4_rb_left = child;
-
- node->ext4_rb_right = old->ext4_rb_right;
- ext4_rb_set_parent(old->ext4_rb_right, node);
- }
-
- node->ext4_rb_parent_color = old->ext4_rb_parent_color;
- node->ext4_rb_left = old->ext4_rb_left;
- ext4_rb_set_parent(old->ext4_rb_left, node);
-
- goto color;
- }
-
- parent = ext4_rb_parent(node);
- color = ext4_rb_color(node);
-
- if (child)
- ext4_rb_set_parent(child, parent);
- if (parent) {
- if (parent->ext4_rb_left == node)
- parent->ext4_rb_left = child;
- else
- parent->ext4_rb_right = child;
- } else
- root->ext4_rb_node = child;
-
-color:
- if (color == EXT4_RB_BLACK)
- __ext4_rb_erase_color(child, parent, root);
-}
-
-static void ext4_rb_augment_path(struct ext4_rb_node *node, ext4_rb_augment_f func,
- void *data)
-{
- struct ext4_rb_node *parent;
-
-up:
- func(node, data);
- parent = ext4_rb_parent(node);
- if (!parent)
- return;
-
- if (node == parent->ext4_rb_left && parent->ext4_rb_right)
- func(parent->ext4_rb_right, data);
- else if (parent->ext4_rb_left)
- func(parent->ext4_rb_left, data);
-
- node = parent;
- goto up;
-}
-
-/*
- * after inserting @node into the tree, update the tree to account for
- * both the new entry and any damage done by rebalance
- */
-void ext4_rb_augment_insert(struct ext4_rb_node *node, ext4_rb_augment_f func,
- void *data)
-{
- if (node->ext4_rb_left)
- node = node->ext4_rb_left;
- else if (node->ext4_rb_right)
- node = node->ext4_rb_right;
-
- ext4_rb_augment_path(node, func, data);
-}
-
-/*
- * before removing the node, find the deepest node on the rebalance path
- * that will still be there after @node gets removed
- */
-struct ext4_rb_node *ext4_rb_augment_erase_begin(struct ext4_rb_node *node)
-{
- struct ext4_rb_node *deepest;
-
- if (!node->ext4_rb_right && !node->ext4_rb_left)
- deepest = ext4_rb_parent(node);
- else if (!node->ext4_rb_right)
- deepest = node->ext4_rb_left;
- else if (!node->ext4_rb_left)
- deepest = node->ext4_rb_right;
- else {
- deepest = ext4_rb_next(node);
- if (deepest->ext4_rb_right)
- deepest = deepest->ext4_rb_right;
- else if (ext4_rb_parent(deepest) != node)
- deepest = ext4_rb_parent(deepest);
- }
-
- return deepest;
-}
-
-/*
- * after removal, update the tree to account for the removed entry
- * and any rebalance damage.
- */
-void ext4_rb_augment_erase_end(struct ext4_rb_node *node, ext4_rb_augment_f func,
- void *data)
-{
- if (node)
- ext4_rb_augment_path(node, func, data);
-}
-
-/*
- * This function returns the first node (in sort order) of the tree.
- */
-struct ext4_rb_node *ext4_rb_first(const struct ext4_rb_root *root)
-{
- struct ext4_rb_node *n;
-
- n = root->ext4_rb_node;
- if (!n)
- return NULL;
- while (n->ext4_rb_left)
- n = n->ext4_rb_left;
- return n;
-}
-
-struct ext4_rb_node *ext4_rb_last(const struct ext4_rb_root *root)
-{
- struct ext4_rb_node *n;
-
- n = root->ext4_rb_node;
- if (!n)
- return NULL;
- while (n->ext4_rb_right)
- n = n->ext4_rb_right;
- return n;
-}
-
-struct ext4_rb_node *ext4_rb_next(const struct ext4_rb_node *node)
-{
- struct ext4_rb_node *parent;
-
- if (ext4_rb_parent(node) == node)
- return NULL;
-
- /* If we have a right-hand child, go down and then left as far
- as we can. */
- if (node->ext4_rb_right) {
- node = node->ext4_rb_right;
- while (node->ext4_rb_left)
- node = node->ext4_rb_left;
- return (struct ext4_rb_node *)node;
- }
-
- /* No right-hand children. Everything down and left is
- smaller than us, so any 'next' node must be in the general
- direction of our parent. Go up the tree; any time the
- ancestor is a right-hand child of its parent, keep going
- up. First time it's a left-hand child of its parent, said
- parent is our 'next' node. */
- while ((parent = ext4_rb_parent(node)) && node == parent->ext4_rb_right)
- node = parent;
-
- return parent;
-}
-
-struct ext4_rb_node *ext4_rb_prev(const struct ext4_rb_node *node)
-{
- struct ext4_rb_node *parent;
-
- if (ext4_rb_parent(node) == node)
- return NULL;
-
- /* If we have a left-hand child, go down and then right as far
- as we can. */
- if (node->ext4_rb_left) {
- node = node->ext4_rb_left;
- while (node->ext4_rb_right)
- node = node->ext4_rb_right;
- return (struct ext4_rb_node *)node;
- }
-
- /* No left-hand children. Go up till we find an ancestor which
- is a right-hand child of its parent */
- while ((parent = ext4_rb_parent(node)) && node == parent->ext4_rb_left)
- node = parent;
-
- return parent;
-}
-
-void ext4_rb_replace_node(struct ext4_rb_node *victim, struct ext4_rb_node *new,
- struct ext4_rb_root *root)
-{
- struct ext4_rb_node *parent = ext4_rb_parent(victim);
-
- /* Set the surrounding nodes to point to the replacement */
- if (parent) {
- if (victim == parent->ext4_rb_left)
- parent->ext4_rb_left = new;
- else
- parent->ext4_rb_right = new;
- } else {
- root->ext4_rb_node = new;
- }
- if (victim->ext4_rb_left)
- ext4_rb_set_parent(victim->ext4_rb_left, new);
- if (victim->ext4_rb_right)
- ext4_rb_set_parent(victim->ext4_rb_right, new);
-
- /* Copy the pointers/colour from the victim to the replacement */
- *new = *victim;
-}
-
-void ext4_rb_erase(struct ext4_rb_node *node, struct ext4_rb_root *root)
-{
- __ext4_rb_erase(node, root);
-}
-
-void ext4_rb_insert(struct ext4_rb_root *root, struct ext4_rb_node *node,
- int (*cmp)(struct ext4_rb_node *, struct ext4_rb_node *))
-{
- struct ext4_rb_node **new = &(root->ext4_rb_node), *parent = NULL;
-
- /* Figure out where to put new node */
- while (*new) {
- int result = cmp(node, *new);
-
- parent = *new;
- if (result < 0) {
- new = &((*new)->ext4_rb_left);
- } else if (result > 0) {
- new = &((*new)->ext4_rb_right);
- } else
- return;
- }
-
- /* Add new node and rebalance tree. */
- ext4_rb_link_node(node, parent, new);
- ext4_rb_insert_color(node, root);
-}
--- a/lwext4/ext4_rbtree.h
+++ /dev/null
@@ -1,201 +1,0 @@
-/*
- Red Black Trees
- (C) 1999 Andrea Arcangeli <[email protected]>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- linux/include/linux/rbtree.h
-
- To use rbtrees you'll have to implement your own insert and search cores.
- This will avoid us to use callbacks and to drop drammatically performances.
- I know it's not the cleaner way, but in C (not in C++) to get
- performances and genericity...
-
- Some example of insert and search follows here. The search is a plain
- normal search over an ordered tree. The insert instead must be implemented
- in two steps: First, the code must insert the element in order as a red leaf
- in the tree, and then the support library function ext4_rb_insert_color() must
- be called. Such function will do the not trivial work to rebalance the
- rbtree, if necessary.
-
------------------------------------------------------------------------
-static inline struct page * ext4_rb_search_page_cache(struct inode * inode,
- unsigned long offset)
-{
- struct ext4_rb_node * n = inode->i_ext4_rb_page_cache.ext4_rb_node;
- struct page * page;
-
- while (n)
- {
- page = ext4_rb_entry(n, struct page, ext4_rb_page_cache);
-
- if (offset < page->offset)
- n = n->ext4_rb_left;
- else if (offset > page->offset)
- n = n->ext4_rb_right;
- else
- return page;
- }
- return NULL;
-}
-
-static inline struct page * __ext4_rb_insert_page_cache(struct inode * inode,
- unsigned long offset,
- struct ext4_rb_node * node)
-{
- struct ext4_rb_node ** p = &inode->i_ext4_rb_page_cache.ext4_rb_node;
- struct ext4_rb_node * parent = NULL;
- struct page * page;
-
- while (*p)
- {
- parent = *p;
- page = ext4_rb_entry(parent, struct page, ext4_rb_page_cache);
-
- if (offset < page->offset)
- p = &(*p)->ext4_rb_left;
- else if (offset > page->offset)
- p = &(*p)->ext4_rb_right;
- else
- return page;
- }
-
- ext4_rb_link_node(node, parent, p);
-
- return NULL;
-}
-
-static inline struct page * ext4_rb_insert_page_cache(struct inode * inode,
- unsigned long offset,
- struct ext4_rb_node * node)
-{
- struct page * ret;
- if ((ret = __ext4_rb_insert_page_cache(inode, offset, node)))
- goto out;
- ext4_rb_insert_color(node, &inode->i_ext4_rb_page_cache);
- out:
- return ret;
-}
------------------------------------------------------------------------
-*/
-
-#ifndef EXT4_RBTREE_H_
-#define EXT4_RBTREE_H_
-
-#include <stddef.h>
-#include <stdbool.h>
-
-#ifndef offsetof
-#define offsetof(type, member) ((size_t) & ((type *)0)->member)
-#endif
-#ifndef container_of
-#define container_of(ptr, type, member) \
- ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
-#endif
-
-struct ext4_rb_node
-{
- unsigned long ext4_rb_parent_color;
-#define EXT4_RB_RED 0
-#define EXT4_RB_BLACK 1
- struct ext4_rb_node *ext4_rb_right;
- struct ext4_rb_node *ext4_rb_left;
-};
-/* The alignment might seem pointless, but allegedly CRIS needs it */
-
-struct ext4_rb_root
-{
- struct ext4_rb_node *ext4_rb_node;
-};
-
-#define ext4_rb_parent(r) ((struct ext4_rb_node *)((r)->ext4_rb_parent_color & ~3))
-#define ext4_rb_color(r) ((r)->ext4_rb_parent_color & 1)
-#define ext4_rb_is_red(r) (!ext4_rb_color(r))
-#define ext4_rb_is_black(r) ext4_rb_color(r)
-#define ext4_rb_set_red(r) \
- do { \
- (r)->ext4_rb_parent_color &= ~1; \
- } while (0)
-#define ext4_rb_set_black(r) \
- do { \
- (r)->ext4_rb_parent_color |= 1; \
- } while (0)
-
-static inline void ext4_rb_set_parent(struct ext4_rb_node *rb, struct ext4_rb_node *p)
-{
- rb->ext4_rb_parent_color =
- (rb->ext4_rb_parent_color & 3) | (unsigned long)p;
-}
-static inline void ext4_rb_set_color(struct ext4_rb_node *rb, int color)
-{
- rb->ext4_rb_parent_color = (rb->ext4_rb_parent_color & ~1) | color;
-}
-
-#define EXT4_RB_ROOT \
- (struct ext4_rb_root) \
- { \
- NULL, \
- }
-#define ext4_rb_entry(ptr, type, member) container_of(ptr, type, member)
-
-#define EXT4_RB_EMPTY_ROOT(root) ((root)->ext4_rb_node == NULL)
-#define EXT4_RB_EMPTY_NODE(node) (ext4_rb_parent(node) == node)
-#define EXT4_RB_CLEAR_NODE(node) (ext4_rb_set_parent(node, node))
-
-static inline void ext4_rb_init_node(struct ext4_rb_node *rb)
-{
- rb->ext4_rb_parent_color = 0;
- rb->ext4_rb_right = NULL;
- rb->ext4_rb_left = NULL;
- EXT4_RB_CLEAR_NODE(rb);
-}
-
-extern void ext4_rb_insert_color(struct ext4_rb_node *, struct ext4_rb_root *);
-extern void ext4_rb_erase(struct ext4_rb_node *, struct ext4_rb_root *);
-
-typedef void (*ext4_rb_augment_f)(struct ext4_rb_node *node, void *data);
-
-extern void ext4_rb_augment_insert(struct ext4_rb_node *node, ext4_rb_augment_f func,
- void *data);
-extern struct ext4_rb_node *ext4_rb_augment_erase_begin(struct ext4_rb_node *node);
-extern void ext4_rb_augment_erase_end(struct ext4_rb_node *node, ext4_rb_augment_f func,
- void *data);
-
-/* Find logical next and previous nodes in a tree */
-extern struct ext4_rb_node *ext4_rb_next(const struct ext4_rb_node *);
-extern struct ext4_rb_node *ext4_rb_prev(const struct ext4_rb_node *);
-extern struct ext4_rb_node *ext4_rb_first(const struct ext4_rb_root *);
-extern struct ext4_rb_node *ext4_rb_last(const struct ext4_rb_root *);
-
-/* Fast replacement of a single node without remove/rebalance/add/rebalance */
-extern void ext4_rb_replace_node(struct ext4_rb_node *victim, struct ext4_rb_node *new,
- struct ext4_rb_root *root);
-
-static inline void ext4_rb_link_node(struct ext4_rb_node *node,
- struct ext4_rb_node *parent,
- struct ext4_rb_node **ext4_rb_link)
-{
- node->ext4_rb_parent_color = (unsigned long)parent;
- node->ext4_rb_left = node->ext4_rb_right = NULL;
-
- *ext4_rb_link = node;
-}
-
-extern void ext4_rb_erase(struct ext4_rb_node *, struct ext4_rb_root *);
-
-extern void ext4_rb_insert(struct ext4_rb_root *, struct ext4_rb_node *,
- int (*)(struct ext4_rb_node *, struct ext4_rb_node *));
-
-#endif /* EXT4_RBTREE_H_ */
--- a/lwext4/ext4_types.h
+++ b/lwext4/ext4_types.h
@@ -45,6 +45,7 @@
#include "ext4_config.h"
#include "ext4_blockdev.h"
#include "ext4_rbtree.h"
+#include "tree.h"
#include <stdint.h>
@@ -678,7 +679,7 @@
void *data;
size_t data_size;
- struct ext4_rb_node node;
+ RB_ENTRY(ext4_xattr_item) node;
};
struct ext4_xattr_ref {
@@ -685,9 +686,12 @@
bool block_loaded;
struct ext4_block block;
struct ext4_inode_ref *inode_ref;
- struct ext4_rb_root root;
bool dirty;
+ size_t ea_size;
struct ext4_fs *fs;
+
+ RB_HEAD(ext4_xattr_tree,
+ ext4_xattr_item) root;
};
#define EXT4_GOOD_OLD_INODE_SIZE 128
--- a/lwext4/ext4_xattr.c
+++ b/lwext4/ext4_xattr.c
@@ -13,13 +13,10 @@
#include <string.h>
#include <stdlib.h>
-static int ext4_xattr_item_cmp(struct ext4_rb_node *a_,
- struct ext4_rb_node *b_)
+static int ext4_xattr_item_cmp(struct ext4_xattr_item *a,
+ struct ext4_xattr_item *b)
{
- struct ext4_xattr_item *a, *b;
int result;
- a = container_of(a_, struct ext4_xattr_item, node);
- b = container_of(b_, struct ext4_xattr_item, node);
result = a->name_index - b->name_index;
if (result)
return result;
@@ -31,54 +28,11 @@
return memcmp(a->name, b->name, a->name_len);
}
-static struct ext4_xattr_item *
-ext4_xattr_item_lookup(struct ext4_rb_root *root,
- uint8_t name_index,
- char *name,
- size_t name_len)
-{
- struct ext4_rb_node *new = root->ext4_rb_node;
+RB_GENERATE (ext4_xattr_tree,
+ ext4_xattr_item,
+ node,
+ ext4_xattr_item_cmp)
- /* Figure out where to put new node */
- while (new) {
- struct ext4_xattr_item *item =
- container_of(new, struct ext4_xattr_item, node);
- int result = name_index - item->name_index;
- if (!result) {
- result = name_len - item->name_len;
- if (!result)
- result = memcmp(name,
- item->name, name_len);
-
- }
-
- if (result < 0)
- new = new->ext4_rb_left;
- else if (result > 0)
- new = new->ext4_rb_right;
- else
- return item;
-
- }
-
- return NULL;
-}
-
-static void
-ext4_xattr_item_insert(struct ext4_rb_root *root,
- struct ext4_xattr_item *item)
-{
- ext4_rb_insert(root, &item->node, ext4_xattr_item_cmp);
-}
-
-static void
-ext4_xattr_item_remove(struct ext4_rb_root *root,
- struct ext4_xattr_item *item)
-{
- ext4_rb_erase(&item->node, root);
-}
-
-
static struct ext4_xattr_item *
ext4_xattr_item_alloc(uint8_t name_index,
char *name,
@@ -221,14 +175,13 @@
}
if (ext4_xattr_item_alloc_data(item,
data,
- to_le32(entry->e_value_size)
- != EOK)) {
+ to_le32(entry->e_value_size))
+ != EOK) {
ext4_xattr_item_free(item);
ret = ENOMEM;
goto Finish;
}
- ext4_xattr_item_insert(&xattr_ref->root,
- item);
+ RB_INSERT(ext4_xattr_tree, &xattr_ref->root, item);
}
@@ -274,16 +227,13 @@
}
if (ext4_xattr_item_alloc_data(item,
data,
- to_le32(entry->e_value_size)
- != EOK)) {
+ to_le32(entry->e_value_size))
+ != EOK) {
ext4_xattr_item_free(item);
ret = ENOMEM;
goto Finish;
}
- ext4_xattr_item_insert(&xattr_ref->root,
- item);
-
-
+ RB_INSERT(ext4_xattr_tree, &xattr_ref->root, item);
}
Finish:
@@ -312,13 +262,15 @@
static void
ext4_xattr_purge_items(struct ext4_xattr_ref *xattr_ref)
{
- struct ext4_rb_node *node;
- while ((node = ext4_rb_first(&xattr_ref->root))) {
- struct ext4_xattr_item *item = ext4_rb_entry(
- node, struct ext4_xattr_item, node);
- ext4_xattr_item_remove(&xattr_ref->root, item);
+ struct ext4_xattr_item *item, *save_item;
+ RB_FOREACH_SAFE(item,
+ ext4_xattr_tree,
+ &xattr_ref->root,
+ save_item) {
+ RB_REMOVE(ext4_xattr_tree, &xattr_ref->root, item);
ext4_xattr_item_free(item);
}
+ xattr_ref->ea_size = 0;
}
int ext4_fs_get_xattr_ref(struct ext4_fs *fs,
@@ -329,7 +281,7 @@
uint64_t xattr_block;
xattr_block = ext4_inode_get_file_acl(inode_ref->inode,
&fs->sb);
- memset(&ref->root, 0, sizeof(ref->root));
+ RB_INIT(&ref->root);
if (xattr_block) {
rc = ext4_block_get(fs->bdev,
&inode_ref->block, xattr_block);
--- /dev/null
+++ b/lwext4/tree.h
@@ -1,0 +1,801 @@
+/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
+/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * Copyright 2002 Niels Provos <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SYS_TREE_H_
+#define _SYS_TREE_H_
+
+#include <sys/cdefs.h>
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+ RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \
+ RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \
+ RB_PROTOTYPE_INSERT(name, type, attr); \
+ RB_PROTOTYPE_REMOVE(name, type, attr); \
+ RB_PROTOTYPE_FIND(name, type, attr); \
+ RB_PROTOTYPE_NFIND(name, type, attr); \
+ RB_PROTOTYPE_NEXT(name, type, attr); \
+ RB_PROTOTYPE_PREV(name, type, attr); \
+ RB_PROTOTYPE_MINMAX(name, type, attr);
+#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \
+ attr void name##_RB_INSERT_COLOR(struct name *, struct type *)
+#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \
+ attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *)
+#define RB_PROTOTYPE_REMOVE(name, type, attr) \
+ attr struct type *name##_RB_REMOVE(struct name *, struct type *)
+#define RB_PROTOTYPE_INSERT(name, type, attr) \
+ attr struct type *name##_RB_INSERT(struct name *, struct type *)
+#define RB_PROTOTYPE_FIND(name, type, attr) \
+ attr struct type *name##_RB_FIND(struct name *, struct type *)
+#define RB_PROTOTYPE_NFIND(name, type, attr) \
+ attr struct type *name##_RB_NFIND(struct name *, struct type *)
+#define RB_PROTOTYPE_NEXT(name, type, attr) \
+ attr struct type *name##_RB_NEXT(struct type *)
+#define RB_PROTOTYPE_PREV(name, type, attr) \
+ attr struct type *name##_RB_PREV(struct type *)
+#define RB_PROTOTYPE_MINMAX(name, type, attr) \
+ attr struct type *name##_RB_MINMAX(struct name *, int)
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+ RB_GENERATE_INSERT_COLOR(name, type, field, attr) \
+ RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \
+ RB_GENERATE_INSERT(name, type, field, cmp, attr) \
+ RB_GENERATE_REMOVE(name, type, field, attr) \
+ RB_GENERATE_FIND(name, type, field, cmp, attr) \
+ RB_GENERATE_NFIND(name, type, field, cmp, attr) \
+ RB_GENERATE_NEXT(name, type, field, attr) \
+ RB_GENERATE_PREV(name, type, field, attr) \
+ RB_GENERATE_MINMAX(name, type, field, attr)
+
+#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \
+attr void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) != NULL && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+}
+
+#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \
+attr void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oleft, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oright, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+}
+
+#define RB_GENERATE_REMOVE(name, type, field, attr) \
+attr struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field)) != NULL) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old)\
+ RB_LEFT(RB_PARENT(old, field), field) = elm;\
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm;\
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field)) != NULL); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+
+#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+}
+
+#define RB_GENERATE_FIND(name, type, field, cmp, attr) \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+}
+
+#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+}
+
+#define RB_GENERATE_NEXT(name, type, field, attr) \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+}
+
+#define RB_GENERATE_PREV(name, type, field, attr) \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_PREV(struct type *elm) \
+{ \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+}
+
+#define RB_GENERATE_MINMAX(name, type, field, attr) \
+attr struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_FROM(x, name, y) \
+ for ((x) = (y); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_SAFE(x, name, head, y) \
+ for ((x) = RB_MIN(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_FROM(x, name, y) \
+ for ((x) = (y); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
+ for ((x) = RB_MAX(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#endif /* _SYS_TREE_H_ */