[dm-devel] [PATCH 2/4] sysfs: use rb-tree for name lookups

Mikulas Patocka mpatocka at redhat.com
Mon Jul 25 21:55:57 UTC 2011



On Thu, 21 Jul 2011, Mikulas Patocka wrote:

> sysfs: use rb-tree for name lookups
> 
> Use red-black tree for name lookups.
> 
> This patch improves time to create 10000 block devices from 120 seconds to 
> 68 seconds.
> 
> Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
> 
> ---
>  fs/sysfs/dir.c   |   45 +++++++++++++++++++++++++++++++++++++++------
>  fs/sysfs/sysfs.h |    5 +++++
>  2 files changed, 44 insertions(+), 6 deletions(-)
> 
> Index: linux-3.0-rc7-fast/fs/sysfs/sysfs.h
> ===================================================================
> --- linux-3.0-rc7-fast.orig/fs/sysfs/sysfs.h	2011-07-18 20:06:24.000000000 +0200
> +++ linux-3.0-rc7-fast/fs/sysfs/sysfs.h	2011-07-18 20:16:32.000000000 +0200
> @@ -11,6 +11,7 @@
>  #include <linux/lockdep.h>
>  #include <linux/kobject_ns.h>
>  #include <linux/fs.h>
> +#include <linux/rbtree.h>
>  
>  struct sysfs_open_dirent;
>  
> @@ -21,6 +22,8 @@ struct sysfs_elem_dir {
>  	struct sysfs_dirent	*children;
>  
>  	unsigned long		subdirs;
> +
> +	struct rb_root		name_tree;
>  };
>  
>  struct sysfs_elem_symlink {
> @@ -61,6 +64,8 @@ struct sysfs_dirent {
>  	struct sysfs_dirent	*s_sibling;
>  	const char		*s_name;
>  
> +	struct rb_node		name_node;
> +
>  	const void		*s_ns; /* namespace tag */
>  	union {
>  		struct sysfs_elem_dir		s_dir;
> Index: linux-3.0-rc7-fast/fs/sysfs/dir.c
> ===================================================================
> --- linux-3.0-rc7-fast.orig/fs/sysfs/dir.c	2011-07-18 20:06:24.000000000 +0200
> +++ linux-3.0-rc7-fast/fs/sysfs/dir.c	2011-07-18 20:16:02.000000000 +0200
> @@ -45,6 +45,9 @@ static void sysfs_link_sibling(struct sy
>  	struct sysfs_dirent *parent_sd = sd->s_parent;
>  	struct sysfs_dirent **pos;
>  
> +	struct rb_node **p;
> +	struct rb_node *parent;
> +
>  	BUG_ON(sd->s_sibling);
>  
>  	if (sysfs_type(sd) == SYSFS_DIR)
> @@ -60,6 +63,26 @@ static void sysfs_link_sibling(struct sy
>  	}
>  	sd->s_sibling = *pos;
>  	*pos = sd;
> +
> +	p = &parent_sd->s_dir.name_tree.rb_node;
> +	parent = NULL;
> +	while (*p) {
> +		int c;
> +		parent = *p;
> +#define node	rb_entry(parent, struct sysfs_dirent, name_node)
> +		c = strcmp(sd->s_name, node->s_name);
> +		if (c < 0) {
> +			p = &node->name_node.rb_left;
> +		} else if (c > 0) {
> +			p = &node->name_node.rb_right;
> +		} else {
> +			printk(KERN_CRIT "sysfs: inserting duplicate filename '%s'\n", sd->s_name);
> +			BUG();
> +		}
> +#undef node
> +	}
> +	rb_link_node(&sd->name_node, parent, p);
> +	rb_insert_color(&sd->name_node, &parent_sd->s_dir.name_tree);
>  }
>  
>  /**
> @@ -87,6 +110,8 @@ static void sysfs_unlink_sibling(struct 
>  			break;
>  		}
>  	}
> +
> +	rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree);
>  }
>  
>  /**
> @@ -546,14 +571,22 @@ struct sysfs_dirent *sysfs_find_dirent(s
>  				       const void *ns,
>  				       const unsigned char *name)
>  {
> -	struct sysfs_dirent *sd;
> +	struct rb_node *p = parent_sd->s_dir.name_tree.rb_node;
>  
> -	for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
> -		if (ns && sd->s_ns && (sd->s_ns != ns))
> -			continue;
> -		if (!strcmp(sd->s_name, name))
> -			return sd;
> +	while (p) {
> +		int c;
> +#define node	rb_entry(p, struct sysfs_dirent, name_node)
> +		c = strcmp(name, node->s_name);
> +		if (c < 0) {
> +			p = node->name_node.rb_left;
> +		} else if (c > 0) {
> +			p = node->name_node.rb_right;
> +		} else {
> +			return node;
> +		}
> +#undef node
>  	}
> +
>  	return NULL;
>  }
>  
> 
> 

This is updated path. The previous patch accidentally ignored namespaces.

Mikulas

---

sysfs: use rb-tree for name lookups

Use red-black tree for name lookups.

Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>

---
 fs/sysfs/dir.c   |   57 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 fs/sysfs/sysfs.h |    5 ++++
 2 files changed, 55 insertions(+), 7 deletions(-)

Index: linux-3.0-fast/fs/sysfs/sysfs.h
===================================================================
--- linux-3.0-fast.orig/fs/sysfs/sysfs.h	2011-07-25 23:31:18.000000000 +0200
+++ linux-3.0-fast/fs/sysfs/sysfs.h	2011-07-25 23:54:34.000000000 +0200
@@ -11,6 +11,7 @@
 #include <linux/lockdep.h>
 #include <linux/kobject_ns.h>
 #include <linux/fs.h>
+#include <linux/rbtree.h>
 
 struct sysfs_open_dirent;
 
@@ -21,6 +22,8 @@ struct sysfs_elem_dir {
 	struct sysfs_dirent	*children;
 
 	unsigned long		subdirs;
+
+	struct rb_root		name_tree;
 };
 
 struct sysfs_elem_symlink {
@@ -61,6 +64,8 @@ struct sysfs_dirent {
 	struct sysfs_dirent	*s_sibling;
 	const char		*s_name;
 
+	struct rb_node		name_node;
+
 	const void		*s_ns; /* namespace tag */
 	union {
 		struct sysfs_elem_dir		s_dir;
Index: linux-3.0-fast/fs/sysfs/dir.c
===================================================================
--- linux-3.0-fast.orig/fs/sysfs/dir.c	2011-07-25 23:31:18.000000000 +0200
+++ linux-3.0-fast/fs/sysfs/dir.c	2011-07-25 23:54:34.000000000 +0200
@@ -45,6 +45,9 @@ static void sysfs_link_sibling(struct sy
 	struct sysfs_dirent *parent_sd = sd->s_parent;
 	struct sysfs_dirent **pos;
 
+	struct rb_node **p;
+	struct rb_node *parent;
+
 	BUG_ON(sd->s_sibling);
 
 	if (sysfs_type(sd) == SYSFS_DIR)
@@ -60,6 +63,23 @@ static void sysfs_link_sibling(struct sy
 	}
 	sd->s_sibling = *pos;
 	*pos = sd;
+
+	p = &parent_sd->s_dir.name_tree.rb_node;
+	parent = NULL;
+	while (*p) {
+		int c;
+		parent = *p;
+#define node	rb_entry(parent, struct sysfs_dirent, name_node)
+		c = strcmp(sd->s_name, node->s_name);
+		if (c < 0) {
+			p = &node->name_node.rb_left;
+		} else {
+			p = &node->name_node.rb_right;
+		}
+#undef node
+	}
+	rb_link_node(&sd->name_node, parent, p);
+	rb_insert_color(&sd->name_node, &parent_sd->s_dir.name_tree);
 }
 
 /**
@@ -87,6 +107,8 @@ static void sysfs_unlink_sibling(struct 
 			break;
 		}
 	}
+
+	rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree);
 }
 
 /**
@@ -546,15 +568,36 @@ struct sysfs_dirent *sysfs_find_dirent(s
 				       const void *ns,
 				       const unsigned char *name)
 {
-	struct sysfs_dirent *sd;
+	struct rb_node *p = parent_sd->s_dir.name_tree.rb_node;
+	struct sysfs_dirent *found = NULL;
 
-	for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
-		if (ns && sd->s_ns && (sd->s_ns != ns))
-			continue;
-		if (!strcmp(sd->s_name, name))
-			return sd;
+	while (p) {
+		int c;
+#define node	rb_entry(p, struct sysfs_dirent, name_node)
+		c = strcmp(name, node->s_name);
+		if (c < 0) {
+			p = node->name_node.rb_left;
+		} else if (c > 0) {
+			p = node->name_node.rb_right;
+		} else {
+			found = node;
+			p = node->name_node.rb_left;
+		}
+#undef node
 	}
-	return NULL;
+
+	if (found && ns) {
+		while (found->s_ns && found->s_ns != ns) {
+			p = rb_next(&found->name_node);
+			if (!p)
+				return NULL;
+			found = rb_entry(p, struct sysfs_dirent, name_node);
+			if (strcmp(name, found->s_name))
+				return NULL;
+		}
+	}
+
+	return found;
 }
 
 /**




More information about the dm-devel mailing list