diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /fs/sysfs | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/bin.c | 2 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 335 | ||||
-rw-r--r-- | fs/sysfs/file.c | 66 | ||||
-rw-r--r-- | fs/sysfs/group.c | 8 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 40 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 10 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 2 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 29 |
8 files changed, 165 insertions, 327 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 614b2b54488..a4759833d62 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -228,8 +228,6 @@ static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
228 | ret = 0; | 228 | ret = 0; |
229 | if (bb->vm_ops->page_mkwrite) | 229 | if (bb->vm_ops->page_mkwrite) |
230 | ret = bb->vm_ops->page_mkwrite(vma, vmf); | 230 | ret = bb->vm_ops->page_mkwrite(vma, vmf); |
231 | else | ||
232 | file_update_time(file); | ||
233 | 231 | ||
234 | sysfs_put_active(attr_sd); | 232 | sysfs_put_active(attr_sd); |
235 | return ret; | 233 | return ret; |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 2fbdff6be25..ea9120a830d 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -22,103 +22,48 @@ | |||
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> | ||
26 | #include "sysfs.h" | 25 | #include "sysfs.h" |
27 | 26 | ||
28 | DEFINE_MUTEX(sysfs_mutex); | 27 | DEFINE_MUTEX(sysfs_mutex); |
29 | DEFINE_SPINLOCK(sysfs_assoc_lock); | 28 | DEFINE_SPINLOCK(sysfs_assoc_lock); |
30 | 29 | ||
31 | #define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb); | ||
32 | |||
33 | static DEFINE_SPINLOCK(sysfs_ino_lock); | 30 | static DEFINE_SPINLOCK(sysfs_ino_lock); |
34 | static DEFINE_IDA(sysfs_ino_ida); | 31 | static DEFINE_IDA(sysfs_ino_ida); |
35 | 32 | ||
36 | /** | 33 | /** |
37 | * sysfs_name_hash | 34 | * sysfs_link_sibling - link sysfs_dirent into sibling list |
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 | ||
78 | * @sd: sysfs_dirent of interest | 35 | * @sd: sysfs_dirent of interest |
79 | * | 36 | * |
80 | * Link @sd into its sibling rbtree which starts from | 37 | * Link @sd into its sibling list which starts from |
81 | * sd->s_parent->s_dir.children. | 38 | * sd->s_parent->s_dir.children. |
82 | * | 39 | * |
83 | * Locking: | 40 | * Locking: |
84 | * mutex_lock(sysfs_mutex) | 41 | * mutex_lock(sysfs_mutex) |
85 | * | ||
86 | * RETURNS: | ||
87 | * 0 on susccess -EEXIST on failure. | ||
88 | */ | 42 | */ |
89 | static int sysfs_link_sibling(struct sysfs_dirent *sd) | 43 | static void sysfs_link_sibling(struct sysfs_dirent *sd) |
90 | { | 44 | { |
91 | struct rb_node **node = &sd->s_parent->s_dir.children.rb_node; | 45 | struct sysfs_dirent *parent_sd = sd->s_parent; |
92 | struct rb_node *parent = NULL; | 46 | struct sysfs_dirent **pos; |
93 | 47 | ||
94 | if (sysfs_type(sd) == SYSFS_DIR) | 48 | BUG_ON(sd->s_sibling); |
95 | sd->s_parent->s_dir.subdirs++; | 49 | |
96 | 50 | /* Store directory entries in order by ino. This allows | |
97 | while (*node) { | 51 | * readdir to properly restart without having to add a |
98 | struct sysfs_dirent *pos; | 52 | * cursor into the s_dir.children list. |
99 | int result; | 53 | */ |
100 | 54 | for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { | |
101 | pos = to_sysfs_dirent(*node); | 55 | if (sd->s_ino < (*pos)->s_ino) |
102 | parent = *node; | 56 | break; |
103 | result = sysfs_sd_compare(sd, pos); | ||
104 | if (result < 0) | ||
105 | node = &pos->s_rb.rb_left; | ||
106 | else if (result > 0) | ||
107 | node = &pos->s_rb.rb_right; | ||
108 | else | ||
109 | return -EEXIST; | ||
110 | } | 57 | } |
111 | /* add new node and rebalance the tree */ | 58 | sd->s_sibling = *pos; |
112 | rb_link_node(&sd->s_rb, parent, node); | 59 | *pos = sd; |
113 | rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children); | ||
114 | return 0; | ||
115 | } | 60 | } |
116 | 61 | ||
117 | /** | 62 | /** |
118 | * sysfs_unlink_sibling - unlink sysfs_dirent from sibling rbtree | 63 | * sysfs_unlink_sibling - unlink sysfs_dirent from sibling list |
119 | * @sd: sysfs_dirent of interest | 64 | * @sd: sysfs_dirent of interest |
120 | * | 65 | * |
121 | * Unlink @sd from its sibling rbtree which starts from | 66 | * Unlink @sd from its sibling list which starts from |
122 | * sd->s_parent->s_dir.children. | 67 | * sd->s_parent->s_dir.children. |
123 | * | 68 | * |
124 | * Locking: | 69 | * Locking: |
@@ -126,30 +71,18 @@ static int sysfs_link_sibling(struct sysfs_dirent *sd) | |||
126 | */ | 71 | */ |
127 | static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | 72 | static void sysfs_unlink_sibling(struct sysfs_dirent *sd) |
128 | { | 73 | { |
129 | if (sysfs_type(sd) == SYSFS_DIR) | 74 | struct sysfs_dirent **pos; |
130 | sd->s_parent->s_dir.subdirs--; | ||
131 | |||
132 | rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); | ||
133 | } | ||
134 | |||
135 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
136 | |||
137 | /* Test for attributes that want to ignore lockdep for read-locking */ | ||
138 | static bool ignore_lockdep(struct sysfs_dirent *sd) | ||
139 | { | ||
140 | return sysfs_type(sd) == SYSFS_KOBJ_ATTR && | ||
141 | sd->s_attr.attr->ignore_lockdep; | ||
142 | } | ||
143 | 75 | ||
144 | #else | 76 | for (pos = &sd->s_parent->s_dir.children; *pos; |
145 | 77 | pos = &(*pos)->s_sibling) { | |
146 | static inline bool ignore_lockdep(struct sysfs_dirent *sd) | 78 | if (*pos == sd) { |
147 | { | 79 | *pos = sd->s_sibling; |
148 | return true; | 80 | sd->s_sibling = NULL; |
81 | break; | ||
82 | } | ||
83 | } | ||
149 | } | 84 | } |
150 | 85 | ||
151 | #endif | ||
152 | |||
153 | /** | 86 | /** |
154 | * sysfs_get_active - get an active reference to sysfs_dirent | 87 | * sysfs_get_active - get an active reference to sysfs_dirent |
155 | * @sd: sysfs_dirent to get an active reference to | 88 | * @sd: sysfs_dirent to get an active reference to |
@@ -173,17 +106,15 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
173 | return NULL; | 106 | return NULL; |
174 | 107 | ||
175 | t = atomic_cmpxchg(&sd->s_active, v, v + 1); | 108 | t = atomic_cmpxchg(&sd->s_active, v, v + 1); |
176 | if (likely(t == v)) | 109 | if (likely(t == v)) { |
177 | break; | 110 | rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); |
111 | return sd; | ||
112 | } | ||
178 | if (t < 0) | 113 | if (t < 0) |
179 | return NULL; | 114 | return NULL; |
180 | 115 | ||
181 | cpu_relax(); | 116 | cpu_relax(); |
182 | } | 117 | } |
183 | |||
184 | if (likely(!ignore_lockdep(sd))) | ||
185 | rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); | ||
186 | return sd; | ||
187 | } | 118 | } |
188 | 119 | ||
189 | /** | 120 | /** |
@@ -195,21 +126,22 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
195 | */ | 126 | */ |
196 | void sysfs_put_active(struct sysfs_dirent *sd) | 127 | void sysfs_put_active(struct sysfs_dirent *sd) |
197 | { | 128 | { |
129 | struct completion *cmpl; | ||
198 | int v; | 130 | int v; |
199 | 131 | ||
200 | if (unlikely(!sd)) | 132 | if (unlikely(!sd)) |
201 | return; | 133 | return; |
202 | 134 | ||
203 | if (likely(!ignore_lockdep(sd))) | 135 | rwsem_release(&sd->dep_map, 1, _RET_IP_); |
204 | rwsem_release(&sd->dep_map, 1, _RET_IP_); | ||
205 | v = atomic_dec_return(&sd->s_active); | 136 | v = atomic_dec_return(&sd->s_active); |
206 | if (likely(v != SD_DEACTIVATED_BIAS)) | 137 | if (likely(v != SD_DEACTIVATED_BIAS)) |
207 | return; | 138 | return; |
208 | 139 | ||
209 | /* atomic_dec_return() is a mb(), we'll always see the updated | 140 | /* atomic_dec_return() is a mb(), we'll always see the updated |
210 | * sd->u.completion. | 141 | * sd->s_sibling. |
211 | */ | 142 | */ |
212 | complete(sd->u.completion); | 143 | cmpl = (void *)sd->s_sibling; |
144 | complete(cmpl); | ||
213 | } | 145 | } |
214 | 146 | ||
215 | /** | 147 | /** |
@@ -223,16 +155,16 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) | |||
223 | DECLARE_COMPLETION_ONSTACK(wait); | 155 | DECLARE_COMPLETION_ONSTACK(wait); |
224 | int v; | 156 | int v; |
225 | 157 | ||
226 | BUG_ON(!(sd->s_flags & SYSFS_FLAG_REMOVED)); | 158 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); |
227 | 159 | ||
228 | if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF)) | 160 | if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF)) |
229 | return; | 161 | return; |
230 | 162 | ||
231 | sd->u.completion = (void *)&wait; | 163 | sd->s_sibling = (void *)&wait; |
232 | 164 | ||
233 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); | 165 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); |
234 | /* atomic_add_return() is a mb(), put_active() will always see | 166 | /* atomic_add_return() is a mb(), put_active() will always see |
235 | * the updated sd->u.completion. | 167 | * the updated sd->s_sibling. |
236 | */ | 168 | */ |
237 | v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active); | 169 | v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active); |
238 | 170 | ||
@@ -241,11 +173,13 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) | |||
241 | wait_for_completion(&wait); | 173 | wait_for_completion(&wait); |
242 | } | 174 | } |
243 | 175 | ||
176 | sd->s_sibling = NULL; | ||
177 | |||
244 | lock_acquired(&sd->dep_map, _RET_IP_); | 178 | lock_acquired(&sd->dep_map, _RET_IP_); |
245 | rwsem_release(&sd->dep_map, 1, _RET_IP_); | 179 | rwsem_release(&sd->dep_map, 1, _RET_IP_); |
246 | } | 180 | } |
247 | 181 | ||
248 | static int sysfs_alloc_ino(unsigned int *pino) | 182 | static int sysfs_alloc_ino(ino_t *pino) |
249 | { | 183 | { |
250 | int ino, rc; | 184 | int ino, rc; |
251 | 185 | ||
@@ -264,7 +198,7 @@ static int sysfs_alloc_ino(unsigned int *pino) | |||
264 | return rc; | 198 | return rc; |
265 | } | 199 | } |
266 | 200 | ||
267 | static void sysfs_free_ino(unsigned int ino) | 201 | static void sysfs_free_ino(ino_t ino) |
268 | { | 202 | { |
269 | spin_lock(&sysfs_ino_lock); | 203 | spin_lock(&sysfs_ino_lock); |
270 | ida_remove(&sysfs_ino_ida, ino); | 204 | ida_remove(&sysfs_ino_ida, ino); |
@@ -300,16 +234,15 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
300 | static int sysfs_dentry_delete(const struct dentry *dentry) | 234 | static int sysfs_dentry_delete(const struct dentry *dentry) |
301 | { | 235 | { |
302 | struct sysfs_dirent *sd = dentry->d_fsdata; | 236 | struct sysfs_dirent *sd = dentry->d_fsdata; |
303 | return !(sd && !(sd->s_flags & SYSFS_FLAG_REMOVED)); | 237 | return !!(sd->s_flags & SYSFS_FLAG_REMOVED); |
304 | } | 238 | } |
305 | 239 | ||
306 | static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) | 240 | static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) |
307 | { | 241 | { |
308 | struct sysfs_dirent *sd; | 242 | struct sysfs_dirent *sd; |
309 | int is_dir; | 243 | int is_dir; |
310 | int type; | ||
311 | 244 | ||
312 | if (flags & LOOKUP_RCU) | 245 | if (nd->flags & LOOKUP_RCU) |
313 | return -ECHILD; | 246 | return -ECHILD; |
314 | 247 | ||
315 | sd = dentry->d_fsdata; | 248 | sd = dentry->d_fsdata; |
@@ -327,15 +260,6 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) | |||
327 | if (strcmp(dentry->d_name.name, sd->s_name) != 0) | 260 | if (strcmp(dentry->d_name.name, sd->s_name) != 0) |
328 | goto out_bad; | 261 | goto out_bad; |
329 | 262 | ||
330 | /* The sysfs dirent has been moved to a different namespace */ | ||
331 | type = KOBJ_NS_TYPE_NONE; | ||
332 | if (sd->s_parent) { | ||
333 | type = sysfs_ns_type(sd->s_parent); | ||
334 | if (type != KOBJ_NS_TYPE_NONE && | ||
335 | sysfs_info(dentry->d_sb)->ns[type] != sd->s_ns) | ||
336 | goto out_bad; | ||
337 | } | ||
338 | |||
339 | mutex_unlock(&sysfs_mutex); | 263 | mutex_unlock(&sysfs_mutex); |
340 | out_valid: | 264 | out_valid: |
341 | return 1; | 265 | return 1; |
@@ -365,15 +289,18 @@ out_bad: | |||
365 | return 0; | 289 | return 0; |
366 | } | 290 | } |
367 | 291 | ||
368 | static void sysfs_dentry_release(struct dentry *dentry) | 292 | static void sysfs_dentry_iput(struct dentry *dentry, struct inode *inode) |
369 | { | 293 | { |
370 | sysfs_put(dentry->d_fsdata); | 294 | struct sysfs_dirent * sd = dentry->d_fsdata; |
295 | |||
296 | sysfs_put(sd); | ||
297 | iput(inode); | ||
371 | } | 298 | } |
372 | 299 | ||
373 | const struct dentry_operations sysfs_dentry_ops = { | 300 | static const struct dentry_operations sysfs_dentry_ops = { |
374 | .d_revalidate = sysfs_dentry_revalidate, | 301 | .d_revalidate = sysfs_dentry_revalidate, |
375 | .d_delete = sysfs_dentry_delete, | 302 | .d_delete = sysfs_dentry_delete, |
376 | .d_release = sysfs_dentry_release, | 303 | .d_iput = sysfs_dentry_iput, |
377 | }; | 304 | }; |
378 | 305 | ||
379 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | 306 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) |
@@ -456,21 +383,13 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
456 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 383 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
457 | { | 384 | { |
458 | struct sysfs_inode_attrs *ps_iattr; | 385 | struct sysfs_inode_attrs *ps_iattr; |
459 | int ret; | ||
460 | 386 | ||
461 | if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) { | 387 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name)) |
462 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | 388 | return -EEXIST; |
463 | sysfs_ns_type(acxt->parent_sd)? "required": "invalid", | ||
464 | acxt->parent_sd->s_name, sd->s_name); | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | 389 | ||
468 | sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); | ||
469 | sd->s_parent = sysfs_get(acxt->parent_sd); | 390 | sd->s_parent = sysfs_get(acxt->parent_sd); |
470 | 391 | ||
471 | ret = sysfs_link_sibling(sd); | 392 | sysfs_link_sibling(sd); |
472 | if (ret) | ||
473 | return ret; | ||
474 | 393 | ||
475 | /* Update timestamps on the parent */ | 394 | /* Update timestamps on the parent */ |
476 | ps_iattr = acxt->parent_sd->s_iattr; | 395 | ps_iattr = acxt->parent_sd->s_iattr; |
@@ -485,18 +404,20 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
485 | /** | 404 | /** |
486 | * sysfs_pathname - return full path to sysfs dirent | 405 | * sysfs_pathname - return full path to sysfs dirent |
487 | * @sd: sysfs_dirent whose path we want | 406 | * @sd: sysfs_dirent whose path we want |
488 | * @path: caller allocated buffer of size PATH_MAX | 407 | * @path: caller allocated buffer |
489 | * | 408 | * |
490 | * Gives the name "/" to the sysfs_root entry; any path returned | 409 | * Gives the name "/" to the sysfs_root entry; any path returned |
491 | * is relative to wherever sysfs is mounted. | 410 | * is relative to wherever sysfs is mounted. |
411 | * | ||
412 | * XXX: does no error checking on @path size | ||
492 | */ | 413 | */ |
493 | static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) | 414 | static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) |
494 | { | 415 | { |
495 | if (sd->s_parent) { | 416 | if (sd->s_parent) { |
496 | sysfs_pathname(sd->s_parent, path); | 417 | sysfs_pathname(sd->s_parent, path); |
497 | strlcat(path, "/", PATH_MAX); | 418 | strcat(path, "/"); |
498 | } | 419 | } |
499 | strlcat(path, sd->s_name, PATH_MAX); | 420 | strcat(path, sd->s_name); |
500 | return path; | 421 | return path; |
501 | } | 422 | } |
502 | 423 | ||
@@ -529,11 +450,9 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
529 | char *path = kzalloc(PATH_MAX, GFP_KERNEL); | 450 | char *path = kzalloc(PATH_MAX, GFP_KERNEL); |
530 | WARN(1, KERN_WARNING | 451 | WARN(1, KERN_WARNING |
531 | "sysfs: cannot create duplicate filename '%s'\n", | 452 | "sysfs: cannot create duplicate filename '%s'\n", |
532 | (path == NULL) ? sd->s_name | 453 | (path == NULL) ? sd->s_name : |
533 | : (sysfs_pathname(acxt->parent_sd, path), | 454 | strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"), |
534 | strlcat(path, "/", PATH_MAX), | 455 | sd->s_name)); |
535 | strlcat(path, sd->s_name, PATH_MAX), | ||
536 | path)); | ||
537 | kfree(path); | 456 | kfree(path); |
538 | } | 457 | } |
539 | 458 | ||
@@ -571,7 +490,7 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
571 | } | 490 | } |
572 | 491 | ||
573 | sd->s_flags |= SYSFS_FLAG_REMOVED; | 492 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
574 | sd->u.removed_list = acxt->removed; | 493 | sd->s_sibling = acxt->removed; |
575 | acxt->removed = sd; | 494 | acxt->removed = sd; |
576 | } | 495 | } |
577 | 496 | ||
@@ -595,7 +514,8 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
595 | while (acxt->removed) { | 514 | while (acxt->removed) { |
596 | struct sysfs_dirent *sd = acxt->removed; | 515 | struct sysfs_dirent *sd = acxt->removed; |
597 | 516 | ||
598 | acxt->removed = sd->u.removed_list; | 517 | acxt->removed = sd->s_sibling; |
518 | sd->s_sibling = NULL; | ||
599 | 519 | ||
600 | sysfs_deactivate(sd); | 520 | sysfs_deactivate(sd); |
601 | unmap_bin_file(sd); | 521 | unmap_bin_file(sd); |
@@ -620,28 +540,12 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
620 | const void *ns, | 540 | const void *ns, |
621 | const unsigned char *name) | 541 | const unsigned char *name) |
622 | { | 542 | { |
623 | struct rb_node *node = parent_sd->s_dir.children.rb_node; | 543 | struct sysfs_dirent *sd; |
624 | unsigned int hash; | ||
625 | |||
626 | if (!!sysfs_ns_type(parent_sd) != !!ns) { | ||
627 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | ||
628 | sysfs_ns_type(parent_sd)? "required": "invalid", | ||
629 | parent_sd->s_name, name); | ||
630 | return NULL; | ||
631 | } | ||
632 | 544 | ||
633 | hash = sysfs_name_hash(ns, name); | 545 | for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) { |
634 | while (node) { | 546 | if (ns && sd->s_ns && (sd->s_ns != ns)) |
635 | struct sysfs_dirent *sd; | 547 | continue; |
636 | int result; | 548 | if (!strcmp(sd->s_name, name)) |
637 | |||
638 | sd = to_sysfs_dirent(node); | ||
639 | result = sysfs_name_compare(hash, ns, name, sd); | ||
640 | if (result < 0) | ||
641 | node = node->rb_left; | ||
642 | else if (result > 0) | ||
643 | node = node->rb_right; | ||
644 | else | ||
645 | return sd; | 549 | return sd; |
646 | } | 550 | } |
647 | return NULL; | 551 | return NULL; |
@@ -757,9 +661,6 @@ int sysfs_create_dir(struct kobject * kobj) | |||
757 | else | 661 | else |
758 | parent_sd = &sysfs_root; | 662 | parent_sd = &sysfs_root; |
759 | 663 | ||
760 | if (!parent_sd) | ||
761 | return -ENOENT; | ||
762 | |||
763 | if (sysfs_ns_type(parent_sd)) | 664 | if (sysfs_ns_type(parent_sd)) |
764 | ns = kobj->ktype->namespace(kobj); | 665 | ns = kobj->ktype->namespace(kobj); |
765 | type = sysfs_read_ns_type(kobj); | 666 | type = sysfs_read_ns_type(kobj); |
@@ -771,7 +672,7 @@ int sysfs_create_dir(struct kobject * kobj) | |||
771 | } | 672 | } |
772 | 673 | ||
773 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | 674 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, |
774 | unsigned int flags) | 675 | struct nameidata *nd) |
775 | { | 676 | { |
776 | struct dentry *ret = NULL; | 677 | struct dentry *ret = NULL; |
777 | struct dentry *parent = dentry->d_parent; | 678 | struct dentry *parent = dentry->d_parent; |
@@ -793,7 +694,6 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
793 | ret = ERR_PTR(-ENOENT); | 694 | ret = ERR_PTR(-ENOENT); |
794 | goto out_unlock; | 695 | goto out_unlock; |
795 | } | 696 | } |
796 | dentry->d_fsdata = sysfs_get(sd); | ||
797 | 697 | ||
798 | /* attach dentry and inode */ | 698 | /* attach dentry and inode */ |
799 | inode = sysfs_get_inode(dir->i_sb, sd); | 699 | inode = sysfs_get_inode(dir->i_sb, sd); |
@@ -803,7 +703,16 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
803 | } | 703 | } |
804 | 704 | ||
805 | /* instantiate and hash dentry */ | 705 | /* instantiate and hash dentry */ |
806 | ret = d_materialise_unique(dentry, inode); | 706 | ret = d_find_alias(inode); |
707 | if (!ret) { | ||
708 | d_set_d_op(dentry, &sysfs_dentry_ops); | ||
709 | dentry->d_fsdata = sysfs_get(sd); | ||
710 | d_add(dentry, inode); | ||
711 | } else { | ||
712 | d_move(ret, dentry); | ||
713 | iput(inode); | ||
714 | } | ||
715 | |||
807 | out_unlock: | 716 | out_unlock: |
808 | mutex_unlock(&sysfs_mutex); | 717 | mutex_unlock(&sysfs_mutex); |
809 | return ret; | 718 | return ret; |
@@ -835,19 +744,21 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd) | |||
835 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | 744 | static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) |
836 | { | 745 | { |
837 | struct sysfs_addrm_cxt acxt; | 746 | struct sysfs_addrm_cxt acxt; |
838 | struct rb_node *pos; | 747 | struct sysfs_dirent **pos; |
839 | 748 | ||
840 | if (!dir_sd) | 749 | if (!dir_sd) |
841 | return; | 750 | return; |
842 | 751 | ||
843 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); | 752 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); |
844 | sysfs_addrm_start(&acxt, dir_sd); | 753 | sysfs_addrm_start(&acxt, dir_sd); |
845 | pos = rb_first(&dir_sd->s_dir.children); | 754 | pos = &dir_sd->s_dir.children; |
846 | while (pos) { | 755 | while (*pos) { |
847 | struct sysfs_dirent *sd = to_sysfs_dirent(pos); | 756 | struct sysfs_dirent *sd = *pos; |
848 | pos = rb_next(pos); | 757 | |
849 | if (sysfs_type(sd) != SYSFS_DIR) | 758 | if (sysfs_type(sd) != SYSFS_DIR) |
850 | sysfs_remove_one(&acxt, sd); | 759 | sysfs_remove_one(&acxt, sd); |
760 | else | ||
761 | pos = &(*pos)->s_sibling; | ||
851 | } | 762 | } |
852 | sysfs_addrm_finish(&acxt); | 763 | sysfs_addrm_finish(&acxt); |
853 | 764 | ||
@@ -878,6 +789,7 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
878 | struct sysfs_dirent *new_parent_sd, const void *new_ns, | 789 | struct sysfs_dirent *new_parent_sd, const void *new_ns, |
879 | const char *new_name) | 790 | const char *new_name) |
880 | { | 791 | { |
792 | const char *dup_name = NULL; | ||
881 | int error; | 793 | int error; |
882 | 794 | ||
883 | mutex_lock(&sysfs_mutex); | 795 | mutex_lock(&sysfs_mutex); |
@@ -894,26 +806,28 @@ int sysfs_rename(struct sysfs_dirent *sd, | |||
894 | /* rename sysfs_dirent */ | 806 | /* rename sysfs_dirent */ |
895 | if (strcmp(sd->s_name, new_name) != 0) { | 807 | if (strcmp(sd->s_name, new_name) != 0) { |
896 | error = -ENOMEM; | 808 | error = -ENOMEM; |
897 | new_name = kstrdup(new_name, GFP_KERNEL); | 809 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); |
898 | if (!new_name) | 810 | if (!new_name) |
899 | goto out; | 811 | goto out; |
900 | 812 | ||
901 | kfree(sd->s_name); | 813 | dup_name = sd->s_name; |
902 | sd->s_name = new_name; | 814 | sd->s_name = new_name; |
903 | } | 815 | } |
904 | 816 | ||
905 | /* Move to the appropriate place in the appropriate directories rbtree. */ | 817 | /* Remove from old parent's list and insert into new parent's list. */ |
906 | sysfs_unlink_sibling(sd); | 818 | if (sd->s_parent != new_parent_sd) { |
907 | sysfs_get(new_parent_sd); | 819 | sysfs_unlink_sibling(sd); |
908 | sysfs_put(sd->s_parent); | 820 | sysfs_get(new_parent_sd); |
821 | sysfs_put(sd->s_parent); | ||
822 | sd->s_parent = new_parent_sd; | ||
823 | sysfs_link_sibling(sd); | ||
824 | } | ||
909 | sd->s_ns = new_ns; | 825 | sd->s_ns = new_ns; |
910 | sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); | ||
911 | sd->s_parent = new_parent_sd; | ||
912 | sysfs_link_sibling(sd); | ||
913 | 826 | ||
914 | error = 0; | 827 | error = 0; |
915 | out: | 828 | out: |
916 | mutex_unlock(&sysfs_mutex); | 829 | mutex_unlock(&sysfs_mutex); |
830 | kfree(dup_name); | ||
917 | return error; | 831 | return error; |
918 | } | 832 | } |
919 | 833 | ||
@@ -956,37 +870,23 @@ static int sysfs_dir_release(struct inode *inode, struct file *filp) | |||
956 | } | 870 | } |
957 | 871 | ||
958 | static struct sysfs_dirent *sysfs_dir_pos(const void *ns, | 872 | static struct sysfs_dirent *sysfs_dir_pos(const void *ns, |
959 | struct sysfs_dirent *parent_sd, loff_t hash, struct sysfs_dirent *pos) | 873 | struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) |
960 | { | 874 | { |
961 | if (pos) { | 875 | if (pos) { |
962 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && | 876 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && |
963 | pos->s_parent == parent_sd && | 877 | pos->s_parent == parent_sd && |
964 | hash == pos->s_hash; | 878 | ino == pos->s_ino; |
965 | sysfs_put(pos); | 879 | sysfs_put(pos); |
966 | if (!valid) | 880 | if (!valid) |
967 | pos = NULL; | 881 | pos = NULL; |
968 | } | 882 | } |
969 | if (!pos && (hash > 1) && (hash < INT_MAX)) { | 883 | if (!pos && (ino > 1) && (ino < INT_MAX)) { |
970 | struct rb_node *node = parent_sd->s_dir.children.rb_node; | 884 | pos = parent_sd->s_dir.children; |
971 | while (node) { | 885 | while (pos && (ino > pos->s_ino)) |
972 | pos = to_sysfs_dirent(node); | 886 | pos = pos->s_sibling; |
973 | |||
974 | if (hash < pos->s_hash) | ||
975 | node = node->rb_left; | ||
976 | else if (hash > pos->s_hash) | ||
977 | node = node->rb_right; | ||
978 | else | ||
979 | break; | ||
980 | } | ||
981 | } | ||
982 | /* Skip over entries in the wrong namespace */ | ||
983 | while (pos && pos->s_ns != ns) { | ||
984 | struct rb_node *node = rb_next(&pos->s_rb); | ||
985 | if (!node) | ||
986 | pos = NULL; | ||
987 | else | ||
988 | pos = to_sysfs_dirent(node); | ||
989 | } | 887 | } |
888 | while (pos && pos->s_ns && pos->s_ns != ns) | ||
889 | pos = pos->s_sibling; | ||
990 | return pos; | 890 | return pos; |
991 | } | 891 | } |
992 | 892 | ||
@@ -994,13 +894,10 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns, | |||
994 | struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) | 894 | struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) |
995 | { | 895 | { |
996 | pos = sysfs_dir_pos(ns, parent_sd, ino, pos); | 896 | pos = sysfs_dir_pos(ns, parent_sd, ino, pos); |
997 | if (pos) do { | 897 | if (pos) |
998 | struct rb_node *node = rb_next(&pos->s_rb); | 898 | pos = pos->s_sibling; |
999 | if (!node) | 899 | while (pos && pos->s_ns && pos->s_ns != ns) |
1000 | pos = NULL; | 900 | pos = pos->s_sibling; |
1001 | else | ||
1002 | pos = to_sysfs_dirent(node); | ||
1003 | } while (pos && pos->s_ns != ns); | ||
1004 | return pos; | 901 | return pos; |
1005 | } | 902 | } |
1006 | 903 | ||
@@ -1041,7 +938,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
1041 | len = strlen(name); | 938 | len = strlen(name); |
1042 | ino = pos->s_ino; | 939 | ino = pos->s_ino; |
1043 | type = dt_type(pos); | 940 | type = dt_type(pos); |
1044 | filp->f_pos = pos->s_hash; | 941 | filp->f_pos = ino; |
1045 | filp->private_data = sysfs_get(pos); | 942 | filp->private_data = sysfs_get(pos); |
1046 | 943 | ||
1047 | mutex_unlock(&sysfs_mutex); | 944 | mutex_unlock(&sysfs_mutex); |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 602f56db044..1ad8c93c1b8 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -466,6 +466,9 @@ void sysfs_notify(struct kobject *k, const char *dir, const char *attr) | |||
466 | mutex_lock(&sysfs_mutex); | 466 | mutex_lock(&sysfs_mutex); |
467 | 467 | ||
468 | if (sd && dir) | 468 | if (sd && dir) |
469 | /* Only directories are tagged, so no need to pass | ||
470 | * a tag explicitly. | ||
471 | */ | ||
469 | sd = sysfs_find_dirent(sd, NULL, dir); | 472 | sd = sysfs_find_dirent(sd, NULL, dir); |
470 | if (sd && attr) | 473 | if (sd && attr) |
471 | sd = sysfs_find_dirent(sd, NULL, attr); | 474 | sd = sysfs_find_dirent(sd, NULL, attr); |
@@ -485,62 +488,17 @@ const struct file_operations sysfs_file_operations = { | |||
485 | .poll = sysfs_poll, | 488 | .poll = sysfs_poll, |
486 | }; | 489 | }; |
487 | 490 | ||
488 | static int sysfs_attr_ns(struct kobject *kobj, const struct attribute *attr, | ||
489 | const void **pns) | ||
490 | { | ||
491 | struct sysfs_dirent *dir_sd = kobj->sd; | ||
492 | const struct sysfs_ops *ops; | ||
493 | const void *ns = NULL; | ||
494 | int err; | ||
495 | |||
496 | if (!dir_sd) { | ||
497 | WARN(1, KERN_ERR "sysfs: kobject %s without dirent\n", | ||
498 | kobject_name(kobj)); | ||
499 | return -ENOENT; | ||
500 | } | ||
501 | |||
502 | err = 0; | ||
503 | if (!sysfs_ns_type(dir_sd)) | ||
504 | goto out; | ||
505 | |||
506 | err = -EINVAL; | ||
507 | if (!kobj->ktype) | ||
508 | goto out; | ||
509 | ops = kobj->ktype->sysfs_ops; | ||
510 | if (!ops) | ||
511 | goto out; | ||
512 | if (!ops->namespace) | ||
513 | goto out; | ||
514 | |||
515 | err = 0; | ||
516 | ns = ops->namespace(kobj, attr); | ||
517 | out: | ||
518 | if (err) { | ||
519 | WARN(1, KERN_ERR "missing sysfs namespace attribute operation for " | ||
520 | "kobject: %s\n", kobject_name(kobj)); | ||
521 | } | ||
522 | *pns = ns; | ||
523 | return err; | ||
524 | } | ||
525 | |||
526 | int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | 491 | int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, |
527 | const struct attribute *attr, int type, umode_t amode) | 492 | const struct attribute *attr, int type, mode_t amode) |
528 | { | 493 | { |
529 | umode_t mode = (amode & S_IALLUGO) | S_IFREG; | 494 | umode_t mode = (amode & S_IALLUGO) | S_IFREG; |
530 | struct sysfs_addrm_cxt acxt; | 495 | struct sysfs_addrm_cxt acxt; |
531 | struct sysfs_dirent *sd; | 496 | struct sysfs_dirent *sd; |
532 | const void *ns; | ||
533 | int rc; | 497 | int rc; |
534 | 498 | ||
535 | rc = sysfs_attr_ns(dir_sd->s_dir.kobj, attr, &ns); | ||
536 | if (rc) | ||
537 | return rc; | ||
538 | |||
539 | sd = sysfs_new_dirent(attr->name, mode, type); | 499 | sd = sysfs_new_dirent(attr->name, mode, type); |
540 | if (!sd) | 500 | if (!sd) |
541 | return -ENOMEM; | 501 | return -ENOMEM; |
542 | |||
543 | sd->s_ns = ns; | ||
544 | sd->s_attr.attr = (void *)attr; | 502 | sd->s_attr.attr = (void *)attr; |
545 | sysfs_dirent_init_lockdep(sd); | 503 | sysfs_dirent_init_lockdep(sd); |
546 | 504 | ||
@@ -624,21 +582,16 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | |||
624 | * | 582 | * |
625 | */ | 583 | */ |
626 | int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, | 584 | int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, |
627 | umode_t mode) | 585 | mode_t mode) |
628 | { | 586 | { |
629 | struct sysfs_dirent *sd; | 587 | struct sysfs_dirent *sd; |
630 | struct iattr newattrs; | 588 | struct iattr newattrs; |
631 | const void *ns; | ||
632 | int rc; | 589 | int rc; |
633 | 590 | ||
634 | rc = sysfs_attr_ns(kobj, attr, &ns); | ||
635 | if (rc) | ||
636 | return rc; | ||
637 | |||
638 | mutex_lock(&sysfs_mutex); | 591 | mutex_lock(&sysfs_mutex); |
639 | 592 | ||
640 | rc = -ENOENT; | 593 | rc = -ENOENT; |
641 | sd = sysfs_find_dirent(kobj->sd, ns, attr->name); | 594 | sd = sysfs_find_dirent(kobj->sd, NULL, attr->name); |
642 | if (!sd) | 595 | if (!sd) |
643 | goto out; | 596 | goto out; |
644 | 597 | ||
@@ -663,12 +616,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); | |||
663 | 616 | ||
664 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) | 617 | void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) |
665 | { | 618 | { |
666 | const void *ns; | 619 | sysfs_hash_and_remove(kobj->sd, NULL, attr->name); |
667 | |||
668 | if (sysfs_attr_ns(kobj, attr, &ns)) | ||
669 | return; | ||
670 | |||
671 | sysfs_hash_and_remove(kobj->sd, ns, attr->name); | ||
672 | } | 620 | } |
673 | 621 | ||
674 | void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr) | 622 | void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr) |
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 2df555c66d5..194414f8298 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
@@ -33,7 +33,7 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, | |||
33 | int error = 0, i; | 33 | int error = 0, i; |
34 | 34 | ||
35 | for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { | 35 | for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { |
36 | umode_t mode = 0; | 36 | mode_t mode = 0; |
37 | 37 | ||
38 | /* in update mode, we're changing the permissions or | 38 | /* in update mode, we're changing the permissions or |
39 | * visibility. Do this by first removing then | 39 | * visibility. Do this by first removing then |
@@ -67,11 +67,7 @@ static int internal_create_group(struct kobject *kobj, int update, | |||
67 | /* Updates may happen before the object has been instantiated */ | 67 | /* Updates may happen before the object has been instantiated */ |
68 | if (unlikely(update && !kobj->sd)) | 68 | if (unlikely(update && !kobj->sd)) |
69 | return -EINVAL; | 69 | return -EINVAL; |
70 | if (!grp->attrs) { | 70 | |
71 | WARN(1, "sysfs: attrs not set by subsystem for group: %s/%s\n", | ||
72 | kobj->name, grp->name ? "" : grp->name); | ||
73 | return -EINVAL; | ||
74 | } | ||
75 | if (grp->name) { | 71 | if (grp->name) { |
76 | error = sysfs_create_subdir(kobj, grp->name, &sd); | 72 | error = sysfs_create_subdir(kobj, grp->name, &sd); |
77 | if (error) | 73 | if (error) |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 0ce3ccf7f40..e3f091a81c7 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -62,8 +62,8 @@ static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | |||
62 | 62 | ||
63 | /* assign default attributes */ | 63 | /* assign default attributes */ |
64 | iattrs->ia_mode = sd->s_mode; | 64 | iattrs->ia_mode = sd->s_mode; |
65 | iattrs->ia_uid = GLOBAL_ROOT_UID; | 65 | iattrs->ia_uid = 0; |
66 | iattrs->ia_gid = GLOBAL_ROOT_GID; | 66 | iattrs->ia_gid = 0; |
67 | iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; | 67 | iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; |
68 | 68 | ||
69 | return attrs; | 69 | return attrs; |
@@ -136,13 +136,12 @@ 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 | if (!sd->s_iattr) { | ||
140 | sd->s_iattr = sysfs_init_inode_attrs(sd); | ||
141 | if (!sd->s_iattr) | ||
142 | return -ENOMEM; | ||
143 | } | ||
144 | |||
145 | iattrs = sd->s_iattr; | 139 | iattrs = sd->s_iattr; |
140 | if (!iattrs) | ||
141 | iattrs = sysfs_init_inode_attrs(sd); | ||
142 | if (!iattrs) | ||
143 | return -ENOMEM; | ||
144 | |||
146 | old_secdata = iattrs->ia_secdata; | 145 | old_secdata = iattrs->ia_secdata; |
147 | old_secdata_len = iattrs->ia_secdata_len; | 146 | old_secdata_len = iattrs->ia_secdata_len; |
148 | 147 | ||
@@ -188,7 +187,7 @@ out: | |||
188 | return error; | 187 | return error; |
189 | } | 188 | } |
190 | 189 | ||
191 | static inline void set_default_inode_attr(struct inode * inode, umode_t mode) | 190 | static inline void set_default_inode_attr(struct inode * inode, mode_t mode) |
192 | { | 191 | { |
193 | inode->i_mode = mode; | 192 | inode->i_mode = mode; |
194 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 193 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
@@ -203,6 +202,18 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
203 | inode->i_ctime = iattr->ia_ctime; | 202 | inode->i_ctime = iattr->ia_ctime; |
204 | } | 203 | } |
205 | 204 | ||
205 | static int sysfs_count_nlink(struct sysfs_dirent *sd) | ||
206 | { | ||
207 | struct sysfs_dirent *child; | ||
208 | int nr = 0; | ||
209 | |||
210 | for (child = sd->s_dir.children; child; child = child->s_sibling) | ||
211 | if (sysfs_type(child) == SYSFS_DIR) | ||
212 | nr++; | ||
213 | |||
214 | return nr + 2; | ||
215 | } | ||
216 | |||
206 | static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) | 217 | static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) |
207 | { | 218 | { |
208 | struct sysfs_inode_attrs *iattrs = sd->s_iattr; | 219 | struct sysfs_inode_attrs *iattrs = sd->s_iattr; |
@@ -219,7 +230,7 @@ static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
219 | } | 230 | } |
220 | 231 | ||
221 | if (sysfs_type(sd) == SYSFS_DIR) | 232 | if (sysfs_type(sd) == SYSFS_DIR) |
222 | set_nlink(inode, sd->s_dir.subdirs + 2); | 233 | inode->i_nlink = sysfs_count_nlink(sd); |
223 | } | 234 | } |
224 | 235 | ||
225 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | 236 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) |
@@ -310,7 +321,7 @@ void sysfs_evict_inode(struct inode *inode) | |||
310 | struct sysfs_dirent *sd = inode->i_private; | 321 | struct sysfs_dirent *sd = inode->i_private; |
311 | 322 | ||
312 | truncate_inode_pages(&inode->i_data, 0); | 323 | truncate_inode_pages(&inode->i_data, 0); |
313 | clear_inode(inode); | 324 | end_writeback(inode); |
314 | sysfs_put(sd); | 325 | sysfs_put(sd); |
315 | } | 326 | } |
316 | 327 | ||
@@ -319,15 +330,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const cha | |||
319 | struct sysfs_addrm_cxt acxt; | 330 | struct sysfs_addrm_cxt acxt; |
320 | struct sysfs_dirent *sd; | 331 | struct sysfs_dirent *sd; |
321 | 332 | ||
322 | if (!dir_sd) { | 333 | if (!dir_sd) |
323 | WARN(1, KERN_WARNING "sysfs: can not remove '%s', no directory\n", | ||
324 | name); | ||
325 | return -ENOENT; | 334 | return -ENOENT; |
326 | } | ||
327 | 335 | ||
328 | sysfs_addrm_start(&acxt, dir_sd); | 336 | sysfs_addrm_start(&acxt, dir_sd); |
329 | 337 | ||
330 | sd = sysfs_find_dirent(dir_sd, ns, name); | 338 | sd = sysfs_find_dirent(dir_sd, ns, name); |
339 | if (sd && (sd->s_ns != ns)) | ||
340 | sd = NULL; | ||
331 | if (sd) | 341 | if (sd) |
332 | sysfs_remove_one(&acxt, sd); | 342 | sysfs_remove_one(&acxt, sd); |
333 | 343 | ||
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index db940a9be04..e34f0d99ea4 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_IRUGO | S_IXUGO, | 39 | .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, |
40 | .s_ino = 1, | 40 | .s_ino = 1, |
41 | }; | 41 | }; |
42 | 42 | ||
@@ -61,14 +61,14 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) | |||
61 | } | 61 | } |
62 | 62 | ||
63 | /* instantiate and link root dentry */ | 63 | /* instantiate and link root dentry */ |
64 | root = d_make_root(inode); | 64 | root = d_alloc_root(inode); |
65 | if (!root) { | 65 | if (!root) { |
66 | pr_debug("%s: could not get root dentry!\n",__func__); | 66 | pr_debug("%s: could not get root dentry!\n",__func__); |
67 | iput(inode); | ||
67 | return -ENOMEM; | 68 | return -ENOMEM; |
68 | } | 69 | } |
69 | root->d_fsdata = &sysfs_root; | 70 | root->d_fsdata = &sysfs_root; |
70 | sb->s_root = root; | 71 | sb->s_root = root; |
71 | sb->s_d_op = &sysfs_dentry_ops; | ||
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
74 | 74 | ||
@@ -118,12 +118,13 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
118 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) | 118 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) |
119 | info->ns[type] = kobj_ns_grab_current(type); | 119 | info->ns[type] = kobj_ns_grab_current(type); |
120 | 120 | ||
121 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); | 121 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info); |
122 | if (IS_ERR(sb) || sb->s_fs_info != info) | 122 | if (IS_ERR(sb) || sb->s_fs_info != info) |
123 | free_sysfs_super_info(info); | 123 | free_sysfs_super_info(info); |
124 | if (IS_ERR(sb)) | 124 | if (IS_ERR(sb)) |
125 | return ERR_CAST(sb); | 125 | return ERR_CAST(sb); |
126 | if (!sb->s_root) { | 126 | if (!sb->s_root) { |
127 | sb->s_flags = flags; | ||
127 | error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); | 128 | error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); |
128 | if (error) { | 129 | if (error) { |
129 | deactivate_locked_super(sb); | 130 | deactivate_locked_super(sb); |
@@ -149,7 +150,6 @@ static struct file_system_type sysfs_fs_type = { | |||
149 | .name = "sysfs", | 150 | .name = "sysfs", |
150 | .mount = sysfs_mount, | 151 | .mount = sysfs_mount, |
151 | .kill_sb = sysfs_kill_sb, | 152 | .kill_sb = sysfs_kill_sb, |
152 | .fs_flags = FS_USERNS_MOUNT, | ||
153 | }; | 153 | }; |
154 | 154 | ||
155 | int __init sysfs_init(void) | 155 | int __init sysfs_init(void) |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 3c9eb5624f5..a7ac78f8e67 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -113,7 +113,7 @@ int sysfs_create_link(struct kobject *kobj, struct kobject *target, | |||
113 | * @target: object we're pointing to. | 113 | * @target: object we're pointing to. |
114 | * @name: name of the symlink. | 114 | * @name: name of the symlink. |
115 | * | 115 | * |
116 | * This function does the same as sysfs_create_link(), but it | 116 | * This function does the same as sysf_create_link(), but it |
117 | * doesn't warn if the link already exists. | 117 | * doesn't warn if the link already exists. |
118 | */ | 118 | */ |
119 | int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target, | 119 | int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target, |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index d73c0932bbd..845ab3ad229 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -11,17 +11,14 @@ | |||
11 | #include <linux/lockdep.h> | 11 | #include <linux/lockdep.h> |
12 | #include <linux/kobject_ns.h> | 12 | #include <linux/kobject_ns.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/rbtree.h> | ||
15 | 14 | ||
16 | struct sysfs_open_dirent; | 15 | struct sysfs_open_dirent; |
17 | 16 | ||
18 | /* type-specific structures for sysfs_dirent->s_* union members */ | 17 | /* type-specific structures for sysfs_dirent->s_* union members */ |
19 | struct sysfs_elem_dir { | 18 | struct sysfs_elem_dir { |
20 | struct kobject *kobj; | 19 | struct kobject *kobj; |
21 | 20 | /* children list starts here and goes through sd->s_sibling */ | |
22 | unsigned long subdirs; | 21 | struct sysfs_dirent *children; |
23 | /* children rbtree starts here and goes through sd->s_rb */ | ||
24 | struct rb_root children; | ||
25 | }; | 22 | }; |
26 | 23 | ||
27 | struct sysfs_elem_symlink { | 24 | struct sysfs_elem_symlink { |
@@ -59,17 +56,10 @@ struct sysfs_dirent { | |||
59 | struct lockdep_map dep_map; | 56 | struct lockdep_map dep_map; |
60 | #endif | 57 | #endif |
61 | struct sysfs_dirent *s_parent; | 58 | struct sysfs_dirent *s_parent; |
59 | struct sysfs_dirent *s_sibling; | ||
62 | const char *s_name; | 60 | const char *s_name; |
63 | 61 | ||
64 | struct rb_node s_rb; | ||
65 | |||
66 | union { | ||
67 | struct completion *completion; | ||
68 | struct sysfs_dirent *removed_list; | ||
69 | } u; | ||
70 | |||
71 | const void *s_ns; /* namespace tag */ | 62 | const void *s_ns; /* namespace tag */ |
72 | unsigned int s_hash; /* ns + name hash */ | ||
73 | union { | 63 | union { |
74 | struct sysfs_elem_dir s_dir; | 64 | struct sysfs_elem_dir s_dir; |
75 | struct sysfs_elem_symlink s_symlink; | 65 | struct sysfs_elem_symlink s_symlink; |
@@ -77,9 +67,9 @@ struct sysfs_dirent { | |||
77 | struct sysfs_elem_bin_attr s_bin_attr; | 67 | struct sysfs_elem_bin_attr s_bin_attr; |
78 | }; | 68 | }; |
79 | 69 | ||
80 | unsigned short s_flags; | 70 | unsigned int s_flags; |
81 | umode_t s_mode; | 71 | unsigned short s_mode; |
82 | unsigned int s_ino; | 72 | ino_t s_ino; |
83 | struct sysfs_inode_attrs *s_iattr; | 73 | struct sysfs_inode_attrs *s_iattr; |
84 | }; | 74 | }; |
85 | 75 | ||
@@ -94,11 +84,11 @@ struct sysfs_dirent { | |||
94 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) | 84 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) |
95 | 85 | ||
96 | /* identify any namespace tag on sysfs_dirents */ | 86 | /* identify any namespace tag on sysfs_dirents */ |
97 | #define SYSFS_NS_TYPE_MASK 0xf00 | 87 | #define SYSFS_NS_TYPE_MASK 0xff00 |
98 | #define SYSFS_NS_TYPE_SHIFT 8 | 88 | #define SYSFS_NS_TYPE_SHIFT 8 |
99 | 89 | ||
100 | #define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) | 90 | #define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) |
101 | #define SYSFS_FLAG_REMOVED 0x02000 | 91 | #define SYSFS_FLAG_REMOVED 0x020000 |
102 | 92 | ||
103 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | 93 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) |
104 | { | 94 | { |
@@ -157,7 +147,6 @@ extern struct kmem_cache *sysfs_dir_cachep; | |||
157 | */ | 147 | */ |
158 | extern struct mutex sysfs_mutex; | 148 | extern struct mutex sysfs_mutex; |
159 | extern spinlock_t sysfs_assoc_lock; | 149 | extern spinlock_t sysfs_assoc_lock; |
160 | extern const struct dentry_operations sysfs_dentry_ops; | ||
161 | 150 | ||
162 | extern const struct file_operations sysfs_dir_operations; | 151 | extern const struct file_operations sysfs_dir_operations; |
163 | extern const struct inode_operations sysfs_dir_inode_operations; | 152 | extern const struct inode_operations sysfs_dir_inode_operations; |
@@ -229,7 +218,7 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, | |||
229 | const struct attribute *attr, int type); | 218 | const struct attribute *attr, int type); |
230 | 219 | ||
231 | int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, | 220 | int sysfs_add_file_mode(struct sysfs_dirent *dir_sd, |
232 | const struct attribute *attr, int type, umode_t amode); | 221 | const struct attribute *attr, int type, mode_t amode); |
233 | /* | 222 | /* |
234 | * bin.c | 223 | * bin.c |
235 | */ | 224 | */ |