aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r--fs/sysfs/dir.c335
1 files changed, 116 insertions, 219 deletions
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
28DEFINE_MUTEX(sysfs_mutex); 27DEFINE_MUTEX(sysfs_mutex);
29DEFINE_SPINLOCK(sysfs_assoc_lock); 28DEFINE_SPINLOCK(sysfs_assoc_lock);
30 29
31#define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb);
32
33static DEFINE_SPINLOCK(sysfs_ino_lock); 30static DEFINE_SPINLOCK(sysfs_ino_lock);
34static DEFINE_IDA(sysfs_ino_ida); 31static 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 */
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
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 */
89static int sysfs_link_sibling(struct sysfs_dirent *sd) 43static 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 */
127static void sysfs_unlink_sibling(struct sysfs_dirent *sd) 72static 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 */
138static 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) {
146static 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 */
196void sysfs_put_active(struct sysfs_dirent *sd) 127void 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
248static int sysfs_alloc_ino(unsigned int *pino) 182static 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
267static void sysfs_free_ino(unsigned int ino) 201static 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)
300static int sysfs_dentry_delete(const struct dentry *dentry) 234static 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
306static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) 240static 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);
340out_valid: 264out_valid:
341 return 1; 265 return 1;
@@ -365,15 +289,18 @@ out_bad:
365 return 0; 289 return 0;
366} 290}
367 291
368static void sysfs_dentry_release(struct dentry *dentry) 292static 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
373const struct dentry_operations sysfs_dentry_ops = { 300static 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
379struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) 306struct 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,
456int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) 383int __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 */
493static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) 414static 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
773static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, 674static 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)
835static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) 744static 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
958static struct sysfs_dirent *sysfs_dir_pos(const void *ns, 872static 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);