diff options
Diffstat (limited to 'fs/sysfs/inode.c')
-rw-r--r-- | fs/sysfs/inode.c | 221 |
1 files changed, 64 insertions, 157 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 5266eec15f6e..10d1b52899f1 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -133,187 +133,94 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
133 | */ | 133 | */ |
134 | static struct lock_class_key sysfs_inode_imutex_key; | 134 | static struct lock_class_key sysfs_inode_imutex_key; |
135 | 135 | ||
136 | struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd) | 136 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
137 | { | 137 | { |
138 | struct inode * inode = new_inode(sysfs_sb); | 138 | inode->i_blocks = 0; |
139 | if (inode) { | 139 | inode->i_mapping->a_ops = &sysfs_aops; |
140 | inode->i_blocks = 0; | 140 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
141 | inode->i_mapping->a_ops = &sysfs_aops; | 141 | inode->i_op = &sysfs_inode_operations; |
142 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 142 | inode->i_ino = sd->s_ino; |
143 | inode->i_op = &sysfs_inode_operations; | 143 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); |
144 | inode->i_ino = sd->s_ino; | 144 | |
145 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | 145 | if (sd->s_iattr) { |
146 | 146 | /* sysfs_dirent has non-default attributes | |
147 | if (sd->s_iattr) { | 147 | * get them for the new inode from persistent copy |
148 | /* sysfs_dirent has non-default attributes | 148 | * in sysfs_dirent |
149 | * get them for the new inode from persistent copy | 149 | */ |
150 | * in sysfs_dirent | 150 | set_inode_attr(inode, sd->s_iattr); |
151 | */ | ||
152 | set_inode_attr(inode, sd->s_iattr); | ||
153 | } else | ||
154 | set_default_inode_attr(inode, mode); | ||
155 | } | ||
156 | return inode; | ||
157 | } | ||
158 | |||
159 | int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *)) | ||
160 | { | ||
161 | int error = 0; | ||
162 | struct inode * inode = NULL; | ||
163 | if (dentry) { | ||
164 | if (!dentry->d_inode) { | ||
165 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
166 | if ((inode = sysfs_new_inode(mode, sd))) { | ||
167 | if (dentry->d_parent && dentry->d_parent->d_inode) { | ||
168 | struct inode *p_inode = dentry->d_parent->d_inode; | ||
169 | p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; | ||
170 | } | ||
171 | goto Proceed; | ||
172 | } | ||
173 | else | ||
174 | error = -ENOMEM; | ||
175 | } else | ||
176 | error = -EEXIST; | ||
177 | } else | ||
178 | error = -ENOENT; | ||
179 | goto Done; | ||
180 | |||
181 | Proceed: | ||
182 | if (init) | ||
183 | error = init(inode); | ||
184 | if (!error) { | ||
185 | d_instantiate(dentry, inode); | ||
186 | if (S_ISDIR(mode)) | ||
187 | dget(dentry); /* pin only directory dentry in core */ | ||
188 | } else | 151 | } else |
189 | iput(inode); | 152 | set_default_inode_attr(inode, sd->s_mode); |
190 | Done: | ||
191 | return error; | ||
192 | } | 153 | } |
193 | 154 | ||
194 | /* | 155 | /** |
195 | * Get the name for corresponding element represented by the given sysfs_dirent | 156 | * sysfs_get_inode - get inode for sysfs_dirent |
157 | * @sd: sysfs_dirent to allocate inode for | ||
158 | * | ||
159 | * Get inode for @sd. If such inode doesn't exist, a new inode | ||
160 | * is allocated and basics are initialized. New inode is | ||
161 | * returned locked. | ||
162 | * | ||
163 | * LOCKING: | ||
164 | * Kernel thread context (may sleep). | ||
165 | * | ||
166 | * RETURNS: | ||
167 | * Pointer to allocated inode on success, NULL on failure. | ||
196 | */ | 168 | */ |
197 | const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) | 169 | struct inode * sysfs_get_inode(struct sysfs_dirent *sd) |
198 | { | 170 | { |
199 | struct attribute * attr; | 171 | struct inode *inode; |
200 | struct bin_attribute * bin_attr; | ||
201 | struct sysfs_symlink * sl; | ||
202 | |||
203 | BUG_ON(!sd || !sd->s_element); | ||
204 | |||
205 | switch (sd->s_type) { | ||
206 | case SYSFS_DIR: | ||
207 | /* Always have a dentry so use that */ | ||
208 | return sd->s_dentry->d_name.name; | ||
209 | |||
210 | case SYSFS_KOBJ_ATTR: | ||
211 | attr = sd->s_element; | ||
212 | return attr->name; | ||
213 | |||
214 | case SYSFS_KOBJ_BIN_ATTR: | ||
215 | bin_attr = sd->s_element; | ||
216 | return bin_attr->attr.name; | ||
217 | 172 | ||
218 | case SYSFS_KOBJ_LINK: | 173 | inode = iget_locked(sysfs_sb, sd->s_ino); |
219 | sl = sd->s_element; | 174 | if (inode && (inode->i_state & I_NEW)) |
220 | return sl->link_name; | 175 | sysfs_init_inode(sd, inode); |
221 | } | ||
222 | return NULL; | ||
223 | } | ||
224 | 176 | ||
225 | static inline void orphan_all_buffers(struct inode *node) | 177 | return inode; |
226 | { | ||
227 | struct sysfs_buffer_collection *set; | ||
228 | struct sysfs_buffer *buf; | ||
229 | |||
230 | mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD); | ||
231 | set = node->i_private; | ||
232 | if (set) { | ||
233 | list_for_each_entry(buf, &set->associates, associates) { | ||
234 | down(&buf->sem); | ||
235 | buf->orphaned = 1; | ||
236 | up(&buf->sem); | ||
237 | } | ||
238 | } | ||
239 | mutex_unlock(&node->i_mutex); | ||
240 | } | 178 | } |
241 | 179 | ||
242 | 180 | /** | |
243 | /* | 181 | * sysfs_instantiate - instantiate dentry |
244 | * Unhashes the dentry corresponding to given sysfs_dirent | 182 | * @dentry: dentry to be instantiated |
245 | * Called with parent inode's i_mutex held. | 183 | * @inode: inode associated with @sd |
184 | * | ||
185 | * Unlock @inode if locked and instantiate @dentry with @inode. | ||
186 | * | ||
187 | * LOCKING: | ||
188 | * None. | ||
246 | */ | 189 | */ |
247 | void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) | 190 | void sysfs_instantiate(struct dentry *dentry, struct inode *inode) |
248 | { | 191 | { |
249 | struct dentry *dentry = NULL; | 192 | BUG_ON(!dentry || dentry->d_inode); |
250 | struct inode *inode; | ||
251 | 193 | ||
252 | /* We're not holding a reference to ->s_dentry dentry but the | 194 | if (inode->i_state & I_NEW) |
253 | * field will stay valid as long as sysfs_lock is held. | 195 | unlock_new_inode(inode); |
254 | */ | ||
255 | spin_lock(&sysfs_lock); | ||
256 | spin_lock(&dcache_lock); | ||
257 | |||
258 | /* dget dentry if it's still alive */ | ||
259 | if (sd->s_dentry && sd->s_dentry->d_inode) | ||
260 | dentry = dget_locked(sd->s_dentry); | ||
261 | |||
262 | spin_unlock(&dcache_lock); | ||
263 | spin_unlock(&sysfs_lock); | ||
264 | |||
265 | /* drop dentry */ | ||
266 | if (dentry) { | ||
267 | spin_lock(&dcache_lock); | ||
268 | spin_lock(&dentry->d_lock); | ||
269 | if (!d_unhashed(dentry) && dentry->d_inode) { | ||
270 | inode = dentry->d_inode; | ||
271 | spin_lock(&inode->i_lock); | ||
272 | __iget(inode); | ||
273 | spin_unlock(&inode->i_lock); | ||
274 | dget_locked(dentry); | ||
275 | __d_drop(dentry); | ||
276 | spin_unlock(&dentry->d_lock); | ||
277 | spin_unlock(&dcache_lock); | ||
278 | simple_unlink(parent->d_inode, dentry); | ||
279 | orphan_all_buffers(inode); | ||
280 | iput(inode); | ||
281 | } else { | ||
282 | spin_unlock(&dentry->d_lock); | ||
283 | spin_unlock(&dcache_lock); | ||
284 | } | ||
285 | 196 | ||
286 | dput(dentry); | 197 | d_instantiate(dentry, inode); |
287 | } | ||
288 | } | 198 | } |
289 | 199 | ||
290 | int sysfs_hash_and_remove(struct dentry * dir, const char * name) | 200 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) |
291 | { | 201 | { |
292 | struct sysfs_dirent * sd; | 202 | struct sysfs_addrm_cxt acxt; |
293 | struct sysfs_dirent * parent_sd; | 203 | struct sysfs_dirent **pos, *sd; |
294 | int found = 0; | ||
295 | 204 | ||
296 | if (!dir) | 205 | if (!dir_sd) |
297 | return -ENOENT; | 206 | return -ENOENT; |
298 | 207 | ||
299 | if (dir->d_inode == NULL) | 208 | sysfs_addrm_start(&acxt, dir_sd); |
300 | /* no inode means this hasn't been made visible yet */ | 209 | |
301 | return -ENOENT; | 210 | for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { |
211 | sd = *pos; | ||
302 | 212 | ||
303 | parent_sd = dir->d_fsdata; | 213 | if (!sysfs_type(sd)) |
304 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); | ||
305 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | ||
306 | if (!sd->s_element) | ||
307 | continue; | 214 | continue; |
308 | if (!strcmp(sysfs_get_name(sd), name)) { | 215 | if (!strcmp(sd->s_name, name)) { |
309 | list_del_init(&sd->s_sibling); | 216 | *pos = sd->s_sibling; |
310 | sysfs_drop_dentry(sd, dir); | 217 | sd->s_sibling = NULL; |
311 | sysfs_put(sd); | 218 | sysfs_remove_one(&acxt, sd); |
312 | found = 1; | ||
313 | break; | 219 | break; |
314 | } | 220 | } |
315 | } | 221 | } |
316 | mutex_unlock(&dir->d_inode->i_mutex); | ||
317 | 222 | ||
318 | return found ? 0 : -ENOENT; | 223 | if (sysfs_addrm_finish(&acxt)) |
224 | return 0; | ||
225 | return -ENOENT; | ||
319 | } | 226 | } |