diff options
Diffstat (limited to 'fs/sysfs/inode.c')
| -rw-r--r-- | fs/sysfs/inode.c | 26 |
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 | ||
| 17 | extern struct super_block * sysfs_sb; | 18 | extern struct super_block * sysfs_sb; |
| 18 | 19 | ||
| 19 | static struct address_space_operations sysfs_aops = { | 20 | static 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 | */ | ||
| 122 | static struct lock_class_key sysfs_inode_imutex_key; | ||
| 123 | |||
| 112 | struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd) | 124 | struct 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 | ||
| 225 | void sysfs_hash_and_remove(struct dentry * dir, const char * name) | 237 | int 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 | } |
