aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2011-07-25 17:57:03 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-22 20:43:53 -0400
commita406f75840e15afbabd98cb64ae36b51424a8033 (patch)
tree7fe7838b426052222ea3592384e51732efa00fee /fs/sysfs/dir.c
parent58f2a4c7932d8bec866d0394f806004146cde827 (diff)
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: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r--fs/sysfs/dir.c89
1 files changed, 50 insertions, 39 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