Blame view
fs/sysfs/inode.c
8.35 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
6d66f5cd2 sysfs: add copyri... |
2 |
* fs/sysfs/inode.c - basic sysfs inode and dentry operations |
1da177e4c Linux-2.6.12-rc2 |
3 |
* |
6d66f5cd2 sysfs: add copyri... |
4 5 6 7 8 |
* Copyright (c) 2001-3 Patrick Mochel * Copyright (c) 2007 SUSE Linux Products GmbH * Copyright (c) 2007 Tejun Heo <teheo@suse.de> * * This file is released under the GPLv2. |
1da177e4c Linux-2.6.12-rc2 |
9 10 11 12 13 14 15 16 17 |
* * Please see Documentation/filesystems/sysfs.txt for more information. */ #undef DEBUG #include <linux/pagemap.h> #include <linux/namei.h> #include <linux/backing-dev.h> |
16f7e0fe2 [PATCH] capable/c... |
18 |
#include <linux/capability.h> |
995982ca7 sysfs_remove_bin_... |
19 |
#include <linux/errno.h> |
e8edc6e03 Detach sched.h fr... |
20 |
#include <linux/sched.h> |
5a0e3ad6a include cleanup: ... |
21 |
#include <linux/slab.h> |
ddd29ec65 sysfs: Add labeli... |
22 23 |
#include <linux/xattr.h> #include <linux/security.h> |
1da177e4c Linux-2.6.12-rc2 |
24 25 26 |
#include "sysfs.h" extern struct super_block * sysfs_sb; |
f5e54d6e5 [PATCH] mark addr... |
27 |
static const struct address_space_operations sysfs_aops = { |
1da177e4c Linux-2.6.12-rc2 |
28 |
.readpage = simple_readpage, |
800d15a53 implement simple ... |
29 30 |
.write_begin = simple_write_begin, .write_end = simple_write_end, |
1da177e4c Linux-2.6.12-rc2 |
31 32 33 |
}; static struct backing_dev_info sysfs_backing_dev_info = { |
d993831fa writeback: add na... |
34 |
.name = "sysfs", |
1da177e4c Linux-2.6.12-rc2 |
35 |
.ra_pages = 0, /* No readahead */ |
e4ad08fe6 mm: bdi: add sepa... |
36 |
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, |
1da177e4c Linux-2.6.12-rc2 |
37 |
}; |
c5ef1c42c [PATCH] mark stru... |
38 |
static const struct inode_operations sysfs_inode_operations ={ |
e61ab4ae4 sysfs: Implement ... |
39 |
.permission = sysfs_permission, |
988d186de [PATCH] sysfs-iat... |
40 |
.setattr = sysfs_setattr, |
e61ab4ae4 sysfs: Implement ... |
41 |
.getattr = sysfs_getattr, |
ddd29ec65 sysfs: Add labeli... |
42 |
.setxattr = sysfs_setxattr, |
988d186de [PATCH] sysfs-iat... |
43 |
}; |
e0bf68dde mm: bdi init hooks |
44 45 46 47 |
int __init sysfs_inode_init(void) { return bdi_init(&sysfs_backing_dev_info); } |
f38506c49 sysfs: mark a loc... |
48 |
static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) |
ddd29ec65 sysfs: Add labeli... |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
{ struct sysfs_inode_attrs *attrs; struct iattr *iattrs; attrs = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); if (!attrs) return NULL; iattrs = &attrs->ia_iattr; /* assign default attributes */ iattrs->ia_mode = sd->s_mode; iattrs->ia_uid = 0; iattrs->ia_gid = 0; iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; return attrs; } |
f38506c49 sysfs: mark a loc... |
66 |
|
35df63c46 sysfs: Fix lockin... |
67 |
int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr) |
988d186de [PATCH] sysfs-iat... |
68 |
{ |
ddd29ec65 sysfs: Add labeli... |
69 70 |
struct sysfs_inode_attrs *sd_attrs; struct iattr *iattrs; |
988d186de [PATCH] sysfs-iat... |
71 |
unsigned int ia_valid = iattr->ia_valid; |
988d186de [PATCH] sysfs-iat... |
72 |
|
ddd29ec65 sysfs: Add labeli... |
73 |
sd_attrs = sd->s_iattr; |
988d186de [PATCH] sysfs-iat... |
74 |
|
ddd29ec65 sysfs: Add labeli... |
75 |
if (!sd_attrs) { |
988d186de [PATCH] sysfs-iat... |
76 |
/* setting attributes for the first time, allocate now */ |
ddd29ec65 sysfs: Add labeli... |
77 78 |
sd_attrs = sysfs_init_inode_attrs(sd); if (!sd_attrs) |
988d186de [PATCH] sysfs-iat... |
79 |
return -ENOMEM; |
ddd29ec65 sysfs: Add labeli... |
80 |
sd->s_iattr = sd_attrs; |
7c0ff870d sysfs: sysfs_sd_s... |
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
} /* attributes were changed at least once in past */ iattrs = &sd_attrs->ia_iattr; if (ia_valid & ATTR_UID) iattrs->ia_uid = iattr->ia_uid; if (ia_valid & ATTR_GID) iattrs->ia_gid = iattr->ia_gid; if (ia_valid & ATTR_ATIME) iattrs->ia_atime = iattr->ia_atime; if (ia_valid & ATTR_MTIME) iattrs->ia_mtime = iattr->ia_mtime; if (ia_valid & ATTR_CTIME) iattrs->ia_ctime = iattr->ia_ctime; if (ia_valid & ATTR_MODE) { umode_t mode = iattr->ia_mode; iattrs->ia_mode = sd->s_mode = mode; |
988d186de [PATCH] sysfs-iat... |
98 |
} |
35df63c46 sysfs: Fix lockin... |
99 100 101 102 103 104 105 106 107 108 109 |
return 0; } int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) { struct inode *inode = dentry->d_inode; struct sysfs_dirent *sd = dentry->d_fsdata; int error; if (!sd) return -EINVAL; |
f8d4f618f sysfs: Serialize ... |
110 |
mutex_lock(&sysfs_mutex); |
35df63c46 sysfs: Fix lockin... |
111 112 |
error = inode_change_ok(inode, iattr); if (error) |
f8d4f618f sysfs: Serialize ... |
113 |
goto out; |
35df63c46 sysfs: Fix lockin... |
114 |
|
75de46b98 fix setattr error... |
115 116 117 |
error = sysfs_sd_setattr(sd, iattr); if (error) goto out; |
3322e79a3 fs: convert simpl... |
118 |
/* this ignores size changes */ |
6a1a90ad1 rename generic_se... |
119 |
setattr_copy(inode, iattr); |
35df63c46 sysfs: Fix lockin... |
120 |
|
f8d4f618f sysfs: Serialize ... |
121 |
out: |
35df63c46 sysfs: Fix lockin... |
122 |
mutex_unlock(&sysfs_mutex); |
ddd29ec65 sysfs: Add labeli... |
123 124 |
return error; } |
988d186de [PATCH] sysfs-iat... |
125 |
|
f44d3e785 sysfs: Update sys... |
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len) { struct sysfs_inode_attrs *iattrs; void *old_secdata; size_t old_secdata_len; iattrs = sd->s_iattr; if (!iattrs) iattrs = sysfs_init_inode_attrs(sd); if (!iattrs) return -ENOMEM; old_secdata = iattrs->ia_secdata; old_secdata_len = iattrs->ia_secdata_len; iattrs->ia_secdata = *secdata; iattrs->ia_secdata_len = *secdata_len; *secdata = old_secdata; *secdata_len = old_secdata_len; return 0; } |
ddd29ec65 sysfs: Add labeli... |
148 149 150 151 |
int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct sysfs_dirent *sd = dentry->d_fsdata; |
ddd29ec65 sysfs: Add labeli... |
152 153 154 155 156 157 |
void *secdata; int error; u32 secdata_len = 0; if (!sd) return -EINVAL; |
ddd29ec65 sysfs: Add labeli... |
158 159 160 161 162 163 164 165 166 167 168 |
if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; error = security_inode_setsecurity(dentry->d_inode, suffix, value, size, flags); if (error) goto out; error = security_inode_getsecctx(dentry->d_inode, &secdata, &secdata_len); if (error) goto out; |
988d186de [PATCH] sysfs-iat... |
169 |
|
f44d3e785 sysfs: Update sys... |
170 171 172 173 174 175 |
mutex_lock(&sysfs_mutex); error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len); mutex_unlock(&sysfs_mutex); if (secdata) security_release_secctx(secdata, secdata_len); |
ddd29ec65 sysfs: Add labeli... |
176 177 178 |
} else return -EINVAL; out: |
988d186de [PATCH] sysfs-iat... |
179 180 |
return error; } |
8215534ce [PATCH] sysfs-iat... |
181 182 183 |
static inline void set_default_inode_attr(struct inode * inode, mode_t mode) { inode->i_mode = mode; |
8215534ce [PATCH] sysfs-iat... |
184 185 186 187 188 |
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; } static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) { |
8215534ce [PATCH] sysfs-iat... |
189 190 191 192 193 194 |
inode->i_uid = iattr->ia_uid; inode->i_gid = iattr->ia_gid; inode->i_atime = iattr->ia_atime; inode->i_mtime = iattr->ia_mtime; inode->i_ctime = iattr->ia_ctime; } |
372e88bd1 sysfs: Move all o... |
195 196 197 198 |
static int sysfs_count_nlink(struct sysfs_dirent *sd) { struct sysfs_dirent *child; int nr = 0; |
bc747f37a sysfs: move sysfs... |
199 |
for (child = sd->s_dir.children; child; child = child->s_sibling) |
372e88bd1 sysfs: Move all o... |
200 201 202 203 204 |
if (sysfs_type(child) == SYSFS_DIR) nr++; return nr + 2; } |
e61ab4ae4 sysfs: Implement ... |
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) { struct sysfs_inode_attrs *iattrs = sd->s_iattr; inode->i_mode = sd->s_mode; if (iattrs) { /* sysfs_dirent has non-default attributes * get them from persistent copy in sysfs_dirent */ set_inode_attr(inode, &iattrs->ia_iattr); security_inode_notifysecctx(inode, iattrs->ia_secdata, iattrs->ia_secdata_len); } if (sysfs_type(sd) == SYSFS_DIR) inode->i_nlink = sysfs_count_nlink(sd); } int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct sysfs_dirent *sd = dentry->d_fsdata; struct inode *inode = dentry->d_inode; mutex_lock(&sysfs_mutex); sysfs_refresh_inode(sd, inode); mutex_unlock(&sysfs_mutex); generic_fillattr(inode, stat); return 0; } |
bc37e2830 sysfs: make sysfs... |
236 |
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
237 |
{ |
372e88bd1 sysfs: Move all o... |
238 |
struct bin_attribute *bin_attr; |
04256b4a8 sysfs: reference ... |
239 |
inode->i_private = sysfs_get(sd); |
fc9f54b99 sysfs: reorganize... |
240 241 242 |
inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; |
fc9f54b99 sysfs: reorganize... |
243 |
|
e61ab4ae4 sysfs: Implement ... |
244 245 |
set_default_inode_attr(inode, sd->s_mode); sysfs_refresh_inode(sd, inode); |
372e88bd1 sysfs: Move all o... |
246 |
|
372e88bd1 sysfs: Move all o... |
247 248 |
/* initialize inode according to type */ switch (sysfs_type(sd)) { |
372e88bd1 sysfs: Move all o... |
249 250 251 |
case SYSFS_DIR: inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; |
372e88bd1 sysfs: Move all o... |
252 253 254 255 256 257 |
break; case SYSFS_KOBJ_ATTR: inode->i_size = PAGE_SIZE; inode->i_fop = &sysfs_file_operations; break; case SYSFS_KOBJ_BIN_ATTR: |
b1fc3d614 sysfs: make s_ele... |
258 |
bin_attr = sd->s_bin_attr.bin_attr; |
372e88bd1 sysfs: Move all o... |
259 260 261 262 263 264 265 266 267 268 269 |
inode->i_size = bin_attr->size; inode->i_fop = &bin_fops; break; case SYSFS_KOBJ_LINK: inode->i_op = &sysfs_symlink_inode_operations; break; default: BUG(); } unlock_new_inode(inode); |
fc9f54b99 sysfs: reorganize... |
270 271 272 |
} /** |
8312a8d7c sysfs: use iget_l... |
273 |
* sysfs_get_inode - get inode for sysfs_dirent |
fac2622bb sysfs: Pass super... |
274 |
* @sb: super block |
fc9f54b99 sysfs: reorganize... |
275 276 |
* @sd: sysfs_dirent to allocate inode for * |
8312a8d7c sysfs: use iget_l... |
277 278 279 |
* Get inode for @sd. If such inode doesn't exist, a new inode * is allocated and basics are initialized. New inode is * returned locked. |
fc9f54b99 sysfs: reorganize... |
280 281 282 283 284 285 286 |
* * LOCKING: * Kernel thread context (may sleep). * * RETURNS: * Pointer to allocated inode on success, NULL on failure. */ |
fac2622bb sysfs: Pass super... |
287 |
struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) |
fc9f54b99 sysfs: reorganize... |
288 289 |
{ struct inode *inode; |
fac2622bb sysfs: Pass super... |
290 |
inode = iget_locked(sb, sd->s_ino); |
8312a8d7c sysfs: use iget_l... |
291 |
if (inode && (inode->i_state & I_NEW)) |
fc9f54b99 sysfs: reorganize... |
292 |
sysfs_init_inode(sd, inode); |
1da177e4c Linux-2.6.12-rc2 |
293 294 |
return inode; } |
04256b4a8 sysfs: reference ... |
295 296 297 298 |
/* * The sysfs_dirent serves as both an inode and a directory entry for sysfs. * To prevent the sysfs inode numbers from being freed prematurely we take a * reference to sysfs_dirent from the sysfs inode. A |
01cd9fef6 switch sysfs to -... |
299 |
* super_operations.evict_inode() implementation is needed to drop that |
04256b4a8 sysfs: reference ... |
300 301 |
* reference upon inode destruction. */ |
01cd9fef6 switch sysfs to -... |
302 |
void sysfs_evict_inode(struct inode *inode) |
04256b4a8 sysfs: reference ... |
303 304 305 306 |
{ struct sysfs_dirent *sd = inode->i_private; truncate_inode_pages(&inode->i_data, 0); |
01cd9fef6 switch sysfs to -... |
307 |
end_writeback(inode); |
04256b4a8 sysfs: reference ... |
308 309 |
sysfs_put(sd); } |
3ff195b01 sysfs: Implement ... |
310 |
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
311 |
{ |
fb6896da3 sysfs: restructur... |
312 |
struct sysfs_addrm_cxt acxt; |
41fc1c274 sysfs: make sysfs... |
313 |
struct sysfs_dirent *sd; |
641e6f30a [PATCH] sysfs: sy... |
314 |
|
608e266a2 sysfs: make kobj ... |
315 |
if (!dir_sd) |
995982ca7 sysfs_remove_bin_... |
316 |
return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
317 |
|
fb6896da3 sysfs: restructur... |
318 |
sysfs_addrm_start(&acxt, dir_sd); |
608e266a2 sysfs: make kobj ... |
319 |
|
3ff195b01 sysfs: Implement ... |
320 |
sd = sysfs_find_dirent(dir_sd, ns, name); |
af10ec77b sysfs: Add suppor... |
321 322 |
if (sd && (sd->s_ns != ns)) sd = NULL; |
41fc1c274 sysfs: make sysfs... |
323 324 |
if (sd) sysfs_remove_one(&acxt, sd); |
3007e997d sysfs: use sysfs_... |
325 |
|
990e53f88 sysfs: make sysfs... |
326 327 328 |
sysfs_addrm_finish(&acxt); if (sd) |
fb6896da3 sysfs: restructur... |
329 |
return 0; |
990e53f88 sysfs: make sysfs... |
330 331 |
else return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
332 |
} |
e61ab4ae4 sysfs: Implement ... |
333 334 335 336 337 338 339 340 341 342 343 |
int sysfs_permission(struct inode *inode, int mask) { struct sysfs_dirent *sd = inode->i_private; mutex_lock(&sysfs_mutex); sysfs_refresh_inode(sd, inode); mutex_unlock(&sysfs_mutex); return generic_permission(inode, mask, NULL); } |