aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2009-11-20 19:08:56 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 14:24:54 -0500
commit832b6af198aefe6034310e124594cc8b833c0ef9 (patch)
tree853eec8f7449dd7fc51c6d4c9b70ea44b81cf0d9 /fs/sysfs
parenta16bbc3430ed94b543222f4c8ef68025f8493e93 (diff)
sysfs: Propagate renames to the vfs on demand
By teaching sysfs_revalidate to hide a dentry for a sysfs_dirent if the sysfs_dirent has been renamed, and by teaching sysfs_lookup to return the original dentry if the sysfs dirent has been renamed. I can show the results of renames correctly without having to update the dcache during the directory rename. This massively simplifies the rename logic allowing a lot of weird sysfs special cases to be removed along with a lot of now unnecesary helper code. Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs')
-rw-r--r--fs/sysfs/dir.c158
-rw-r--r--fs/sysfs/inode.c12
-rw-r--r--fs/sysfs/sysfs.h1
3 files changed, 32 insertions, 139 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index f3af45e47eaa..97954c69ff0e 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -25,7 +25,6 @@
25#include "sysfs.h" 25#include "sysfs.h"
26 26
27DEFINE_MUTEX(sysfs_mutex); 27DEFINE_MUTEX(sysfs_mutex);
28DEFINE_MUTEX(sysfs_rename_mutex);
29DEFINE_SPINLOCK(sysfs_assoc_lock); 28DEFINE_SPINLOCK(sysfs_assoc_lock);
30 29
31static DEFINE_SPINLOCK(sysfs_ino_lock); 30static DEFINE_SPINLOCK(sysfs_ino_lock);
@@ -85,46 +84,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
85} 84}
86 85
87/** 86/**
88 * sysfs_get_dentry - get dentry for the given sysfs_dirent
89 * @sd: sysfs_dirent of interest
90 *
91 * Get dentry for @sd. Dentry is looked up if currently not
92 * present. This function descends from the root looking up
93 * dentry for each step.
94 *
95 * LOCKING:
96 * mutex_lock(sysfs_rename_mutex)
97 *
98 * RETURNS:
99 * Pointer to found dentry on success, ERR_PTR() value on error.
100 */
101struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
102{
103 struct dentry *dentry = dget(sysfs_sb->s_root);
104
105 while (dentry->d_fsdata != sd) {
106 struct sysfs_dirent *cur;
107 struct dentry *parent;
108
109 /* find the first ancestor which hasn't been looked up */
110 cur = sd;
111 while (cur->s_parent != dentry->d_fsdata)
112 cur = cur->s_parent;
113
114 /* look it up */
115 parent = dentry;
116 mutex_lock(&parent->d_inode->i_mutex);
117 dentry = lookup_one_noperm(cur->s_name, parent);
118 mutex_unlock(&parent->d_inode->i_mutex);
119 dput(parent);
120
121 if (IS_ERR(dentry))
122 break;
123 }
124 return dentry;
125}
126
127/**
128 * sysfs_get_active - get an active reference to sysfs_dirent 87 * sysfs_get_active - get an active reference to sysfs_dirent
129 * @sd: sysfs_dirent to get an active reference to 88 * @sd: sysfs_dirent to get an active reference to
130 * 89 *
@@ -315,6 +274,14 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
315 if (sd->s_flags & SYSFS_FLAG_REMOVED) 274 if (sd->s_flags & SYSFS_FLAG_REMOVED)
316 goto out_bad; 275 goto out_bad;
317 276
277 /* The sysfs dirent has been moved? */
278 if (dentry->d_parent->d_fsdata != sd->s_parent)
279 goto out_bad;
280
281 /* The sysfs dirent has been renamed */
282 if (strcmp(dentry->d_name.name, sd->s_name) != 0)
283 goto out_bad;
284
318 mutex_unlock(&sysfs_mutex); 285 mutex_unlock(&sysfs_mutex);
319out_valid: 286out_valid:
320 return 1; 287 return 1;
@@ -322,6 +289,12 @@ out_bad:
322 /* Remove the dentry from the dcache hashes. 289 /* Remove the dentry from the dcache hashes.
323 * If this is a deleted dentry we use d_drop instead of d_delete 290 * If this is a deleted dentry we use d_drop instead of d_delete
324 * so sysfs doesn't need to cope with negative dentries. 291 * so sysfs doesn't need to cope with negative dentries.
292 *
293 * If this is a dentry that has simply been renamed we
294 * use d_drop to remove it from the dcache lookup on its
295 * old parent. If this dentry persists later when a lookup
296 * is performed at its new name the dentry will be readded
297 * to the dcache hashes.
325 */ 298 */
326 is_dir = (sysfs_type(sd) == SYSFS_DIR); 299 is_dir = (sysfs_type(sd) == SYSFS_DIR);
327 mutex_unlock(&sysfs_mutex); 300 mutex_unlock(&sysfs_mutex);
@@ -705,10 +678,15 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
705 } 678 }
706 679
707 /* instantiate and hash dentry */ 680 /* instantiate and hash dentry */
708 dentry->d_op = &sysfs_dentry_ops; 681 ret = d_find_alias(inode);
709 dentry->d_fsdata = sysfs_get(sd); 682 if (!ret) {
710 d_instantiate(dentry, inode); 683 dentry->d_op = &sysfs_dentry_ops;
711 d_rehash(dentry); 684 dentry->d_fsdata = sysfs_get(sd);
685 d_add(dentry, inode);
686 } else {
687 d_move(ret, dentry);
688 iput(inode);
689 }
712 690
713 out_unlock: 691 out_unlock:
714 mutex_unlock(&sysfs_mutex); 692 mutex_unlock(&sysfs_mutex);
@@ -785,62 +763,32 @@ void sysfs_remove_dir(struct kobject * kobj)
785int sysfs_rename_dir(struct kobject * kobj, const char *new_name) 763int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
786{ 764{
787 struct sysfs_dirent *sd = kobj->sd; 765 struct sysfs_dirent *sd = kobj->sd;
788 struct dentry *parent = NULL;
789 struct dentry *old_dentry = NULL, *new_dentry = NULL;
790 const char *dup_name = NULL; 766 const char *dup_name = NULL;
791 int error; 767 int error;
792 768
793 mutex_lock(&sysfs_rename_mutex); 769 mutex_lock(&sysfs_mutex);
794 770
795 error = 0; 771 error = 0;
796 if (strcmp(sd->s_name, new_name) == 0) 772 if (strcmp(sd->s_name, new_name) == 0)
797 goto out; /* nothing to rename */ 773 goto out; /* nothing to rename */
798 774
799 /* get the original dentry */
800 old_dentry = sysfs_get_dentry(sd);
801 if (IS_ERR(old_dentry)) {
802 error = PTR_ERR(old_dentry);
803 old_dentry = NULL;
804 goto out;
805 }
806
807 parent = old_dentry->d_parent;
808
809 /* lock parent and get dentry for new name */
810 mutex_lock(&parent->d_inode->i_mutex);
811 mutex_lock(&sysfs_mutex);
812
813 error = -EEXIST; 775 error = -EEXIST;
814 if (sysfs_find_dirent(sd->s_parent, new_name)) 776 if (sysfs_find_dirent(sd->s_parent, new_name))
815 goto out_unlock; 777 goto out;
816
817 error = -ENOMEM;
818 new_dentry = d_alloc_name(parent, new_name);
819 if (!new_dentry)
820 goto out_unlock;
821 778
822 /* rename sysfs_dirent */ 779 /* rename sysfs_dirent */
823 error = -ENOMEM; 780 error = -ENOMEM;
824 new_name = dup_name = kstrdup(new_name, GFP_KERNEL); 781 new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
825 if (!new_name) 782 if (!new_name)
826 goto out_unlock; 783 goto out;
827 784
828 dup_name = sd->s_name; 785 dup_name = sd->s_name;
829 sd->s_name = new_name; 786 sd->s_name = new_name;
830 787
831 /* rename */
832 d_add(new_dentry, NULL);
833 d_move(old_dentry, new_dentry);
834
835 error = 0; 788 error = 0;
836 out_unlock: 789 out:
837 mutex_unlock(&sysfs_mutex); 790 mutex_unlock(&sysfs_mutex);
838 mutex_unlock(&parent->d_inode->i_mutex);
839 kfree(dup_name); 791 kfree(dup_name);
840 dput(old_dentry);
841 dput(new_dentry);
842 out:
843 mutex_unlock(&sysfs_rename_mutex);
844 return error; 792 return error;
845} 793}
846 794
@@ -848,12 +796,11 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
848{ 796{
849 struct sysfs_dirent *sd = kobj->sd; 797 struct sysfs_dirent *sd = kobj->sd;
850 struct sysfs_dirent *new_parent_sd; 798 struct sysfs_dirent *new_parent_sd;
851 struct dentry *old_parent, *new_parent = NULL;
852 struct dentry *old_dentry = NULL, *new_dentry = NULL;
853 int error; 799 int error;
854 800
855 mutex_lock(&sysfs_rename_mutex);
856 BUG_ON(!sd->s_parent); 801 BUG_ON(!sd->s_parent);
802
803 mutex_lock(&sysfs_mutex);
857 new_parent_sd = (new_parent_kobj && new_parent_kobj->sd) ? 804 new_parent_sd = (new_parent_kobj && new_parent_kobj->sd) ?
858 new_parent_kobj->sd : &sysfs_root; 805 new_parent_kobj->sd : &sysfs_root;
859 806
@@ -861,61 +808,20 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
861 if (sd->s_parent == new_parent_sd) 808 if (sd->s_parent == new_parent_sd)
862 goto out; /* nothing to move */ 809 goto out; /* nothing to move */
863 810
864 /* get dentries */
865 old_dentry = sysfs_get_dentry(sd);
866 if (IS_ERR(old_dentry)) {
867 error = PTR_ERR(old_dentry);
868 old_dentry = NULL;
869 goto out;
870 }
871 old_parent = old_dentry->d_parent;
872
873 new_parent = sysfs_get_dentry(new_parent_sd);
874 if (IS_ERR(new_parent)) {
875 error = PTR_ERR(new_parent);
876 new_parent = NULL;
877 goto out;
878 }
879
880again:
881 mutex_lock(&old_parent->d_inode->i_mutex);
882 if (!mutex_trylock(&new_parent->d_inode->i_mutex)) {
883 mutex_unlock(&old_parent->d_inode->i_mutex);
884 goto again;
885 }
886 mutex_lock(&sysfs_mutex);
887
888 error = -EEXIST; 811 error = -EEXIST;
889 if (sysfs_find_dirent(new_parent_sd, sd->s_name)) 812 if (sysfs_find_dirent(new_parent_sd, sd->s_name))
890 goto out_unlock; 813 goto out;
891
892 error = -ENOMEM;
893 new_dentry = d_alloc_name(new_parent, sd->s_name);
894 if (!new_dentry)
895 goto out_unlock;
896
897 error = 0;
898 d_add(new_dentry, NULL);
899 d_move(old_dentry, new_dentry);
900 814
901 /* Remove from old parent's list and insert into new parent's list. */ 815 /* Remove from old parent's list and insert into new parent's list. */
902 sysfs_unlink_sibling(sd); 816 sysfs_unlink_sibling(sd);
903 sysfs_get(new_parent_sd); 817 sysfs_get(new_parent_sd);
904 drop_nlink(old_parent->d_inode);
905 sysfs_put(sd->s_parent); 818 sysfs_put(sd->s_parent);
906 sd->s_parent = new_parent_sd; 819 sd->s_parent = new_parent_sd;
907 inc_nlink(new_parent->d_inode);
908 sysfs_link_sibling(sd); 820 sysfs_link_sibling(sd);
909 821
910 out_unlock: 822 error = 0;
823out:
911 mutex_unlock(&sysfs_mutex); 824 mutex_unlock(&sysfs_mutex);
912 mutex_unlock(&new_parent->d_inode->i_mutex);
913 mutex_unlock(&old_parent->d_inode->i_mutex);
914 out:
915 dput(new_parent);
916 dput(old_dentry);
917 dput(new_dentry);
918 mutex_unlock(&sysfs_rename_mutex);
919 return error; 825 return error;
920} 826}
921 827
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 1ffd5559926f..9f783d4e4b51 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -205,17 +205,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
205 inode->i_ctime = iattr->ia_ctime; 205 inode->i_ctime = iattr->ia_ctime;
206} 206}
207 207
208
209/*
210 * sysfs has a different i_mutex lock order behavior for i_mutex than other
211 * filesystems; sysfs i_mutex is called in many places with subsystem locks
212 * held. At the same time, many of the VFS locking rules do not apply to
213 * sysfs at all (cross directory rename for example). To untangle this mess
214 * (which gives false positives in lockdep), we're giving sysfs inodes their
215 * own class for i_mutex.
216 */
217static struct lock_class_key sysfs_inode_imutex_key;
218
219static int sysfs_count_nlink(struct sysfs_dirent *sd) 208static int sysfs_count_nlink(struct sysfs_dirent *sd)
220{ 209{
221 struct sysfs_dirent *child; 210 struct sysfs_dirent *child;
@@ -268,7 +257,6 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
268 inode->i_mapping->a_ops = &sysfs_aops; 257 inode->i_mapping->a_ops = &sysfs_aops;
269 inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; 258 inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
270 inode->i_op = &sysfs_inode_operations; 259 inode->i_op = &sysfs_inode_operations;
271 lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
272 260
273 set_default_inode_attr(inode, sd->s_mode); 261 set_default_inode_attr(inode, sd->s_mode);
274 sysfs_refresh_inode(sd, inode); 262 sysfs_refresh_inode(sd, inode);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 90b35012abb2..98a15bf1efe1 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -103,7 +103,6 @@ extern struct kmem_cache *sysfs_dir_cachep;
103 * dir.c 103 * dir.c
104 */ 104 */
105extern struct mutex sysfs_mutex; 105extern struct mutex sysfs_mutex;
106extern struct mutex sysfs_rename_mutex;
107extern spinlock_t sysfs_assoc_lock; 106extern spinlock_t sysfs_assoc_lock;
108 107
109extern const struct file_operations sysfs_dir_operations; 108extern const struct file_operations sysfs_dir_operations;