aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/inode.c')
-rw-r--r--fs/sysfs/inode.c38
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
18extern struct super_block * sysfs_sb; 19extern 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
31static struct inode_operations sysfs_inode_operations ={ 32static const struct inode_operations sysfs_inode_operations ={
32 .setattr = sysfs_setattr, 33 .setattr = sysfs_setattr,
33}; 34};
34 35
36void 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
35int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) 46int 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
223static 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)
217void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) 244void 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;