diff options
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 754 |
1 files changed, 199 insertions, 555 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 83e76b3813c9..9161db4d6b5c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -1,5 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * dir.c - Operations for sysfs directories. | 2 | * fs/sysfs/dir.c - sysfs core and dir operation implementation |
3 | * | ||
4 | * Copyright (c) 2001-3 Patrick Mochel | ||
5 | * Copyright (c) 2007 SUSE Linux Products GmbH | ||
6 | * Copyright (c) 2007 Tejun Heo <teheo@suse.de> | ||
7 | * | ||
8 | * This file is released under the GPLv2. | ||
9 | * | ||
10 | * Please see Documentation/filesystems/sysfs.txt for more information. | ||
3 | */ | 11 | */ |
4 | 12 | ||
5 | #undef DEBUG | 13 | #undef DEBUG |
@@ -11,10 +19,11 @@ | |||
11 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
12 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
13 | #include <linux/completion.h> | 21 | #include <linux/completion.h> |
14 | #include <asm/semaphore.h> | 22 | #include <linux/mutex.h> |
15 | #include "sysfs.h" | 23 | #include "sysfs.h" |
16 | 24 | ||
17 | DEFINE_MUTEX(sysfs_mutex); | 25 | DEFINE_MUTEX(sysfs_mutex); |
26 | DEFINE_MUTEX(sysfs_rename_mutex); | ||
18 | spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; | 27 | spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; |
19 | 28 | ||
20 | static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; | 29 | static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; |
@@ -25,18 +34,28 @@ static DEFINE_IDA(sysfs_ino_ida); | |||
25 | * @sd: sysfs_dirent of interest | 34 | * @sd: sysfs_dirent of interest |
26 | * | 35 | * |
27 | * Link @sd into its sibling list which starts from | 36 | * Link @sd into its sibling list which starts from |
28 | * sd->s_parent->s_children. | 37 | * sd->s_parent->s_dir.children. |
29 | * | 38 | * |
30 | * Locking: | 39 | * Locking: |
31 | * mutex_lock(sysfs_mutex) | 40 | * mutex_lock(sysfs_mutex) |
32 | */ | 41 | */ |
33 | void sysfs_link_sibling(struct sysfs_dirent *sd) | 42 | static void sysfs_link_sibling(struct sysfs_dirent *sd) |
34 | { | 43 | { |
35 | struct sysfs_dirent *parent_sd = sd->s_parent; | 44 | struct sysfs_dirent *parent_sd = sd->s_parent; |
45 | struct sysfs_dirent **pos; | ||
36 | 46 | ||
37 | BUG_ON(sd->s_sibling); | 47 | BUG_ON(sd->s_sibling); |
38 | sd->s_sibling = parent_sd->s_children; | 48 | |
39 | parent_sd->s_children = sd; | 49 | /* Store directory entries in order by ino. This allows |
50 | * readdir to properly restart without having to add a | ||
51 | * cursor into the s_dir.children list. | ||
52 | */ | ||
53 | for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) { | ||
54 | if (sd->s_ino < (*pos)->s_ino) | ||
55 | break; | ||
56 | } | ||
57 | sd->s_sibling = *pos; | ||
58 | *pos = sd; | ||
40 | } | 59 | } |
41 | 60 | ||
42 | /** | 61 | /** |
@@ -44,16 +63,17 @@ void sysfs_link_sibling(struct sysfs_dirent *sd) | |||
44 | * @sd: sysfs_dirent of interest | 63 | * @sd: sysfs_dirent of interest |
45 | * | 64 | * |
46 | * Unlink @sd from its sibling list which starts from | 65 | * Unlink @sd from its sibling list which starts from |
47 | * sd->s_parent->s_children. | 66 | * sd->s_parent->s_dir.children. |
48 | * | 67 | * |
49 | * Locking: | 68 | * Locking: |
50 | * mutex_lock(sysfs_mutex) | 69 | * mutex_lock(sysfs_mutex) |
51 | */ | 70 | */ |
52 | void sysfs_unlink_sibling(struct sysfs_dirent *sd) | 71 | static void sysfs_unlink_sibling(struct sysfs_dirent *sd) |
53 | { | 72 | { |
54 | struct sysfs_dirent **pos; | 73 | struct sysfs_dirent **pos; |
55 | 74 | ||
56 | for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) { | 75 | for (pos = &sd->s_parent->s_dir.children; *pos; |
76 | pos = &(*pos)->s_sibling) { | ||
57 | if (*pos == sd) { | 77 | if (*pos == sd) { |
58 | *pos = sd->s_sibling; | 78 | *pos = sd->s_sibling; |
59 | sd->s_sibling = NULL; | 79 | sd->s_sibling = NULL; |
@@ -67,96 +87,39 @@ void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
67 | * @sd: sysfs_dirent of interest | 87 | * @sd: sysfs_dirent of interest |
68 | * | 88 | * |
69 | * Get dentry for @sd. Dentry is looked up if currently not | 89 | * Get dentry for @sd. Dentry is looked up if currently not |
70 | * present. This function climbs sysfs_dirent tree till it | 90 | * present. This function descends from the root looking up |
71 | * reaches a sysfs_dirent with valid dentry attached and descends | 91 | * dentry for each step. |
72 | * down from there looking up dentry for each step. | ||
73 | * | 92 | * |
74 | * LOCKING: | 93 | * LOCKING: |
75 | * Kernel thread context (may sleep) | 94 | * mutex_lock(sysfs_rename_mutex) |
76 | * | 95 | * |
77 | * RETURNS: | 96 | * RETURNS: |
78 | * Pointer to found dentry on success, ERR_PTR() value on error. | 97 | * Pointer to found dentry on success, ERR_PTR() value on error. |
79 | */ | 98 | */ |
80 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) | 99 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) |
81 | { | 100 | { |
82 | struct sysfs_dirent *cur; | 101 | struct dentry *dentry = dget(sysfs_sb->s_root); |
83 | struct dentry *parent_dentry, *dentry; | ||
84 | int i, depth; | ||
85 | |||
86 | /* Find the first parent which has valid s_dentry and get the | ||
87 | * dentry. | ||
88 | */ | ||
89 | mutex_lock(&sysfs_mutex); | ||
90 | restart0: | ||
91 | spin_lock(&sysfs_assoc_lock); | ||
92 | restart1: | ||
93 | spin_lock(&dcache_lock); | ||
94 | 102 | ||
95 | dentry = NULL; | 103 | while (dentry->d_fsdata != sd) { |
96 | depth = 0; | 104 | struct sysfs_dirent *cur; |
97 | cur = sd; | 105 | struct dentry *parent; |
98 | while (!cur->s_dentry || !cur->s_dentry->d_inode) { | ||
99 | if (cur->s_flags & SYSFS_FLAG_REMOVED) { | ||
100 | dentry = ERR_PTR(-ENOENT); | ||
101 | depth = 0; | ||
102 | break; | ||
103 | } | ||
104 | cur = cur->s_parent; | ||
105 | depth++; | ||
106 | } | ||
107 | if (!IS_ERR(dentry)) | ||
108 | dentry = dget_locked(cur->s_dentry); | ||
109 | 106 | ||
110 | spin_unlock(&dcache_lock); | 107 | /* find the first ancestor which hasn't been looked up */ |
111 | spin_unlock(&sysfs_assoc_lock); | 108 | cur = sd; |
112 | 109 | while (cur->s_parent != dentry->d_fsdata) | |
113 | /* from the found dentry, look up depth times */ | ||
114 | while (depth--) { | ||
115 | /* find and get depth'th ancestor */ | ||
116 | for (cur = sd, i = 0; cur && i < depth; i++) | ||
117 | cur = cur->s_parent; | 110 | cur = cur->s_parent; |
118 | 111 | ||
119 | /* This can happen if tree structure was modified due | ||
120 | * to move/rename. Restart. | ||
121 | */ | ||
122 | if (i != depth) { | ||
123 | dput(dentry); | ||
124 | goto restart0; | ||
125 | } | ||
126 | |||
127 | sysfs_get(cur); | ||
128 | |||
129 | mutex_unlock(&sysfs_mutex); | ||
130 | |||
131 | /* look it up */ | 112 | /* look it up */ |
132 | parent_dentry = dentry; | 113 | parent = dentry; |
133 | dentry = lookup_one_len_kern(cur->s_name, parent_dentry, | 114 | mutex_lock(&parent->d_inode->i_mutex); |
115 | dentry = lookup_one_len_kern(cur->s_name, parent, | ||
134 | strlen(cur->s_name)); | 116 | strlen(cur->s_name)); |
135 | dput(parent_dentry); | 117 | mutex_unlock(&parent->d_inode->i_mutex); |
136 | 118 | dput(parent); | |
137 | if (IS_ERR(dentry)) { | ||
138 | sysfs_put(cur); | ||
139 | return dentry; | ||
140 | } | ||
141 | 119 | ||
142 | mutex_lock(&sysfs_mutex); | 120 | if (IS_ERR(dentry)) |
143 | spin_lock(&sysfs_assoc_lock); | 121 | break; |
144 | |||
145 | /* This, again, can happen if tree structure has | ||
146 | * changed and we looked up the wrong thing. Restart. | ||
147 | */ | ||
148 | if (cur->s_dentry != dentry) { | ||
149 | dput(dentry); | ||
150 | sysfs_put(cur); | ||
151 | goto restart1; | ||
152 | } | ||
153 | |||
154 | spin_unlock(&sysfs_assoc_lock); | ||
155 | |||
156 | sysfs_put(cur); | ||
157 | } | 122 | } |
158 | |||
159 | mutex_unlock(&sysfs_mutex); | ||
160 | return dentry; | 123 | return dentry; |
161 | } | 124 | } |
162 | 125 | ||
@@ -319,7 +282,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
319 | parent_sd = sd->s_parent; | 282 | parent_sd = sd->s_parent; |
320 | 283 | ||
321 | if (sysfs_type(sd) == SYSFS_KOBJ_LINK) | 284 | if (sysfs_type(sd) == SYSFS_KOBJ_LINK) |
322 | sysfs_put(sd->s_elem.symlink.target_sd); | 285 | sysfs_put(sd->s_symlink.target_sd); |
323 | if (sysfs_type(sd) & SYSFS_COPY_NAME) | 286 | if (sysfs_type(sd) & SYSFS_COPY_NAME) |
324 | kfree(sd->s_name); | 287 | kfree(sd->s_name); |
325 | kfree(sd->s_iattr); | 288 | kfree(sd->s_iattr); |
@@ -335,22 +298,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | |||
335 | { | 298 | { |
336 | struct sysfs_dirent * sd = dentry->d_fsdata; | 299 | struct sysfs_dirent * sd = dentry->d_fsdata; |
337 | 300 | ||
338 | if (sd) { | 301 | sysfs_put(sd); |
339 | /* sd->s_dentry is protected with sysfs_assoc_lock. | ||
340 | * This allows sysfs_drop_dentry() to dereference it. | ||
341 | */ | ||
342 | spin_lock(&sysfs_assoc_lock); | ||
343 | |||
344 | /* The dentry might have been deleted or another | ||
345 | * lookup could have happened updating sd->s_dentry to | ||
346 | * point the new dentry. Ignore if it isn't pointing | ||
347 | * to this dentry. | ||
348 | */ | ||
349 | if (sd->s_dentry == dentry) | ||
350 | sd->s_dentry = NULL; | ||
351 | spin_unlock(&sysfs_assoc_lock); | ||
352 | sysfs_put(sd); | ||
353 | } | ||
354 | iput(inode); | 302 | iput(inode); |
355 | } | 303 | } |
356 | 304 | ||
@@ -378,7 +326,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
378 | 326 | ||
379 | atomic_set(&sd->s_count, 1); | 327 | atomic_set(&sd->s_count, 1); |
380 | atomic_set(&sd->s_active, 0); | 328 | atomic_set(&sd->s_active, 0); |
381 | atomic_set(&sd->s_event, 1); | ||
382 | 329 | ||
383 | sd->s_name = name; | 330 | sd->s_name = name; |
384 | sd->s_mode = mode; | 331 | sd->s_mode = mode; |
@@ -393,30 +340,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
393 | return NULL; | 340 | return NULL; |
394 | } | 341 | } |
395 | 342 | ||
396 | /** | ||
397 | * sysfs_attach_dentry - associate sysfs_dirent with dentry | ||
398 | * @sd: target sysfs_dirent | ||
399 | * @dentry: dentry to associate | ||
400 | * | ||
401 | * Associate @sd with @dentry. This is protected by | ||
402 | * sysfs_assoc_lock to avoid race with sysfs_d_iput(). | ||
403 | * | ||
404 | * LOCKING: | ||
405 | * mutex_lock(sysfs_mutex) | ||
406 | */ | ||
407 | static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) | ||
408 | { | ||
409 | dentry->d_op = &sysfs_dentry_ops; | ||
410 | dentry->d_fsdata = sysfs_get(sd); | ||
411 | |||
412 | /* protect sd->s_dentry against sysfs_d_iput */ | ||
413 | spin_lock(&sysfs_assoc_lock); | ||
414 | sd->s_dentry = dentry; | ||
415 | spin_unlock(&sysfs_assoc_lock); | ||
416 | |||
417 | d_rehash(dentry); | ||
418 | } | ||
419 | |||
420 | static int sysfs_ilookup_test(struct inode *inode, void *arg) | 343 | static int sysfs_ilookup_test(struct inode *inode, void *arg) |
421 | { | 344 | { |
422 | struct sysfs_dirent *sd = arg; | 345 | struct sysfs_dirent *sd = arg; |
@@ -480,10 +403,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
480 | * @sd: sysfs_dirent to be added | 403 | * @sd: sysfs_dirent to be added |
481 | * | 404 | * |
482 | * Get @acxt->parent_sd and set sd->s_parent to it and increment | 405 | * Get @acxt->parent_sd and set sd->s_parent to it and increment |
483 | * nlink of parent inode if @sd is a directory. @sd is NOT | 406 | * nlink of parent inode if @sd is a directory and link into the |
484 | * linked into the children list of the parent. The caller | 407 | * children list of the parent. |
485 | * should invoke sysfs_link_sibling() after this function | ||
486 | * completes if @sd needs to be on the children list. | ||
487 | * | 408 | * |
488 | * This function should be called between calls to | 409 | * This function should be called between calls to |
489 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | 410 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be |
@@ -491,15 +412,30 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
491 | * | 412 | * |
492 | * LOCKING: | 413 | * LOCKING: |
493 | * Determined by sysfs_addrm_start(). | 414 | * Determined by sysfs_addrm_start(). |
415 | * | ||
416 | * RETURNS: | ||
417 | * 0 on success, -EEXIST if entry with the given name already | ||
418 | * exists. | ||
494 | */ | 419 | */ |
495 | void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 420 | int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
496 | { | 421 | { |
422 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) { | ||
423 | printk(KERN_WARNING "sysfs: duplicate filename '%s' " | ||
424 | "can not be created\n", sd->s_name); | ||
425 | WARN_ON(1); | ||
426 | return -EEXIST; | ||
427 | } | ||
428 | |||
497 | sd->s_parent = sysfs_get(acxt->parent_sd); | 429 | sd->s_parent = sysfs_get(acxt->parent_sd); |
498 | 430 | ||
499 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | 431 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) |
500 | inc_nlink(acxt->parent_inode); | 432 | inc_nlink(acxt->parent_inode); |
501 | 433 | ||
502 | acxt->cnt++; | 434 | acxt->cnt++; |
435 | |||
436 | sysfs_link_sibling(sd); | ||
437 | |||
438 | return 0; | ||
503 | } | 439 | } |
504 | 440 | ||
505 | /** | 441 | /** |
@@ -508,9 +444,7 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
508 | * @sd: sysfs_dirent to be added | 444 | * @sd: sysfs_dirent to be added |
509 | * | 445 | * |
510 | * Mark @sd removed and drop nlink of parent inode if @sd is a | 446 | * Mark @sd removed and drop nlink of parent inode if @sd is a |
511 | * directory. @sd is NOT unlinked from the children list of the | 447 | * directory. @sd is unlinked from the children list. |
512 | * parent. The caller is repsonsible for removing @sd from the | ||
513 | * children list before calling this function. | ||
514 | * | 448 | * |
515 | * This function should be called between calls to | 449 | * This function should be called between calls to |
516 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be | 450 | * sysfs_addrm_start() and sysfs_addrm_finish() and should be |
@@ -521,7 +455,9 @@ void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
521 | */ | 455 | */ |
522 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 456 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
523 | { | 457 | { |
524 | BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED)); | 458 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); |
459 | |||
460 | sysfs_unlink_sibling(sd); | ||
525 | 461 | ||
526 | sd->s_flags |= SYSFS_FLAG_REMOVED; | 462 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
527 | sd->s_sibling = acxt->removed; | 463 | sd->s_sibling = acxt->removed; |
@@ -540,53 +476,49 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
540 | * Drop dentry for @sd. @sd must have been unlinked from its | 476 | * Drop dentry for @sd. @sd must have been unlinked from its |
541 | * parent on entry to this function such that it can't be looked | 477 | * parent on entry to this function such that it can't be looked |
542 | * up anymore. | 478 | * up anymore. |
543 | * | ||
544 | * @sd->s_dentry which is protected with sysfs_assoc_lock points | ||
545 | * to the currently associated dentry but we're not holding a | ||
546 | * reference to it and racing with dput(). Grab dcache_lock and | ||
547 | * verify dentry before dropping it. If @sd->s_dentry is NULL or | ||
548 | * dput() beats us, no need to bother. | ||
549 | */ | 479 | */ |
550 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) | 480 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) |
551 | { | 481 | { |
552 | struct dentry *dentry = NULL; | ||
553 | struct inode *inode; | 482 | struct inode *inode; |
483 | struct dentry *dentry; | ||
554 | 484 | ||
555 | /* We're not holding a reference to ->s_dentry dentry but the | 485 | inode = ilookup(sysfs_sb, sd->s_ino); |
556 | * field will stay valid as long as sysfs_assoc_lock is held. | 486 | if (!inode) |
487 | return; | ||
488 | |||
489 | /* Drop any existing dentries associated with sd. | ||
490 | * | ||
491 | * For the dentry to be properly freed we need to grab a | ||
492 | * reference to the dentry under the dcache lock, unhash it, | ||
493 | * and then put it. The playing with the dentry count allows | ||
494 | * dput to immediately free the dentry if it is not in use. | ||
557 | */ | 495 | */ |
558 | spin_lock(&sysfs_assoc_lock); | 496 | repeat: |
559 | spin_lock(&dcache_lock); | 497 | spin_lock(&dcache_lock); |
560 | 498 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | |
561 | /* drop dentry if it's there and dput() didn't kill it yet */ | 499 | if (d_unhashed(dentry)) |
562 | if (sd->s_dentry && sd->s_dentry->d_inode) { | 500 | continue; |
563 | dentry = dget_locked(sd->s_dentry); | 501 | dget_locked(dentry); |
564 | spin_lock(&dentry->d_lock); | 502 | spin_lock(&dentry->d_lock); |
565 | __d_drop(dentry); | 503 | __d_drop(dentry); |
566 | spin_unlock(&dentry->d_lock); | 504 | spin_unlock(&dentry->d_lock); |
505 | spin_unlock(&dcache_lock); | ||
506 | dput(dentry); | ||
507 | goto repeat; | ||
567 | } | 508 | } |
568 | |||
569 | spin_unlock(&dcache_lock); | 509 | spin_unlock(&dcache_lock); |
570 | spin_unlock(&sysfs_assoc_lock); | ||
571 | |||
572 | /* dentries for shadowed inodes are pinned, unpin */ | ||
573 | if (dentry && sysfs_is_shadowed_inode(dentry->d_inode)) | ||
574 | dput(dentry); | ||
575 | dput(dentry); | ||
576 | 510 | ||
577 | /* adjust nlink and update timestamp */ | 511 | /* adjust nlink and update timestamp */ |
578 | inode = ilookup(sysfs_sb, sd->s_ino); | 512 | mutex_lock(&inode->i_mutex); |
579 | if (inode) { | ||
580 | mutex_lock(&inode->i_mutex); | ||
581 | 513 | ||
582 | inode->i_ctime = CURRENT_TIME; | 514 | inode->i_ctime = CURRENT_TIME; |
515 | drop_nlink(inode); | ||
516 | if (sysfs_type(sd) == SYSFS_DIR) | ||
583 | drop_nlink(inode); | 517 | drop_nlink(inode); |
584 | if (sysfs_type(sd) == SYSFS_DIR) | ||
585 | drop_nlink(inode); | ||
586 | 518 | ||
587 | mutex_unlock(&inode->i_mutex); | 519 | mutex_unlock(&inode->i_mutex); |
588 | iput(inode); | 520 | |
589 | } | 521 | iput(inode); |
590 | } | 522 | } |
591 | 523 | ||
592 | /** | 524 | /** |
@@ -599,11 +531,8 @@ static void sysfs_drop_dentry(struct sysfs_dirent *sd) | |||
599 | * | 531 | * |
600 | * LOCKING: | 532 | * LOCKING: |
601 | * All mutexes acquired by sysfs_addrm_start() are released. | 533 | * All mutexes acquired by sysfs_addrm_start() are released. |
602 | * | ||
603 | * RETURNS: | ||
604 | * Number of added/removed sysfs_dirents since sysfs_addrm_start(). | ||
605 | */ | 534 | */ |
606 | int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | 535 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) |
607 | { | 536 | { |
608 | /* release resources acquired by sysfs_addrm_start() */ | 537 | /* release resources acquired by sysfs_addrm_start() */ |
609 | mutex_unlock(&sysfs_mutex); | 538 | mutex_unlock(&sysfs_mutex); |
@@ -629,8 +558,6 @@ int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
629 | sysfs_deactivate(sd); | 558 | sysfs_deactivate(sd); |
630 | sysfs_put(sd); | 559 | sysfs_put(sd); |
631 | } | 560 | } |
632 | |||
633 | return acxt->cnt; | ||
634 | } | 561 | } |
635 | 562 | ||
636 | /** | 563 | /** |
@@ -651,8 +578,8 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
651 | { | 578 | { |
652 | struct sysfs_dirent *sd; | 579 | struct sysfs_dirent *sd; |
653 | 580 | ||
654 | for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) | 581 | for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) |
655 | if (sysfs_type(sd) && !strcmp(sd->s_name, name)) | 582 | if (!strcmp(sd->s_name, name)) |
656 | return sd; | 583 | return sd; |
657 | return NULL; | 584 | return NULL; |
658 | } | 585 | } |
@@ -690,28 +617,25 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
690 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; | 617 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
691 | struct sysfs_addrm_cxt acxt; | 618 | struct sysfs_addrm_cxt acxt; |
692 | struct sysfs_dirent *sd; | 619 | struct sysfs_dirent *sd; |
620 | int rc; | ||
693 | 621 | ||
694 | /* allocate */ | 622 | /* allocate */ |
695 | sd = sysfs_new_dirent(name, mode, SYSFS_DIR); | 623 | sd = sysfs_new_dirent(name, mode, SYSFS_DIR); |
696 | if (!sd) | 624 | if (!sd) |
697 | return -ENOMEM; | 625 | return -ENOMEM; |
698 | sd->s_elem.dir.kobj = kobj; | 626 | sd->s_dir.kobj = kobj; |
699 | 627 | ||
700 | /* link in */ | 628 | /* link in */ |
701 | sysfs_addrm_start(&acxt, parent_sd); | 629 | sysfs_addrm_start(&acxt, parent_sd); |
630 | rc = sysfs_add_one(&acxt, sd); | ||
631 | sysfs_addrm_finish(&acxt); | ||
702 | 632 | ||
703 | if (!sysfs_find_dirent(parent_sd, name)) { | 633 | if (rc == 0) |
704 | sysfs_add_one(&acxt, sd); | 634 | *p_sd = sd; |
705 | sysfs_link_sibling(sd); | 635 | else |
706 | } | ||
707 | |||
708 | if (!sysfs_addrm_finish(&acxt)) { | ||
709 | sysfs_put(sd); | 636 | sysfs_put(sd); |
710 | return -EEXIST; | ||
711 | } | ||
712 | 637 | ||
713 | *p_sd = sd; | 638 | return rc; |
714 | return 0; | ||
715 | } | 639 | } |
716 | 640 | ||
717 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | 641 | int sysfs_create_subdir(struct kobject *kobj, const char *name, |
@@ -723,24 +647,18 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
723 | /** | 647 | /** |
724 | * sysfs_create_dir - create a directory for an object. | 648 | * sysfs_create_dir - create a directory for an object. |
725 | * @kobj: object we're creating directory for. | 649 | * @kobj: object we're creating directory for. |
726 | * @shadow_parent: parent object. | ||
727 | */ | 650 | */ |
728 | int sysfs_create_dir(struct kobject *kobj, | 651 | int sysfs_create_dir(struct kobject * kobj) |
729 | struct sysfs_dirent *shadow_parent_sd) | ||
730 | { | 652 | { |
731 | struct sysfs_dirent *parent_sd, *sd; | 653 | struct sysfs_dirent *parent_sd, *sd; |
732 | int error = 0; | 654 | int error = 0; |
733 | 655 | ||
734 | BUG_ON(!kobj); | 656 | BUG_ON(!kobj); |
735 | 657 | ||
736 | if (shadow_parent_sd) | 658 | if (kobj->parent) |
737 | parent_sd = shadow_parent_sd; | ||
738 | else if (kobj->parent) | ||
739 | parent_sd = kobj->parent->sd; | 659 | parent_sd = kobj->parent->sd; |
740 | else if (sysfs_mount && sysfs_mount->mnt_sb) | ||
741 | parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata; | ||
742 | else | 660 | else |
743 | return -EFAULT; | 661 | parent_sd = &sysfs_root; |
744 | 662 | ||
745 | error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); | 663 | error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); |
746 | if (!error) | 664 | if (!error) |
@@ -748,39 +666,20 @@ int sysfs_create_dir(struct kobject *kobj, | |||
748 | return error; | 666 | return error; |
749 | } | 667 | } |
750 | 668 | ||
751 | static int sysfs_count_nlink(struct sysfs_dirent *sd) | ||
752 | { | ||
753 | struct sysfs_dirent *child; | ||
754 | int nr = 0; | ||
755 | |||
756 | for (child = sd->s_children; child; child = child->s_sibling) | ||
757 | if (sysfs_type(child) == SYSFS_DIR) | ||
758 | nr++; | ||
759 | return nr + 2; | ||
760 | } | ||
761 | |||
762 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | 669 | static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, |
763 | struct nameidata *nd) | 670 | struct nameidata *nd) |
764 | { | 671 | { |
765 | struct dentry *ret = NULL; | 672 | struct dentry *ret = NULL; |
766 | struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata; | 673 | struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; |
767 | struct sysfs_dirent * sd; | 674 | struct sysfs_dirent *sd; |
768 | struct bin_attribute *bin_attr; | ||
769 | struct inode *inode; | 675 | struct inode *inode; |
770 | int found = 0; | ||
771 | 676 | ||
772 | mutex_lock(&sysfs_mutex); | 677 | mutex_lock(&sysfs_mutex); |
773 | 678 | ||
774 | for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) { | 679 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); |
775 | if (sysfs_type(sd) && | ||
776 | !strcmp(sd->s_name, dentry->d_name.name)) { | ||
777 | found = 1; | ||
778 | break; | ||
779 | } | ||
780 | } | ||
781 | 680 | ||
782 | /* no such entry */ | 681 | /* no such entry */ |
783 | if (!found) | 682 | if (!sd) |
784 | goto out_unlock; | 683 | goto out_unlock; |
785 | 684 | ||
786 | /* attach dentry and inode */ | 685 | /* attach dentry and inode */ |
@@ -790,33 +689,11 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
790 | goto out_unlock; | 689 | goto out_unlock; |
791 | } | 690 | } |
792 | 691 | ||
793 | if (inode->i_state & I_NEW) { | 692 | /* instantiate and hash dentry */ |
794 | /* initialize inode according to type */ | 693 | dentry->d_op = &sysfs_dentry_ops; |
795 | switch (sysfs_type(sd)) { | 694 | dentry->d_fsdata = sysfs_get(sd); |
796 | case SYSFS_DIR: | 695 | d_instantiate(dentry, inode); |
797 | inode->i_op = &sysfs_dir_inode_operations; | 696 | d_rehash(dentry); |
798 | inode->i_fop = &sysfs_dir_operations; | ||
799 | inode->i_nlink = sysfs_count_nlink(sd); | ||
800 | break; | ||
801 | case SYSFS_KOBJ_ATTR: | ||
802 | inode->i_size = PAGE_SIZE; | ||
803 | inode->i_fop = &sysfs_file_operations; | ||
804 | break; | ||
805 | case SYSFS_KOBJ_BIN_ATTR: | ||
806 | bin_attr = sd->s_elem.bin_attr.bin_attr; | ||
807 | inode->i_size = bin_attr->size; | ||
808 | inode->i_fop = &bin_fops; | ||
809 | break; | ||
810 | case SYSFS_KOBJ_LINK: | ||
811 | inode->i_op = &sysfs_symlink_inode_operations; | ||
812 | break; | ||
813 | default: | ||
814 | BUG(); | ||
815 | } | ||
816 | } | ||
817 | |||
818 | sysfs_instantiate(dentry, inode); | ||
819 | sysfs_attach_dentry(sd, dentry); | ||
820 | 697 | ||
821 | out_unlock: | 698 | out_unlock: |
822 | mutex_unlock(&sysfs_mutex); | 699 | mutex_unlock(&sysfs_mutex); |
@@ -833,7 +710,6 @@ static void remove_dir(struct sysfs_dirent *sd) | |||
833 | struct sysfs_addrm_cxt acxt; | 710 | struct sysfs_addrm_cxt acxt; |
834 | 711 | ||
835 | sysfs_addrm_start(&acxt, sd->s_parent); | 712 | sysfs_addrm_start(&acxt, sd->s_parent); |
836 | sysfs_unlink_sibling(sd); | ||
837 | sysfs_remove_one(&acxt, sd); | 713 | sysfs_remove_one(&acxt, sd); |
838 | sysfs_addrm_finish(&acxt); | 714 | sysfs_addrm_finish(&acxt); |
839 | } | 715 | } |
@@ -854,15 +730,13 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) | |||
854 | 730 | ||
855 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); | 731 | pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); |
856 | sysfs_addrm_start(&acxt, dir_sd); | 732 | sysfs_addrm_start(&acxt, dir_sd); |
857 | pos = &dir_sd->s_children; | 733 | pos = &dir_sd->s_dir.children; |
858 | while (*pos) { | 734 | while (*pos) { |
859 | struct sysfs_dirent *sd = *pos; | 735 | struct sysfs_dirent *sd = *pos; |
860 | 736 | ||
861 | if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) { | 737 | if (sysfs_type(sd) != SYSFS_DIR) |
862 | *pos = sd->s_sibling; | ||
863 | sd->s_sibling = NULL; | ||
864 | sysfs_remove_one(&acxt, sd); | 738 | sysfs_remove_one(&acxt, sd); |
865 | } else | 739 | else |
866 | pos = &(*pos)->s_sibling; | 740 | pos = &(*pos)->s_sibling; |
867 | } | 741 | } |
868 | sysfs_addrm_finish(&acxt); | 742 | sysfs_addrm_finish(&acxt); |
@@ -890,90 +764,68 @@ void sysfs_remove_dir(struct kobject * kobj) | |||
890 | __sysfs_remove_dir(sd); | 764 | __sysfs_remove_dir(sd); |
891 | } | 765 | } |
892 | 766 | ||
893 | int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd, | 767 | int sysfs_rename_dir(struct kobject * kobj, const char *new_name) |
894 | const char *new_name) | ||
895 | { | 768 | { |
896 | struct sysfs_dirent *sd = kobj->sd; | 769 | struct sysfs_dirent *sd = kobj->sd; |
897 | struct dentry *new_parent = NULL; | 770 | struct dentry *parent = NULL; |
898 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | 771 | struct dentry *old_dentry = NULL, *new_dentry = NULL; |
899 | const char *dup_name = NULL; | 772 | const char *dup_name = NULL; |
900 | int error; | 773 | int error; |
901 | 774 | ||
902 | /* get dentries */ | 775 | mutex_lock(&sysfs_rename_mutex); |
776 | |||
777 | error = 0; | ||
778 | if (strcmp(sd->s_name, new_name) == 0) | ||
779 | goto out; /* nothing to rename */ | ||
780 | |||
781 | /* get the original dentry */ | ||
903 | old_dentry = sysfs_get_dentry(sd); | 782 | old_dentry = sysfs_get_dentry(sd); |
904 | if (IS_ERR(old_dentry)) { | 783 | if (IS_ERR(old_dentry)) { |
905 | error = PTR_ERR(old_dentry); | 784 | error = PTR_ERR(old_dentry); |
906 | goto out_dput; | 785 | goto out; |
907 | } | ||
908 | |||
909 | new_parent = sysfs_get_dentry(new_parent_sd); | ||
910 | if (IS_ERR(new_parent)) { | ||
911 | error = PTR_ERR(new_parent); | ||
912 | goto out_dput; | ||
913 | } | 786 | } |
914 | 787 | ||
915 | /* lock new_parent and get dentry for new name */ | 788 | parent = old_dentry->d_parent; |
916 | mutex_lock(&new_parent->d_inode->i_mutex); | ||
917 | 789 | ||
918 | new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); | 790 | /* lock parent and get dentry for new name */ |
919 | if (IS_ERR(new_dentry)) { | 791 | mutex_lock(&parent->d_inode->i_mutex); |
920 | error = PTR_ERR(new_dentry); | 792 | mutex_lock(&sysfs_mutex); |
921 | goto out_unlock; | ||
922 | } | ||
923 | 793 | ||
924 | /* By allowing two different directories with the same | 794 | error = -EEXIST; |
925 | * d_parent we allow this routine to move between different | 795 | if (sysfs_find_dirent(sd->s_parent, new_name)) |
926 | * shadows of the same directory | ||
927 | */ | ||
928 | error = -EINVAL; | ||
929 | if (old_dentry->d_parent->d_inode != new_parent->d_inode || | ||
930 | new_dentry->d_parent->d_inode != new_parent->d_inode || | ||
931 | old_dentry == new_dentry) | ||
932 | goto out_unlock; | 796 | goto out_unlock; |
933 | 797 | ||
934 | error = -EEXIST; | 798 | error = -ENOMEM; |
935 | if (new_dentry->d_inode) | 799 | new_dentry = d_alloc_name(parent, new_name); |
800 | if (!new_dentry) | ||
936 | goto out_unlock; | 801 | goto out_unlock; |
937 | 802 | ||
938 | /* rename kobject and sysfs_dirent */ | 803 | /* rename kobject and sysfs_dirent */ |
939 | error = -ENOMEM; | 804 | error = -ENOMEM; |
940 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); | 805 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); |
941 | if (!new_name) | 806 | if (!new_name) |
942 | goto out_drop; | 807 | goto out_unlock; |
943 | 808 | ||
944 | error = kobject_set_name(kobj, "%s", new_name); | 809 | error = kobject_set_name(kobj, "%s", new_name); |
945 | if (error) | 810 | if (error) |
946 | goto out_drop; | 811 | goto out_unlock; |
947 | |||
948 | mutex_lock(&sysfs_mutex); | ||
949 | 812 | ||
950 | dup_name = sd->s_name; | 813 | dup_name = sd->s_name; |
951 | sd->s_name = new_name; | 814 | sd->s_name = new_name; |
952 | 815 | ||
953 | /* move under the new parent */ | 816 | /* rename */ |
954 | d_add(new_dentry, NULL); | 817 | d_add(new_dentry, NULL); |
955 | d_move(sd->s_dentry, new_dentry); | 818 | d_move(old_dentry, new_dentry); |
956 | |||
957 | sysfs_unlink_sibling(sd); | ||
958 | sysfs_get(new_parent_sd); | ||
959 | sysfs_put(sd->s_parent); | ||
960 | sd->s_parent = new_parent_sd; | ||
961 | sysfs_link_sibling(sd); | ||
962 | |||
963 | mutex_unlock(&sysfs_mutex); | ||
964 | 819 | ||
965 | error = 0; | 820 | error = 0; |
966 | goto out_unlock; | ||
967 | |||
968 | out_drop: | ||
969 | d_drop(new_dentry); | ||
970 | out_unlock: | 821 | out_unlock: |
971 | mutex_unlock(&new_parent->d_inode->i_mutex); | 822 | mutex_unlock(&sysfs_mutex); |
972 | out_dput: | 823 | mutex_unlock(&parent->d_inode->i_mutex); |
973 | kfree(dup_name); | 824 | kfree(dup_name); |
974 | dput(new_parent); | ||
975 | dput(old_dentry); | 825 | dput(old_dentry); |
976 | dput(new_dentry); | 826 | dput(new_dentry); |
827 | out: | ||
828 | mutex_unlock(&sysfs_rename_mutex); | ||
977 | return error; | 829 | return error; |
978 | } | 830 | } |
979 | 831 | ||
@@ -985,96 +837,69 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | |||
985 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | 837 | struct dentry *old_dentry = NULL, *new_dentry = NULL; |
986 | int error; | 838 | int error; |
987 | 839 | ||
840 | mutex_lock(&sysfs_rename_mutex); | ||
988 | BUG_ON(!sd->s_parent); | 841 | BUG_ON(!sd->s_parent); |
989 | new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; | 842 | new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; |
990 | 843 | ||
844 | error = 0; | ||
845 | if (sd->s_parent == new_parent_sd) | ||
846 | goto out; /* nothing to move */ | ||
847 | |||
991 | /* get dentries */ | 848 | /* get dentries */ |
992 | old_dentry = sysfs_get_dentry(sd); | 849 | old_dentry = sysfs_get_dentry(sd); |
993 | if (IS_ERR(old_dentry)) { | 850 | if (IS_ERR(old_dentry)) { |
994 | error = PTR_ERR(old_dentry); | 851 | error = PTR_ERR(old_dentry); |
995 | goto out_dput; | 852 | goto out; |
996 | } | 853 | } |
997 | old_parent = sd->s_parent->s_dentry; | 854 | old_parent = old_dentry->d_parent; |
998 | 855 | ||
999 | new_parent = sysfs_get_dentry(new_parent_sd); | 856 | new_parent = sysfs_get_dentry(new_parent_sd); |
1000 | if (IS_ERR(new_parent)) { | 857 | if (IS_ERR(new_parent)) { |
1001 | error = PTR_ERR(new_parent); | 858 | error = PTR_ERR(new_parent); |
1002 | goto out_dput; | 859 | goto out; |
1003 | } | 860 | } |
1004 | 861 | ||
1005 | if (old_parent->d_inode == new_parent->d_inode) { | ||
1006 | error = 0; | ||
1007 | goto out_dput; /* nothing to move */ | ||
1008 | } | ||
1009 | again: | 862 | again: |
1010 | mutex_lock(&old_parent->d_inode->i_mutex); | 863 | mutex_lock(&old_parent->d_inode->i_mutex); |
1011 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { | 864 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { |
1012 | mutex_unlock(&old_parent->d_inode->i_mutex); | 865 | mutex_unlock(&old_parent->d_inode->i_mutex); |
1013 | goto again; | 866 | goto again; |
1014 | } | 867 | } |
868 | mutex_lock(&sysfs_mutex); | ||
1015 | 869 | ||
1016 | new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name)); | 870 | error = -EEXIST; |
1017 | if (IS_ERR(new_dentry)) { | 871 | if (sysfs_find_dirent(new_parent_sd, sd->s_name)) |
1018 | error = PTR_ERR(new_dentry); | ||
1019 | goto out_unlock; | 872 | goto out_unlock; |
1020 | } else | 873 | |
1021 | error = 0; | 874 | error = -ENOMEM; |
875 | new_dentry = d_alloc_name(new_parent, sd->s_name); | ||
876 | if (!new_dentry) | ||
877 | goto out_unlock; | ||
878 | |||
879 | error = 0; | ||
1022 | d_add(new_dentry, NULL); | 880 | d_add(new_dentry, NULL); |
1023 | d_move(sd->s_dentry, new_dentry); | 881 | d_move(old_dentry, new_dentry); |
1024 | dput(new_dentry); | 882 | dput(new_dentry); |
1025 | 883 | ||
1026 | /* Remove from old parent's list and insert into new parent's list. */ | 884 | /* Remove from old parent's list and insert into new parent's list. */ |
1027 | mutex_lock(&sysfs_mutex); | ||
1028 | |||
1029 | sysfs_unlink_sibling(sd); | 885 | sysfs_unlink_sibling(sd); |
1030 | sysfs_get(new_parent_sd); | 886 | sysfs_get(new_parent_sd); |
1031 | sysfs_put(sd->s_parent); | 887 | sysfs_put(sd->s_parent); |
1032 | sd->s_parent = new_parent_sd; | 888 | sd->s_parent = new_parent_sd; |
1033 | sysfs_link_sibling(sd); | 889 | sysfs_link_sibling(sd); |
1034 | 890 | ||
1035 | mutex_unlock(&sysfs_mutex); | ||
1036 | |||
1037 | out_unlock: | 891 | out_unlock: |
892 | mutex_unlock(&sysfs_mutex); | ||
1038 | mutex_unlock(&new_parent->d_inode->i_mutex); | 893 | mutex_unlock(&new_parent->d_inode->i_mutex); |
1039 | mutex_unlock(&old_parent->d_inode->i_mutex); | 894 | mutex_unlock(&old_parent->d_inode->i_mutex); |
1040 | out_dput: | 895 | out: |
1041 | dput(new_parent); | 896 | dput(new_parent); |
1042 | dput(old_dentry); | 897 | dput(old_dentry); |
1043 | dput(new_dentry); | 898 | dput(new_dentry); |
899 | mutex_unlock(&sysfs_rename_mutex); | ||
1044 | return error; | 900 | return error; |
1045 | } | 901 | } |
1046 | 902 | ||
1047 | static int sysfs_dir_open(struct inode *inode, struct file *file) | ||
1048 | { | ||
1049 | struct dentry * dentry = file->f_path.dentry; | ||
1050 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | ||
1051 | struct sysfs_dirent * sd; | ||
1052 | |||
1053 | sd = sysfs_new_dirent("_DIR_", 0, 0); | ||
1054 | if (sd) { | ||
1055 | mutex_lock(&sysfs_mutex); | ||
1056 | sd->s_parent = sysfs_get(parent_sd); | ||
1057 | sysfs_link_sibling(sd); | ||
1058 | mutex_unlock(&sysfs_mutex); | ||
1059 | } | ||
1060 | |||
1061 | file->private_data = sd; | ||
1062 | return sd ? 0 : -ENOMEM; | ||
1063 | } | ||
1064 | |||
1065 | static int sysfs_dir_close(struct inode *inode, struct file *file) | ||
1066 | { | ||
1067 | struct sysfs_dirent * cursor = file->private_data; | ||
1068 | |||
1069 | mutex_lock(&sysfs_mutex); | ||
1070 | sysfs_unlink_sibling(cursor); | ||
1071 | mutex_unlock(&sysfs_mutex); | ||
1072 | |||
1073 | release_sysfs_dirent(cursor); | ||
1074 | |||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | /* Relationship between s_mode and the DT_xxx types */ | 903 | /* Relationship between s_mode and the DT_xxx types */ |
1079 | static inline unsigned char dt_type(struct sysfs_dirent *sd) | 904 | static inline unsigned char dt_type(struct sysfs_dirent *sd) |
1080 | { | 905 | { |
@@ -1085,232 +910,51 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
1085 | { | 910 | { |
1086 | struct dentry *dentry = filp->f_path.dentry; | 911 | struct dentry *dentry = filp->f_path.dentry; |
1087 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | 912 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; |
1088 | struct sysfs_dirent *cursor = filp->private_data; | 913 | struct sysfs_dirent *pos; |
1089 | struct sysfs_dirent **pos; | ||
1090 | ino_t ino; | 914 | ino_t ino; |
1091 | int i = filp->f_pos; | ||
1092 | 915 | ||
1093 | switch (i) { | 916 | if (filp->f_pos == 0) { |
1094 | case 0: | 917 | ino = parent_sd->s_ino; |
1095 | ino = parent_sd->s_ino; | 918 | if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) |
1096 | if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) | ||
1097 | break; | ||
1098 | filp->f_pos++; | 919 | filp->f_pos++; |
1099 | i++; | 920 | } |
1100 | /* fallthrough */ | 921 | if (filp->f_pos == 1) { |
1101 | case 1: | 922 | if (parent_sd->s_parent) |
1102 | if (parent_sd->s_parent) | 923 | ino = parent_sd->s_parent->s_ino; |
1103 | ino = parent_sd->s_parent->s_ino; | 924 | else |
1104 | else | 925 | ino = parent_sd->s_ino; |
1105 | ino = parent_sd->s_ino; | 926 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) |
1106 | if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) | ||
1107 | break; | ||
1108 | filp->f_pos++; | 927 | filp->f_pos++; |
1109 | i++; | 928 | } |
1110 | /* fallthrough */ | 929 | if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { |
1111 | default: | 930 | mutex_lock(&sysfs_mutex); |
1112 | mutex_lock(&sysfs_mutex); | ||
1113 | |||
1114 | pos = &parent_sd->s_children; | ||
1115 | while (*pos != cursor) | ||
1116 | pos = &(*pos)->s_sibling; | ||
1117 | |||
1118 | /* unlink cursor */ | ||
1119 | *pos = cursor->s_sibling; | ||
1120 | |||
1121 | if (filp->f_pos == 2) | ||
1122 | pos = &parent_sd->s_children; | ||
1123 | |||
1124 | for ( ; *pos; pos = &(*pos)->s_sibling) { | ||
1125 | struct sysfs_dirent *next = *pos; | ||
1126 | const char * name; | ||
1127 | int len; | ||
1128 | |||
1129 | if (!sysfs_type(next)) | ||
1130 | continue; | ||
1131 | |||
1132 | name = next->s_name; | ||
1133 | len = strlen(name); | ||
1134 | ino = next->s_ino; | ||
1135 | |||
1136 | if (filldir(dirent, name, len, filp->f_pos, ino, | ||
1137 | dt_type(next)) < 0) | ||
1138 | break; | ||
1139 | 931 | ||
1140 | filp->f_pos++; | 932 | /* Skip the dentries we have already reported */ |
1141 | } | 933 | pos = parent_sd->s_dir.children; |
934 | while (pos && (filp->f_pos > pos->s_ino)) | ||
935 | pos = pos->s_sibling; | ||
1142 | 936 | ||
1143 | /* put cursor back in */ | 937 | for ( ; pos; pos = pos->s_sibling) { |
1144 | cursor->s_sibling = *pos; | 938 | const char * name; |
1145 | *pos = cursor; | 939 | int len; |
1146 | 940 | ||
1147 | mutex_unlock(&sysfs_mutex); | 941 | name = pos->s_name; |
1148 | } | 942 | len = strlen(name); |
1149 | return 0; | 943 | filp->f_pos = ino = pos->s_ino; |
1150 | } | ||
1151 | |||
1152 | static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) | ||
1153 | { | ||
1154 | struct dentry * dentry = file->f_path.dentry; | ||
1155 | 944 | ||
1156 | switch (origin) { | 945 | if (filldir(dirent, name, len, filp->f_pos, ino, |
1157 | case 1: | 946 | dt_type(pos)) < 0) |
1158 | offset += file->f_pos; | ||
1159 | case 0: | ||
1160 | if (offset >= 0) | ||
1161 | break; | 947 | break; |
1162 | default: | ||
1163 | return -EINVAL; | ||
1164 | } | ||
1165 | if (offset != file->f_pos) { | ||
1166 | mutex_lock(&sysfs_mutex); | ||
1167 | |||
1168 | file->f_pos = offset; | ||
1169 | if (file->f_pos >= 2) { | ||
1170 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
1171 | struct sysfs_dirent *cursor = file->private_data; | ||
1172 | struct sysfs_dirent **pos; | ||
1173 | loff_t n = file->f_pos - 2; | ||
1174 | |||
1175 | sysfs_unlink_sibling(cursor); | ||
1176 | |||
1177 | pos = &sd->s_children; | ||
1178 | while (n && *pos) { | ||
1179 | struct sysfs_dirent *next = *pos; | ||
1180 | if (sysfs_type(next)) | ||
1181 | n--; | ||
1182 | pos = &(*pos)->s_sibling; | ||
1183 | } | ||
1184 | |||
1185 | cursor->s_sibling = *pos; | ||
1186 | *pos = cursor; | ||
1187 | } | 948 | } |
1188 | 949 | if (!pos) | |
950 | filp->f_pos = INT_MAX; | ||
1189 | mutex_unlock(&sysfs_mutex); | 951 | mutex_unlock(&sysfs_mutex); |
1190 | } | 952 | } |
1191 | |||
1192 | return offset; | ||
1193 | } | ||
1194 | |||
1195 | |||
1196 | /** | ||
1197 | * sysfs_make_shadowed_dir - Setup so a directory can be shadowed | ||
1198 | * @kobj: object we're creating shadow of. | ||
1199 | */ | ||
1200 | |||
1201 | int sysfs_make_shadowed_dir(struct kobject *kobj, | ||
1202 | void * (*follow_link)(struct dentry *, struct nameidata *)) | ||
1203 | { | ||
1204 | struct dentry *dentry; | ||
1205 | struct inode *inode; | ||
1206 | struct inode_operations *i_op; | ||
1207 | |||
1208 | /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */ | ||
1209 | dentry = sysfs_get_dentry(kobj->sd); | ||
1210 | if (IS_ERR(dentry)) | ||
1211 | return PTR_ERR(dentry); | ||
1212 | |||
1213 | inode = dentry->d_inode; | ||
1214 | if (inode->i_op != &sysfs_dir_inode_operations) { | ||
1215 | dput(dentry); | ||
1216 | return -EINVAL; | ||
1217 | } | ||
1218 | |||
1219 | i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); | ||
1220 | if (!i_op) | ||
1221 | return -ENOMEM; | ||
1222 | |||
1223 | memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op)); | ||
1224 | i_op->follow_link = follow_link; | ||
1225 | |||
1226 | /* Locking of inode->i_op? | ||
1227 | * Since setting i_op is a single word write and they | ||
1228 | * are atomic we should be ok here. | ||
1229 | */ | ||
1230 | inode->i_op = i_op; | ||
1231 | return 0; | 953 | return 0; |
1232 | } | 954 | } |
1233 | 955 | ||
1234 | /** | ||
1235 | * sysfs_create_shadow_dir - create a shadow directory for an object. | ||
1236 | * @kobj: object we're creating directory for. | ||
1237 | * | ||
1238 | * sysfs_make_shadowed_dir must already have been called on this | ||
1239 | * directory. | ||
1240 | */ | ||
1241 | |||
1242 | struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj) | ||
1243 | { | ||
1244 | struct sysfs_dirent *parent_sd = kobj->sd->s_parent; | ||
1245 | struct dentry *dir, *parent, *shadow; | ||
1246 | struct inode *inode; | ||
1247 | struct sysfs_dirent *sd; | ||
1248 | struct sysfs_addrm_cxt acxt; | ||
1249 | |||
1250 | dir = sysfs_get_dentry(kobj->sd); | ||
1251 | if (IS_ERR(dir)) { | ||
1252 | sd = (void *)dir; | ||
1253 | goto out; | ||
1254 | } | ||
1255 | parent = dir->d_parent; | ||
1256 | |||
1257 | inode = dir->d_inode; | ||
1258 | sd = ERR_PTR(-EINVAL); | ||
1259 | if (!sysfs_is_shadowed_inode(inode)) | ||
1260 | goto out_dput; | ||
1261 | |||
1262 | shadow = d_alloc(parent, &dir->d_name); | ||
1263 | if (!shadow) | ||
1264 | goto nomem; | ||
1265 | |||
1266 | sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR); | ||
1267 | if (!sd) | ||
1268 | goto nomem; | ||
1269 | sd->s_elem.dir.kobj = kobj; | ||
1270 | |||
1271 | sysfs_addrm_start(&acxt, parent_sd); | ||
1272 | |||
1273 | /* add but don't link into children list */ | ||
1274 | sysfs_add_one(&acxt, sd); | ||
1275 | |||
1276 | /* attach and instantiate dentry */ | ||
1277 | sysfs_attach_dentry(sd, shadow); | ||
1278 | d_instantiate(shadow, igrab(inode)); | ||
1279 | inc_nlink(inode); /* tj: synchronization? */ | ||
1280 | |||
1281 | sysfs_addrm_finish(&acxt); | ||
1282 | |||
1283 | dget(shadow); /* Extra count - pin the dentry in core */ | ||
1284 | |||
1285 | goto out_dput; | ||
1286 | |||
1287 | nomem: | ||
1288 | dput(shadow); | ||
1289 | sd = ERR_PTR(-ENOMEM); | ||
1290 | out_dput: | ||
1291 | dput(dir); | ||
1292 | out: | ||
1293 | return sd; | ||
1294 | } | ||
1295 | |||
1296 | /** | ||
1297 | * sysfs_remove_shadow_dir - remove an object's directory. | ||
1298 | * @shadow_sd: sysfs_dirent of shadow directory | ||
1299 | * | ||
1300 | * The only thing special about this is that we remove any files in | ||
1301 | * the directory before we remove the directory, and we've inlined | ||
1302 | * what used to be sysfs_rmdir() below, instead of calling separately. | ||
1303 | */ | ||
1304 | |||
1305 | void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd) | ||
1306 | { | ||
1307 | __sysfs_remove_dir(shadow_sd); | ||
1308 | } | ||
1309 | 956 | ||
1310 | const struct file_operations sysfs_dir_operations = { | 957 | const struct file_operations sysfs_dir_operations = { |
1311 | .open = sysfs_dir_open, | ||
1312 | .release = sysfs_dir_close, | ||
1313 | .llseek = sysfs_dir_lseek, | ||
1314 | .read = generic_read_dir, | 958 | .read = generic_read_dir, |
1315 | .readdir = sysfs_readdir, | 959 | .readdir = sysfs_readdir, |
1316 | }; | 960 | }; |