aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-13 15:27:23 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 19:09:08 -0400
commit3007e997de91ec59af39a3f9c91595b31ae6e08b (patch)
tree4ed4df3ef3a249d2a4b562e36876fc8d4a3fabd9 /fs/sysfs/dir.c
parent5f9953237f684ea1778adb9d26162da00b282225 (diff)
sysfs: use sysfs_mutex to protect the sysfs_dirent tree
As kobj sysfs dentries and inodes are gonna be made reclaimable, i_mutex can't be used to protect sysfs_dirent tree. Use sysfs_mutex globally instead. As the whole tree is protected with sysfs_mutex, there is no reason to keep sysfs_rename_sem. Drop it. While at it, add docbook comments to functions which require sysfs_mutex locking. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r--fs/sysfs/dir.c101
1 files changed, 71 insertions, 30 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 1b5643407a95..9fc8558fd86c 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -14,7 +14,7 @@
14#include <asm/semaphore.h> 14#include <asm/semaphore.h>
15#include "sysfs.h" 15#include "sysfs.h"
16 16
17DECLARE_RWSEM(sysfs_rename_sem); 17DEFINE_MUTEX(sysfs_mutex);
18spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; 18spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
19 19
20static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; 20static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
@@ -28,7 +28,7 @@ static DEFINE_IDA(sysfs_ino_ida);
28 * sd->s_parent->s_children. 28 * sd->s_parent->s_children.
29 * 29 *
30 * Locking: 30 * Locking:
31 * mutex_lock(sd->s_parent->dentry->d_inode->i_mutex) 31 * mutex_lock(sysfs_mutex)
32 */ 32 */
33static void sysfs_link_sibling(struct sysfs_dirent *sd) 33static void sysfs_link_sibling(struct sysfs_dirent *sd)
34{ 34{
@@ -47,7 +47,7 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd)
47 * sd->s_parent->s_children. 47 * sd->s_parent->s_children.
48 * 48 *
49 * Locking: 49 * Locking:
50 * mutex_lock(sd->s_parent->dentry->d_inode->i_mutex) 50 * mutex_lock(sysfs_mutex)
51 */ 51 */
52static void sysfs_unlink_sibling(struct sysfs_dirent *sd) 52static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
53{ 53{
@@ -215,6 +215,9 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
215 struct sysfs_dirent *parent_sd; 215 struct sysfs_dirent *parent_sd;
216 216
217 repeat: 217 repeat:
218 /* Moving/renaming is always done while holding reference.
219 * sd->s_parent won't change beneath us.
220 */
218 parent_sd = sd->s_parent; 221 parent_sd = sd->s_parent;
219 222
220 if (sysfs_type(sd) == SYSFS_KOBJ_LINK) 223 if (sysfs_type(sd) == SYSFS_KOBJ_LINK)
@@ -291,6 +294,17 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
291 return NULL; 294 return NULL;
292} 295}
293 296
297/**
298 * sysfs_attach_dentry - associate sysfs_dirent with dentry
299 * @sd: target sysfs_dirent
300 * @dentry: dentry to associate
301 *
302 * Associate @sd with @dentry. This is protected by
303 * sysfs_assoc_lock to avoid race with sysfs_d_iput().
304 *
305 * LOCKING:
306 * mutex_lock(sysfs_mutex)
307 */
294static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry) 308static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
295{ 309{
296 dentry->d_op = &sysfs_dentry_ops; 310 dentry->d_op = &sysfs_dentry_ops;
@@ -304,6 +318,17 @@ static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
304 d_rehash(dentry); 318 d_rehash(dentry);
305} 319}
306 320
321/**
322 * sysfs_attach_dirent - attach sysfs_dirent to its parent and dentry
323 * @sd: sysfs_dirent to attach
324 * @parent_sd: parent to attach to (optional)
325 * @dentry: dentry to be associated to @sd (optional)
326 *
327 * Attach @sd to @parent_sd and/or @dentry. Both are optional.
328 *
329 * LOCKING:
330 * mutex_lock(sysfs_mutex)
331 */
307void sysfs_attach_dirent(struct sysfs_dirent *sd, 332void sysfs_attach_dirent(struct sysfs_dirent *sd,
308 struct sysfs_dirent *parent_sd, struct dentry *dentry) 333 struct sysfs_dirent *parent_sd, struct dentry *dentry)
309{ 334{
@@ -324,7 +349,7 @@ void sysfs_attach_dirent(struct sysfs_dirent *sd,
324 * Look for sysfs_dirent with name @name under @parent_sd. 349 * Look for sysfs_dirent with name @name under @parent_sd.
325 * 350 *
326 * LOCKING: 351 * LOCKING:
327 * mutex_lock(parent->i_mutex) 352 * mutex_lock(sysfs_mutex)
328 * 353 *
329 * RETURNS: 354 * RETURNS:
330 * Pointer to sysfs_dirent if found, NULL if not. 355 * Pointer to sysfs_dirent if found, NULL if not.
@@ -349,7 +374,7 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
349 * it if found. 374 * it if found.
350 * 375 *
351 * LOCKING: 376 * LOCKING:
352 * Kernel thread context (may sleep) 377 * Kernel thread context (may sleep). Grabs sysfs_mutex.
353 * 378 *
354 * RETURNS: 379 * RETURNS:
355 * Pointer to sysfs_dirent if found, NULL if not. 380 * Pointer to sysfs_dirent if found, NULL if not.
@@ -359,10 +384,10 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
359{ 384{
360 struct sysfs_dirent *sd; 385 struct sysfs_dirent *sd;
361 386
362 mutex_lock(&parent_sd->s_dentry->d_inode->i_mutex); 387 mutex_lock(&sysfs_mutex);
363 sd = sysfs_find_dirent(parent_sd, name); 388 sd = sysfs_find_dirent(parent_sd, name);
364 sysfs_get(sd); 389 sysfs_get(sd);
365 mutex_unlock(&parent_sd->s_dentry->d_inode->i_mutex); 390 mutex_unlock(&sysfs_mutex);
366 391
367 return sd; 392 return sd;
368} 393}
@@ -408,14 +433,20 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
408 } 433 }
409 434
410 /* link in */ 435 /* link in */
436 mutex_lock(&sysfs_mutex);
437
411 error = -EEXIST; 438 error = -EEXIST;
412 if (sysfs_find_dirent(parent_sd, name)) 439 if (sysfs_find_dirent(parent_sd, name)) {
440 mutex_unlock(&sysfs_mutex);
413 goto out_iput; 441 goto out_iput;
442 }
414 443
415 sysfs_instantiate(dentry, inode); 444 sysfs_instantiate(dentry, inode);
416 inc_nlink(parent->d_inode); 445 inc_nlink(parent->d_inode);
417 sysfs_attach_dirent(sd, parent_sd, dentry); 446 sysfs_attach_dirent(sd, parent_sd, dentry);
418 447
448 mutex_unlock(&sysfs_mutex);
449
419 *p_sd = sd; 450 *p_sd = sd;
420 error = 0; 451 error = 0;
421 goto out_unlock; /* pin directory dentry in core */ 452 goto out_unlock; /* pin directory dentry in core */
@@ -493,6 +524,8 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
493 if (!inode) 524 if (!inode)
494 return ERR_PTR(-ENOMEM); 525 return ERR_PTR(-ENOMEM);
495 526
527 mutex_lock(&sysfs_mutex);
528
496 if (inode->i_state & I_NEW) { 529 if (inode->i_state & I_NEW) {
497 /* initialize inode according to type */ 530 /* initialize inode according to type */
498 switch (sysfs_type(sd)) { 531 switch (sysfs_type(sd)) {
@@ -516,6 +549,8 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
516 sysfs_instantiate(dentry, inode); 549 sysfs_instantiate(dentry, inode);
517 sysfs_attach_dentry(sd, dentry); 550 sysfs_attach_dentry(sd, dentry);
518 551
552 mutex_unlock(&sysfs_mutex);
553
519 return NULL; 554 return NULL;
520} 555}
521 556
@@ -526,17 +561,13 @@ const struct inode_operations sysfs_dir_inode_operations = {
526 561
527static void remove_dir(struct sysfs_dirent *sd) 562static void remove_dir(struct sysfs_dirent *sd)
528{ 563{
529 struct dentry *parent = sd->s_parent->s_dentry; 564 mutex_lock(&sysfs_mutex);
530
531 mutex_lock(&parent->d_inode->i_mutex);
532
533 sysfs_unlink_sibling(sd); 565 sysfs_unlink_sibling(sd);
534 sd->s_flags |= SYSFS_FLAG_REMOVED; 566 sd->s_flags |= SYSFS_FLAG_REMOVED;
567 mutex_unlock(&sysfs_mutex);
535 568
536 pr_debug(" o %s removing done\n", sd->s_name); 569 pr_debug(" o %s removing done\n", sd->s_name);
537 570
538 mutex_unlock(&parent->d_inode->i_mutex);
539
540 sysfs_drop_dentry(sd); 571 sysfs_drop_dentry(sd);
541 sysfs_deactivate(sd); 572 sysfs_deactivate(sd);
542 sysfs_put(sd); 573 sysfs_put(sd);
@@ -552,15 +583,12 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
552{ 583{
553 struct sysfs_dirent *removed = NULL; 584 struct sysfs_dirent *removed = NULL;
554 struct sysfs_dirent **pos; 585 struct sysfs_dirent **pos;
555 struct dentry *dir;
556 586
557 if (!dir_sd) 587 if (!dir_sd)
558 return; 588 return;
559 589
560 dir = dir_sd->s_dentry;
561
562 pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); 590 pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
563 mutex_lock(&dir->d_inode->i_mutex); 591 mutex_lock(&sysfs_mutex);
564 pos = &dir_sd->s_children; 592 pos = &dir_sd->s_children;
565 while (*pos) { 593 while (*pos) {
566 struct sysfs_dirent *sd = *pos; 594 struct sysfs_dirent *sd = *pos;
@@ -573,7 +601,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
573 } else 601 } else
574 pos = &(*pos)->s_sibling; 602 pos = &(*pos)->s_sibling;
575 } 603 }
576 mutex_unlock(&dir->d_inode->i_mutex); 604 mutex_unlock(&sysfs_mutex);
577 605
578 while (removed) { 606 while (removed) {
579 struct sysfs_dirent *sd = removed; 607 struct sysfs_dirent *sd = removed;
@@ -621,7 +649,6 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
621 if (!new_parent_sd) 649 if (!new_parent_sd)
622 return -EFAULT; 650 return -EFAULT;
623 651
624 down_write(&sysfs_rename_sem);
625 mutex_lock(&new_parent->d_inode->i_mutex); 652 mutex_lock(&new_parent->d_inode->i_mutex);
626 653
627 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); 654 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
@@ -661,12 +688,16 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
661 d_add(new_dentry, NULL); 688 d_add(new_dentry, NULL);
662 d_move(sd->s_dentry, new_dentry); 689 d_move(sd->s_dentry, new_dentry);
663 690
691 mutex_lock(&sysfs_mutex);
692
664 sysfs_unlink_sibling(sd); 693 sysfs_unlink_sibling(sd);
665 sysfs_get(new_parent_sd); 694 sysfs_get(new_parent_sd);
666 sysfs_put(sd->s_parent); 695 sysfs_put(sd->s_parent);
667 sd->s_parent = new_parent_sd; 696 sd->s_parent = new_parent_sd;
668 sysfs_link_sibling(sd); 697 sysfs_link_sibling(sd);
669 698
699 mutex_unlock(&sysfs_mutex);
700
670 error = 0; 701 error = 0;
671 goto out_unlock; 702 goto out_unlock;
672 703
@@ -678,7 +709,6 @@ int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
678 dput(new_dentry); 709 dput(new_dentry);
679 out_unlock: 710 out_unlock:
680 mutex_unlock(&new_parent->d_inode->i_mutex); 711 mutex_unlock(&new_parent->d_inode->i_mutex);
681 up_write(&sysfs_rename_sem);
682 return error; 712 return error;
683} 713}
684 714
@@ -717,12 +747,15 @@ again:
717 dput(new_dentry); 747 dput(new_dentry);
718 748
719 /* Remove from old parent's list and insert into new parent's list. */ 749 /* Remove from old parent's list and insert into new parent's list. */
750 mutex_lock(&sysfs_mutex);
751
720 sysfs_unlink_sibling(sd); 752 sysfs_unlink_sibling(sd);
721 sysfs_get(new_parent_sd); 753 sysfs_get(new_parent_sd);
722 sysfs_put(sd->s_parent); 754 sysfs_put(sd->s_parent);
723 sd->s_parent = new_parent_sd; 755 sd->s_parent = new_parent_sd;
724 sysfs_link_sibling(sd); 756 sysfs_link_sibling(sd);
725 757
758 mutex_unlock(&sysfs_mutex);
726out: 759out:
727 mutex_unlock(&new_parent_dentry->d_inode->i_mutex); 760 mutex_unlock(&new_parent_dentry->d_inode->i_mutex);
728 mutex_unlock(&old_parent_dentry->d_inode->i_mutex); 761 mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
@@ -736,11 +769,12 @@ static int sysfs_dir_open(struct inode *inode, struct file *file)
736 struct sysfs_dirent * parent_sd = dentry->d_fsdata; 769 struct sysfs_dirent * parent_sd = dentry->d_fsdata;
737 struct sysfs_dirent * sd; 770 struct sysfs_dirent * sd;
738 771
739 mutex_lock(&dentry->d_inode->i_mutex);
740 sd = sysfs_new_dirent("_DIR_", 0, 0); 772 sd = sysfs_new_dirent("_DIR_", 0, 0);
741 if (sd) 773 if (sd) {
774 mutex_lock(&sysfs_mutex);
742 sysfs_attach_dirent(sd, parent_sd, NULL); 775 sysfs_attach_dirent(sd, parent_sd, NULL);
743 mutex_unlock(&dentry->d_inode->i_mutex); 776 mutex_unlock(&sysfs_mutex);
777 }
744 778
745 file->private_data = sd; 779 file->private_data = sd;
746 return sd ? 0 : -ENOMEM; 780 return sd ? 0 : -ENOMEM;
@@ -748,12 +782,11 @@ static int sysfs_dir_open(struct inode *inode, struct file *file)
748 782
749static int sysfs_dir_close(struct inode *inode, struct file *file) 783static int sysfs_dir_close(struct inode *inode, struct file *file)
750{ 784{
751 struct dentry * dentry = file->f_path.dentry;
752 struct sysfs_dirent * cursor = file->private_data; 785 struct sysfs_dirent * cursor = file->private_data;
753 786
754 mutex_lock(&dentry->d_inode->i_mutex); 787 mutex_lock(&sysfs_mutex);
755 sysfs_unlink_sibling(cursor); 788 sysfs_unlink_sibling(cursor);
756 mutex_unlock(&dentry->d_inode->i_mutex); 789 mutex_unlock(&sysfs_mutex);
757 790
758 release_sysfs_dirent(cursor); 791 release_sysfs_dirent(cursor);
759 792
@@ -794,6 +827,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
794 i++; 827 i++;
795 /* fallthrough */ 828 /* fallthrough */
796 default: 829 default:
830 mutex_lock(&sysfs_mutex);
831
797 pos = &parent_sd->s_children; 832 pos = &parent_sd->s_children;
798 while (*pos != cursor) 833 while (*pos != cursor)
799 pos = &(*pos)->s_sibling; 834 pos = &(*pos)->s_sibling;
@@ -826,6 +861,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
826 /* put cursor back in */ 861 /* put cursor back in */
827 cursor->s_sibling = *pos; 862 cursor->s_sibling = *pos;
828 *pos = cursor; 863 *pos = cursor;
864
865 mutex_unlock(&sysfs_mutex);
829 } 866 }
830 return 0; 867 return 0;
831} 868}
@@ -834,7 +871,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
834{ 871{
835 struct dentry * dentry = file->f_path.dentry; 872 struct dentry * dentry = file->f_path.dentry;
836 873
837 mutex_lock(&dentry->d_inode->i_mutex);
838 switch (origin) { 874 switch (origin) {
839 case 1: 875 case 1:
840 offset += file->f_pos; 876 offset += file->f_pos;
@@ -842,10 +878,11 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
842 if (offset >= 0) 878 if (offset >= 0)
843 break; 879 break;
844 default: 880 default:
845 mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
846 return -EINVAL; 881 return -EINVAL;
847 } 882 }
848 if (offset != file->f_pos) { 883 if (offset != file->f_pos) {
884 mutex_lock(&sysfs_mutex);
885
849 file->f_pos = offset; 886 file->f_pos = offset;
850 if (file->f_pos >= 2) { 887 if (file->f_pos >= 2) {
851 struct sysfs_dirent *sd = dentry->d_fsdata; 888 struct sysfs_dirent *sd = dentry->d_fsdata;
@@ -866,8 +903,10 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
866 cursor->s_sibling = *pos; 903 cursor->s_sibling = *pos;
867 *pos = cursor; 904 *pos = cursor;
868 } 905 }
906
907 mutex_unlock(&sysfs_mutex);
869 } 908 }
870 mutex_unlock(&dentry->d_inode->i_mutex); 909
871 return offset; 910 return offset;
872} 911}
873 912
@@ -933,7 +972,9 @@ struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
933 sd->s_elem.dir.kobj = kobj; 972 sd->s_elem.dir.kobj = kobj;
934 /* point to parent_sd but don't attach to it */ 973 /* point to parent_sd but don't attach to it */
935 sd->s_parent = sysfs_get(parent_sd); 974 sd->s_parent = sysfs_get(parent_sd);
975 mutex_lock(&sysfs_mutex);
936 sysfs_attach_dirent(sd, NULL, shadow); 976 sysfs_attach_dirent(sd, NULL, shadow);
977 mutex_unlock(&sysfs_mutex);
937 978
938 d_instantiate(shadow, igrab(inode)); 979 d_instantiate(shadow, igrab(inode));
939 inc_nlink(inode); 980 inc_nlink(inode);