aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/sysfs/dir.c91
1 files changed, 16 insertions, 75 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 9fe83d23dc2c..1c3dc5d01ccd 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -78,9 +78,8 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
78 * @sd: sysfs_dirent of interest 78 * @sd: sysfs_dirent of interest
79 * 79 *
80 * Get dentry for @sd. Dentry is looked up if currently not 80 * Get dentry for @sd. Dentry is looked up if currently not
81 * present. This function climbs sysfs_dirent tree till it 81 * present. This function descends from the root looking up
82 * reaches a sysfs_dirent with valid dentry attached and descends 82 * dentry for each step.
83 * down from there looking up dentry for each step.
84 * 83 *
85 * LOCKING: 84 * LOCKING:
86 * mutex_lock(sysfs_rename_mutex) 85 * mutex_lock(sysfs_rename_mutex)
@@ -90,86 +89,28 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
90 */ 89 */
91struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) 90struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
92{ 91{
93 struct sysfs_dirent *cur; 92 struct dentry *dentry = dget(sysfs_sb->s_root);
94 struct dentry *parent_dentry, *dentry;
95 int i, depth;
96 93
97 /* Find the first parent which has valid s_dentry and get the 94 while (dentry->d_fsdata != sd) {
98 * dentry. 95 struct sysfs_dirent *cur;
99 */ 96 struct dentry *parent;
100 mutex_lock(&sysfs_mutex);
101 restart0:
102 spin_lock(&sysfs_assoc_lock);
103 restart1:
104 spin_lock(&dcache_lock);
105
106 dentry = NULL;
107 depth = 0;
108 cur = sd;
109 while (!cur->s_dentry || !cur->s_dentry->d_inode) {
110 if (cur->s_flags & SYSFS_FLAG_REMOVED) {
111 dentry = ERR_PTR(-ENOENT);
112 depth = 0;
113 break;
114 }
115 cur = cur->s_parent;
116 depth++;
117 }
118 if (!IS_ERR(dentry))
119 dentry = dget_locked(cur->s_dentry);
120 97
121 spin_unlock(&dcache_lock); 98 /* find the first ancestor which hasn't been looked up */
122 spin_unlock(&sysfs_assoc_lock); 99 cur = sd;
123 100 while (cur->s_parent != dentry->d_fsdata)
124 /* from the found dentry, look up depth times */
125 while (depth--) {
126 /* find and get depth'th ancestor */
127 for (cur = sd, i = 0; cur && i < depth; i++)
128 cur = cur->s_parent; 101 cur = cur->s_parent;
129 102
130 /* This can happen if tree structure was modified due
131 * to move/rename. Restart.
132 */
133 if (i != depth) {
134 dput(dentry);
135 goto restart0;
136 }
137
138 sysfs_get(cur);
139
140 mutex_unlock(&sysfs_mutex);
141
142 /* look it up */ 103 /* look it up */
143 parent_dentry = dentry; 104 parent = dentry;
144 mutex_lock(&parent_dentry->d_inode->i_mutex); 105 mutex_lock(&parent->d_inode->i_mutex);
145 dentry = lookup_one_len_kern(cur->s_name, parent_dentry, 106 dentry = lookup_one_len_kern(cur->s_name, parent,
146 strlen(cur->s_name)); 107 strlen(cur->s_name));
147 mutex_unlock(&parent_dentry->d_inode->i_mutex); 108 mutex_unlock(&parent->d_inode->i_mutex);
148 dput(parent_dentry); 109 dput(parent);
149
150 if (IS_ERR(dentry)) {
151 sysfs_put(cur);
152 return dentry;
153 }
154 110
155 mutex_lock(&sysfs_mutex); 111 if (IS_ERR(dentry))
156 spin_lock(&sysfs_assoc_lock); 112 break;
157
158 /* This, again, can happen if tree structure has
159 * changed and we looked up the wrong thing. Restart.
160 */
161 if (cur->s_dentry != dentry) {
162 dput(dentry);
163 sysfs_put(cur);
164 goto restart1;
165 }
166
167 spin_unlock(&sysfs_assoc_lock);
168
169 sysfs_put(cur);
170 } 113 }
171
172 mutex_unlock(&sysfs_mutex);
173 return dentry; 114 return dentry;
174} 115}
175 116