diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/debugfs/inode.c | 149 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 224 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 11 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 2 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 17 |
5 files changed, 282 insertions, 121 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 956d5ddddf6e..b80bc846a15a 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -23,9 +23,13 @@ | |||
23 | #include <linux/debugfs.h> | 23 | #include <linux/debugfs.h> |
24 | #include <linux/fsnotify.h> | 24 | #include <linux/fsnotify.h> |
25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/parser.h> | ||
26 | #include <linux/magic.h> | 28 | #include <linux/magic.h> |
27 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
28 | 30 | ||
31 | #define DEBUGFS_DEFAULT_MODE 0755 | ||
32 | |||
29 | static struct vfsmount *debugfs_mount; | 33 | static struct vfsmount *debugfs_mount; |
30 | static int debugfs_mount_count; | 34 | static int debugfs_mount_count; |
31 | static bool debugfs_registered; | 35 | static bool debugfs_registered; |
@@ -125,11 +129,154 @@ static inline int debugfs_positive(struct dentry *dentry) | |||
125 | return dentry->d_inode && !d_unhashed(dentry); | 129 | return dentry->d_inode && !d_unhashed(dentry); |
126 | } | 130 | } |
127 | 131 | ||
132 | struct debugfs_mount_opts { | ||
133 | uid_t uid; | ||
134 | gid_t gid; | ||
135 | umode_t mode; | ||
136 | }; | ||
137 | |||
138 | enum { | ||
139 | Opt_uid, | ||
140 | Opt_gid, | ||
141 | Opt_mode, | ||
142 | Opt_err | ||
143 | }; | ||
144 | |||
145 | static const match_table_t tokens = { | ||
146 | {Opt_uid, "uid=%u"}, | ||
147 | {Opt_gid, "gid=%u"}, | ||
148 | {Opt_mode, "mode=%o"}, | ||
149 | {Opt_err, NULL} | ||
150 | }; | ||
151 | |||
152 | struct debugfs_fs_info { | ||
153 | struct debugfs_mount_opts mount_opts; | ||
154 | }; | ||
155 | |||
156 | static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) | ||
157 | { | ||
158 | substring_t args[MAX_OPT_ARGS]; | ||
159 | int option; | ||
160 | int token; | ||
161 | char *p; | ||
162 | |||
163 | opts->mode = DEBUGFS_DEFAULT_MODE; | ||
164 | |||
165 | while ((p = strsep(&data, ",")) != NULL) { | ||
166 | if (!*p) | ||
167 | continue; | ||
168 | |||
169 | token = match_token(p, tokens, args); | ||
170 | switch (token) { | ||
171 | case Opt_uid: | ||
172 | if (match_int(&args[0], &option)) | ||
173 | return -EINVAL; | ||
174 | opts->uid = option; | ||
175 | break; | ||
176 | case Opt_gid: | ||
177 | if (match_octal(&args[0], &option)) | ||
178 | return -EINVAL; | ||
179 | opts->gid = option; | ||
180 | break; | ||
181 | case Opt_mode: | ||
182 | if (match_octal(&args[0], &option)) | ||
183 | return -EINVAL; | ||
184 | opts->mode = option & S_IALLUGO; | ||
185 | break; | ||
186 | /* | ||
187 | * We might like to report bad mount options here; | ||
188 | * but traditionally debugfs has ignored all mount options | ||
189 | */ | ||
190 | } | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int debugfs_apply_options(struct super_block *sb) | ||
197 | { | ||
198 | struct debugfs_fs_info *fsi = sb->s_fs_info; | ||
199 | struct inode *inode = sb->s_root->d_inode; | ||
200 | struct debugfs_mount_opts *opts = &fsi->mount_opts; | ||
201 | |||
202 | inode->i_mode &= ~S_IALLUGO; | ||
203 | inode->i_mode |= opts->mode; | ||
204 | |||
205 | inode->i_uid = opts->uid; | ||
206 | inode->i_gid = opts->gid; | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int debugfs_remount(struct super_block *sb, int *flags, char *data) | ||
212 | { | ||
213 | int err; | ||
214 | struct debugfs_fs_info *fsi = sb->s_fs_info; | ||
215 | |||
216 | err = debugfs_parse_options(data, &fsi->mount_opts); | ||
217 | if (err) | ||
218 | goto fail; | ||
219 | |||
220 | debugfs_apply_options(sb); | ||
221 | |||
222 | fail: | ||
223 | return err; | ||
224 | } | ||
225 | |||
226 | static int debugfs_show_options(struct seq_file *m, struct dentry *root) | ||
227 | { | ||
228 | struct debugfs_fs_info *fsi = root->d_sb->s_fs_info; | ||
229 | struct debugfs_mount_opts *opts = &fsi->mount_opts; | ||
230 | |||
231 | if (opts->uid != 0) | ||
232 | seq_printf(m, ",uid=%u", opts->uid); | ||
233 | if (opts->gid != 0) | ||
234 | seq_printf(m, ",gid=%u", opts->gid); | ||
235 | if (opts->mode != DEBUGFS_DEFAULT_MODE) | ||
236 | seq_printf(m, ",mode=%o", opts->mode); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static const struct super_operations debugfs_super_operations = { | ||
242 | .statfs = simple_statfs, | ||
243 | .remount_fs = debugfs_remount, | ||
244 | .show_options = debugfs_show_options, | ||
245 | }; | ||
246 | |||
128 | static int debug_fill_super(struct super_block *sb, void *data, int silent) | 247 | static int debug_fill_super(struct super_block *sb, void *data, int silent) |
129 | { | 248 | { |
130 | static struct tree_descr debug_files[] = {{""}}; | 249 | static struct tree_descr debug_files[] = {{""}}; |
250 | struct debugfs_fs_info *fsi; | ||
251 | int err; | ||
252 | |||
253 | save_mount_options(sb, data); | ||
254 | |||
255 | fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL); | ||
256 | sb->s_fs_info = fsi; | ||
257 | if (!fsi) { | ||
258 | err = -ENOMEM; | ||
259 | goto fail; | ||
260 | } | ||
261 | |||
262 | err = debugfs_parse_options(data, &fsi->mount_opts); | ||
263 | if (err) | ||
264 | goto fail; | ||
265 | |||
266 | err = simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); | ||
267 | if (err) | ||
268 | goto fail; | ||
269 | |||
270 | sb->s_op = &debugfs_super_operations; | ||
271 | |||
272 | debugfs_apply_options(sb); | ||
273 | |||
274 | return 0; | ||
131 | 275 | ||
132 | return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); | 276 | fail: |
277 | kfree(fsi); | ||
278 | sb->s_fs_info = NULL; | ||
279 | return err; | ||
133 | } | 280 | } |
134 | 281 | ||
135 | static struct dentry *debug_mount(struct file_system_type *fs_type, | 282 | static struct dentry *debug_mount(struct file_system_type *fs_type, |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 7fdf6a7b7436..2a7a3f5d1ca6 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -22,76 +22,103 @@ | |||
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/security.h> | 24 | #include <linux/security.h> |
25 | #include <linux/hash.h> | ||
25 | #include "sysfs.h" | 26 | #include "sysfs.h" |
26 | 27 | ||
27 | DEFINE_MUTEX(sysfs_mutex); | 28 | DEFINE_MUTEX(sysfs_mutex); |
28 | DEFINE_SPINLOCK(sysfs_assoc_lock); | 29 | DEFINE_SPINLOCK(sysfs_assoc_lock); |
29 | 30 | ||
31 | #define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb); | ||
32 | |||
30 | static DEFINE_SPINLOCK(sysfs_ino_lock); | 33 | static DEFINE_SPINLOCK(sysfs_ino_lock); |
31 | static DEFINE_IDA(sysfs_ino_ida); | 34 | static DEFINE_IDA(sysfs_ino_ida); |
32 | 35 | ||
33 | /** | 36 | /** |
34 | * sysfs_link_sibling - link sysfs_dirent into sibling list | 37 | * sysfs_name_hash |
38 | * @ns: Namespace tag to hash | ||
39 | * @name: Null terminated string to hash | ||
40 | * | ||
41 | * Returns 31 bit hash of ns + name (so it fits in an off_t ) | ||
42 | */ | ||
43 | static unsigned int sysfs_name_hash(const void *ns, const char *name) | ||
44 | { | ||
45 | unsigned long hash = init_name_hash(); | ||
46 | unsigned int len = strlen(name); | ||
47 | while (len--) | ||
48 | hash = partial_name_hash(*name++, hash); | ||
49 | hash = ( end_name_hash(hash) ^ hash_ptr( (void *)ns, 31 ) ); | ||
50 | hash &= 0x7fffffffU; | ||
51 | /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ | ||
52 | if (hash < 1) | ||
53 | hash += 2; | ||
54 | if (hash >= INT_MAX) | ||
55 | hash = INT_MAX - 1; | ||
56 | return hash; | ||
57 | } | ||
58 | |||
59 | static int sysfs_name_compare(unsigned int hash, const void *ns, | ||
60 | const char *name, const struct sysfs_dirent *sd) | ||
61 | { | ||
62 | if (hash != sd->s_hash) | ||
63 | return hash - sd->s_hash; | ||
64 | if (ns != sd->s_ns) | ||
65 | return ns - sd->s_ns; | ||
66 | return strcmp(name, sd->s_name); | ||
67 | } | ||
68 | |||
69 | static int sysfs_sd_compare(const struct sysfs_dirent *left, | ||
70 | const struct sysfs_dirent *right) | ||
71 | { | ||
72 | return sysfs_name_compare(left->s_hash, left->s_ns, left->s_name, | ||
73 | right); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * sysfs_link_subling - link sysfs_dirent into sibling rbtree | ||
35 | * @sd: sysfs_dirent of interest | 78 | * @sd: sysfs_dirent of interest |
36 | * | 79 | * |
37 | * Link @sd into its sibling list which starts from | 80 | * Link @sd into its sibling rbtree which starts from |
38 | * sd->s_parent->s_dir.children. | 81 | * sd->s_parent->s_dir.children. |
39 | * | 82 | * |
40 | * Locking: | 83 | * Locking: |
41 | * mutex_lock(sysfs_mutex) | 84 | * mutex_lock(sysfs_mutex) |
85 | * | ||
86 | * RETURNS: | ||
87 | * 0 on susccess -EEXIST on failure. | ||
42 | */ | 88 | */ |
43 | static void sysfs_link_sibling(struct sysfs_dirent *sd) | 89 | static int sysfs_link_sibling(struct sysfs_dirent *sd) |
44 | { | 90 | { |
45 | struct sysfs_dirent *parent_sd = sd->s_parent; | 91 | struct rb_node **node = &sd->s_parent->s_dir.children.rb_node; |
46 | 92 | struct rb_node *parent = NULL; | |
47 | struct rb_node **p; | ||
48 | struct rb_node *parent; | ||
49 | 93 | ||
50 | if (sysfs_type(sd) == SYSFS_DIR) | 94 | if (sysfs_type(sd) == SYSFS_DIR) |
51 | parent_sd->s_dir.subdirs++; | 95 | sd->s_parent->s_dir.subdirs++; |
52 | 96 | ||
53 | p = &parent_sd->s_dir.inode_tree.rb_node; | 97 | while (*node) { |
54 | parent = NULL; | 98 | struct sysfs_dirent *pos; |
55 | while (*p) { | 99 | int result; |
56 | parent = *p; | 100 | |
57 | #define node rb_entry(parent, struct sysfs_dirent, inode_node) | 101 | pos = to_sysfs_dirent(*node); |
58 | if (sd->s_ino < node->s_ino) { | 102 | parent = *node; |
59 | p = &node->inode_node.rb_left; | 103 | result = sysfs_sd_compare(sd, pos); |
60 | } else if (sd->s_ino > node->s_ino) { | 104 | if (result < 0) |
61 | p = &node->inode_node.rb_right; | 105 | node = &pos->s_rb.rb_left; |
62 | } else { | 106 | else if (result > 0) |
63 | printk(KERN_CRIT "sysfs: inserting duplicate inode '%lx'\n", | 107 | node = &pos->s_rb.rb_right; |
64 | (unsigned long) sd->s_ino); | 108 | else |
65 | BUG(); | 109 | return -EEXIST; |
66 | } | ||
67 | #undef node | ||
68 | } | ||
69 | rb_link_node(&sd->inode_node, parent, p); | ||
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 | } | 110 | } |
86 | rb_link_node(&sd->name_node, parent, p); | 111 | /* add new node and rebalance the tree */ |
87 | rb_insert_color(&sd->name_node, &parent_sd->s_dir.name_tree); | 112 | rb_link_node(&sd->s_rb, parent, node); |
113 | rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children); | ||
114 | return 0; | ||
88 | } | 115 | } |
89 | 116 | ||
90 | /** | 117 | /** |
91 | * sysfs_unlink_sibling - unlink sysfs_dirent from sibling list | 118 | * sysfs_unlink_sibling - unlink sysfs_dirent from sibling rbtree |
92 | * @sd: sysfs_dirent of interest | 119 | * @sd: sysfs_dirent of interest |
93 | * | 120 | * |
94 | * Unlink @sd from its sibling list which starts from | 121 | * Unlink @sd from its sibling rbtree which starts from |
95 | * sd->s_parent->s_dir.children. | 122 | * sd->s_parent->s_dir.children. |
96 | * | 123 | * |
97 | * Locking: | 124 | * Locking: |
@@ -102,8 +129,7 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
102 | if (sysfs_type(sd) == SYSFS_DIR) | 129 | if (sysfs_type(sd) == SYSFS_DIR) |
103 | sd->s_parent->s_dir.subdirs--; | 130 | sd->s_parent->s_dir.subdirs--; |
104 | 131 | ||
105 | rb_erase(&sd->inode_node, &sd->s_parent->s_dir.inode_tree); | 132 | rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); |
106 | rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree); | ||
107 | } | 133 | } |
108 | 134 | ||
109 | /** | 135 | /** |
@@ -198,7 +224,7 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) | |||
198 | rwsem_release(&sd->dep_map, 1, _RET_IP_); | 224 | rwsem_release(&sd->dep_map, 1, _RET_IP_); |
199 | } | 225 | } |
200 | 226 | ||
201 | static int sysfs_alloc_ino(ino_t *pino) | 227 | static int sysfs_alloc_ino(unsigned int *pino) |
202 | { | 228 | { |
203 | int ino, rc; | 229 | int ino, rc; |
204 | 230 | ||
@@ -217,7 +243,7 @@ static int sysfs_alloc_ino(ino_t *pino) | |||
217 | return rc; | 243 | return rc; |
218 | } | 244 | } |
219 | 245 | ||
220 | static void sysfs_free_ino(ino_t ino) | 246 | static void sysfs_free_ino(unsigned int ino) |
221 | { | 247 | { |
222 | spin_lock(&sysfs_ino_lock); | 248 | spin_lock(&sysfs_ino_lock); |
223 | ida_remove(&sysfs_ino_ida, ino); | 249 | ida_remove(&sysfs_ino_ida, ino); |
@@ -402,6 +428,7 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
402 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 428 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
403 | { | 429 | { |
404 | struct sysfs_inode_attrs *ps_iattr; | 430 | struct sysfs_inode_attrs *ps_iattr; |
431 | int ret; | ||
405 | 432 | ||
406 | if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) { | 433 | if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) { |
407 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | 434 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", |
@@ -410,12 +437,12 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
410 | return -EINVAL; | 437 | return -EINVAL; |
411 | } | 438 | } |
412 | 439 | ||
413 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name)) | 440 | sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); |
414 | return -EEXIST; | ||
415 | |||
416 | sd->s_parent = sysfs_get(acxt->parent_sd); | 441 | sd->s_parent = sysfs_get(acxt->parent_sd); |
417 | 442 | ||
418 | sysfs_link_sibling(sd); | 443 | ret = sysfs_link_sibling(sd); |
444 | if (ret) | ||
445 | return ret; | ||
419 | 446 | ||
420 | /* Update timestamps on the parent */ | 447 | /* Update timestamps on the parent */ |
421 | ps_iattr = acxt->parent_sd->s_iattr; | 448 | ps_iattr = acxt->parent_sd->s_iattr; |
@@ -565,8 +592,8 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
565 | const void *ns, | 592 | const void *ns, |
566 | const unsigned char *name) | 593 | const unsigned char *name) |
567 | { | 594 | { |
568 | struct rb_node *p = parent_sd->s_dir.name_tree.rb_node; | 595 | struct rb_node *node = parent_sd->s_dir.children.rb_node; |
569 | struct sysfs_dirent *found = NULL; | 596 | unsigned int hash; |
570 | 597 | ||
571 | if (!!sysfs_ns_type(parent_sd) != !!ns) { | 598 | if (!!sysfs_ns_type(parent_sd) != !!ns) { |
572 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | 599 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", |
@@ -575,33 +602,21 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
575 | return NULL; | 602 | return NULL; |
576 | } | 603 | } |
577 | 604 | ||
578 | while (p) { | 605 | hash = sysfs_name_hash(ns, name); |
579 | int c; | 606 | while (node) { |
580 | #define node rb_entry(p, struct sysfs_dirent, name_node) | 607 | struct sysfs_dirent *sd; |
581 | c = strcmp(name, node->s_name); | 608 | int result; |
582 | if (c < 0) { | 609 | |
583 | p = node->name_node.rb_left; | 610 | sd = to_sysfs_dirent(node); |
584 | } else if (c > 0) { | 611 | result = sysfs_name_compare(hash, ns, name, sd); |
585 | p = node->name_node.rb_right; | 612 | if (result < 0) |
586 | } else { | 613 | node = node->rb_left; |
587 | found = node; | 614 | else if (result > 0) |
588 | p = node->name_node.rb_left; | 615 | node = node->rb_right; |
589 | } | 616 | else |
590 | #undef node | 617 | return sd; |
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 | } | 618 | } |
603 | 619 | return NULL; | |
604 | return found; | ||
605 | } | 620 | } |
606 | 621 | ||
607 | /** | 622 | /** |
@@ -804,9 +819,9 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | |||
804 | 819 | ||
805 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); | 820 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); |
806 | sysfs_addrm_start(&acxt, dir_sd); | 821 | sysfs_addrm_start(&acxt, dir_sd); |
807 | pos = rb_first(&dir_sd->s_dir.inode_tree); | 822 | pos = rb_first(&dir_sd->s_dir.children); |
808 | while (pos) { | 823 | while (pos) { |
809 | struct sysfs_dirent *sd = rb_entry(pos, struct sysfs_dirent, inode_node); | 824 | struct sysfs_dirent *sd = to_sysfs_dirent(pos); |
810 | pos = rb_next(pos); | 825 | pos = rb_next(pos); |
811 | if (sysfs_type(sd) != SYSFS_DIR) | 826 | if (sysfs_type(sd) != SYSFS_DIR) |
812 | sysfs_remove_one(&acxt, sd); | 827 | sysfs_remove_one(&acxt, sd); |
@@ -863,6 +878,7 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
863 | 878 | ||
864 | dup_name = sd->s_name; | 879 | dup_name = sd->s_name; |
865 | sd->s_name = new_name; | 880 | sd->s_name = new_name; |
881 | sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); | ||
866 | } | 882 | } |
867 | 883 | ||
868 | /* Move to the appropriate place in the appropriate directories rbtree. */ | 884 | /* Move to the appropriate place in the appropriate directories rbtree. */ |
@@ -919,38 +935,36 @@ static int sysfs_dir_release(struct inode *inode, struct file *filp) | |||
919 | } | 935 | } |
920 | 936 | ||
921 | static struct sysfs_dirent *sysfs_dir_pos(const void *ns, | 937 | static struct sysfs_dirent *sysfs_dir_pos(const void *ns, |
922 | struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) | 938 | struct sysfs_dirent *parent_sd, loff_t hash, struct sysfs_dirent *pos) |
923 | { | 939 | { |
924 | if (pos) { | 940 | if (pos) { |
925 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && | 941 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && |
926 | pos->s_parent == parent_sd && | 942 | pos->s_parent == parent_sd && |
927 | ino == pos->s_ino; | 943 | hash == pos->s_hash; |
928 | sysfs_put(pos); | 944 | sysfs_put(pos); |
929 | if (!valid) | 945 | if (!valid) |
930 | pos = NULL; | 946 | pos = NULL; |
931 | } | 947 | } |
932 | if (!pos && (ino > 1) && (ino < INT_MAX)) { | 948 | if (!pos && (hash > 1) && (hash < INT_MAX)) { |
933 | struct rb_node *p = parent_sd->s_dir.inode_tree.rb_node; | 949 | struct rb_node *node = parent_sd->s_dir.children.rb_node; |
934 | while (p) { | 950 | while (node) { |
935 | #define node rb_entry(p, struct sysfs_dirent, inode_node) | 951 | pos = to_sysfs_dirent(node); |
936 | if (ino < node->s_ino) { | 952 | |
937 | pos = node; | 953 | if (hash < pos->s_hash) |
938 | p = node->inode_node.rb_left; | 954 | node = node->rb_left; |
939 | } else if (ino > node->s_ino) { | 955 | else if (hash > pos->s_hash) |
940 | p = node->inode_node.rb_right; | 956 | node = node->rb_right; |
941 | } else { | 957 | else |
942 | pos = node; | ||
943 | break; | 958 | break; |
944 | } | ||
945 | #undef node | ||
946 | } | 959 | } |
947 | } | 960 | } |
961 | /* Skip over entries in the wrong namespace */ | ||
948 | while (pos && pos->s_ns != ns) { | 962 | while (pos && pos->s_ns != ns) { |
949 | struct rb_node *p = rb_next(&pos->inode_node); | 963 | struct rb_node *node = rb_next(&pos->s_rb); |
950 | if (!p) | 964 | if (!node) |
951 | pos = NULL; | 965 | pos = NULL; |
952 | else | 966 | else |
953 | pos = rb_entry(p, struct sysfs_dirent, inode_node); | 967 | pos = to_sysfs_dirent(node); |
954 | } | 968 | } |
955 | return pos; | 969 | return pos; |
956 | } | 970 | } |
@@ -960,11 +974,11 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns, | |||
960 | { | 974 | { |
961 | pos = sysfs_dir_pos(ns, parent_sd, ino, pos); | 975 | pos = sysfs_dir_pos(ns, parent_sd, ino, pos); |
962 | if (pos) do { | 976 | if (pos) do { |
963 | struct rb_node *p = rb_next(&pos->inode_node); | 977 | struct rb_node *node = rb_next(&pos->s_rb); |
964 | if (!p) | 978 | if (!node) |
965 | pos = NULL; | 979 | pos = NULL; |
966 | else | 980 | else |
967 | pos = rb_entry(p, struct sysfs_dirent, inode_node); | 981 | pos = to_sysfs_dirent(node); |
968 | } while (pos && pos->s_ns != ns); | 982 | } while (pos && pos->s_ns != ns); |
969 | return pos; | 983 | return pos; |
970 | } | 984 | } |
@@ -1006,7 +1020,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
1006 | len = strlen(name); | 1020 | len = strlen(name); |
1007 | ino = pos->s_ino; | 1021 | ino = pos->s_ino; |
1008 | type = dt_type(pos); | 1022 | type = dt_type(pos); |
1009 | filp->f_pos = ino; | 1023 | filp->f_pos = pos->s_hash; |
1010 | filp->private_data = sysfs_get(pos); | 1024 | filp->private_data = sysfs_get(pos); |
1011 | 1025 | ||
1012 | mutex_unlock(&sysfs_mutex); | 1026 | mutex_unlock(&sysfs_mutex); |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 85eb81683a29..feb2d69396cf 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -136,12 +136,13 @@ static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *sec | |||
136 | void *old_secdata; | 136 | void *old_secdata; |
137 | size_t old_secdata_len; | 137 | size_t old_secdata_len; |
138 | 138 | ||
139 | iattrs = sd->s_iattr; | 139 | if (!sd->s_iattr) { |
140 | if (!iattrs) | 140 | sd->s_iattr = sysfs_init_inode_attrs(sd); |
141 | iattrs = sysfs_init_inode_attrs(sd); | 141 | if (!sd->s_iattr) |
142 | if (!iattrs) | 142 | return -ENOMEM; |
143 | return -ENOMEM; | 143 | } |
144 | 144 | ||
145 | iattrs = sd->s_iattr; | ||
145 | old_secdata = iattrs->ia_secdata; | 146 | old_secdata = iattrs->ia_secdata; |
146 | old_secdata_len = iattrs->ia_secdata_len; | 147 | old_secdata_len = iattrs->ia_secdata_len; |
147 | 148 | ||
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index e34f0d99ea4e..140f26a34288 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -36,7 +36,7 @@ struct sysfs_dirent sysfs_root = { | |||
36 | .s_name = "", | 36 | .s_name = "", |
37 | .s_count = ATOMIC_INIT(1), | 37 | .s_count = ATOMIC_INIT(1), |
38 | .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), | 38 | .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), |
39 | .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, | 39 | .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, |
40 | .s_ino = 1, | 40 | .s_ino = 1, |
41 | }; | 41 | }; |
42 | 42 | ||
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 7484a36ee678..661a9639570b 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -20,9 +20,8 @@ struct sysfs_elem_dir { | |||
20 | struct kobject *kobj; | 20 | struct kobject *kobj; |
21 | 21 | ||
22 | unsigned long subdirs; | 22 | unsigned long subdirs; |
23 | 23 | /* children rbtree starts here and goes through sd->s_rb */ | |
24 | struct rb_root inode_tree; | 24 | struct rb_root children; |
25 | struct rb_root name_tree; | ||
26 | }; | 25 | }; |
27 | 26 | ||
28 | struct sysfs_elem_symlink { | 27 | struct sysfs_elem_symlink { |
@@ -62,8 +61,7 @@ struct sysfs_dirent { | |||
62 | struct sysfs_dirent *s_parent; | 61 | struct sysfs_dirent *s_parent; |
63 | const char *s_name; | 62 | const char *s_name; |
64 | 63 | ||
65 | struct rb_node inode_node; | 64 | struct rb_node s_rb; |
66 | struct rb_node name_node; | ||
67 | 65 | ||
68 | union { | 66 | union { |
69 | struct completion *completion; | 67 | struct completion *completion; |
@@ -71,6 +69,7 @@ struct sysfs_dirent { | |||
71 | } u; | 69 | } u; |
72 | 70 | ||
73 | const void *s_ns; /* namespace tag */ | 71 | const void *s_ns; /* namespace tag */ |
72 | unsigned int s_hash; /* ns + name hash */ | ||
74 | union { | 73 | union { |
75 | struct sysfs_elem_dir s_dir; | 74 | struct sysfs_elem_dir s_dir; |
76 | struct sysfs_elem_symlink s_symlink; | 75 | struct sysfs_elem_symlink s_symlink; |
@@ -78,9 +77,9 @@ struct sysfs_dirent { | |||
78 | struct sysfs_elem_bin_attr s_bin_attr; | 77 | struct sysfs_elem_bin_attr s_bin_attr; |
79 | }; | 78 | }; |
80 | 79 | ||
81 | unsigned int s_flags; | 80 | unsigned short s_flags; |
82 | umode_t s_mode; | 81 | umode_t s_mode; |
83 | ino_t s_ino; | 82 | unsigned int s_ino; |
84 | struct sysfs_inode_attrs *s_iattr; | 83 | struct sysfs_inode_attrs *s_iattr; |
85 | }; | 84 | }; |
86 | 85 | ||
@@ -95,11 +94,11 @@ struct sysfs_dirent { | |||
95 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) | 94 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) |
96 | 95 | ||
97 | /* identify any namespace tag on sysfs_dirents */ | 96 | /* identify any namespace tag on sysfs_dirents */ |
98 | #define SYSFS_NS_TYPE_MASK 0xff00 | 97 | #define SYSFS_NS_TYPE_MASK 0xf00 |
99 | #define SYSFS_NS_TYPE_SHIFT 8 | 98 | #define SYSFS_NS_TYPE_SHIFT 8 |
100 | 99 | ||
101 | #define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) | 100 | #define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) |
102 | #define SYSFS_FLAG_REMOVED 0x020000 | 101 | #define SYSFS_FLAG_REMOVED 0x02000 |
103 | 102 | ||
104 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | 103 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) |
105 | { | 104 | { |