Blame view
fs/sysfs/inode.c
8.15 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> |
57cc7215b headers: kobject.... |
22 |
#include <linux/sysfs.h> |
ddd29ec65 sysfs: Add labeli... |
23 24 |
#include <linux/xattr.h> #include <linux/security.h> |
1da177e4c Linux-2.6.12-rc2 |
25 26 27 |
#include "sysfs.h" extern struct super_block * sysfs_sb; |
f5e54d6e5 [PATCH] mark addr... |
28 |
static const struct address_space_operations sysfs_aops = { |
1da177e4c Linux-2.6.12-rc2 |
29 |
.readpage = simple_readpage, |
800d15a53 implement simple ... |
30 31 |
.write_begin = simple_write_begin, .write_end = simple_write_end, |
1da177e4c Linux-2.6.12-rc2 |
32 33 34 |
}; static struct backing_dev_info sysfs_backing_dev_info = { |
d993831fa writeback: add na... |
35 |
.name = "sysfs", |
1da177e4c Linux-2.6.12-rc2 |
36 |
.ra_pages = 0, /* No readahead */ |
e4ad08fe6 mm: bdi: add sepa... |
37 |
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, |
1da177e4c Linux-2.6.12-rc2 |
38 |
}; |
c5ef1c42c [PATCH] mark stru... |
39 |
static const struct inode_operations sysfs_inode_operations ={ |
e61ab4ae4 sysfs: Implement ... |
40 |
.permission = sysfs_permission, |
988d186de [PATCH] sysfs-iat... |
41 |
.setattr = sysfs_setattr, |
e61ab4ae4 sysfs: Implement ... |
42 |
.getattr = sysfs_getattr, |
ddd29ec65 sysfs: Add labeli... |
43 |
.setxattr = sysfs_setxattr, |
988d186de [PATCH] sysfs-iat... |
44 |
}; |
e0bf68dde mm: bdi init hooks |
45 46 47 48 |
int __init sysfs_inode_init(void) { return bdi_init(&sysfs_backing_dev_info); } |
f38506c49 sysfs: mark a loc... |
49 |
static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) |
ddd29ec65 sysfs: Add labeli... |
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
{ 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... |
67 |
|
35df63c46 sysfs: Fix lockin... |
68 |
int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr) |
988d186de [PATCH] sysfs-iat... |
69 |
{ |
ddd29ec65 sysfs: Add labeli... |
70 71 |
struct sysfs_inode_attrs *sd_attrs; struct iattr *iattrs; |
988d186de [PATCH] sysfs-iat... |
72 |
unsigned int ia_valid = iattr->ia_valid; |
988d186de [PATCH] sysfs-iat... |
73 |
|
ddd29ec65 sysfs: Add labeli... |
74 |
sd_attrs = sd->s_iattr; |
988d186de [PATCH] sysfs-iat... |
75 |
|
ddd29ec65 sysfs: Add labeli... |
76 |
if (!sd_attrs) { |
988d186de [PATCH] sysfs-iat... |
77 |
/* setting attributes for the first time, allocate now */ |
ddd29ec65 sysfs: Add labeli... |
78 79 |
sd_attrs = sysfs_init_inode_attrs(sd); if (!sd_attrs) |
988d186de [PATCH] sysfs-iat... |
80 |
return -ENOMEM; |
ddd29ec65 sysfs: Add labeli... |
81 |
sd->s_iattr = sd_attrs; |
7c0ff870d sysfs: sysfs_sd_s... |
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
} /* 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... |
99 |
} |
35df63c46 sysfs: Fix lockin... |
100 101 102 103 104 105 106 107 108 109 110 |
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 ... |
111 |
mutex_lock(&sysfs_mutex); |
35df63c46 sysfs: Fix lockin... |
112 113 |
error = inode_change_ok(inode, iattr); if (error) |
f8d4f618f sysfs: Serialize ... |
114 |
goto out; |
35df63c46 sysfs: Fix lockin... |
115 |
|
75de46b98 fix setattr error... |
116 117 118 |
error = sysfs_sd_setattr(sd, iattr); if (error) goto out; |
3322e79a3 fs: convert simpl... |
119 |
/* this ignores size changes */ |
6a1a90ad1 rename generic_se... |
120 |
setattr_copy(inode, iattr); |
35df63c46 sysfs: Fix lockin... |
121 |
|
f8d4f618f sysfs: Serialize ... |
122 |
out: |
35df63c46 sysfs: Fix lockin... |
123 |
mutex_unlock(&sysfs_mutex); |
ddd29ec65 sysfs: Add labeli... |
124 125 |
return error; } |
988d186de [PATCH] sysfs-iat... |
126 |
|
f44d3e785 sysfs: Update sys... |
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
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... |
149 150 151 152 |
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... |
153 154 155 156 157 158 |
void *secdata; int error; u32 secdata_len = 0; if (!sd) return -EINVAL; |
ddd29ec65 sysfs: Add labeli... |
159 160 161 162 163 164 165 166 167 168 169 |
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... |
170 |
|
f44d3e785 sysfs: Update sys... |
171 172 173 174 175 176 |
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... |
177 178 179 |
} else return -EINVAL; out: |
988d186de [PATCH] sysfs-iat... |
180 181 |
return error; } |
faef2b6c9 sysfs: propagate ... |
182 |
static inline void set_default_inode_attr(struct inode * inode, umode_t mode) |
8215534ce [PATCH] sysfs-iat... |
183 184 |
{ inode->i_mode = mode; |
8215534ce [PATCH] sysfs-iat... |
185 186 187 188 189 |
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... |
190 191 192 193 194 195 |
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; } |
e61ab4ae4 sysfs: Implement ... |
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
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) |
bfe868486 filesystems: add ... |
212 |
set_nlink(inode, sd->s_dir.subdirs + 2); |
e61ab4ae4 sysfs: Implement ... |
213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
} 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... |
227 |
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
1da177e4c Linux-2.6.12-rc2 |
228 |
{ |
372e88bd1 sysfs: Move all o... |
229 |
struct bin_attribute *bin_attr; |
04256b4a8 sysfs: reference ... |
230 |
inode->i_private = sysfs_get(sd); |
fc9f54b99 sysfs: reorganize... |
231 232 233 |
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... |
234 |
|
e61ab4ae4 sysfs: Implement ... |
235 236 |
set_default_inode_attr(inode, sd->s_mode); sysfs_refresh_inode(sd, inode); |
372e88bd1 sysfs: Move all o... |
237 |
|
372e88bd1 sysfs: Move all o... |
238 239 |
/* initialize inode according to type */ switch (sysfs_type(sd)) { |
372e88bd1 sysfs: Move all o... |
240 241 242 |
case SYSFS_DIR: inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; |
372e88bd1 sysfs: Move all o... |
243 244 245 246 247 248 |
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... |
249 |
bin_attr = sd->s_bin_attr.bin_attr; |
372e88bd1 sysfs: Move all o... |
250 251 252 253 254 255 256 257 258 259 260 |
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... |
261 262 263 |
} /** |
8312a8d7c sysfs: use iget_l... |
264 |
* sysfs_get_inode - get inode for sysfs_dirent |
fac2622bb sysfs: Pass super... |
265 |
* @sb: super block |
fc9f54b99 sysfs: reorganize... |
266 267 |
* @sd: sysfs_dirent to allocate inode for * |
8312a8d7c sysfs: use iget_l... |
268 269 270 |
* 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... |
271 272 273 274 275 276 277 |
* * LOCKING: * Kernel thread context (may sleep). * * RETURNS: * Pointer to allocated inode on success, NULL on failure. */ |
fac2622bb sysfs: Pass super... |
278 |
struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) |
fc9f54b99 sysfs: reorganize... |
279 280 |
{ struct inode *inode; |
fac2622bb sysfs: Pass super... |
281 |
inode = iget_locked(sb, sd->s_ino); |
8312a8d7c sysfs: use iget_l... |
282 |
if (inode && (inode->i_state & I_NEW)) |
fc9f54b99 sysfs: reorganize... |
283 |
sysfs_init_inode(sd, inode); |
1da177e4c Linux-2.6.12-rc2 |
284 285 |
return inode; } |
04256b4a8 sysfs: reference ... |
286 287 288 289 |
/* * 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 -... |
290 |
* super_operations.evict_inode() implementation is needed to drop that |
04256b4a8 sysfs: reference ... |
291 292 |
* reference upon inode destruction. */ |
01cd9fef6 switch sysfs to -... |
293 |
void sysfs_evict_inode(struct inode *inode) |
04256b4a8 sysfs: reference ... |
294 295 296 297 |
{ struct sysfs_dirent *sd = inode->i_private; truncate_inode_pages(&inode->i_data, 0); |
01cd9fef6 switch sysfs to -... |
298 |
end_writeback(inode); |
04256b4a8 sysfs: reference ... |
299 300 |
sysfs_put(sd); } |
3ff195b01 sysfs: Implement ... |
301 |
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
302 |
{ |
fb6896da3 sysfs: restructur... |
303 |
struct sysfs_addrm_cxt acxt; |
41fc1c274 sysfs: make sysfs... |
304 |
struct sysfs_dirent *sd; |
641e6f30a [PATCH] sysfs: sy... |
305 |
|
608e266a2 sysfs: make kobj ... |
306 |
if (!dir_sd) |
995982ca7 sysfs_remove_bin_... |
307 |
return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
308 |
|
fb6896da3 sysfs: restructur... |
309 |
sysfs_addrm_start(&acxt, dir_sd); |
608e266a2 sysfs: make kobj ... |
310 |
|
3ff195b01 sysfs: Implement ... |
311 |
sd = sysfs_find_dirent(dir_sd, ns, name); |
41fc1c274 sysfs: make sysfs... |
312 313 |
if (sd) sysfs_remove_one(&acxt, sd); |
3007e997d sysfs: use sysfs_... |
314 |
|
990e53f88 sysfs: make sysfs... |
315 316 317 |
sysfs_addrm_finish(&acxt); if (sd) |
fb6896da3 sysfs: restructur... |
318 |
return 0; |
990e53f88 sysfs: make sysfs... |
319 320 |
else return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
321 |
} |
e61ab4ae4 sysfs: Implement ... |
322 |
|
10556cb21 ->permission() sa... |
323 |
int sysfs_permission(struct inode *inode, int mask) |
e61ab4ae4 sysfs: Implement ... |
324 |
{ |
b74c79e99 fs: provide rcu-w... |
325 |
struct sysfs_dirent *sd; |
10556cb21 ->permission() sa... |
326 |
if (mask & MAY_NOT_BLOCK) |
b74c79e99 fs: provide rcu-w... |
327 328 329 |
return -ECHILD; sd = inode->i_private; |
e61ab4ae4 sysfs: Implement ... |
330 331 332 333 |
mutex_lock(&sysfs_mutex); sysfs_refresh_inode(sd, inode); mutex_unlock(&sysfs_mutex); |
2830ba7f3 ->permission() sa... |
334 |
return generic_permission(inode, mask); |
e61ab4ae4 sysfs: Implement ... |
335 |
} |