diff options
Diffstat (limited to 'fs/sysfs/inode.c')
| -rw-r--r-- | fs/sysfs/inode.c | 176 |
1 files changed, 108 insertions, 68 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e28cecf179f5..220b758523ae 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
| @@ -37,7 +37,9 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | static const struct inode_operations sysfs_inode_operations ={ | 39 | static const struct inode_operations sysfs_inode_operations ={ |
| 40 | .permission = sysfs_permission, | ||
| 40 | .setattr = sysfs_setattr, | 41 | .setattr = sysfs_setattr, |
| 42 | .getattr = sysfs_getattr, | ||
| 41 | .setxattr = sysfs_setxattr, | 43 | .setxattr = sysfs_setxattr, |
| 42 | }; | 44 | }; |
| 43 | 45 | ||
| @@ -46,7 +48,7 @@ int __init sysfs_inode_init(void) | |||
| 46 | return bdi_init(&sysfs_backing_dev_info); | 48 | return bdi_init(&sysfs_backing_dev_info); |
| 47 | } | 49 | } |
| 48 | 50 | ||
| 49 | struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | 51 | static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) |
| 50 | { | 52 | { |
| 51 | struct sysfs_inode_attrs *attrs; | 53 | struct sysfs_inode_attrs *attrs; |
| 52 | struct iattr *iattrs; | 54 | struct iattr *iattrs; |
| @@ -64,30 +66,15 @@ struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | |||
| 64 | 66 | ||
| 65 | return attrs; | 67 | return attrs; |
| 66 | } | 68 | } |
| 67 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 69 | |
| 70 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr) | ||
| 68 | { | 71 | { |
| 69 | struct inode * inode = dentry->d_inode; | ||
| 70 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
| 71 | struct sysfs_inode_attrs *sd_attrs; | 72 | struct sysfs_inode_attrs *sd_attrs; |
| 72 | struct iattr *iattrs; | 73 | struct iattr *iattrs; |
| 73 | unsigned int ia_valid = iattr->ia_valid; | 74 | unsigned int ia_valid = iattr->ia_valid; |
| 74 | int error; | ||
| 75 | |||
| 76 | if (!sd) | ||
| 77 | return -EINVAL; | ||
| 78 | 75 | ||
| 79 | sd_attrs = sd->s_iattr; | 76 | sd_attrs = sd->s_iattr; |
| 80 | 77 | ||
| 81 | error = inode_change_ok(inode, iattr); | ||
| 82 | if (error) | ||
| 83 | return error; | ||
| 84 | |||
| 85 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ | ||
| 86 | |||
| 87 | error = inode_setattr(inode, iattr); | ||
| 88 | if (error) | ||
| 89 | return error; | ||
| 90 | |||
| 91 | if (!sd_attrs) { | 78 | if (!sd_attrs) { |
| 92 | /* setting attributes for the first time, allocate now */ | 79 | /* setting attributes for the first time, allocate now */ |
| 93 | sd_attrs = sysfs_init_inode_attrs(sd); | 80 | sd_attrs = sysfs_init_inode_attrs(sd); |
| @@ -103,42 +90,78 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | |||
| 103 | if (ia_valid & ATTR_GID) | 90 | if (ia_valid & ATTR_GID) |
| 104 | iattrs->ia_gid = iattr->ia_gid; | 91 | iattrs->ia_gid = iattr->ia_gid; |
| 105 | if (ia_valid & ATTR_ATIME) | 92 | if (ia_valid & ATTR_ATIME) |
| 106 | iattrs->ia_atime = timespec_trunc(iattr->ia_atime, | 93 | iattrs->ia_atime = iattr->ia_atime; |
| 107 | inode->i_sb->s_time_gran); | ||
| 108 | if (ia_valid & ATTR_MTIME) | 94 | if (ia_valid & ATTR_MTIME) |
| 109 | iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, | 95 | iattrs->ia_mtime = iattr->ia_mtime; |
| 110 | inode->i_sb->s_time_gran); | ||
| 111 | if (ia_valid & ATTR_CTIME) | 96 | if (ia_valid & ATTR_CTIME) |
| 112 | iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, | 97 | iattrs->ia_ctime = iattr->ia_ctime; |
| 113 | inode->i_sb->s_time_gran); | ||
| 114 | if (ia_valid & ATTR_MODE) { | 98 | if (ia_valid & ATTR_MODE) { |
| 115 | umode_t mode = iattr->ia_mode; | 99 | umode_t mode = iattr->ia_mode; |
| 116 | |||
| 117 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
| 118 | mode &= ~S_ISGID; | ||
| 119 | iattrs->ia_mode = sd->s_mode = mode; | 100 | iattrs->ia_mode = sd->s_mode = mode; |
| 120 | } | 101 | } |
| 121 | } | 102 | } |
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) | ||
| 107 | { | ||
| 108 | struct inode *inode = dentry->d_inode; | ||
| 109 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
| 110 | int error; | ||
| 111 | |||
| 112 | if (!sd) | ||
| 113 | return -EINVAL; | ||
| 114 | |||
| 115 | error = inode_change_ok(inode, iattr); | ||
| 116 | if (error) | ||
| 117 | return error; | ||
| 118 | |||
| 119 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ | ||
| 120 | |||
| 121 | error = inode_setattr(inode, iattr); | ||
| 122 | if (error) | ||
| 123 | return error; | ||
| 124 | |||
| 125 | mutex_lock(&sysfs_mutex); | ||
| 126 | error = sysfs_sd_setattr(sd, iattr); | ||
| 127 | mutex_unlock(&sysfs_mutex); | ||
| 128 | |||
| 122 | return error; | 129 | return error; |
| 123 | } | 130 | } |
| 124 | 131 | ||
| 132 | static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len) | ||
| 133 | { | ||
| 134 | struct sysfs_inode_attrs *iattrs; | ||
| 135 | void *old_secdata; | ||
| 136 | size_t old_secdata_len; | ||
| 137 | |||
| 138 | iattrs = sd->s_iattr; | ||
| 139 | if (!iattrs) | ||
| 140 | iattrs = sysfs_init_inode_attrs(sd); | ||
| 141 | if (!iattrs) | ||
| 142 | return -ENOMEM; | ||
| 143 | |||
| 144 | old_secdata = iattrs->ia_secdata; | ||
| 145 | old_secdata_len = iattrs->ia_secdata_len; | ||
| 146 | |||
| 147 | iattrs->ia_secdata = *secdata; | ||
| 148 | iattrs->ia_secdata_len = *secdata_len; | ||
| 149 | |||
| 150 | *secdata = old_secdata; | ||
| 151 | *secdata_len = old_secdata_len; | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 125 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 155 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
| 126 | size_t size, int flags) | 156 | size_t size, int flags) |
| 127 | { | 157 | { |
| 128 | struct sysfs_dirent *sd = dentry->d_fsdata; | 158 | struct sysfs_dirent *sd = dentry->d_fsdata; |
| 129 | struct sysfs_inode_attrs *iattrs; | ||
| 130 | void *secdata; | 159 | void *secdata; |
| 131 | int error; | 160 | int error; |
| 132 | u32 secdata_len = 0; | 161 | u32 secdata_len = 0; |
| 133 | 162 | ||
| 134 | if (!sd) | 163 | if (!sd) |
| 135 | return -EINVAL; | 164 | return -EINVAL; |
| 136 | if (!sd->s_iattr) | ||
| 137 | sd->s_iattr = sysfs_init_inode_attrs(sd); | ||
| 138 | if (!sd->s_iattr) | ||
| 139 | return -ENOMEM; | ||
| 140 | |||
| 141 | iattrs = sd->s_iattr; | ||
| 142 | 165 | ||
| 143 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { | 166 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { |
| 144 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; | 167 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
| @@ -150,12 +173,13 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
| 150 | &secdata, &secdata_len); | 173 | &secdata, &secdata_len); |
| 151 | if (error) | 174 | if (error) |
| 152 | goto out; | 175 | goto out; |
| 153 | if (iattrs->ia_secdata) | ||
| 154 | security_release_secctx(iattrs->ia_secdata, | ||
| 155 | iattrs->ia_secdata_len); | ||
| 156 | iattrs->ia_secdata = secdata; | ||
| 157 | iattrs->ia_secdata_len = secdata_len; | ||
| 158 | 176 | ||
| 177 | mutex_lock(&sysfs_mutex); | ||
| 178 | error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len); | ||
| 179 | mutex_unlock(&sysfs_mutex); | ||
| 180 | |||
| 181 | if (secdata) | ||
| 182 | security_release_secctx(secdata, secdata_len); | ||
| 159 | } else | 183 | } else |
| 160 | return -EINVAL; | 184 | return -EINVAL; |
| 161 | out: | 185 | out: |
| @@ -170,7 +194,6 @@ static inline void set_default_inode_attr(struct inode * inode, mode_t mode) | |||
| 170 | 194 | ||
| 171 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | 195 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) |
| 172 | { | 196 | { |
| 173 | inode->i_mode = iattr->ia_mode; | ||
| 174 | inode->i_uid = iattr->ia_uid; | 197 | inode->i_uid = iattr->ia_uid; |
| 175 | inode->i_gid = iattr->ia_gid; | 198 | inode->i_gid = iattr->ia_gid; |
| 176 | inode->i_atime = iattr->ia_atime; | 199 | inode->i_atime = iattr->ia_atime; |
| @@ -178,17 +201,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
| 178 | inode->i_ctime = iattr->ia_ctime; | 201 | inode->i_ctime = iattr->ia_ctime; |
| 179 | } | 202 | } |
| 180 | 203 | ||
| 181 | |||
| 182 | /* | ||
| 183 | * sysfs has a different i_mutex lock order behavior for i_mutex than other | ||
| 184 | * filesystems; sysfs i_mutex is called in many places with subsystem locks | ||
| 185 | * held. At the same time, many of the VFS locking rules do not apply to | ||
| 186 | * sysfs at all (cross directory rename for example). To untangle this mess | ||
| 187 | * (which gives false positives in lockdep), we're giving sysfs inodes their | ||
| 188 | * own class for i_mutex. | ||
| 189 | */ | ||
| 190 | static struct lock_class_key sysfs_inode_imutex_key; | ||
| 191 | |||
| 192 | static int sysfs_count_nlink(struct sysfs_dirent *sd) | 204 | static int sysfs_count_nlink(struct sysfs_dirent *sd) |
| 193 | { | 205 | { |
| 194 | struct sysfs_dirent *child; | 206 | struct sysfs_dirent *child; |
| @@ -201,38 +213,55 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) | |||
| 201 | return nr + 2; | 213 | return nr + 2; |
| 202 | } | 214 | } |
| 203 | 215 | ||
| 216 | static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) | ||
| 217 | { | ||
| 218 | struct sysfs_inode_attrs *iattrs = sd->s_iattr; | ||
| 219 | |||
| 220 | inode->i_mode = sd->s_mode; | ||
| 221 | if (iattrs) { | ||
| 222 | /* sysfs_dirent has non-default attributes | ||
| 223 | * get them from persistent copy in sysfs_dirent | ||
| 224 | */ | ||
| 225 | set_inode_attr(inode, &iattrs->ia_iattr); | ||
| 226 | security_inode_notifysecctx(inode, | ||
| 227 | iattrs->ia_secdata, | ||
| 228 | iattrs->ia_secdata_len); | ||
| 229 | } | ||
| 230 | |||
| 231 | if (sysfs_type(sd) == SYSFS_DIR) | ||
| 232 | inode->i_nlink = sysfs_count_nlink(sd); | ||
| 233 | } | ||
| 234 | |||
| 235 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | ||
| 236 | { | ||
| 237 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
| 238 | struct inode *inode = dentry->d_inode; | ||
| 239 | |||
| 240 | mutex_lock(&sysfs_mutex); | ||
| 241 | sysfs_refresh_inode(sd, inode); | ||
| 242 | mutex_unlock(&sysfs_mutex); | ||
| 243 | |||
| 244 | generic_fillattr(inode, stat); | ||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 204 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 248 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
| 205 | { | 249 | { |
| 206 | struct bin_attribute *bin_attr; | 250 | struct bin_attribute *bin_attr; |
| 207 | struct sysfs_inode_attrs *iattrs; | ||
| 208 | 251 | ||
| 209 | inode->i_private = sysfs_get(sd); | 252 | inode->i_private = sysfs_get(sd); |
| 210 | inode->i_mapping->a_ops = &sysfs_aops; | 253 | inode->i_mapping->a_ops = &sysfs_aops; |
| 211 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 254 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
| 212 | inode->i_op = &sysfs_inode_operations; | 255 | inode->i_op = &sysfs_inode_operations; |
| 213 | inode->i_ino = sd->s_ino; | ||
| 214 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | ||
| 215 | 256 | ||
| 216 | iattrs = sd->s_iattr; | 257 | set_default_inode_attr(inode, sd->s_mode); |
| 217 | if (iattrs) { | 258 | sysfs_refresh_inode(sd, inode); |
| 218 | /* sysfs_dirent has non-default attributes | ||
| 219 | * get them for the new inode from persistent copy | ||
| 220 | * in sysfs_dirent | ||
| 221 | */ | ||
| 222 | set_inode_attr(inode, &iattrs->ia_iattr); | ||
| 223 | if (iattrs->ia_secdata) | ||
| 224 | security_inode_notifysecctx(inode, | ||
| 225 | iattrs->ia_secdata, | ||
| 226 | iattrs->ia_secdata_len); | ||
| 227 | } else | ||
| 228 | set_default_inode_attr(inode, sd->s_mode); | ||
| 229 | 259 | ||
| 230 | /* initialize inode according to type */ | 260 | /* initialize inode according to type */ |
| 231 | switch (sysfs_type(sd)) { | 261 | switch (sysfs_type(sd)) { |
| 232 | case SYSFS_DIR: | 262 | case SYSFS_DIR: |
| 233 | inode->i_op = &sysfs_dir_inode_operations; | 263 | inode->i_op = &sysfs_dir_inode_operations; |
| 234 | inode->i_fop = &sysfs_dir_operations; | 264 | inode->i_fop = &sysfs_dir_operations; |
| 235 | inode->i_nlink = sysfs_count_nlink(sd); | ||
| 236 | break; | 265 | break; |
| 237 | case SYSFS_KOBJ_ATTR: | 266 | case SYSFS_KOBJ_ATTR: |
| 238 | inode->i_size = PAGE_SIZE; | 267 | inode->i_size = PAGE_SIZE; |
| @@ -315,3 +344,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | |||
| 315 | else | 344 | else |
| 316 | return -ENOENT; | 345 | return -ENOENT; |
| 317 | } | 346 | } |
| 347 | |||
| 348 | int sysfs_permission(struct inode *inode, int mask) | ||
| 349 | { | ||
| 350 | struct sysfs_dirent *sd = inode->i_private; | ||
| 351 | |||
| 352 | mutex_lock(&sysfs_mutex); | ||
| 353 | sysfs_refresh_inode(sd, inode); | ||
| 354 | mutex_unlock(&sysfs_mutex); | ||
| 355 | |||
| 356 | return generic_permission(inode, mask, NULL); | ||
| 357 | } | ||
