Blame view

fs/configfs/file.c 9.42 KB
7063fbf22   Joel Becker   [PATCH] configfs:...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  /* -*- mode: c; c-basic-offset: 8; -*-
   * vim: noexpandtab sw=8 ts=8 sts=0:
   *
   * file.c - operations for regular (text) files.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public
   * License as published by the Free Software Foundation; either
   * version 2 of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public
   * License along with this program; if not, write to the
   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   * Boston, MA 021110-1307, USA.
   *
   * Based on sysfs:
   * 	sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
   *
   * configfs Copyright (C) 2005 Oracle.  All rights reserved.
   */
  
  #include <linux/fs.h>
  #include <linux/module.h>
7063fbf22   Joel Becker   [PATCH] configfs:...
29
  #include <linux/slab.h>
6d748924b   Johannes Berg   [PATCH] configsfs...
30
  #include <linux/mutex.h>
7063fbf22   Joel Becker   [PATCH] configfs:...
31
  #include <asm/uaccess.h>
7063fbf22   Joel Becker   [PATCH] configfs:...
32
33
34
  
  #include <linux/configfs.h>
  #include "configfs_internal.h"
b23cdde4c   Joel Becker   configfs: consist...
35
36
37
38
39
40
41
  /*
   * A simple attribute can only be 4096 characters.  Why 4k?  Because the
   * original code limited it to PAGE_SIZE.  That's a bad idea, though,
   * because an attribute of 16k on ia64 won't work on x86.  So we limit to
   * 4k, our minimum common page size.
   */
  #define SIMPLE_ATTR_SIZE 4096
7063fbf22   Joel Becker   [PATCH] configfs:...
42
43
44
45
46
47
  
  struct configfs_buffer {
  	size_t			count;
  	loff_t			pos;
  	char			* page;
  	struct configfs_item_operations	* ops;
6d748924b   Johannes Berg   [PATCH] configsfs...
48
  	struct mutex		mutex;
7063fbf22   Joel Becker   [PATCH] configfs:...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  	int			needs_read_fill;
  };
  
  
  /**
   *	fill_read_buffer - allocate and fill buffer from item.
   *	@dentry:	dentry pointer.
   *	@buffer:	data buffer for file.
   *
   *	Allocate @buffer->page, if it hasn't been already, then call the
   *	config_item's show() method to fill the buffer with this attribute's
   *	data.
   *	This is called only once, on the file's first read.
   */
  static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buffer)
  {
  	struct configfs_attribute * attr = to_attr(dentry);
  	struct config_item * item = to_item(dentry->d_parent);
  	struct configfs_item_operations * ops = buffer->ops;
  	int ret = 0;
  	ssize_t count;
  
  	if (!buffer->page)
  		buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
  	if (!buffer->page)
  		return -ENOMEM;
  
  	count = ops->show_attribute(item,attr,buffer->page);
  	buffer->needs_read_fill = 0;
b23cdde4c   Joel Becker   configfs: consist...
78
  	BUG_ON(count > (ssize_t)SIMPLE_ATTR_SIZE);
7063fbf22   Joel Becker   [PATCH] configfs:...
79
80
81
82
83
84
  	if (count >= 0)
  		buffer->count = count;
  	else
  		ret = count;
  	return ret;
  }
7063fbf22   Joel Becker   [PATCH] configfs:...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  /**
   *	configfs_read_file - read an attribute.
   *	@file:	file pointer.
   *	@buf:	buffer to fill.
   *	@count:	number of bytes to read.
   *	@ppos:	starting offset in file.
   *
   *	Userspace wants to read an attribute file. The attribute descriptor
   *	is in the file's ->d_fsdata. The target item is in the directory's
   *	->d_fsdata.
   *
   *	We call fill_read_buffer() to allocate and fill the buffer from the
   *	item's show() method exactly once (if the read is happening from
   *	the beginning of the file). That should fill the entire buffer with
   *	all the data the item has to offer for that attribute.
   *	We then call flush_read_buffer() to copy the buffer to userspace
   *	in the increments specified.
   */
  
  static ssize_t
  configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  {
  	struct configfs_buffer * buffer = file->private_data;
  	ssize_t retval = 0;
6d748924b   Johannes Berg   [PATCH] configsfs...
109
  	mutex_lock(&buffer->mutex);
7063fbf22   Joel Becker   [PATCH] configfs:...
110
  	if (buffer->needs_read_fill) {
867fa491a   Josef "Jeff" Sipek   [PATCH] configfs:...
111
  		if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
7063fbf22   Joel Becker   [PATCH] configfs:...
112
113
  			goto out;
  	}
4779efca1   Zach Brown   [PATCH] pr_debug:...
114
115
  	pr_debug("%s: count = %zd, ppos = %lld, buf = %s
  ",
8e24eea72   Harvey Harrison   fs: replace remai...
116
  		 __func__, count, *ppos, buffer->page);
92f4c701a   Akinobu Mita   use simple_read_f...
117
118
  	retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
  					 buffer->count);
7063fbf22   Joel Becker   [PATCH] configfs:...
119
  out:
6d748924b   Johannes Berg   [PATCH] configsfs...
120
  	mutex_unlock(&buffer->mutex);
7063fbf22   Joel Becker   [PATCH] configfs:...
121
122
123
124
125
126
127
  	return retval;
  }
  
  
  /**
   *	fill_write_buffer - copy buffer from userspace.
   *	@buffer:	data buffer for file.
3d0f89bb1   Joel Becker   configfs: Add per...
128
   *	@buf:		data from user.
7063fbf22   Joel Becker   [PATCH] configfs:...
129
130
131
132
133
134
135
136
137
138
139
140
   *	@count:		number of bytes in @userbuf.
   *
   *	Allocate @buffer->page if it hasn't been already, then
   *	copy the user-supplied buffer into it.
   */
  
  static int
  fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size_t count)
  {
  	int error;
  
  	if (!buffer->page)
ff05d1c46   Joel Becker   configfs: Zero te...
141
  		buffer->page = (char *)__get_free_pages(GFP_KERNEL, 0);
7063fbf22   Joel Becker   [PATCH] configfs:...
142
143
  	if (!buffer->page)
  		return -ENOMEM;
b23cdde4c   Joel Becker   configfs: consist...
144
145
  	if (count >= SIMPLE_ATTR_SIZE)
  		count = SIMPLE_ATTR_SIZE - 1;
7063fbf22   Joel Becker   [PATCH] configfs:...
146
147
  	error = copy_from_user(buffer->page,buf,count);
  	buffer->needs_read_fill = 1;
ff05d1c46   Joel Becker   configfs: Zero te...
148
149
150
  	/* if buf is assumed to contain a string, terminate it by \0,
  	 * so e.g. sscanf() can scan the string easily */
  	buffer->page[count] = 0;
7063fbf22   Joel Becker   [PATCH] configfs:...
151
152
153
154
155
156
  	return error ? -EFAULT : count;
  }
  
  
  /**
   *	flush_write_buffer - push buffer to config_item.
3d0f89bb1   Joel Becker   configfs: Add per...
157
   *	@dentry:	dentry to the attribute
7063fbf22   Joel Becker   [PATCH] configfs:...
158
   *	@buffer:	data buffer for file.
3d0f89bb1   Joel Becker   configfs: Add per...
159
   *	@count:		number of bytes
7063fbf22   Joel Becker   [PATCH] configfs:...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
   *
   *	Get the correct pointers for the config_item and the attribute we're
   *	dealing with, then call the store() method for the attribute,
   *	passing the buffer that we acquired in fill_write_buffer().
   */
  
  static int
  flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size_t count)
  {
  	struct configfs_attribute * attr = to_attr(dentry);
  	struct config_item * item = to_item(dentry->d_parent);
  	struct configfs_item_operations * ops = buffer->ops;
  
  	return ops->store_attribute(item,attr,buffer->page,count);
  }
  
  
  /**
   *	configfs_write_file - write an attribute.
   *	@file:	file pointer
   *	@buf:	data to write
   *	@count:	number of bytes
   *	@ppos:	starting offset
   *
   *	Similar to configfs_read_file(), though working in the opposite direction.
   *	We allocate and fill the data from the user in fill_write_buffer(),
   *	then push it to the config_item in flush_write_buffer().
   *	There is no easy way for us to know if userspace is only doing a partial
   *	write, so we don't support them. We expect the entire buffer to come
   *	on the first write.
   *	Hint: if you're writing a value, first read the file, modify only the
   *	the value you're changing, then write entire buffer back.
   */
  
  static ssize_t
  configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  {
  	struct configfs_buffer * buffer = file->private_data;
3d0f89bb1   Joel Becker   configfs: Add per...
198
  	ssize_t len;
7063fbf22   Joel Becker   [PATCH] configfs:...
199

6d748924b   Johannes Berg   [PATCH] configsfs...
200
  	mutex_lock(&buffer->mutex);
3d0f89bb1   Joel Becker   configfs: Add per...
201
202
  	len = fill_write_buffer(buffer, buf, count);
  	if (len > 0)
867fa491a   Josef "Jeff" Sipek   [PATCH] configfs:...
203
  		len = flush_write_buffer(file->f_path.dentry, buffer, count);
3d0f89bb1   Joel Becker   configfs: Add per...
204
205
  	if (len > 0)
  		*ppos += len;
6d748924b   Johannes Berg   [PATCH] configsfs...
206
  	mutex_unlock(&buffer->mutex);
3d0f89bb1   Joel Becker   configfs: Add per...
207
  	return len;
7063fbf22   Joel Becker   [PATCH] configfs:...
208
209
210
211
  }
  
  static int check_perm(struct inode * inode, struct file * file)
  {
867fa491a   Josef "Jeff" Sipek   [PATCH] configfs:...
212
213
  	struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent);
  	struct configfs_attribute * attr = to_attr(file->f_path.dentry);
7063fbf22   Joel Becker   [PATCH] configfs:...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  	struct configfs_buffer * buffer;
  	struct configfs_item_operations * ops = NULL;
  	int error = 0;
  
  	if (!item || !attr)
  		goto Einval;
  
  	/* Grab the module reference for this attribute if we have one */
  	if (!try_module_get(attr->ca_owner)) {
  		error = -ENODEV;
  		goto Done;
  	}
  
  	if (item->ci_type)
  		ops = item->ci_type->ct_item_ops;
  	else
  		goto Eaccess;
  
  	/* File needs write support.
  	 * The inode's perms must say it's ok,
  	 * and we must have a store method.
  	 */
  	if (file->f_mode & FMODE_WRITE) {
  
  		if (!(inode->i_mode & S_IWUGO) || !ops->store_attribute)
  			goto Eaccess;
  
  	}
  
  	/* File needs read support.
  	 * The inode's perms must say it's ok, and we there
  	 * must be a show method for it.
  	 */
  	if (file->f_mode & FMODE_READ) {
  		if (!(inode->i_mode & S_IRUGO) || !ops->show_attribute)
  			goto Eaccess;
  	}
  
  	/* No error? Great, allocate a buffer for the file, and store it
  	 * it in file->private_data for easy access.
  	 */
f8314dc60   Panagiotis Issaris   [PATCH] fs: Conve...
255
  	buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
559c9ac39   Chandra Seetharaman   configfs: handle ...
256
  	if (!buffer) {
7063fbf22   Joel Becker   [PATCH] configfs:...
257
  		error = -ENOMEM;
559c9ac39   Chandra Seetharaman   configfs: handle ...
258
259
  		goto Enomem;
  	}
6d748924b   Johannes Berg   [PATCH] configsfs...
260
  	mutex_init(&buffer->mutex);
559c9ac39   Chandra Seetharaman   configfs: handle ...
261
262
263
  	buffer->needs_read_fill = 1;
  	buffer->ops = ops;
  	file->private_data = buffer;
7063fbf22   Joel Becker   [PATCH] configfs:...
264
265
266
267
268
269
270
  	goto Done;
  
   Einval:
  	error = -EINVAL;
  	goto Done;
   Eaccess:
  	error = -EACCES;
559c9ac39   Chandra Seetharaman   configfs: handle ...
271
   Enomem:
7063fbf22   Joel Becker   [PATCH] configfs:...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  	module_put(attr->ca_owner);
   Done:
  	if (error && item)
  		config_item_put(item);
  	return error;
  }
  
  static int configfs_open_file(struct inode * inode, struct file * filp)
  {
  	return check_perm(inode,filp);
  }
  
  static int configfs_release(struct inode * inode, struct file * filp)
  {
867fa491a   Josef "Jeff" Sipek   [PATCH] configfs:...
286
287
  	struct config_item * item = to_item(filp->f_path.dentry->d_parent);
  	struct configfs_attribute * attr = to_attr(filp->f_path.dentry);
7063fbf22   Joel Becker   [PATCH] configfs:...
288
289
290
291
292
293
294
295
296
297
298
  	struct module * owner = attr->ca_owner;
  	struct configfs_buffer * buffer = filp->private_data;
  
  	if (item)
  		config_item_put(item);
  	/* After this point, attr should not be accessed. */
  	module_put(owner);
  
  	if (buffer) {
  		if (buffer->page)
  			free_page((unsigned long)buffer->page);
6d748924b   Johannes Berg   [PATCH] configsfs...
299
  		mutex_destroy(&buffer->mutex);
7063fbf22   Joel Becker   [PATCH] configfs:...
300
301
302
303
  		kfree(buffer);
  	}
  	return 0;
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
304
  const struct file_operations configfs_file_operations = {
7063fbf22   Joel Becker   [PATCH] configfs:...
305
306
307
308
309
310
311
312
313
314
315
316
317
  	.read		= configfs_read_file,
  	.write		= configfs_write_file,
  	.llseek		= generic_file_llseek,
  	.open		= configfs_open_file,
  	.release	= configfs_release,
  };
  
  
  int configfs_add_file(struct dentry * dir, const struct configfs_attribute * attr, int type)
  {
  	struct configfs_dirent * parent_sd = dir->d_fsdata;
  	umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
  	int error = 0;
116ba5d5e   Joonwoo Park   configfs: file.c ...
318
  	mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL);
7063fbf22   Joel Becker   [PATCH] configfs:...
319
  	error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
1b1dcc1b5   Jes Sorensen   [PATCH] mutex sub...
320
  	mutex_unlock(&dir->d_inode->i_mutex);
7063fbf22   Joel Becker   [PATCH] configfs:...
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  
  	return error;
  }
  
  
  /**
   *	configfs_create_file - create an attribute file for an item.
   *	@item:	item we're creating for.
   *	@attr:	atrribute descriptor.
   */
  
  int configfs_create_file(struct config_item * item, const struct configfs_attribute * attr)
  {
  	BUG_ON(!item || !item->ci_dentry || !attr);
  
  	return configfs_add_file(item->ci_dentry, attr,
  				 CONFIGFS_ITEM_ATTR);
  }