[PATCH] configfs: User-driven configuration filesystem
[linux-2.6.git] / fs / configfs / file.c
1 /* -*- mode: c; c-basic-offset: 8; -*-
2  * vim: noexpandtab sw=8 ts=8 sts=0:
3  *
4  * file.c - operations for regular (text) files.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA.
20  *
21  * Based on sysfs:
22  *      sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
23  *
24  * configfs Copyright (C) 2005 Oracle.  All rights reserved.
25  */
26
27 #include <linux/fs.h>
28 #include <linux/module.h>
29 #include <linux/dnotify.h>
30 #include <linux/slab.h>
31 #include <asm/uaccess.h>
32 #include <asm/semaphore.h>
33
34 #include <linux/configfs.h>
35 #include "configfs_internal.h"
36
37
38 struct configfs_buffer {
39         size_t                  count;
40         loff_t                  pos;
41         char                    * page;
42         struct configfs_item_operations * ops;
43         struct semaphore        sem;
44         int                     needs_read_fill;
45 };
46
47
48 /**
49  *      fill_read_buffer - allocate and fill buffer from item.
50  *      @dentry:        dentry pointer.
51  *      @buffer:        data buffer for file.
52  *
53  *      Allocate @buffer->page, if it hasn't been already, then call the
54  *      config_item's show() method to fill the buffer with this attribute's
55  *      data.
56  *      This is called only once, on the file's first read.
57  */
58 static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buffer)
59 {
60         struct configfs_attribute * attr = to_attr(dentry);
61         struct config_item * item = to_item(dentry->d_parent);
62         struct configfs_item_operations * ops = buffer->ops;
63         int ret = 0;
64         ssize_t count;
65
66         if (!buffer->page)
67                 buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
68         if (!buffer->page)
69                 return -ENOMEM;
70
71         count = ops->show_attribute(item,attr,buffer->page);
72         buffer->needs_read_fill = 0;
73         BUG_ON(count > (ssize_t)PAGE_SIZE);
74         if (count >= 0)
75                 buffer->count = count;
76         else
77                 ret = count;
78         return ret;
79 }
80
81
82 /**
83  *      flush_read_buffer - push buffer to userspace.
84  *      @buffer:        data buffer for file.
85  *      @userbuf:       user-passed buffer.
86  *      @count:         number of bytes requested.
87  *      @ppos:          file position.
88  *
89  *      Copy the buffer we filled in fill_read_buffer() to userspace.
90  *      This is done at the reader's leisure, copying and advancing
91  *      the amount they specify each time.
92  *      This may be called continuously until the buffer is empty.
93  */
94 static int flush_read_buffer(struct configfs_buffer * buffer, char __user * buf,
95                              size_t count, loff_t * ppos)
96 {
97         int error;
98
99         if (*ppos > buffer->count)
100                 return 0;
101
102         if (count > (buffer->count - *ppos))
103                 count = buffer->count - *ppos;
104
105         error = copy_to_user(buf,buffer->page + *ppos,count);
106         if (!error)
107                 *ppos += count;
108         return error ? -EFAULT : count;
109 }
110
111 /**
112  *      configfs_read_file - read an attribute.
113  *      @file:  file pointer.
114  *      @buf:   buffer to fill.
115  *      @count: number of bytes to read.
116  *      @ppos:  starting offset in file.
117  *
118  *      Userspace wants to read an attribute file. The attribute descriptor
119  *      is in the file's ->d_fsdata. The target item is in the directory's
120  *      ->d_fsdata.
121  *
122  *      We call fill_read_buffer() to allocate and fill the buffer from the
123  *      item's show() method exactly once (if the read is happening from
124  *      the beginning of the file). That should fill the entire buffer with
125  *      all the data the item has to offer for that attribute.
126  *      We then call flush_read_buffer() to copy the buffer to userspace
127  *      in the increments specified.
128  */
129
130 static ssize_t
131 configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
132 {
133         struct configfs_buffer * buffer = file->private_data;
134         ssize_t retval = 0;
135
136         down(&buffer->sem);
137         if (buffer->needs_read_fill) {
138                 if ((retval = fill_read_buffer(file->f_dentry,buffer)))
139                         goto out;
140         }
141         pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
142                  __FUNCTION__,count,*ppos,buffer->page);
143         retval = flush_read_buffer(buffer,buf,count,ppos);
144 out:
145         up(&buffer->sem);
146         return retval;
147 }
148
149
150 /**
151  *      fill_write_buffer - copy buffer from userspace.
152  *      @buffer:        data buffer for file.
153  *      @userbuf:       data from user.
154  *      @count:         number of bytes in @userbuf.
155  *
156  *      Allocate @buffer->page if it hasn't been already, then
157  *      copy the user-supplied buffer into it.
158  */
159
160 static int
161 fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size_t count)
162 {
163         int error;
164
165         if (!buffer->page)
166                 buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
167         if (!buffer->page)
168                 return -ENOMEM;
169
170         if (count > PAGE_SIZE)
171                 count = PAGE_SIZE;
172         error = copy_from_user(buffer->page,buf,count);
173         buffer->needs_read_fill = 1;
174         return error ? -EFAULT : count;
175 }
176
177
178 /**
179  *      flush_write_buffer - push buffer to config_item.
180  *      @file:          file pointer.
181  *      @buffer:        data buffer for file.
182  *
183  *      Get the correct pointers for the config_item and the attribute we're
184  *      dealing with, then call the store() method for the attribute,
185  *      passing the buffer that we acquired in fill_write_buffer().
186  */
187
188 static int
189 flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size_t count)
190 {
191         struct configfs_attribute * attr = to_attr(dentry);
192         struct config_item * item = to_item(dentry->d_parent);
193         struct configfs_item_operations * ops = buffer->ops;
194
195         return ops->store_attribute(item,attr,buffer->page,count);
196 }
197
198
199 /**
200  *      configfs_write_file - write an attribute.
201  *      @file:  file pointer
202  *      @buf:   data to write
203  *      @count: number of bytes
204  *      @ppos:  starting offset
205  *
206  *      Similar to configfs_read_file(), though working in the opposite direction.
207  *      We allocate and fill the data from the user in fill_write_buffer(),
208  *      then push it to the config_item in flush_write_buffer().
209  *      There is no easy way for us to know if userspace is only doing a partial
210  *      write, so we don't support them. We expect the entire buffer to come
211  *      on the first write.
212  *      Hint: if you're writing a value, first read the file, modify only the
213  *      the value you're changing, then write entire buffer back.
214  */
215
216 static ssize_t
217 configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
218 {
219         struct configfs_buffer * buffer = file->private_data;
220
221         down(&buffer->sem);
222         count = fill_write_buffer(buffer,buf,count);
223         if (count > 0)
224                 count = flush_write_buffer(file->f_dentry,buffer,count);
225         if (count > 0)
226                 *ppos += count;
227         up(&buffer->sem);
228         return count;
229 }
230
231 static int check_perm(struct inode * inode, struct file * file)
232 {
233         struct config_item *item = configfs_get_config_item(file->f_dentry->d_parent);
234         struct configfs_attribute * attr = to_attr(file->f_dentry);
235         struct configfs_buffer * buffer;
236         struct configfs_item_operations * ops = NULL;
237         int error = 0;
238
239         if (!item || !attr)
240                 goto Einval;
241
242         /* Grab the module reference for this attribute if we have one */
243         if (!try_module_get(attr->ca_owner)) {
244                 error = -ENODEV;
245                 goto Done;
246         }
247
248         if (item->ci_type)
249                 ops = item->ci_type->ct_item_ops;
250         else
251                 goto Eaccess;
252
253         /* File needs write support.
254          * The inode's perms must say it's ok,
255          * and we must have a store method.
256          */
257         if (file->f_mode & FMODE_WRITE) {
258
259                 if (!(inode->i_mode & S_IWUGO) || !ops->store_attribute)
260                         goto Eaccess;
261
262         }
263
264         /* File needs read support.
265          * The inode's perms must say it's ok, and we there
266          * must be a show method for it.
267          */
268         if (file->f_mode & FMODE_READ) {
269                 if (!(inode->i_mode & S_IRUGO) || !ops->show_attribute)
270                         goto Eaccess;
271         }
272
273         /* No error? Great, allocate a buffer for the file, and store it
274          * it in file->private_data for easy access.
275          */
276         buffer = kmalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
277         if (buffer) {
278                 memset(buffer,0,sizeof(struct configfs_buffer));
279                 init_MUTEX(&buffer->sem);
280                 buffer->needs_read_fill = 1;
281                 buffer->ops = ops;
282                 file->private_data = buffer;
283         } else
284                 error = -ENOMEM;
285         goto Done;
286
287  Einval:
288         error = -EINVAL;
289         goto Done;
290  Eaccess:
291         error = -EACCES;
292         module_put(attr->ca_owner);
293  Done:
294         if (error && item)
295                 config_item_put(item);
296         return error;
297 }
298
299 static int configfs_open_file(struct inode * inode, struct file * filp)
300 {
301         return check_perm(inode,filp);
302 }
303
304 static int configfs_release(struct inode * inode, struct file * filp)
305 {
306         struct config_item * item = to_item(filp->f_dentry->d_parent);
307         struct configfs_attribute * attr = to_attr(filp->f_dentry);
308         struct module * owner = attr->ca_owner;
309         struct configfs_buffer * buffer = filp->private_data;
310
311         if (item)
312                 config_item_put(item);
313         /* After this point, attr should not be accessed. */
314         module_put(owner);
315
316         if (buffer) {
317                 if (buffer->page)
318                         free_page((unsigned long)buffer->page);
319                 kfree(buffer);
320         }
321         return 0;
322 }
323
324 struct file_operations configfs_file_operations = {
325         .read           = configfs_read_file,
326         .write          = configfs_write_file,
327         .llseek         = generic_file_llseek,
328         .open           = configfs_open_file,
329         .release        = configfs_release,
330 };
331
332
333 int configfs_add_file(struct dentry * dir, const struct configfs_attribute * attr, int type)
334 {
335         struct configfs_dirent * parent_sd = dir->d_fsdata;
336         umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
337         int error = 0;
338
339         down(&dir->d_inode->i_sem);
340         error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
341         up(&dir->d_inode->i_sem);
342
343         return error;
344 }
345
346
347 /**
348  *      configfs_create_file - create an attribute file for an item.
349  *      @item:  item we're creating for.
350  *      @attr:  atrribute descriptor.
351  */
352
353 int configfs_create_file(struct config_item * item, const struct configfs_attribute * attr)
354 {
355         BUG_ON(!item || !item->ci_dentry || !attr);
356
357         return configfs_add_file(item->ci_dentry, attr,
358                                  CONFIGFS_ITEM_ATTR);
359 }
360