aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-08-20 08:36:30 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:51:08 -0400
commit932ea2e374dd1ca26676297a5eccd1cdab86f7cd (patch)
tree83bba794de7f1f9f9290192f4f95a8ed9c91dfb6 /fs/sysfs
parent89bec09705d2033b8b765f3c3ac5093f80bd5bc4 (diff)
sysfs: Introduce sysfs_rename_mutex
Looking carefully at the rename code we have a subtle dependency that the structure of sysfs not change while we are performing a rename. If the parent directory of the object we are renaming changes while the rename is being performed nasty things could happen when we go to release our locks. So introduce a sysfs_rename_mutex to prevent this highly unlikely theoretical issue. In addition hold sysfs_rename_mutex over all calls to sysfs_get_dentry. Allowing sysfs_get_dentry to be simplified in the future. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs')
-rw-r--r--fs/sysfs/dir.c8
-rw-r--r--fs/sysfs/file.c4
-rw-r--r--fs/sysfs/sysfs.h1
3 files changed, 12 insertions, 1 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 1af963e66e3..9fe83d23dc2 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -15,6 +15,7 @@
15#include "sysfs.h" 15#include "sysfs.h"
16 16
17DEFINE_MUTEX(sysfs_mutex); 17DEFINE_MUTEX(sysfs_mutex);
18DEFINE_MUTEX(sysfs_rename_mutex);
18spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; 19spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
19 20
20static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; 21static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
@@ -82,7 +83,7 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
82 * down from there looking up dentry for each step. 83 * down from there looking up dentry for each step.
83 * 84 *
84 * LOCKING: 85 * LOCKING:
85 * Kernel thread context (may sleep) 86 * mutex_lock(sysfs_rename_mutex)
86 * 87 *
87 * RETURNS: 88 * RETURNS:
88 * Pointer to found dentry on success, ERR_PTR() value on error. 89 * Pointer to found dentry on success, ERR_PTR() value on error.
@@ -858,6 +859,8 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
858 const char *dup_name = NULL; 859 const char *dup_name = NULL;
859 int error; 860 int error;
860 861
862 mutex_lock(&sysfs_rename_mutex);
863
861 /* get the original dentry */ 864 /* get the original dentry */
862 sd = kobj->sd; 865 sd = kobj->sd;
863 old_dentry = sysfs_get_dentry(sd); 866 old_dentry = sysfs_get_dentry(sd);
@@ -915,6 +918,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
915 kfree(dup_name); 918 kfree(dup_name);
916 dput(old_dentry); 919 dput(old_dentry);
917 dput(new_dentry); 920 dput(new_dentry);
921 mutex_unlock(&sysfs_rename_mutex);
918 return error; 922 return error;
919} 923}
920 924
@@ -926,6 +930,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
926 struct dentry *old_dentry = NULL, *new_dentry = NULL; 930 struct dentry *old_dentry = NULL, *new_dentry = NULL;
927 int error; 931 int error;
928 932
933 mutex_lock(&sysfs_rename_mutex);
929 BUG_ON(!sd->s_parent); 934 BUG_ON(!sd->s_parent);
930 new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; 935 new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root;
931 936
@@ -982,6 +987,7 @@ again:
982 dput(new_parent); 987 dput(new_parent);
983 dput(old_dentry); 988 dput(old_dentry);
984 dput(new_dentry); 989 dput(new_dentry);
990 mutex_unlock(&sysfs_rename_mutex);
985 return error; 991 return error;
986} 992}
987 993
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 16f39c30b09..ff93c92164b 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -470,7 +470,9 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
470 if (!victim_sd) 470 if (!victim_sd)
471 goto out; 471 goto out;
472 472
473 mutex_lock(&sysfs_rename_mutex);
473 victim = sysfs_get_dentry(victim_sd); 474 victim = sysfs_get_dentry(victim_sd);
475 mutex_unlock(&sysfs_rename_mutex);
474 if (IS_ERR(victim)) { 476 if (IS_ERR(victim)) {
475 rc = PTR_ERR(victim); 477 rc = PTR_ERR(victim);
476 victim = NULL; 478 victim = NULL;
@@ -509,7 +511,9 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
509 if (!victim_sd) 511 if (!victim_sd)
510 goto out; 512 goto out;
511 513
514 mutex_lock(&sysfs_rename_mutex);
512 victim = sysfs_get_dentry(victim_sd); 515 victim = sysfs_get_dentry(victim_sd);
516 mutex_unlock(&sysfs_rename_mutex);
513 if (IS_ERR(victim)) { 517 if (IS_ERR(victim)) {
514 rc = PTR_ERR(victim); 518 rc = PTR_ERR(victim);
515 victim = NULL; 519 victim = NULL;
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 77253aabc4a..179e6a26ece 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -90,6 +90,7 @@ extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
90 90
91extern spinlock_t sysfs_assoc_lock; 91extern spinlock_t sysfs_assoc_lock;
92extern struct mutex sysfs_mutex; 92extern struct mutex sysfs_mutex;
93extern struct mutex sysfs_rename_mutex;
93extern struct super_block * sysfs_sb; 94extern struct super_block * sysfs_sb;
94extern const struct file_operations sysfs_dir_operations; 95extern const struct file_operations sysfs_dir_operations;
95extern const struct file_operations sysfs_file_operations; 96extern const struct file_operations sysfs_file_operations;