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#include <linux/fs.h>
28#include <linux/module.h>
29#include <linux/slab.h>
30#include <linux/mutex.h>
31#include <asm/uaccess.h>
32
33#include <linux/configfs.h>
34#include "configfs_internal.h"
35
36
37
38
39
40
41
42#define SIMPLE_ATTR_SIZE 4096
43
44struct configfs_buffer {
45 size_t count;
46 loff_t pos;
47 char * page;
48 struct configfs_item_operations * ops;
49 struct mutex mutex;
50 int needs_read_fill;
51};
52
53
54
55
56
57
58
59
60
61
62
63
64static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buffer)
65{
66 struct configfs_attribute * attr = to_attr(dentry);
67 struct config_item * item = to_item(dentry->d_parent);
68 struct configfs_item_operations * ops = buffer->ops;
69 int ret = 0;
70 ssize_t count;
71
72 if (!buffer->page)
73 buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
74 if (!buffer->page)
75 return -ENOMEM;
76
77 count = ops->show_attribute(item,attr,buffer->page);
78 buffer->needs_read_fill = 0;
79 BUG_ON(count > (ssize_t)SIMPLE_ATTR_SIZE);
80 if (count >= 0)
81 buffer->count = count;
82 else
83 ret = count;
84 return ret;
85}
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106static ssize_t
107configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
108{
109 struct configfs_buffer * buffer = file->private_data;
110 ssize_t retval = 0;
111
112 mutex_lock(&buffer->mutex);
113 if (buffer->needs_read_fill) {
114 if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
115 goto out;
116 }
117 pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
118 __func__, count, *ppos, buffer->page);
119 retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
120 buffer->count);
121out:
122 mutex_unlock(&buffer->mutex);
123 return retval;
124}
125
126
127
128
129
130
131
132
133
134
135
136
137static int
138fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size_t count)
139{
140 int error;
141
142 if (!buffer->page)
143 buffer->page = (char *)__get_free_pages(GFP_KERNEL, 0);
144 if (!buffer->page)
145 return -ENOMEM;
146
147 if (count >= SIMPLE_ATTR_SIZE)
148 count = SIMPLE_ATTR_SIZE - 1;
149 error = copy_from_user(buffer->page,buf,count);
150 buffer->needs_read_fill = 1;
151
152
153 buffer->page[count] = 0;
154 return error ? -EFAULT : count;
155}
156
157
158
159
160
161
162
163
164
165
166
167
168
169static int
170flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size_t count)
171{
172 struct configfs_attribute * attr = to_attr(dentry);
173 struct config_item * item = to_item(dentry->d_parent);
174 struct configfs_item_operations * ops = buffer->ops;
175
176 return ops->store_attribute(item,attr,buffer->page,count);
177}
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197static ssize_t
198configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
199{
200 struct configfs_buffer * buffer = file->private_data;
201 ssize_t len;
202
203 mutex_lock(&buffer->mutex);
204 len = fill_write_buffer(buffer, buf, count);
205 if (len > 0)
206 len = flush_write_buffer(file->f_path.dentry, buffer, count);
207 if (len > 0)
208 *ppos += len;
209 mutex_unlock(&buffer->mutex);
210 return len;
211}
212
213static int check_perm(struct inode * inode, struct file * file)
214{
215 struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent);
216 struct configfs_attribute * attr = to_attr(file->f_path.dentry);
217 struct configfs_buffer * buffer;
218 struct configfs_item_operations * ops = NULL;
219 int error = 0;
220
221 if (!item || !attr)
222 goto Einval;
223
224
225 if (!try_module_get(attr->ca_owner)) {
226 error = -ENODEV;
227 goto Done;
228 }
229
230 if (item->ci_type)
231 ops = item->ci_type->ct_item_ops;
232 else
233 goto Eaccess;
234
235
236
237
238
239 if (file->f_mode & FMODE_WRITE) {
240
241 if (!(inode->i_mode & S_IWUGO) || !ops->store_attribute)
242 goto Eaccess;
243
244 }
245
246
247
248
249
250 if (file->f_mode & FMODE_READ) {
251 if (!(inode->i_mode & S_IRUGO) || !ops->show_attribute)
252 goto Eaccess;
253 }
254
255
256
257
258 buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
259 if (!buffer) {
260 error = -ENOMEM;
261 goto Enomem;
262 }
263 mutex_init(&buffer->mutex);
264 buffer->needs_read_fill = 1;
265 buffer->ops = ops;
266 file->private_data = buffer;
267 goto Done;
268
269 Einval:
270 error = -EINVAL;
271 goto Done;
272 Eaccess:
273 error = -EACCES;
274 Enomem:
275 module_put(attr->ca_owner);
276 Done:
277 if (error && item)
278 config_item_put(item);
279 return error;
280}
281
282static int configfs_open_file(struct inode * inode, struct file * filp)
283{
284 return check_perm(inode,filp);
285}
286
287static int configfs_release(struct inode * inode, struct file * filp)
288{
289 struct config_item * item = to_item(filp->f_path.dentry->d_parent);
290 struct configfs_attribute * attr = to_attr(filp->f_path.dentry);
291 struct module * owner = attr->ca_owner;
292 struct configfs_buffer * buffer = filp->private_data;
293
294 if (item)
295 config_item_put(item);
296
297 module_put(owner);
298
299 if (buffer) {
300 if (buffer->page)
301 free_page((unsigned long)buffer->page);
302 mutex_destroy(&buffer->mutex);
303 kfree(buffer);
304 }
305 return 0;
306}
307
308const struct file_operations configfs_file_operations = {
309 .read = configfs_read_file,
310 .write = configfs_write_file,
311 .llseek = generic_file_llseek,
312 .open = configfs_open_file,
313 .release = configfs_release,
314};
315
316
317int configfs_add_file(struct dentry * dir, const struct configfs_attribute * attr, int type)
318{
319 struct configfs_dirent * parent_sd = dir->d_fsdata;
320 umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
321 int error = 0;
322
323 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL);
324 error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
325 mutex_unlock(&dir->d_inode->i_mutex);
326
327 return error;
328}
329
330
331
332
333
334
335
336
337int configfs_create_file(struct config_item * item, const struct configfs_attribute * attr)
338{
339 BUG_ON(!item || !item->ci_dentry || !attr);
340
341 return configfs_add_file(item->ci_dentry, attr,
342 CONFIGFS_ITEM_ATTR);
343}
344
345