Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f72c0ca authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Greg Kroah-Hartman
Browse files

sysfs: use rb-tree for name lookups



sysfs: use rb-tree for name lookups

Use red-black tree for name lookups.

Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7f9838fd
Loading
Loading
Loading
Loading
+50 −7
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd)
	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 sysfs_dirent *sd)
	}
	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 sysfs_dirent *sd)
			break;
		}
	}

	rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree);
}

/**
@@ -546,15 +568,36 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
				       const void *ns,
				       const unsigned char *name)
{
	struct sysfs_dirent *sd;

	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;
	struct rb_node *p = parent_sd->s_dir.name_tree.rb_node;
	struct sysfs_dirent *found = NULL;

	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
	}

	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;
}

/**
+5 −0
Original line number Diff line number Diff line
@@ -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;