aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/sysfs/dir.c89
-rw-r--r--fs/sysfs/sysfs.h5
2 files changed, 52 insertions, 42 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index a4846979d4e8..c3646d93a032 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -43,26 +43,30 @@ static DEFINE_IDA(sysfs_ino_ida);
43static void sysfs_link_sibling(struct sysfs_dirent *sd) 43static void sysfs_link_sibling(struct sysfs_dirent *sd)
44{ 44{
45 struct sysfs_dirent *parent_sd = sd->s_parent; 45 struct sysfs_dirent *parent_sd = sd->s_parent;
46 struct sysfs_dirent **pos;
47 46
48 struct rb_node **p; 47 struct rb_node **p;
49 struct rb_node *parent; 48 struct rb_node *parent;
50 49
51 BUG_ON(sd->s_sibling);
52
53 if (sysfs_type(sd) == SYSFS_DIR) 50 if (sysfs_type(sd) == SYSFS_DIR)
54 parent_sd->s_dir.subdirs++; 51 parent_sd->s_dir.subdirs++;
55 52
56 /* Store directory entries in order by ino. This allows 53 p = &parent_sd->s_dir.inode_tree.rb_node;
57 * readdir to properly restart without having to add a 54 parent = NULL;
58 * cursor into the s_dir.children list. 55 while (*p) {
59 */ 56 parent = *p;
60 for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { 57#define node rb_entry(parent, struct sysfs_dirent, inode_node)
61 if (sd->s_ino < (*pos)->s_ino) 58 if (sd->s_ino < node->s_ino) {
62 break; 59 p = &node->inode_node.rb_left;
60 } else if (sd->s_ino > node->s_ino) {
61 p = &node->inode_node.rb_right;
62 } else {
63 printk(KERN_CRIT "sysfs: inserting duplicate inode '%lx'\n", sd->s_ino);
64 BUG();
65 }
66#undef node
63 } 67 }
64 sd->s_sibling = *pos; 68 rb_link_node(&sd->inode_node, parent, p);
65 *pos = sd; 69 rb_insert_color(&sd->inode_node, &parent_sd->s_dir.inode_tree);
66 70
67 p = &parent_sd->s_dir.name_tree.rb_node; 71 p = &parent_sd->s_dir.name_tree.rb_node;
68 parent = NULL; 72 parent = NULL;
@@ -94,20 +98,10 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd)
94 */ 98 */
95static void sysfs_unlink_sibling(struct sysfs_dirent *sd) 99static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
96{ 100{
97 struct sysfs_dirent **pos;
98
99 if (sysfs_type(sd) == SYSFS_DIR) 101 if (sysfs_type(sd) == SYSFS_DIR)
100 sd->s_parent->s_dir.subdirs--; 102 sd->s_parent->s_dir.subdirs--;
101 103
102 for (pos = &sd->s_parent->s_dir.children; *pos; 104 rb_erase(&sd->inode_node, &sd->s_parent->s_dir.inode_tree);
103 pos = &(*pos)->s_sibling) {
104 if (*pos == sd) {
105 *pos = sd->s_sibling;
106 sd->s_sibling = NULL;
107 break;
108 }
109 }
110
111 rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree); 105 rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree);
112} 106}
113 107
@@ -788,21 +782,19 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd)
788static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) 782static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
789{ 783{
790 struct sysfs_addrm_cxt acxt; 784 struct sysfs_addrm_cxt acxt;
791 struct sysfs_dirent **pos; 785 struct rb_node *pos;
792 786
793 if (!dir_sd) 787 if (!dir_sd)
794 return; 788 return;
795 789
796 pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); 790 pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
797 sysfs_addrm_start(&acxt, dir_sd); 791 sysfs_addrm_start(&acxt, dir_sd);
798 pos = &dir_sd->s_dir.children; 792 pos = rb_first(&dir_sd->s_dir.inode_tree);
799 while (*pos) { 793 while (pos) {
800 struct sysfs_dirent *sd = *pos; 794 struct sysfs_dirent *sd = rb_entry(pos, struct sysfs_dirent, inode_node);
801 795 pos = rb_next(pos);
802 if (sysfs_type(sd) != SYSFS_DIR) 796 if (sysfs_type(sd) != SYSFS_DIR)
803 sysfs_remove_one(&acxt, sd); 797 sysfs_remove_one(&acxt, sd);
804 else
805 pos = &(*pos)->s_sibling;
806 } 798 }
807 sysfs_addrm_finish(&acxt); 799 sysfs_addrm_finish(&acxt);
808 800
@@ -925,12 +917,28 @@ static struct sysfs_dirent *sysfs_dir_pos(const void *ns,
925 pos = NULL; 917 pos = NULL;
926 } 918 }
927 if (!pos && (ino > 1) && (ino < INT_MAX)) { 919 if (!pos && (ino > 1) && (ino < INT_MAX)) {
928 pos = parent_sd->s_dir.children; 920 struct rb_node *p = parent_sd->s_dir.inode_tree.rb_node;
929 while (pos && (ino > pos->s_ino)) 921 while (p) {
930 pos = pos->s_sibling; 922#define node rb_entry(p, struct sysfs_dirent, inode_node)
923 if (ino < node->s_ino) {
924 pos = node;
925 p = node->inode_node.rb_left;
926 } else if (ino > node->s_ino) {
927 p = node->inode_node.rb_right;
928 } else {
929 pos = node;
930 break;
931 }
932#undef node
933 }
934 }
935 while (pos && pos->s_ns && pos->s_ns != ns) {
936 struct rb_node *p = rb_next(&pos->inode_node);
937 if (!p)
938 pos = NULL;
939 else
940 pos = rb_entry(p, struct sysfs_dirent, inode_node);
931 } 941 }
932 while (pos && pos->s_ns && pos->s_ns != ns)
933 pos = pos->s_sibling;
934 return pos; 942 return pos;
935} 943}
936 944
@@ -938,10 +946,13 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns,
938 struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) 946 struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
939{ 947{
940 pos = sysfs_dir_pos(ns, parent_sd, ino, pos); 948 pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
941 if (pos) 949 if (pos) do {
942 pos = pos->s_sibling; 950 struct rb_node *p = rb_next(&pos->inode_node);
943 while (pos && pos->s_ns && pos->s_ns != ns) 951 if (!p)
944 pos = pos->s_sibling; 952 pos = NULL;
953 else
954 pos = rb_entry(p, struct sysfs_dirent, inode_node);
955 } while (pos && pos->s_ns && pos->s_ns != ns);
945 return pos; 956 return pos;
946} 957}
947 958
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 3c261681713b..ce29e28b766d 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -18,11 +18,10 @@ struct sysfs_open_dirent;
18/* type-specific structures for sysfs_dirent->s_* union members */ 18/* type-specific structures for sysfs_dirent->s_* union members */
19struct sysfs_elem_dir { 19struct sysfs_elem_dir {
20 struct kobject *kobj; 20 struct kobject *kobj;
21 /* children list starts here and goes through sd->s_sibling */
22 struct sysfs_dirent *children;
23 21
24 unsigned long subdirs; 22 unsigned long subdirs;
25 23
24 struct rb_root inode_tree;
26 struct rb_root name_tree; 25 struct rb_root name_tree;
27}; 26};
28 27
@@ -61,9 +60,9 @@ struct sysfs_dirent {
61 struct lockdep_map dep_map; 60 struct lockdep_map dep_map;
62#endif 61#endif
63 struct sysfs_dirent *s_parent; 62 struct sysfs_dirent *s_parent;
64 struct sysfs_dirent *s_sibling;
65 const char *s_name; 63 const char *s_name;
66 64
65 struct rb_node inode_node;
67 struct rb_node name_node; 66 struct rb_node name_node;
68 67
69 union { 68 union {