|
@@ -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
|
|
|
|
- * readdir to properly restart without having to add a
|
|
|
|
- * cursor into the s_dir.children list.
|
|
|
|
- */
|
|
|
|
- for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
|
|
|
|
- if (sd->s_ino < (*pos)->s_ino)
|
|
|
|
- break;
|
|
|
|
|
|
+ p = &parent_sd->s_dir.inode_tree.rb_node;
|
|
|
|
+ parent = NULL;
|
|
|
|
+ while (*p) {
|
|
|
|
+ parent = *p;
|
|
|
|
+#define node rb_entry(parent, struct sysfs_dirent, inode_node)
|
|
|
|
+ if (sd->s_ino < node->s_ino) {
|
|
|
|
+ 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();
|
|
|
|
+ }
|
|
|
|
+#undef node
|
|
}
|
|
}
|
|
- sd->s_sibling = *pos;
|
|
|
|
- *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)
|
|
*/
|
|
*/
|
|
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;
|
|
|
|
- pos = &(*pos)->s_sibling) {
|
|
|
|
- if (*pos == sd) {
|
|
|
|
- *pos = sd->s_sibling;
|
|
|
|
- sd->s_sibling = NULL;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ rb_erase(&sd->inode_node, &sd->s_parent->s_dir.inode_tree);
|
|
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)
|
|
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;
|
|
|
|
- while (*pos) {
|
|
|
|
- struct sysfs_dirent *sd = *pos;
|
|
|
|
-
|
|
|
|
|
|
+ pos = rb_first(&dir_sd->s_dir.inode_tree);
|
|
|
|
+ while (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,
|
|
pos = NULL;
|
|
pos = NULL;
|
|
}
|
|
}
|
|
if (!pos && (ino > 1) && (ino < INT_MAX)) {
|
|
if (!pos && (ino > 1) && (ino < INT_MAX)) {
|
|
- pos = parent_sd->s_dir.children;
|
|
|
|
- while (pos && (ino > pos->s_ino))
|
|
|
|
- pos = pos->s_sibling;
|
|
|
|
|
|
+ struct rb_node *p = parent_sd->s_dir.inode_tree.rb_node;
|
|
|
|
+ while (p) {
|
|
|
|
+#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,
|
|
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)
|
|
|
|
- pos = pos->s_sibling;
|
|
|
|
- while (pos && pos->s_ns && pos->s_ns != ns)
|
|
|
|
- pos = pos->s_sibling;
|
|
|
|
|
|
+ if (pos) do {
|
|
|
|
+ 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);
|
|
return pos;
|
|
return pos;
|
|
}
|
|
}
|
|
|
|
|