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 | |
| 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')
| -rw-r--r-- | fs/sysfs/dir.c | 89 | ||||
| -rw-r--r-- | fs/sysfs/sysfs.h | 5 |
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); | |||
| 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 | ||
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 */ |
| 19 | struct sysfs_elem_dir { | 19 | struct 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 { |
