diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2011-07-25 17:57:03 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-08-22 20:43:53 -0400 |
commit | a406f75840e15afbabd98cb64ae36b51424a8033 (patch) | |
tree | 7fe7838b426052222ea3592384e51732efa00fee /fs/sysfs/dir.c | |
parent | 58f2a4c7932d8bec866d0394f806004146cde827 (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.c | 89 |
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); | |||
43 | static void sysfs_link_sibling(struct sysfs_dirent *sd) | 43 | static 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 | */ |
95 | static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | 99 | static 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) | |||
788 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | 782 | static 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 | ||