[Ocfs2-tools-commits] zab commits r253 - in trunk/libocfs2: . include

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Fri Sep 24 17:16:44 CDT 2004


Author: zab
Date: 2004-09-24 17:16:42 -0500 (Fri, 24 Sep 2004)
New Revision: 253

Added:
   trunk/libocfs2/include/kernel-rbtree.h
   trunk/libocfs2/kernel-rbtree.c
Modified:
   trunk/libocfs2/Makefile
   trunk/libocfs2/bitmap.c
   trunk/libocfs2/include/bitmap.h
Log:
o Import rbtrees from the kernel into libocfs
o use rbtrees to back the holy bitmaps (easy, no overlapping)

fsck will be using the trees in a few places as it builds up its
book-keeping of the file system.


Modified: trunk/libocfs2/Makefile
===================================================================
--- trunk/libocfs2/Makefile	2004-09-24 18:52:07 UTC (rev 252)
+++ trunk/libocfs2/Makefile	2004-09-24 22:16:42 UTC (rev 253)
@@ -66,7 +66,8 @@
 	unlink.c	\
 	bitmap.c	\
 	fileio.c	\
-	checkhb.c
+	checkhb.c	\
+	kernel-rbtree.c
 
 HFILES =				\
 	include/jfs_user.h		\

Modified: trunk/libocfs2/bitmap.c
===================================================================
--- trunk/libocfs2/bitmap.c	2004-09-24 18:52:07 UTC (rev 252)
+++ trunk/libocfs2/bitmap.c	2004-09-24 22:16:42 UTC (rev 253)
@@ -36,13 +36,14 @@
 #include "ocfs2.h"
 
 #include "bitmap.h"
+#include "kernel-rbtree.h"
 
 
 /* The public API */
 
 void ocfs2_bitmap_free(ocfs2_bitmap *bitmap)
 {
-	struct list_head *pos, *next;
+	struct rb_node *node;
 	struct ocfs2_bitmap_cluster *bc;
 
 	if (bitmap->b_ops->destroy_notify)
@@ -52,12 +53,10 @@
 	 * If the bitmap needs to do extra cleanup of clusters,
 	 * it should have done it in destroy_notify
 	 */
-	for (pos = bitmap->b_clusters.next, next = pos->next;
-	     pos != &bitmap->b_clusters;
-	     pos = next, next = pos->next) {
-		bc = list_entry(pos, struct ocfs2_bitmap_cluster,
-				bc_list);
-		list_del(pos);
+	while ((node = rb_first(&bitmap->b_clusters)) != NULL) {
+		bc = rb_entry(node, struct ocfs2_bitmap_cluster, bc_node);
+
+		rb_erase(&bc->bc_node, &bitmap->b_clusters);
 		ocfs2_bitmap_free_cluster(bc);
 	}
 
@@ -150,7 +149,7 @@
 	bitmap->b_fs = fs;
 	bitmap->b_total_bits = total_bits;
 	bitmap->b_ops = ops;
-	INIT_LIST_HEAD(&bitmap->b_clusters);
+	bitmap->b_clusters = RB_ROOT;
 	bitmap->b_private = private_data;
 	if (description) {
 		ret = ocfs2_malloc0(sizeof(char) *
@@ -291,51 +290,81 @@
 	memcpy(prev->bc_bitmap + (prev_bits / 8), next->bc_bitmap,
 	       next->bc_total_bits / 8);
 
-	list_del(&next->bc_list);
+	rb_erase(&next->bc_node, &bitmap->b_clusters);
 	ocfs2_bitmap_free_cluster(next);
 
 	return 0;
 }
 
+/* Find a bitmap cluster in the tree that intersects the bit region
+ * that is passed in.  The rb_node garbage lets insertion share this
+ * searching code, most trivial callers will pass in NULLs. */
+static
+struct ocfs2_bitmap_cluster *ocfs2_bitmap_lookup(ocfs2_bitmap *bitmap, 
+						 uint64_t bitno, 
+						 uint64_t total_bits, 
+						 struct rb_node ***ret_p,
+						 struct rb_node **ret_parent)
+{
+	struct rb_node **p = &bitmap->b_clusters.rb_node;
+	struct rb_node *parent = NULL;
+	struct ocfs2_bitmap_cluster *bc = NULL;
+
+	while (*p)
+	{
+		parent = *p;
+		bc = rb_entry(parent, struct ocfs2_bitmap_cluster, bc_node);
+
+		if (bitno + total_bits <= bc->bc_start_bit) {
+			p = &(*p)->rb_left;
+			bc = NULL;
+		} else if (bitno >= (bc->bc_start_bit + bc->bc_total_bits)) {
+			p = &(*p)->rb_right;
+			bc = NULL;
+		} else
+			break;
+	}
+	if (ret_p != NULL)
+		*ret_p = p;
+	if (ret_parent != NULL)
+		*ret_parent = parent;
+	return bc;
+}
+
 errcode_t ocfs2_bitmap_insert_cluster(ocfs2_bitmap *bitmap,
 				      struct ocfs2_bitmap_cluster *bc)
 {
-	struct list_head *pos, *prev;
 	struct ocfs2_bitmap_cluster *bc_tmp;
+	struct rb_node **p, *parent, *node;
 
 	if (bc->bc_start_bit > bitmap->b_total_bits)
 		return OCFS2_ET_INVALID_BIT;
 
-	prev = &bitmap->b_clusters;
-	list_for_each(pos, &bitmap->b_clusters) {
-		bc_tmp = list_entry(pos, struct ocfs2_bitmap_cluster,
-				    bc_list);
-		if (bc->bc_start_bit >=
-		    (bc_tmp->bc_start_bit + bc_tmp->bc_total_bits)) {
-			prev = pos;
-			continue;
-		}
-		if ((bc->bc_start_bit + bc->bc_total_bits) <=
-		    bc_tmp->bc_start_bit)
-			break;
-
+	/* we shouldn't find an existing cluster that intersects our new one */
+	bc_tmp = ocfs2_bitmap_lookup(bitmap, bc->bc_start_bit, 
+				     bc->bc_total_bits, &p, &parent);
+	if (bc_tmp)
 		return OCFS2_ET_INVALID_BIT;
-	}
 
-	list_add(&bc->bc_list, prev);
+	rb_link_node(&bc->bc_node, parent, p);
+	rb_insert_color(&bc->bc_node, &bitmap->b_clusters);
 
-	if (pos != &bitmap->b_clusters) {
-		bc_tmp = list_entry(pos, struct ocfs2_bitmap_cluster,
-				    bc_list);
-		ocfs2_bitmap_merge_cluster(bitmap, bc, bc_tmp);
-	}
+	/* try to merge our new extent with its neighbours in the tree */
 
-	if (prev != &bitmap->b_clusters) {
-		bc_tmp = list_entry(prev, struct ocfs2_bitmap_cluster,
-				    bc_list);
+	node = rb_prev(&bc->bc_node);
+	if (node) {
+		bc_tmp = list_entry(node, struct ocfs2_bitmap_cluster,
+				    bc_node);
 		ocfs2_bitmap_merge_cluster(bitmap, bc_tmp, bc);
 	}
 
+	node = rb_next(&bc->bc_node);
+	if (node != NULL) {
+		bc_tmp = list_entry(node, struct ocfs2_bitmap_cluster,
+				    bc_node);
+		ocfs2_bitmap_merge_cluster(bitmap, bc, bc_tmp);
+	}
+
 	return 0;
 }
 
@@ -347,81 +376,57 @@
 errcode_t ocfs2_bitmap_set_generic(ocfs2_bitmap *bitmap, uint64_t bitno,
 				   int *oldval)
 {
+	struct ocfs2_bitmap_cluster *bc;
 	int old_tmp;
-	struct list_head *pos;
-	struct ocfs2_bitmap_cluster *bc;
+	
+	bc = ocfs2_bitmap_lookup(bitmap, bitno, 1, NULL, NULL);
+	if (!bc)
+		return OCFS2_ET_INVALID_BIT;
 
-	list_for_each(pos, &bitmap->b_clusters) {
-		bc = list_entry(pos, struct ocfs2_bitmap_cluster,
-				bc_list);
-		if (bitno < bc->bc_start_bit)
-			break;
-		if (bitno >= (bc->bc_start_bit + bc->bc_total_bits))
-			continue;
+	old_tmp = __test_and_set_bit(bitno - bc->bc_start_bit,
+				     (unsigned long *)(bc->bc_bitmap));
+	if (oldval)
+		*oldval = old_tmp;
 
-		old_tmp = __test_and_set_bit(bitno - bc->bc_start_bit,
-					     (unsigned long *)(bc->bc_bitmap));
-		if (oldval)
-			*oldval = old_tmp;
+	if (!old_tmp)
+		bc->bc_set_bits++;
 
-		if (!old_tmp)
-			bc->bc_set_bits++;
-
-		return 0;
-	}
-
-	return OCFS2_ET_INVALID_BIT;
+	return 0;
 }
 
 errcode_t ocfs2_bitmap_clear_generic(ocfs2_bitmap *bitmap,
 				     uint64_t bitno, int *oldval)
 {
+	struct ocfs2_bitmap_cluster *bc;
 	int old_tmp;
-	struct list_head *pos;
-	struct ocfs2_bitmap_cluster *bc;
+	
+	bc = ocfs2_bitmap_lookup(bitmap, bitno, 1, NULL, NULL);
+	if (!bc)
+		return OCFS2_ET_INVALID_BIT;
 
-	list_for_each(pos, &bitmap->b_clusters) {
-		bc = list_entry(pos, struct ocfs2_bitmap_cluster,
-				bc_list);
-		if (bitno < bc->bc_start_bit)
-			break;
-		if (bitno > (bc->bc_start_bit + bc->bc_total_bits))
-			continue;
+	old_tmp = __test_and_clear_bit(bitno - bc->bc_start_bit,
+				       (unsigned long *)bc->bc_bitmap);
+	if (oldval)
+		*oldval = old_tmp;
 
-		old_tmp = __test_and_clear_bit(bitno - bc->bc_start_bit,
-					       (unsigned long *)bc->bc_bitmap);
-		if (oldval)
-			*oldval = old_tmp;
+	if (old_tmp)
+		bc->bc_set_bits--;
 
-		if (old_tmp)
-			bc->bc_set_bits--;
-
-		return 0;
-	}
-
-	return OCFS2_ET_INVALID_BIT;
+	return 0;
 }
 
 errcode_t ocfs2_bitmap_test_generic(ocfs2_bitmap *bitmap,
 				    uint64_t bitno, int *val)
 {
-	struct list_head *pos;
 	struct ocfs2_bitmap_cluster *bc;
+	
+	bc = ocfs2_bitmap_lookup(bitmap, bitno, 1, NULL, NULL);
+	if (!bc)
+		return OCFS2_ET_INVALID_BIT;
 
-	list_for_each(pos, &bitmap->b_clusters) {
-		bc = list_entry(pos, struct ocfs2_bitmap_cluster,
-				bc_list);
-		if (bitno < bc->bc_start_bit)
-			break;
-		if (bitno >= (bc->bc_start_bit + bc->bc_total_bits))
-			continue;
-
-		*val = test_bit(bitno - bc->bc_start_bit,
-				(unsigned long *)bc->bc_bitmap) ? 1 : 0;
-		return 0;
-	}
-
-	return OCFS2_ET_INVALID_BIT;
+	*val = test_bit(bitno - bc->bc_start_bit,
+			(unsigned long *)bc->bc_bitmap) ? 1 : 0;
+	return 0;
 }
 
 
@@ -589,15 +594,16 @@
 
 static void dump_clusters(ocfs2_bitmap *bitmap)
 {
-	struct list_head *pos;
 	struct ocfs2_bitmap_cluster *bc;
+	struct rb_node *node;
 
 	fprintf(stdout, "Bitmap \"%s\": total = %"PRIu64", set = %"PRIu64"\n",
 		bitmap->b_description, bitmap->b_total_bits,
 		bitmap->b_set_bits);
-	list_for_each(pos, &bitmap->b_clusters) {
-		bc = list_entry(pos, struct ocfs2_bitmap_cluster,
-				bc_list);
+
+	for (node = rb_first(&bitmap->b_clusters);node; node = rb_next(node)) {
+		bc = rb_entry(node, struct ocfs2_bitmap_cluster, bc_node);
+
 		fprintf(stdout,
 			"(start: %"PRIu64", n: %d, set: %d, cpos: %"PRIu32")\n",
 			bc->bc_start_bit, bc->bc_total_bits,

Modified: trunk/libocfs2/include/bitmap.h
===================================================================
--- trunk/libocfs2/include/bitmap.h	2004-09-24 18:52:07 UTC (rev 252)
+++ trunk/libocfs2/include/bitmap.h	2004-09-24 22:16:42 UTC (rev 253)
@@ -27,9 +27,8 @@
 #ifndef _BITMAP_H
 #define _BITMAP_H
 
-#include "kernel-list.h"
+#include "kernel-rbtree.h"
 
-
 struct ocfs2_bitmap_operations {
 	errcode_t (*set_bit)(ocfs2_bitmap *bm, uint64_t bit,
 			     int *oldval);
@@ -53,12 +52,12 @@
 						   from if it is a
 						   physical bitmap
 						   inode */
-	struct list_head b_clusters;
+	struct rb_root b_clusters;
 	void *b_private;
 };
 
 struct ocfs2_bitmap_cluster {
-	struct list_head bc_list;
+	struct rb_node bc_node;
 	uint64_t bc_start_bit;		/* Bit offset.  Must be
 					   aligned on
 					   (clustersize * 8) */

Added: trunk/libocfs2/include/kernel-rbtree.h
===================================================================
--- trunk/libocfs2/include/kernel-rbtree.h	2004-09-24 18:52:07 UTC (rev 252)
+++ trunk/libocfs2/include/kernel-rbtree.h	2004-09-24 22:16:42 UTC (rev 253)
@@ -0,0 +1,141 @@
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea at suse.de>
+  
+  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
+
+  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
+  int two steps: as first thing the code must insert the element in
+  order as a red leaf in the tree, then the support library function
+  rb_insert_color() must be called. Such function will do the
+  not trivial work to rebalance the rbtree if necessary.
+
+-----------------------------------------------------------------------
+static inline struct page * rb_search_page_cache(struct inode * inode,
+						 unsigned long offset)
+{
+	struct rb_node * n = inode->i_rb_page_cache.rb_node;
+	struct page * page;
+
+	while (n)
+	{
+		page = rb_entry(n, struct page, rb_page_cache);
+
+		if (offset < page->offset)
+			n = n->rb_left;
+		else if (offset > page->offset)
+			n = n->rb_right;
+		else
+			return page;
+	}
+	return NULL;
+}
+
+static inline struct page * __rb_insert_page_cache(struct inode * inode,
+						   unsigned long offset,
+						   struct rb_node * node)
+{
+	struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
+	struct rb_node * parent = NULL;
+	struct page * page;
+
+	while (*p)
+	{
+		parent = *p;
+		page = rb_entry(parent, struct page, rb_page_cache);
+
+		if (offset < page->offset)
+			p = &(*p)->rb_left;
+		else if (offset > page->offset)
+			p = &(*p)->rb_right;
+		else
+			return page;
+	}
+
+	rb_link_node(node, parent, p);
+
+	return NULL;
+}
+
+static inline struct page * rb_insert_page_cache(struct inode * inode,
+						 unsigned long offset,
+						 struct rb_node * node)
+{
+	struct page * ret;
+	if ((ret = __rb_insert_page_cache(inode, offset, node)))
+		goto out;
+	rb_insert_color(node, &inode->i_rb_page_cache);
+ out:
+	return ret;
+}
+-----------------------------------------------------------------------
+*/
+
+#ifndef	_LINUX_RBTREE_H
+#define	_LINUX_RBTREE_H
+
+#include <stdlib.h>
+
+struct rb_node
+{
+	struct rb_node *rb_parent;
+	int rb_color;
+#define	RB_RED		0
+#define	RB_BLACK	1
+	struct rb_node *rb_right;
+	struct rb_node *rb_left;
+};
+
+struct rb_root
+{
+	struct rb_node *rb_node;
+};
+
+#define RB_ROOT	(struct rb_root) { NULL, }
+#define	rb_entry(ptr, type, member)					\
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+extern void rb_insert_color(struct rb_node *, struct rb_root *);
+extern void rb_erase(struct rb_node *, struct rb_root *);
+
+/* Find logical next and previous nodes in a tree */
+extern struct rb_node *rb_next(struct rb_node *);
+extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
+extern struct rb_node *rb_last(struct rb_root *);
+
+/* Fast replacement of a single node without remove/rebalance/add/rebalance */
+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 
+			    struct rb_root *root);
+
+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
+				struct rb_node ** rb_link)
+{
+	node->rb_parent = parent;
+	node->rb_color = RB_RED;
+	node->rb_left = node->rb_right = NULL;
+
+	*rb_link = node;
+}
+
+#endif	/* _LINUX_RBTREE_H */

Added: trunk/libocfs2/kernel-rbtree.c
===================================================================
--- trunk/libocfs2/kernel-rbtree.c	2004-09-24 18:52:07 UTC (rev 252)
+++ trunk/libocfs2/kernel-rbtree.c	2004-09-24 22:16:42 UTC (rev 253)
@@ -0,0 +1,394 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ * 
+ * kernel-rbtree.c
+ *
+ * This is imported from the Linux kernel to give us a tested and
+ * portable tree library.
+ */
+/*
+  Red Black Trees
+  (C) 1999  Andrea Arcangeli <andrea at suse.de>
+  (C) 2002  David Woodhouse <dwmw2 at infradead.org>
+  
+  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 "kernel-rbtree.h"
+
+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *right = node->rb_right;
+
+	if ((node->rb_right = right->rb_left))
+		right->rb_left->rb_parent = node;
+	right->rb_left = node;
+
+	if ((right->rb_parent = node->rb_parent))
+	{
+		if (node == node->rb_parent->rb_left)
+			node->rb_parent->rb_left = right;
+		else
+			node->rb_parent->rb_right = right;
+	}
+	else
+		root->rb_node = right;
+	node->rb_parent = right;
+}
+
+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *left = node->rb_left;
+
+	if ((node->rb_left = left->rb_right))
+		left->rb_right->rb_parent = node;
+	left->rb_right = node;
+
+	if ((left->rb_parent = node->rb_parent))
+	{
+		if (node == node->rb_parent->rb_right)
+			node->rb_parent->rb_right = left;
+		else
+			node->rb_parent->rb_left = left;
+	}
+	else
+		root->rb_node = left;
+	node->rb_parent = left;
+}
+
+void rb_insert_color(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *parent, *gparent;
+
+	while ((parent = node->rb_parent) && parent->rb_color == RB_RED)
+	{
+		gparent = parent->rb_parent;
+
+		if (parent == gparent->rb_left)
+		{
+			{
+				register struct rb_node *uncle = gparent->rb_right;
+				if (uncle && uncle->rb_color == RB_RED)
+				{
+					uncle->rb_color = RB_BLACK;
+					parent->rb_color = RB_BLACK;
+					gparent->rb_color = RB_RED;
+					node = gparent;
+					continue;
+				}
+			}
+
+			if (parent->rb_right == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_left(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+
+			parent->rb_color = RB_BLACK;
+			gparent->rb_color = RB_RED;
+			__rb_rotate_right(gparent, root);
+		} else {
+			{
+				register struct rb_node *uncle = gparent->rb_left;
+				if (uncle && uncle->rb_color == RB_RED)
+				{
+					uncle->rb_color = RB_BLACK;
+					parent->rb_color = RB_BLACK;
+					gparent->rb_color = RB_RED;
+					node = gparent;
+					continue;
+				}
+			}
+
+			if (parent->rb_left == node)
+			{
+				register struct rb_node *tmp;
+				__rb_rotate_right(parent, root);
+				tmp = parent;
+				parent = node;
+				node = tmp;
+			}
+
+			parent->rb_color = RB_BLACK;
+			gparent->rb_color = RB_RED;
+			__rb_rotate_left(gparent, root);
+		}
+	}
+
+	root->rb_node->rb_color = RB_BLACK;
+}
+
+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
+			     struct rb_root *root)
+{
+	struct rb_node *other;
+
+	while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node)
+	{
+		if (parent->rb_left == node)
+		{
+			other = parent->rb_right;
+			if (other->rb_color == RB_RED)
+			{
+				other->rb_color = RB_BLACK;
+				parent->rb_color = RB_RED;
+				__rb_rotate_left(parent, root);
+				other = parent->rb_right;
+			}
+			if ((!other->rb_left ||
+			     other->rb_left->rb_color == RB_BLACK)
+			    && (!other->rb_right ||
+				other->rb_right->rb_color == RB_BLACK))
+			{
+				other->rb_color = RB_RED;
+				node = parent;
+				parent = node->rb_parent;
+			}
+			else
+			{
+				if (!other->rb_right ||
+				    other->rb_right->rb_color == RB_BLACK)
+				{
+					register struct rb_node *o_left;
+					if ((o_left = other->rb_left))
+						o_left->rb_color = RB_BLACK;
+					other->rb_color = RB_RED;
+					__rb_rotate_right(other, root);
+					other = parent->rb_right;
+				}
+				other->rb_color = parent->rb_color;
+				parent->rb_color = RB_BLACK;
+				if (other->rb_right)
+					other->rb_right->rb_color = RB_BLACK;
+				__rb_rotate_left(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+		else
+		{
+			other = parent->rb_left;
+			if (other->rb_color == RB_RED)
+			{
+				other->rb_color = RB_BLACK;
+				parent->rb_color = RB_RED;
+				__rb_rotate_right(parent, root);
+				other = parent->rb_left;
+			}
+			if ((!other->rb_left ||
+			     other->rb_left->rb_color == RB_BLACK)
+			    && (!other->rb_right ||
+				other->rb_right->rb_color == RB_BLACK))
+			{
+				other->rb_color = RB_RED;
+				node = parent;
+				parent = node->rb_parent;
+			}
+			else
+			{
+				if (!other->rb_left ||
+				    other->rb_left->rb_color == RB_BLACK)
+				{
+					register struct rb_node *o_right;
+					if ((o_right = other->rb_right))
+						o_right->rb_color = RB_BLACK;
+					other->rb_color = RB_RED;
+					__rb_rotate_left(other, root);
+					other = parent->rb_left;
+				}
+				other->rb_color = parent->rb_color;
+				parent->rb_color = RB_BLACK;
+				if (other->rb_left)
+					other->rb_left->rb_color = RB_BLACK;
+				__rb_rotate_right(parent, root);
+				node = root->rb_node;
+				break;
+			}
+		}
+	}
+	if (node)
+		node->rb_color = RB_BLACK;
+}
+
+void rb_erase(struct rb_node *node, struct rb_root *root)
+{
+	struct rb_node *child, *parent;
+	int color;
+
+	if (!node->rb_left)
+		child = node->rb_right;
+	else if (!node->rb_right)
+		child = node->rb_left;
+	else
+	{
+		struct rb_node *old = node, *left;
+
+		node = node->rb_right;
+		while ((left = node->rb_left) != NULL)
+			node = left;
+		child = node->rb_right;
+		parent = node->rb_parent;
+		color = node->rb_color;
+
+		if (child)
+			child->rb_parent = parent;
+		if (parent)
+		{
+			if (parent->rb_left == node)
+				parent->rb_left = child;
+			else
+				parent->rb_right = child;
+		}
+		else
+			root->rb_node = child;
+
+		if (node->rb_parent == old)
+			parent = node;
+		node->rb_parent = old->rb_parent;
+		node->rb_color = old->rb_color;
+		node->rb_right = old->rb_right;
+		node->rb_left = old->rb_left;
+
+		if (old->rb_parent)
+		{
+			if (old->rb_parent->rb_left == old)
+				old->rb_parent->rb_left = node;
+			else
+				old->rb_parent->rb_right = node;
+		} else
+			root->rb_node = node;
+
+		old->rb_left->rb_parent = node;
+		if (old->rb_right)
+			old->rb_right->rb_parent = node;
+		goto color;
+	}
+
+	parent = node->rb_parent;
+	color = node->rb_color;
+
+	if (child)
+		child->rb_parent = parent;
+	if (parent)
+	{
+		if (parent->rb_left == node)
+			parent->rb_left = child;
+		else
+			parent->rb_right = child;
+	}
+	else
+		root->rb_node = child;
+
+ color:
+	if (color == RB_BLACK)
+		__rb_erase_color(child, parent, root);
+}
+
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_left)
+		n = n->rb_left;
+	return n;
+}
+
+struct rb_node *rb_last(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return NULL;
+	while (n->rb_right)
+		n = n->rb_right;
+	return n;
+}
+
+struct rb_node *rb_next(struct rb_node *node)
+{
+	/* If we have a right-hand child, go down and then left as far
+	   as we can. */
+	if (node->rb_right) {
+		node = node->rb_right; 
+		while (node->rb_left)
+			node=node->rb_left;
+		return 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 (node->rb_parent && node == node->rb_parent->rb_right)
+		node = node->rb_parent;
+
+	return node->rb_parent;
+}
+
+struct rb_node *rb_prev(struct rb_node *node)
+{
+	/* If we have a left-hand child, go down and then right as far
+	   as we can. */
+	if (node->rb_left) {
+		node = node->rb_left; 
+		while (node->rb_right)
+			node=node->rb_right;
+		return node;
+	}
+
+	/* No left-hand children. Go up till we find an ancestor which
+	   is a right-hand child of its parent */
+	while (node->rb_parent && node == node->rb_parent->rb_left)
+		node = node->rb_parent;
+
+	return node->rb_parent;
+}
+
+void rb_replace_node(struct rb_node *victim, struct rb_node *new,
+		     struct rb_root *root)
+{
+	struct rb_node *parent = victim->rb_parent;
+
+	/* Set the surrounding nodes to point to the replacement */
+	if (parent) {
+		if (victim == parent->rb_left)
+			parent->rb_left = new;
+		else
+			parent->rb_right = new;
+	} else {
+		root->rb_node = new;
+	}
+	if (victim->rb_left)
+		victim->rb_left->rb_parent = new;
+	if (victim->rb_right)
+		victim->rb_right->rb_parent = new;
+
+	/* Copy the pointers/colour from the victim to the replacement */
+	*new = *victim;
+}



More information about the Ocfs2-tools-commits mailing list