Blame view

fs/sysfs/inode.c 8.15 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
6d66f5cd2   Tejun Heo   sysfs: add copyri...
2
   * fs/sysfs/inode.c - basic sysfs inode and dentry operations
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
6d66f5cd2   Tejun Heo   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   Linus Torvalds   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   Randy Dunlap   [PATCH] capable/c...
18
  #include <linux/capability.h>
995982ca7   Randy.Dunlap   sysfs_remove_bin_...
19
  #include <linux/errno.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
20
  #include <linux/sched.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
57cc7215b   Alexey Dobriyan   headers: kobject....
22
  #include <linux/sysfs.h>
ddd29ec65   David P. Quigley   sysfs: Add labeli...
23
24
  #include <linux/xattr.h>
  #include <linux/security.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
  #include "sysfs.h"
  
  extern struct super_block * sysfs_sb;
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
28
  static const struct address_space_operations sysfs_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  	.readpage	= simple_readpage,
800d15a53   Nick Piggin   implement simple ...
30
31
  	.write_begin	= simple_write_begin,
  	.write_end	= simple_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
  };
  
  static struct backing_dev_info sysfs_backing_dev_info = {
d993831fa   Jens Axboe   writeback: add na...
35
  	.name		= "sysfs",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  	.ra_pages	= 0,	/* No readahead */
e4ad08fe6   Miklos Szeredi   mm: bdi: add sepa...
37
  	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  };
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
39
  static const struct inode_operations sysfs_inode_operations ={
e61ab4ae4   Eric W. Biederman   sysfs: Implement ...
40
  	.permission	= sysfs_permission,
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
41
  	.setattr	= sysfs_setattr,
e61ab4ae4   Eric W. Biederman   sysfs: Implement ...
42
  	.getattr	= sysfs_getattr,
ddd29ec65   David P. Quigley   sysfs: Add labeli...
43
  	.setxattr	= sysfs_setxattr,
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
44
  };
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
45
46
47
48
  int __init sysfs_inode_init(void)
  {
  	return bdi_init(&sysfs_backing_dev_info);
  }
f38506c49   Stefan Richter   sysfs: mark a loc...
49
  static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd)
ddd29ec65   David P. Quigley   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   Stefan Richter   sysfs: mark a loc...
67

35df63c46   Eric W. Biederman   sysfs: Fix lockin...
68
  int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr)
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
69
  {
ddd29ec65   David P. Quigley   sysfs: Add labeli...
70
71
  	struct sysfs_inode_attrs *sd_attrs;
  	struct iattr *iattrs;
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
72
  	unsigned int ia_valid = iattr->ia_valid;
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
73

ddd29ec65   David P. Quigley   sysfs: Add labeli...
74
  	sd_attrs = sd->s_iattr;
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
75

ddd29ec65   David P. Quigley   sysfs: Add labeli...
76
  	if (!sd_attrs) {
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
77
  		/* setting attributes for the first time, allocate now */
ddd29ec65   David P. Quigley   sysfs: Add labeli...
78
79
  		sd_attrs = sysfs_init_inode_attrs(sd);
  		if (!sd_attrs)
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
80
  			return -ENOMEM;
ddd29ec65   David P. Quigley   sysfs: Add labeli...
81
  		sd->s_iattr = sd_attrs;
7c0ff870d   Eric W. Biederman   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   Maneesh Soni   [PATCH] sysfs-iat...
99
  	}
35df63c46   Eric W. Biederman   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   Eric W. Biederman   sysfs: Serialize ...
111
  	mutex_lock(&sysfs_mutex);
35df63c46   Eric W. Biederman   sysfs: Fix lockin...
112
113
  	error = inode_change_ok(inode, iattr);
  	if (error)
f8d4f618f   Eric W. Biederman   sysfs: Serialize ...
114
  		goto out;
35df63c46   Eric W. Biederman   sysfs: Fix lockin...
115

75de46b98   Nick Piggin   fix setattr error...
116
117
118
  	error = sysfs_sd_setattr(sd, iattr);
  	if (error)
  		goto out;
3322e79a3   Nick Piggin   fs: convert simpl...
119
  	/* this ignores size changes */
6a1a90ad1   Christoph Hellwig   rename generic_se...
120
  	setattr_copy(inode, iattr);
35df63c46   Eric W. Biederman   sysfs: Fix lockin...
121

f8d4f618f   Eric W. Biederman   sysfs: Serialize ...
122
  out:
35df63c46   Eric W. Biederman   sysfs: Fix lockin...
123
  	mutex_unlock(&sysfs_mutex);
ddd29ec65   David P. Quigley   sysfs: Add labeli...
124
125
  	return error;
  }
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
126

f44d3e785   Eric W. Biederman   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   David P. Quigley   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   David P. Quigley   sysfs: Add labeli...
153
154
155
156
157
158
  	void *secdata;
  	int error;
  	u32 secdata_len = 0;
  
  	if (!sd)
  		return -EINVAL;
ddd29ec65   David P. Quigley   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   Maneesh Soni   [PATCH] sysfs-iat...
170

f44d3e785   Eric W. Biederman   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   David P. Quigley   sysfs: Add labeli...
177
178
179
  	} else
  		return -EINVAL;
  out:
988d186de   Maneesh Soni   [PATCH] sysfs-iat...
180
181
  	return error;
  }
faef2b6c9   Al Viro   sysfs: propagate ...
182
  static inline void set_default_inode_attr(struct inode * inode, umode_t mode)
8215534ce   Maneesh Soni   [PATCH] sysfs-iat...
183
184
  {
  	inode->i_mode = mode;
8215534ce   Maneesh Soni   [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   Maneesh Soni   [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   Eric W. Biederman   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   Miklos Szeredi   filesystems: add ...
212
  		set_nlink(inode, sd->s_dir.subdirs + 2);
e61ab4ae4   Eric W. Biederman   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   Tejun Heo   sysfs: make sysfs...
227
  static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
  {
372e88bd1   Eric W. Biederman   sysfs: Move all o...
229
  	struct bin_attribute *bin_attr;
04256b4a8   Eric W. Biederman   sysfs: reference ...
230
  	inode->i_private = sysfs_get(sd);
fc9f54b99   Tejun Heo   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   Tejun Heo   sysfs: reorganize...
234

e61ab4ae4   Eric W. Biederman   sysfs: Implement ...
235
236
  	set_default_inode_attr(inode, sd->s_mode);
  	sysfs_refresh_inode(sd, inode);
372e88bd1   Eric W. Biederman   sysfs: Move all o...
237

372e88bd1   Eric W. Biederman   sysfs: Move all o...
238
239
  	/* initialize inode according to type */
  	switch (sysfs_type(sd)) {
372e88bd1   Eric W. Biederman   sysfs: Move all o...
240
241
242
  	case SYSFS_DIR:
  		inode->i_op = &sysfs_dir_inode_operations;
  		inode->i_fop = &sysfs_dir_operations;
372e88bd1   Eric W. Biederman   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   Tejun Heo   sysfs: make s_ele...
249
  		bin_attr = sd->s_bin_attr.bin_attr;
372e88bd1   Eric W. Biederman   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   Tejun Heo   sysfs: reorganize...
261
262
263
  }
  
  /**
8312a8d7c   Tejun Heo   sysfs: use iget_l...
264
   *	sysfs_get_inode - get inode for sysfs_dirent
fac2622bb   Eric W. Biederman   sysfs: Pass super...
265
   *	@sb: super block
fc9f54b99   Tejun Heo   sysfs: reorganize...
266
267
   *	@sd: sysfs_dirent to allocate inode for
   *
8312a8d7c   Tejun Heo   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   Tejun Heo   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   Eric W. Biederman   sysfs: Pass super...
278
  struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd)
fc9f54b99   Tejun Heo   sysfs: reorganize...
279
280
  {
  	struct inode *inode;
fac2622bb   Eric W. Biederman   sysfs: Pass super...
281
  	inode = iget_locked(sb, sd->s_ino);
8312a8d7c   Tejun Heo   sysfs: use iget_l...
282
  	if (inode && (inode->i_state & I_NEW))
fc9f54b99   Tejun Heo   sysfs: reorganize...
283
  		sysfs_init_inode(sd, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  	return inode;
  }
04256b4a8   Eric W. Biederman   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   Al Viro   switch sysfs to -...
290
   * super_operations.evict_inode() implementation is needed to drop that
04256b4a8   Eric W. Biederman   sysfs: reference ...
291
292
   * reference upon inode destruction.
   */
01cd9fef6   Al Viro   switch sysfs to -...
293
  void sysfs_evict_inode(struct inode *inode)
04256b4a8   Eric W. Biederman   sysfs: reference ...
294
295
296
297
  {
  	struct sysfs_dirent *sd  = inode->i_private;
  
  	truncate_inode_pages(&inode->i_data, 0);
01cd9fef6   Al Viro   switch sysfs to -...
298
  	end_writeback(inode);
04256b4a8   Eric W. Biederman   sysfs: reference ...
299
300
  	sysfs_put(sd);
  }
3ff195b01   Eric W. Biederman   sysfs: Implement ...
301
  int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  {
fb6896da3   Tejun Heo   sysfs: restructur...
303
  	struct sysfs_addrm_cxt acxt;
41fc1c274   Tejun Heo   sysfs: make sysfs...
304
  	struct sysfs_dirent *sd;
641e6f30a   Greg Kroah-Hartman   [PATCH] sysfs: sy...
305

608e266a2   Tejun Heo   sysfs: make kobj ...
306
  	if (!dir_sd)
995982ca7   Randy.Dunlap   sysfs_remove_bin_...
307
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308

fb6896da3   Tejun Heo   sysfs: restructur...
309
  	sysfs_addrm_start(&acxt, dir_sd);
608e266a2   Tejun Heo   sysfs: make kobj ...
310

3ff195b01   Eric W. Biederman   sysfs: Implement ...
311
  	sd = sysfs_find_dirent(dir_sd, ns, name);
41fc1c274   Tejun Heo   sysfs: make sysfs...
312
313
  	if (sd)
  		sysfs_remove_one(&acxt, sd);
3007e997d   Tejun Heo   sysfs: use sysfs_...
314

990e53f88   Tejun Heo   sysfs: make sysfs...
315
316
317
  	sysfs_addrm_finish(&acxt);
  
  	if (sd)
fb6896da3   Tejun Heo   sysfs: restructur...
318
  		return 0;
990e53f88   Tejun Heo   sysfs: make sysfs...
319
320
  	else
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  }
e61ab4ae4   Eric W. Biederman   sysfs: Implement ...
322

10556cb21   Al Viro   ->permission() sa...
323
  int sysfs_permission(struct inode *inode, int mask)
e61ab4ae4   Eric W. Biederman   sysfs: Implement ...
324
  {
b74c79e99   Nick Piggin   fs: provide rcu-w...
325
  	struct sysfs_dirent *sd;
10556cb21   Al Viro   ->permission() sa...
326
  	if (mask & MAY_NOT_BLOCK)
b74c79e99   Nick Piggin   fs: provide rcu-w...
327
328
329
  		return -ECHILD;
  
  	sd = inode->i_private;
e61ab4ae4   Eric W. Biederman   sysfs: Implement ...
330
331
332
333
  
  	mutex_lock(&sysfs_mutex);
  	sysfs_refresh_inode(sd, inode);
  	mutex_unlock(&sysfs_mutex);
2830ba7f3   Al Viro   ->permission() sa...
334
  	return generic_permission(inode, mask);
e61ab4ae4   Eric W. Biederman   sysfs: Implement ...
335
  }