aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/sysfs/dir.c101
-rw-r--r--fs/sysfs/file.c31
-rw-r--r--fs/sysfs/inode.c11
-rw-r--r--fs/sysfs/symlink.c51
-rw-r--r--fs/sysfs/sysfs.h2
5 files changed, 116 insertions, 80 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);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 20703b9ee064..d0deed3e60b5 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -415,29 +415,28 @@ const struct file_operations sysfs_file_operations = {
415int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, 415int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
416 int type) 416 int type)
417{ 417{
418 struct dentry *dir = dir_sd->s_dentry;
419 umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; 418 umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
420 struct sysfs_dirent *sd; 419 struct sysfs_dirent *sd;
421 int error = 0;
422 420
423 mutex_lock(&dir->d_inode->i_mutex); 421 sd = sysfs_new_dirent(attr->name, mode, type);
422 if (!sd)
423 return -ENOMEM;
424 sd->s_elem.attr.attr = (void *)attr;
424 425
425 if (sysfs_find_dirent(dir_sd, attr->name)) { 426 mutex_lock(&sysfs_mutex);
426 error = -EEXIST;
427 goto out_unlock;
428 }
429 427
430 sd = sysfs_new_dirent(attr->name, mode, type); 428 if (!sysfs_find_dirent(dir_sd, attr->name)) {
431 if (!sd) { 429 sysfs_attach_dirent(sd, dir_sd, NULL);
432 error = -ENOMEM; 430 sd = NULL;
433 goto out_unlock;
434 } 431 }
435 sd->s_elem.attr.attr = (void *)attr;
436 sysfs_attach_dirent(sd, dir_sd, NULL);
437 432
438 out_unlock: 433 mutex_unlock(&sysfs_mutex);
439 mutex_unlock(&dir->d_inode->i_mutex); 434
440 return error; 435 if (sd) {
436 sysfs_put(sd);
437 return -EEXIST;
438 }
439 return 0;
441} 440}
442 441
443 442
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index e4c23939fb36..d439c0b4bfce 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -277,20 +277,14 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)
277 277
278int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) 278int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
279{ 279{
280 struct dentry *dir;
281 struct sysfs_dirent **pos, *sd; 280 struct sysfs_dirent **pos, *sd;
282 int found = 0; 281 int found = 0;
283 282
284 if (!dir_sd) 283 if (!dir_sd)
285 return -ENOENT; 284 return -ENOENT;
286 285
287 dir = dir_sd->s_dentry; 286 mutex_lock(&sysfs_mutex);
288 287
289 if (dir->d_inode == NULL)
290 /* no inode means this hasn't been made visible yet */
291 return -ENOENT;
292
293 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
294 for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { 288 for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
295 sd = *pos; 289 sd = *pos;
296 290
@@ -304,7 +298,8 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
304 break; 298 break;
305 } 299 }
306 } 300 }
307 mutex_unlock(&dir->d_inode->i_mutex); 301
302 mutex_unlock(&sysfs_mutex);
308 303
309 if (!found) 304 if (!found)
310 return -ENOENT; 305 return -ENOENT;
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index cbd95a4109de..683316f0aa96 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -44,20 +44,6 @@ static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
44 } 44 }
45} 45}
46 46
47static int sysfs_add_link(struct sysfs_dirent * parent_sd, const char * name,
48 struct sysfs_dirent * target_sd)
49{
50 struct sysfs_dirent * sd;
51
52 sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
53 if (!sd)
54 return -ENOMEM;
55
56 sd->s_elem.symlink.target_sd = target_sd;
57 sysfs_attach_dirent(sd, parent_sd, NULL);
58 return 0;
59}
60
61/** 47/**
62 * sysfs_create_link - create symlink between two objects. 48 * sysfs_create_link - create symlink between two objects.
63 * @kobj: object whose directory we're creating the link in. 49 * @kobj: object whose directory we're creating the link in.
@@ -68,7 +54,8 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
68{ 54{
69 struct sysfs_dirent *parent_sd = NULL; 55 struct sysfs_dirent *parent_sd = NULL;
70 struct sysfs_dirent *target_sd = NULL; 56 struct sysfs_dirent *target_sd = NULL;
71 int error = -EEXIST; 57 struct sysfs_dirent *sd = NULL;
58 int error;
72 59
73 BUG_ON(!name); 60 BUG_ON(!name);
74 61
@@ -78,8 +65,9 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
78 } else 65 } else
79 parent_sd = kobj->sd; 66 parent_sd = kobj->sd;
80 67
68 error = -EFAULT;
81 if (!parent_sd) 69 if (!parent_sd)
82 return -EFAULT; 70 goto out_put;
83 71
84 /* target->sd can go away beneath us but is protected with 72 /* target->sd can go away beneath us but is protected with
85 * sysfs_assoc_lock. Fetch target_sd from it. 73 * sysfs_assoc_lock. Fetch target_sd from it.
@@ -89,17 +77,30 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
89 target_sd = sysfs_get(target->sd); 77 target_sd = sysfs_get(target->sd);
90 spin_unlock(&sysfs_assoc_lock); 78 spin_unlock(&sysfs_assoc_lock);
91 79
80 error = -ENOENT;
92 if (!target_sd) 81 if (!target_sd)
93 return -ENOENT; 82 goto out_put;
83
84 error = -ENOMEM;
85 sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
86 if (!sd)
87 goto out_put;
88 sd->s_elem.symlink.target_sd = target_sd;
94 89
95 mutex_lock(&parent_sd->s_dentry->d_inode->i_mutex); 90 mutex_lock(&sysfs_mutex);
96 if (!sysfs_find_dirent(parent_sd, name)) 91 error = -EEXIST;
97 error = sysfs_add_link(parent_sd, name, target_sd); 92 if (sysfs_find_dirent(parent_sd, name))
98 mutex_unlock(&parent_sd->s_dentry->d_inode->i_mutex); 93 goto out_unlock;
94 sysfs_attach_dirent(sd, parent_sd, NULL);
95 mutex_unlock(&sysfs_mutex);
99 96
100 if (error) 97 return 0;
101 sysfs_put(target_sd);
102 98
99 out_unlock:
100 mutex_unlock(&sysfs_mutex);
101 out_put:
102 sysfs_put(target_sd);
103 sysfs_put(sd);
103 return error; 104 return error;
104} 105}
105 106
@@ -144,9 +145,9 @@ static int sysfs_getlink(struct dentry *dentry, char * path)
144 struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd; 145 struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd;
145 int error; 146 int error;
146 147
147 down_read(&sysfs_rename_sem); 148 mutex_lock(&sysfs_mutex);
148 error = sysfs_get_target_path(parent_sd, target_sd, path); 149 error = sysfs_get_target_path(parent_sd, target_sd, path);
149 up_read(&sysfs_rename_sem); 150 mutex_unlock(&sysfs_mutex);
150 151
151 return error; 152 return error;
152} 153}
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 457267721f4e..26051616ed11 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -82,7 +82,7 @@ extern void sysfs_drop_dentry(struct sysfs_dirent *sd);
82extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); 82extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
83 83
84extern spinlock_t sysfs_assoc_lock; 84extern spinlock_t sysfs_assoc_lock;
85extern struct rw_semaphore sysfs_rename_sem; 85extern struct mutex sysfs_mutex;
86extern struct super_block * sysfs_sb; 86extern struct super_block * sysfs_sb;
87extern const struct file_operations sysfs_dir_operations; 87extern const struct file_operations sysfs_dir_operations;
88extern const struct file_operations sysfs_file_operations; 88extern const struct file_operations sysfs_file_operations;