diff options
Diffstat (limited to 'fs/sysfs/inode.c')
-rw-r--r-- | fs/sysfs/inode.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e79e38d52c00..dd1344b007f5 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/backing-dev.h> | 13 | #include <linux/backing-dev.h> |
14 | #include <linux/capability.h> | 14 | #include <linux/capability.h> |
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <asm/semaphore.h> | ||
16 | #include "sysfs.h" | 17 | #include "sysfs.h" |
17 | 18 | ||
18 | extern struct super_block * sysfs_sb; | 19 | extern struct super_block * sysfs_sb; |
@@ -28,10 +29,20 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
28 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, | 29 | .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, |
29 | }; | 30 | }; |
30 | 31 | ||
31 | static struct inode_operations sysfs_inode_operations ={ | 32 | static const struct inode_operations sysfs_inode_operations ={ |
32 | .setattr = sysfs_setattr, | 33 | .setattr = sysfs_setattr, |
33 | }; | 34 | }; |
34 | 35 | ||
36 | void sysfs_delete_inode(struct inode *inode) | ||
37 | { | ||
38 | /* Free the shadowed directory inode operations */ | ||
39 | if (sysfs_is_shadowed_inode(inode)) { | ||
40 | kfree(inode->i_op); | ||
41 | inode->i_op = NULL; | ||
42 | } | ||
43 | return generic_delete_inode(inode); | ||
44 | } | ||
45 | |||
35 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 46 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) |
36 | { | 47 | { |
37 | struct inode * inode = dentry->d_inode; | 48 | struct inode * inode = dentry->d_inode; |
@@ -209,6 +220,22 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) | |||
209 | return NULL; | 220 | return NULL; |
210 | } | 221 | } |
211 | 222 | ||
223 | static inline void orphan_all_buffers(struct inode *node) | ||
224 | { | ||
225 | struct sysfs_buffer_collection *set = node->i_private; | ||
226 | struct sysfs_buffer *buf; | ||
227 | |||
228 | mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD); | ||
229 | if (node->i_private) { | ||
230 | list_for_each_entry(buf, &set->associates, associates) { | ||
231 | down(&buf->sem); | ||
232 | buf->orphaned = 1; | ||
233 | up(&buf->sem); | ||
234 | } | ||
235 | } | ||
236 | mutex_unlock(&node->i_mutex); | ||
237 | } | ||
238 | |||
212 | 239 | ||
213 | /* | 240 | /* |
214 | * Unhashes the dentry corresponding to given sysfs_dirent | 241 | * Unhashes the dentry corresponding to given sysfs_dirent |
@@ -217,16 +244,23 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) | |||
217 | void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) | 244 | void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) |
218 | { | 245 | { |
219 | struct dentry * dentry = sd->s_dentry; | 246 | struct dentry * dentry = sd->s_dentry; |
247 | struct inode *inode; | ||
220 | 248 | ||
221 | if (dentry) { | 249 | if (dentry) { |
222 | spin_lock(&dcache_lock); | 250 | spin_lock(&dcache_lock); |
223 | spin_lock(&dentry->d_lock); | 251 | spin_lock(&dentry->d_lock); |
224 | if (!(d_unhashed(dentry) && dentry->d_inode)) { | 252 | if (!(d_unhashed(dentry) && dentry->d_inode)) { |
253 | inode = dentry->d_inode; | ||
254 | spin_lock(&inode->i_lock); | ||
255 | __iget(inode); | ||
256 | spin_unlock(&inode->i_lock); | ||
225 | dget_locked(dentry); | 257 | dget_locked(dentry); |
226 | __d_drop(dentry); | 258 | __d_drop(dentry); |
227 | spin_unlock(&dentry->d_lock); | 259 | spin_unlock(&dentry->d_lock); |
228 | spin_unlock(&dcache_lock); | 260 | spin_unlock(&dcache_lock); |
229 | simple_unlink(parent->d_inode, dentry); | 261 | simple_unlink(parent->d_inode, dentry); |
262 | orphan_all_buffers(inode); | ||
263 | iput(inode); | ||
230 | } else { | 264 | } else { |
231 | spin_unlock(&dentry->d_lock); | 265 | spin_unlock(&dentry->d_lock); |
232 | spin_unlock(&dcache_lock); | 266 | spin_unlock(&dcache_lock); |
@@ -248,7 +282,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name) | |||
248 | return -ENOENT; | 282 | return -ENOENT; |
249 | 283 | ||
250 | parent_sd = dir->d_fsdata; | 284 | parent_sd = dir->d_fsdata; |
251 | mutex_lock(&dir->d_inode->i_mutex); | 285 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); |
252 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 286 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
253 | if (!sd->s_element) | 287 | if (!sd->s_element) |
254 | continue; | 288 | continue; |