提交 a406f758 编写于 作者: M Mikulas Patocka 提交者: Greg Kroah-Hartman

sysfs: use rb-tree for inode number lookup

sysfs: use rb-tree for inode number lookup

This patch makes sysfs use red-black tree for inode number lookup.
Together with a previous patch to use red-black tree for name lookup,
this patch makes all sysfs lookups to have O(log n) complexity.
Signed-off-by: NMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 58f2a4c7
...@@ -43,26 +43,30 @@ static DEFINE_IDA(sysfs_ino_ida); ...@@ -43,26 +43,30 @@ static DEFINE_IDA(sysfs_ino_ida);
static void sysfs_link_sibling(struct sysfs_dirent *sd) static void sysfs_link_sibling(struct sysfs_dirent *sd)
{ {
struct sysfs_dirent *parent_sd = sd->s_parent; struct sysfs_dirent *parent_sd = sd->s_parent;
struct sysfs_dirent **pos;
struct rb_node **p; struct rb_node **p;
struct rb_node *parent; struct rb_node *parent;
BUG_ON(sd->s_sibling);
if (sysfs_type(sd) == SYSFS_DIR) if (sysfs_type(sd) == SYSFS_DIR)
parent_sd->s_dir.subdirs++; parent_sd->s_dir.subdirs++;
/* Store directory entries in order by ino. This allows p = &parent_sd->s_dir.inode_tree.rb_node;
* readdir to properly restart without having to add a parent = NULL;
* cursor into the s_dir.children list. while (*p) {
*/ parent = *p;
for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { #define node rb_entry(parent, struct sysfs_dirent, inode_node)
if (sd->s_ino < (*pos)->s_ino) if (sd->s_ino < node->s_ino) {
break; p = &node->inode_node.rb_left;
} else if (sd->s_ino > node->s_ino) {
p = &node->inode_node.rb_right;
} else {
printk(KERN_CRIT "sysfs: inserting duplicate inode '%lx'\n", sd->s_ino);
BUG();
} }
sd->s_sibling = *pos; #undef node
*pos = sd; }
rb_link_node(&sd->inode_node, parent, p);
rb_insert_color(&sd->inode_node, &parent_sd->s_dir.inode_tree);
p = &parent_sd->s_dir.name_tree.rb_node; p = &parent_sd->s_dir.name_tree.rb_node;
parent = NULL; parent = NULL;
...@@ -94,20 +98,10 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd) ...@@ -94,20 +98,10 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd)
*/ */
static void sysfs_unlink_sibling(struct sysfs_dirent *sd) static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
{ {
struct sysfs_dirent **pos;
if (sysfs_type(sd) == SYSFS_DIR) if (sysfs_type(sd) == SYSFS_DIR)
sd->s_parent->s_dir.subdirs--; sd->s_parent->s_dir.subdirs--;
for (pos = &sd->s_parent->s_dir.children; *pos; rb_erase(&sd->inode_node, &sd->s_parent->s_dir.inode_tree);
pos = &(*pos)->s_sibling) {
if (*pos == sd) {
*pos = sd->s_sibling;
sd->s_sibling = NULL;
break;
}
}
rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree); rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree);
} }
...@@ -788,21 +782,19 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd) ...@@ -788,21 +782,19 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd)
static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
{ {
struct sysfs_addrm_cxt acxt; struct sysfs_addrm_cxt acxt;
struct sysfs_dirent **pos; struct rb_node *pos;
if (!dir_sd) if (!dir_sd)
return; return;
pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
sysfs_addrm_start(&acxt, dir_sd); sysfs_addrm_start(&acxt, dir_sd);
pos = &dir_sd->s_dir.children; pos = rb_first(&dir_sd->s_dir.inode_tree);
while (*pos) { while (pos) {
struct sysfs_dirent *sd = *pos; struct sysfs_dirent *sd = rb_entry(pos, struct sysfs_dirent, inode_node);
pos = rb_next(pos);
if (sysfs_type(sd) != SYSFS_DIR) if (sysfs_type(sd) != SYSFS_DIR)
sysfs_remove_one(&acxt, sd); sysfs_remove_one(&acxt, sd);
else
pos = &(*pos)->s_sibling;
} }
sysfs_addrm_finish(&acxt); sysfs_addrm_finish(&acxt);
...@@ -925,12 +917,28 @@ static struct sysfs_dirent *sysfs_dir_pos(const void *ns, ...@@ -925,12 +917,28 @@ static struct sysfs_dirent *sysfs_dir_pos(const void *ns,
pos = NULL; pos = NULL;
} }
if (!pos && (ino > 1) && (ino < INT_MAX)) { if (!pos && (ino > 1) && (ino < INT_MAX)) {
pos = parent_sd->s_dir.children; struct rb_node *p = parent_sd->s_dir.inode_tree.rb_node;
while (pos && (ino > pos->s_ino)) while (p) {
pos = pos->s_sibling; #define node rb_entry(p, struct sysfs_dirent, inode_node)
if (ino < node->s_ino) {
pos = node;
p = node->inode_node.rb_left;
} else if (ino > node->s_ino) {
p = node->inode_node.rb_right;
} else {
pos = node;
break;
}
#undef node
}
}
while (pos && pos->s_ns && pos->s_ns != ns) {
struct rb_node *p = rb_next(&pos->inode_node);
if (!p)
pos = NULL;
else
pos = rb_entry(p, struct sysfs_dirent, inode_node);
} }
while (pos && pos->s_ns && pos->s_ns != ns)
pos = pos->s_sibling;
return pos; return pos;
} }
...@@ -938,10 +946,13 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns, ...@@ -938,10 +946,13 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns,
struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
{ {
pos = sysfs_dir_pos(ns, parent_sd, ino, pos); pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
if (pos) if (pos) do {
pos = pos->s_sibling; struct rb_node *p = rb_next(&pos->inode_node);
while (pos && pos->s_ns && pos->s_ns != ns) if (!p)
pos = pos->s_sibling; pos = NULL;
else
pos = rb_entry(p, struct sysfs_dirent, inode_node);
} while (pos && pos->s_ns && pos->s_ns != ns);
return pos; return pos;
} }
......
...@@ -18,11 +18,10 @@ struct sysfs_open_dirent; ...@@ -18,11 +18,10 @@ struct sysfs_open_dirent;
/* type-specific structures for sysfs_dirent->s_* union members */ /* type-specific structures for sysfs_dirent->s_* union members */
struct sysfs_elem_dir { struct sysfs_elem_dir {
struct kobject *kobj; struct kobject *kobj;
/* children list starts here and goes through sd->s_sibling */
struct sysfs_dirent *children;
unsigned long subdirs; unsigned long subdirs;
struct rb_root inode_tree;
struct rb_root name_tree; struct rb_root name_tree;
}; };
...@@ -61,9 +60,9 @@ struct sysfs_dirent { ...@@ -61,9 +60,9 @@ struct sysfs_dirent {
struct lockdep_map dep_map; struct lockdep_map dep_map;
#endif #endif
struct sysfs_dirent *s_parent; struct sysfs_dirent *s_parent;
struct sysfs_dirent *s_sibling;
const char *s_name; const char *s_name;
struct rb_node inode_node;
struct rb_node name_node; struct rb_node name_node;
union { union {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册