diff options
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 182 |
1 files changed, 126 insertions, 56 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index ea9120a830d8..48ffbdf0d017 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -43,20 +43,48 @@ 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 | BUG_ON(sd->s_sibling); | 47 | struct rb_node **p; |
49 | 48 | struct rb_node *parent; | |
50 | /* Store directory entries in order by ino. This allows | 49 | |
51 | * readdir to properly restart without having to add a | 50 | if (sysfs_type(sd) == SYSFS_DIR) |
52 | * cursor into the s_dir.children list. | 51 | parent_sd->s_dir.subdirs++; |
53 | */ | 52 | |
54 | for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { | 53 | p = &parent_sd->s_dir.inode_tree.rb_node; |
55 | if (sd->s_ino < (*pos)->s_ino) | 54 | parent = NULL; |
56 | break; | 55 | while (*p) { |
56 | parent = *p; | ||
57 | #define node rb_entry(parent, struct sysfs_dirent, inode_node) | ||
58 | if (sd->s_ino < node->s_ino) { | ||
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", | ||
64 | (unsigned long) sd->s_ino); | ||
65 | BUG(); | ||
66 | } | ||
67 | #undef node | ||
57 | } | 68 | } |
58 | sd->s_sibling = *pos; | 69 | rb_link_node(&sd->inode_node, parent, p); |
59 | *pos = sd; | 70 | rb_insert_color(&sd->inode_node, &parent_sd->s_dir.inode_tree); |
71 | |||
72 | p = &parent_sd->s_dir.name_tree.rb_node; | ||
73 | parent = NULL; | ||
74 | while (*p) { | ||
75 | int c; | ||
76 | parent = *p; | ||
77 | #define node rb_entry(parent, struct sysfs_dirent, name_node) | ||
78 | c = strcmp(sd->s_name, node->s_name); | ||
79 | if (c < 0) { | ||
80 | p = &node->name_node.rb_left; | ||
81 | } else { | ||
82 | p = &node->name_node.rb_right; | ||
83 | } | ||
84 | #undef node | ||
85 | } | ||
86 | rb_link_node(&sd->name_node, parent, p); | ||
87 | rb_insert_color(&sd->name_node, &parent_sd->s_dir.name_tree); | ||
60 | } | 88 | } |
61 | 89 | ||
62 | /** | 90 | /** |
@@ -71,16 +99,11 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd) | |||
71 | */ | 99 | */ |
72 | static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | 100 | static void sysfs_unlink_sibling(struct sysfs_dirent *sd) |
73 | { | 101 | { |
74 | struct sysfs_dirent **pos; | 102 | if (sysfs_type(sd) == SYSFS_DIR) |
103 | sd->s_parent->s_dir.subdirs--; | ||
75 | 104 | ||
76 | for (pos = &sd->s_parent->s_dir.children; *pos; | 105 | rb_erase(&sd->inode_node, &sd->s_parent->s_dir.inode_tree); |
77 | pos = &(*pos)->s_sibling) { | 106 | rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree); |
78 | if (*pos == sd) { | ||
79 | *pos = sd->s_sibling; | ||
80 | sd->s_sibling = NULL; | ||
81 | break; | ||
82 | } | ||
83 | } | ||
84 | } | 107 | } |
85 | 108 | ||
86 | /** | 109 | /** |
@@ -126,7 +149,6 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
126 | */ | 149 | */ |
127 | void sysfs_put_active(struct sysfs_dirent *sd) | 150 | void sysfs_put_active(struct sysfs_dirent *sd) |
128 | { | 151 | { |
129 | struct completion *cmpl; | ||
130 | int v; | 152 | int v; |
131 | 153 | ||
132 | if (unlikely(!sd)) | 154 | if (unlikely(!sd)) |
@@ -138,10 +160,9 @@ void sysfs_put_active(struct sysfs_dirent *sd) | |||
138 | return; | 160 | return; |
139 | 161 | ||
140 | /* atomic_dec_return() is a mb(), we'll always see the updated | 162 | /* atomic_dec_return() is a mb(), we'll always see the updated |
141 | * sd->s_sibling. | 163 | * sd->u.completion. |
142 | */ | 164 | */ |
143 | cmpl = (void *)sd->s_sibling; | 165 | complete(sd->u.completion); |
144 | complete(cmpl); | ||
145 | } | 166 | } |
146 | 167 | ||
147 | /** | 168 | /** |
@@ -155,16 +176,16 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) | |||
155 | DECLARE_COMPLETION_ONSTACK(wait); | 176 | DECLARE_COMPLETION_ONSTACK(wait); |
156 | int v; | 177 | int v; |
157 | 178 | ||
158 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); | 179 | BUG_ON(!(sd->s_flags & SYSFS_FLAG_REMOVED)); |
159 | 180 | ||
160 | if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF)) | 181 | if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF)) |
161 | return; | 182 | return; |
162 | 183 | ||
163 | sd->s_sibling = (void *)&wait; | 184 | sd->u.completion = (void *)&wait; |
164 | 185 | ||
165 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); | 186 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); |
166 | /* atomic_add_return() is a mb(), put_active() will always see | 187 | /* atomic_add_return() is a mb(), put_active() will always see |
167 | * the updated sd->s_sibling. | 188 | * the updated sd->u.completion. |
168 | */ | 189 | */ |
169 | v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active); | 190 | v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active); |
170 | 191 | ||
@@ -173,8 +194,6 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) | |||
173 | wait_for_completion(&wait); | 194 | wait_for_completion(&wait); |
174 | } | 195 | } |
175 | 196 | ||
176 | sd->s_sibling = NULL; | ||
177 | |||
178 | lock_acquired(&sd->dep_map, _RET_IP_); | 197 | lock_acquired(&sd->dep_map, _RET_IP_); |
179 | rwsem_release(&sd->dep_map, 1, _RET_IP_); | 198 | rwsem_release(&sd->dep_map, 1, _RET_IP_); |
180 | } | 199 | } |
@@ -384,6 +403,13 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
384 | { | 403 | { |
385 | struct sysfs_inode_attrs *ps_iattr; | 404 | struct sysfs_inode_attrs *ps_iattr; |
386 | 405 | ||
406 | if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) { | ||
407 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | ||
408 | sysfs_ns_type(acxt->parent_sd)? "required": "invalid", | ||
409 | acxt->parent_sd->s_name, sd->s_name); | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
387 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name)) | 413 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name)) |
388 | return -EEXIST; | 414 | return -EEXIST; |
389 | 415 | ||
@@ -490,7 +516,7 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
490 | } | 516 | } |
491 | 517 | ||
492 | sd->s_flags |= SYSFS_FLAG_REMOVED; | 518 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
493 | sd->s_sibling = acxt->removed; | 519 | sd->u.removed_list = acxt->removed; |
494 | acxt->removed = sd; | 520 | acxt->removed = sd; |
495 | } | 521 | } |
496 | 522 | ||
@@ -514,8 +540,7 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
514 | while (acxt->removed) { | 540 | while (acxt->removed) { |
515 | struct sysfs_dirent *sd = acxt->removed; | 541 | struct sysfs_dirent *sd = acxt->removed; |
516 | 542 | ||
517 | acxt->removed = sd->s_sibling; | 543 | acxt->removed = sd->u.removed_list; |
518 | sd->s_sibling = NULL; | ||
519 | 544 | ||
520 | sysfs_deactivate(sd); | 545 | sysfs_deactivate(sd); |
521 | unmap_bin_file(sd); | 546 | unmap_bin_file(sd); |
@@ -540,15 +565,43 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
540 | const void *ns, | 565 | const void *ns, |
541 | const unsigned char *name) | 566 | const unsigned char *name) |
542 | { | 567 | { |
543 | struct sysfs_dirent *sd; | 568 | struct rb_node *p = parent_sd->s_dir.name_tree.rb_node; |
569 | struct sysfs_dirent *found = NULL; | ||
544 | 570 | ||
545 | for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) { | 571 | if (!!sysfs_ns_type(parent_sd) != !!ns) { |
546 | if (ns && sd->s_ns && (sd->s_ns != ns)) | 572 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", |
547 | continue; | 573 | sysfs_ns_type(parent_sd)? "required": "invalid", |
548 | if (!strcmp(sd->s_name, name)) | 574 | parent_sd->s_name, name); |
549 | return sd; | 575 | return NULL; |
550 | } | 576 | } |
551 | return NULL; | 577 | |
578 | while (p) { | ||
579 | int c; | ||
580 | #define node rb_entry(p, struct sysfs_dirent, name_node) | ||
581 | c = strcmp(name, node->s_name); | ||
582 | if (c < 0) { | ||
583 | p = node->name_node.rb_left; | ||
584 | } else if (c > 0) { | ||
585 | p = node->name_node.rb_right; | ||
586 | } else { | ||
587 | found = node; | ||
588 | p = node->name_node.rb_left; | ||
589 | } | ||
590 | #undef node | ||
591 | } | ||
592 | |||
593 | if (found) { | ||
594 | while (found->s_ns != ns) { | ||
595 | p = rb_next(&found->name_node); | ||
596 | if (!p) | ||
597 | return NULL; | ||
598 | found = rb_entry(p, struct sysfs_dirent, name_node); | ||
599 | if (strcmp(name, found->s_name)) | ||
600 | return NULL; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | return found; | ||
552 | } | 605 | } |
553 | 606 | ||
554 | /** | 607 | /** |
@@ -744,21 +797,19 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd) | |||
744 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | 797 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) |
745 | { | 798 | { |
746 | struct sysfs_addrm_cxt acxt; | 799 | struct sysfs_addrm_cxt acxt; |
747 | struct sysfs_dirent **pos; | 800 | struct rb_node *pos; |
748 | 801 | ||
749 | if (!dir_sd) | 802 | if (!dir_sd) |
750 | return; | 803 | return; |
751 | 804 | ||
752 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); | 805 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); |
753 | sysfs_addrm_start(&acxt, dir_sd); | 806 | sysfs_addrm_start(&acxt, dir_sd); |
754 | pos = &dir_sd->s_dir.children; | 807 | pos = rb_first(&dir_sd->s_dir.inode_tree); |
755 | while (*pos) { | 808 | while (pos) { |
756 | struct sysfs_dirent *sd = *pos; | 809 | struct sysfs_dirent *sd = rb_entry(pos, struct sysfs_dirent, inode_node); |
757 | 810 | pos = rb_next(pos); | |
758 | if (sysfs_type(sd) != SYSFS_DIR) | 811 | if (sysfs_type(sd) != SYSFS_DIR) |
759 | sysfs_remove_one(&acxt, sd); | 812 | sysfs_remove_one(&acxt, sd); |
760 | else | ||
761 | pos = &(*pos)->s_sibling; | ||
762 | } | 813 | } |
763 | sysfs_addrm_finish(&acxt); | 814 | sysfs_addrm_finish(&acxt); |
764 | 815 | ||
@@ -881,12 +932,28 @@ static struct sysfs_dirent *sysfs_dir_pos(const void *ns, | |||
881 | pos = NULL; | 932 | pos = NULL; |
882 | } | 933 | } |
883 | if (!pos && (ino > 1) && (ino < INT_MAX)) { | 934 | if (!pos && (ino > 1) && (ino < INT_MAX)) { |
884 | pos = parent_sd->s_dir.children; | 935 | struct rb_node *p = parent_sd->s_dir.inode_tree.rb_node; |
885 | while (pos && (ino > pos->s_ino)) | 936 | while (p) { |
886 | pos = pos->s_sibling; | 937 | #define node rb_entry(p, struct sysfs_dirent, inode_node) |
938 | if (ino < node->s_ino) { | ||
939 | pos = node; | ||
940 | p = node->inode_node.rb_left; | ||
941 | } else if (ino > node->s_ino) { | ||
942 | p = node->inode_node.rb_right; | ||
943 | } else { | ||
944 | pos = node; | ||
945 | break; | ||
946 | } | ||
947 | #undef node | ||
948 | } | ||
949 | } | ||
950 | while (pos && pos->s_ns != ns) { | ||
951 | struct rb_node *p = rb_next(&pos->inode_node); | ||
952 | if (!p) | ||
953 | pos = NULL; | ||
954 | else | ||
955 | pos = rb_entry(p, struct sysfs_dirent, inode_node); | ||
887 | } | 956 | } |
888 | while (pos && pos->s_ns && pos->s_ns != ns) | ||
889 | pos = pos->s_sibling; | ||
890 | return pos; | 957 | return pos; |
891 | } | 958 | } |
892 | 959 | ||
@@ -894,10 +961,13 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns, | |||
894 | struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) | 961 | struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) |
895 | { | 962 | { |
896 | pos = sysfs_dir_pos(ns, parent_sd, ino, pos); | 963 | pos = sysfs_dir_pos(ns, parent_sd, ino, pos); |
897 | if (pos) | 964 | if (pos) do { |
898 | pos = pos->s_sibling; | 965 | struct rb_node *p = rb_next(&pos->inode_node); |
899 | while (pos && pos->s_ns && pos->s_ns != ns) | 966 | if (!p) |
900 | pos = pos->s_sibling; | 967 | pos = NULL; |
968 | else | ||
969 | pos = rb_entry(p, struct sysfs_dirent, inode_node); | ||
970 | } while (pos && pos->s_ns != ns); | ||
901 | return pos; | 971 | return pos; |
902 | } | 972 | } |
903 | 973 | ||