aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-20 14:16:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-20 14:16:20 -0400
commit4a52246302f01596f0edf7b4a3e6425e23479192 (patch)
treef384d86722d3ccfc875e3e5e8d8726e993a922ee /fs
parent9f9d2760da8c7f94fae119fac3e13d5a1702f8f0 (diff)
parentadc80ae60eae24a43a357bf5b30fb496f34aa605 (diff)
Merge tag 'driver-core-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core patches for 3.4-rc1 from Greg KH: "Here's the big driver core merge for 3.4-rc1. Lots of various things here, sysfs fixes/tweaks (with the nlink breakage reverted), dynamic debugging updates, w1 drivers, hyperv driver updates, and a variety of other bits and pieces, full information in the shortlog." * tag 'driver-core-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (78 commits) Tools: hv: Support enumeration from all the pools Tools: hv: Fully support the new KVP verbs in the user level daemon Drivers: hv: Support the newly introduced KVP messages in the driver Drivers: hv: Add new message types to enhance KVP regulator: Support driver probe deferral Revert "sysfs: Kill nlink counting." uevent: send events in correct order according to seqnum (v3) driver core: minor comment formatting cleanups driver core: move the deferred probe pointer into the private area drivercore: Add driver probe deferral mechanism DS2781 Maxim Stand-Alone Fuel Gauge battery and w1 slave drivers w1_bq27000: Only one thread can access the bq27000 at a time. w1_bq27000 - remove w1_bq27000_write w1_bq27000: remove unnecessary NULL test. sysfs: Fix memory leak in sysfs_sd_setsecdata(). intel_idle: Revert change of auto_demotion_disable_flags for Nehalem w1: Fix w1_bq27000 driver-core: documentation: fix up Greg's email address powernow-k6: Really enable auto-loading powernow-k7: Fix CPU family number ...
Diffstat (limited to 'fs')
-rw-r--r--fs/debugfs/inode.c149
-rw-r--r--fs/sysfs/dir.c224
-rw-r--r--fs/sysfs/inode.c11
-rw-r--r--fs/sysfs/mount.c2
-rw-r--r--fs/sysfs/sysfs.h17
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
29static struct vfsmount *debugfs_mount; 33static struct vfsmount *debugfs_mount;
30static int debugfs_mount_count; 34static int debugfs_mount_count;
31static bool debugfs_registered; 35static 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
132struct debugfs_mount_opts {
133 uid_t uid;
134 gid_t gid;
135 umode_t mode;
136};
137
138enum {
139 Opt_uid,
140 Opt_gid,
141 Opt_mode,
142 Opt_err
143};
144
145static 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
152struct debugfs_fs_info {
153 struct debugfs_mount_opts mount_opts;
154};
155
156static 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
196static 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
211static 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
222fail:
223 return err;
224}
225
226static 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
241static const struct super_operations debugfs_super_operations = {
242 .statfs = simple_statfs,
243 .remount_fs = debugfs_remount,
244 .show_options = debugfs_show_options,
245};
246
128static int debug_fill_super(struct super_block *sb, void *data, int silent) 247static 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); 276fail:
277 kfree(fsi);
278 sb->s_fs_info = NULL;
279 return err;
133} 280}
134 281
135static struct dentry *debug_mount(struct file_system_type *fs_type, 282static 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
27DEFINE_MUTEX(sysfs_mutex); 28DEFINE_MUTEX(sysfs_mutex);
28DEFINE_SPINLOCK(sysfs_assoc_lock); 29DEFINE_SPINLOCK(sysfs_assoc_lock);
29 30
31#define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb);
32
30static DEFINE_SPINLOCK(sysfs_ino_lock); 33static DEFINE_SPINLOCK(sysfs_ino_lock);
31static DEFINE_IDA(sysfs_ino_ida); 34static 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 */
43static 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
59static 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
69static 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 */
43static void sysfs_link_sibling(struct sysfs_dirent *sd) 89static 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
201static int sysfs_alloc_ino(ino_t *pino) 227static 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
220static void sysfs_free_ino(ino_t ino) 246static 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,
402int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) 428int __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
921static struct sysfs_dirent *sysfs_dir_pos(const void *ns, 937static 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
28struct sysfs_elem_symlink { 27struct 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
104static inline unsigned int sysfs_type(struct sysfs_dirent *sd) 103static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
105{ 104{