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.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index f0b347bd12ca..e79e38d52c00 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -12,11 +12,12 @@
12#include <linux/namei.h> 12#include <linux/namei.h>
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 "sysfs.h" 16#include "sysfs.h"
16 17
17extern struct super_block * sysfs_sb; 18extern struct super_block * sysfs_sb;
18 19
19static struct address_space_operations sysfs_aops = { 20static const struct address_space_operations sysfs_aops = {
20 .readpage = simple_readpage, 21 .readpage = simple_readpage,
21 .prepare_write = simple_prepare_write, 22 .prepare_write = simple_prepare_write,
22 .commit_write = simple_commit_write 23 .commit_write = simple_commit_write
@@ -109,15 +110,26 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
109 inode->i_ctime = iattr->ia_ctime; 110 inode->i_ctime = iattr->ia_ctime;
110} 111}
111 112
113
114/*
115 * sysfs has a different i_mutex lock order behavior for i_mutex than other
116 * filesystems; sysfs i_mutex is called in many places with subsystem locks
117 * held. At the same time, many of the VFS locking rules do not apply to
118 * sysfs at all (cross directory rename for example). To untangle this mess
119 * (which gives false positives in lockdep), we're giving sysfs inodes their
120 * own class for i_mutex.
121 */
122static struct lock_class_key sysfs_inode_imutex_key;
123
112struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd) 124struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd)
113{ 125{
114 struct inode * inode = new_inode(sysfs_sb); 126 struct inode * inode = new_inode(sysfs_sb);
115 if (inode) { 127 if (inode) {
116 inode->i_blksize = PAGE_CACHE_SIZE;
117 inode->i_blocks = 0; 128 inode->i_blocks = 0;
118 inode->i_mapping->a_ops = &sysfs_aops; 129 inode->i_mapping->a_ops = &sysfs_aops;
119 inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; 130 inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
120 inode->i_op = &sysfs_inode_operations; 131 inode->i_op = &sysfs_inode_operations;
132 lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
121 133
122 if (sd->s_iattr) { 134 if (sd->s_iattr) {
123 /* sysfs_dirent has non-default attributes 135 /* sysfs_dirent has non-default attributes
@@ -222,17 +234,18 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
222 } 234 }
223} 235}
224 236
225void sysfs_hash_and_remove(struct dentry * dir, const char * name) 237int sysfs_hash_and_remove(struct dentry * dir, const char * name)
226{ 238{
227 struct sysfs_dirent * sd; 239 struct sysfs_dirent * sd;
228 struct sysfs_dirent * parent_sd; 240 struct sysfs_dirent * parent_sd;
241 int found = 0;
229 242
230 if (!dir) 243 if (!dir)
231 return; 244 return -ENOENT;
232 245
233 if (dir->d_inode == NULL) 246 if (dir->d_inode == NULL)
234 /* no inode means this hasn't been made visible yet */ 247 /* no inode means this hasn't been made visible yet */
235 return; 248 return -ENOENT;
236 249
237 parent_sd = dir->d_fsdata; 250 parent_sd = dir->d_fsdata;
238 mutex_lock(&dir->d_inode->i_mutex); 251 mutex_lock(&dir->d_inode->i_mutex);
@@ -243,8 +256,11 @@ void sysfs_hash_and_remove(struct dentry * dir, const char * name)
243 list_del_init(&sd->s_sibling); 256 list_del_init(&sd->s_sibling);
244 sysfs_drop_dentry(sd, dir); 257 sysfs_drop_dentry(sd, dir);
245 sysfs_put(sd); 258 sysfs_put(sd);
259 found = 1;
246 break; 260 break;
247 } 261 }
248 } 262 }
249 mutex_unlock(&dir->d_inode->i_mutex); 263 mutex_unlock(&dir->d_inode->i_mutex);
264
265 return found ? 0 : -ENOENT;
250} 266}