aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r--fs/sysfs/file.c82
1 files changed, 58 insertions, 24 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 9cfe53e1e00d..c0e117649a4d 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -7,6 +7,7 @@
7#include <linux/kobject.h> 7#include <linux/kobject.h>
8#include <linux/namei.h> 8#include <linux/namei.h>
9#include <linux/poll.h> 9#include <linux/poll.h>
10#include <linux/list.h>
10#include <asm/uaccess.h> 11#include <asm/uaccess.h>
11#include <asm/semaphore.h> 12#include <asm/semaphore.h>
12 13
@@ -50,17 +51,29 @@ static struct sysfs_ops subsys_sysfs_ops = {
50 .store = subsys_attr_store, 51 .store = subsys_attr_store,
51}; 52};
52 53
54/**
55 * add_to_collection - add buffer to a collection
56 * @buffer: buffer to be added
57 * @node inode of set to add to
58 */
53 59
54struct sysfs_buffer { 60static inline void
55 size_t count; 61add_to_collection(struct sysfs_buffer *buffer, struct inode *node)
56 loff_t pos; 62{
57 char * page; 63 struct sysfs_buffer_collection *set = node->i_private;
58 struct sysfs_ops * ops;
59 struct semaphore sem;
60 int needs_read_fill;
61 int event;
62};
63 64
65 mutex_lock(&node->i_mutex);
66 list_add(&buffer->associates, &set->associates);
67 mutex_unlock(&node->i_mutex);
68}
69
70static inline void
71remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
72{
73 mutex_lock(&node->i_mutex);
74 list_del(&buffer->associates);
75 mutex_unlock(&node->i_mutex);
76}
64 77
65/** 78/**
66 * fill_read_buffer - allocate and fill buffer from object. 79 * fill_read_buffer - allocate and fill buffer from object.
@@ -70,7 +83,8 @@ struct sysfs_buffer {
70 * Allocate @buffer->page, if it hasn't been already, then call the 83 * Allocate @buffer->page, if it hasn't been already, then call the
71 * kobject's show() method to fill the buffer with this attribute's 84 * kobject's show() method to fill the buffer with this attribute's
72 * data. 85 * data.
73 * This is called only once, on the file's first read. 86 * This is called only once, on the file's first read unless an error
87 * is returned.
74 */ 88 */
75static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) 89static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
76{ 90{
@@ -88,12 +102,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
88 102
89 buffer->event = atomic_read(&sd->s_event); 103 buffer->event = atomic_read(&sd->s_event);
90 count = ops->show(kobj,attr,buffer->page); 104 count = ops->show(kobj,attr,buffer->page);
91 buffer->needs_read_fill = 0;
92 BUG_ON(count > (ssize_t)PAGE_SIZE); 105 BUG_ON(count > (ssize_t)PAGE_SIZE);
93 if (count >= 0) 106 if (count >= 0) {
107 buffer->needs_read_fill = 0;
94 buffer->count = count; 108 buffer->count = count;
95 else 109 } else {
96 ret = count; 110 ret = count;
111 }
97 return ret; 112 return ret;
98} 113}
99 114
@@ -153,6 +168,10 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
153 ssize_t retval = 0; 168 ssize_t retval = 0;
154 169
155 down(&buffer->sem); 170 down(&buffer->sem);
171 if (buffer->orphaned) {
172 retval = -ENODEV;
173 goto out;
174 }
156 if (buffer->needs_read_fill) { 175 if (buffer->needs_read_fill) {
157 if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) 176 if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
158 goto out; 177 goto out;
@@ -165,7 +184,6 @@ out:
165 return retval; 184 return retval;
166} 185}
167 186
168
169/** 187/**
170 * fill_write_buffer - copy buffer from userspace. 188 * fill_write_buffer - copy buffer from userspace.
171 * @buffer: data buffer for file. 189 * @buffer: data buffer for file.
@@ -243,19 +261,25 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
243 ssize_t len; 261 ssize_t len;
244 262
245 down(&buffer->sem); 263 down(&buffer->sem);
264 if (buffer->orphaned) {
265 len = -ENODEV;
266 goto out;
267 }
246 len = fill_write_buffer(buffer, buf, count); 268 len = fill_write_buffer(buffer, buf, count);
247 if (len > 0) 269 if (len > 0)
248 len = flush_write_buffer(file->f_path.dentry, buffer, len); 270 len = flush_write_buffer(file->f_path.dentry, buffer, len);
249 if (len > 0) 271 if (len > 0)
250 *ppos += len; 272 *ppos += len;
273out:
251 up(&buffer->sem); 274 up(&buffer->sem);
252 return len; 275 return len;
253} 276}
254 277
255static int check_perm(struct inode * inode, struct file * file) 278static int sysfs_open_file(struct inode *inode, struct file *file)
256{ 279{
257 struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); 280 struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
258 struct attribute * attr = to_attr(file->f_path.dentry); 281 struct attribute * attr = to_attr(file->f_path.dentry);
282 struct sysfs_buffer_collection *set;
259 struct sysfs_buffer * buffer; 283 struct sysfs_buffer * buffer;
260 struct sysfs_ops * ops = NULL; 284 struct sysfs_ops * ops = NULL;
261 int error = 0; 285 int error = 0;
@@ -285,6 +309,18 @@ static int check_perm(struct inode * inode, struct file * file)
285 if (!ops) 309 if (!ops)
286 goto Eaccess; 310 goto Eaccess;
287 311
312 /* make sure we have a collection to add our buffers to */
313 mutex_lock(&inode->i_mutex);
314 if (!(set = inode->i_private)) {
315 if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) {
316 error = -ENOMEM;
317 goto Done;
318 } else {
319 INIT_LIST_HEAD(&set->associates);
320 }
321 }
322 mutex_unlock(&inode->i_mutex);
323
288 /* File needs write support. 324 /* File needs write support.
289 * The inode's perms must say it's ok, 325 * The inode's perms must say it's ok,
290 * and we must have a store method. 326 * and we must have a store method.
@@ -310,9 +346,11 @@ static int check_perm(struct inode * inode, struct file * file)
310 */ 346 */
311 buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); 347 buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
312 if (buffer) { 348 if (buffer) {
349 INIT_LIST_HEAD(&buffer->associates);
313 init_MUTEX(&buffer->sem); 350 init_MUTEX(&buffer->sem);
314 buffer->needs_read_fill = 1; 351 buffer->needs_read_fill = 1;
315 buffer->ops = ops; 352 buffer->ops = ops;
353 add_to_collection(buffer, inode);
316 file->private_data = buffer; 354 file->private_data = buffer;
317 } else 355 } else
318 error = -ENOMEM; 356 error = -ENOMEM;
@@ -325,16 +363,11 @@ static int check_perm(struct inode * inode, struct file * file)
325 error = -EACCES; 363 error = -EACCES;
326 module_put(attr->owner); 364 module_put(attr->owner);
327 Done: 365 Done:
328 if (error && kobj) 366 if (error)
329 kobject_put(kobj); 367 kobject_put(kobj);
330 return error; 368 return error;
331} 369}
332 370
333static int sysfs_open_file(struct inode * inode, struct file * filp)
334{
335 return check_perm(inode,filp);
336}
337
338static int sysfs_release(struct inode * inode, struct file * filp) 371static int sysfs_release(struct inode * inode, struct file * filp)
339{ 372{
340 struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); 373 struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
@@ -342,8 +375,9 @@ static int sysfs_release(struct inode * inode, struct file * filp)
342 struct module * owner = attr->owner; 375 struct module * owner = attr->owner;
343 struct sysfs_buffer * buffer = filp->private_data; 376 struct sysfs_buffer * buffer = filp->private_data;
344 377
345 if (kobj) 378 if (buffer)
346 kobject_put(kobj); 379 remove_from_collection(buffer, inode);
380 kobject_put(kobj);
347 /* After this point, attr should not be accessed. */ 381 /* After this point, attr should not be accessed. */
348 module_put(owner); 382 module_put(owner);
349 383
@@ -548,7 +582,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
548 582
549void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) 583void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
550{ 584{
551 sysfs_hash_and_remove(kobj->dentry,attr->name); 585 sysfs_hash_and_remove(kobj->dentry, attr->name);
552} 586}
553 587
554 588