aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs')
-rw-r--r--fs/sysfs/dir.c1
-rw-r--r--fs/sysfs/file.c76
-rw-r--r--fs/sysfs/sysfs.h1
3 files changed, 78 insertions, 0 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 6cfdc9a87772..610b5bdbe75b 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -43,6 +43,7 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
43 43
44 memset(sd, 0, sizeof(*sd)); 44 memset(sd, 0, sizeof(*sd));
45 atomic_set(&sd->s_count, 1); 45 atomic_set(&sd->s_count, 1);
46 atomic_set(&sd->s_event, 0);
46 INIT_LIST_HEAD(&sd->s_children); 47 INIT_LIST_HEAD(&sd->s_children);
47 list_add(&sd->s_sibling, &parent_sd->s_children); 48 list_add(&sd->s_sibling, &parent_sd->s_children);
48 sd->s_element = element; 49 sd->s_element = element;
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index f1cb1ddde511..cf3786625bfa 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -6,6 +6,7 @@
6#include <linux/fsnotify.h> 6#include <linux/fsnotify.h>
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 <asm/uaccess.h> 10#include <asm/uaccess.h>
10#include <asm/semaphore.h> 11#include <asm/semaphore.h>
11 12
@@ -57,6 +58,7 @@ struct sysfs_buffer {
57 struct sysfs_ops * ops; 58 struct sysfs_ops * ops;
58 struct semaphore sem; 59 struct semaphore sem;
59 int needs_read_fill; 60 int needs_read_fill;
61 int event;
60}; 62};
61 63
62 64
@@ -72,6 +74,7 @@ struct sysfs_buffer {
72 */ 74 */
73static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) 75static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
74{ 76{
77 struct sysfs_dirent * sd = dentry->d_fsdata;
75 struct attribute * attr = to_attr(dentry); 78 struct attribute * attr = to_attr(dentry);
76 struct kobject * kobj = to_kobj(dentry->d_parent); 79 struct kobject * kobj = to_kobj(dentry->d_parent);
77 struct sysfs_ops * ops = buffer->ops; 80 struct sysfs_ops * ops = buffer->ops;
@@ -83,6 +86,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
83 if (!buffer->page) 86 if (!buffer->page)
84 return -ENOMEM; 87 return -ENOMEM;
85 88
89 buffer->event = atomic_read(&sd->s_event);
86 count = ops->show(kobj,attr,buffer->page); 90 count = ops->show(kobj,attr,buffer->page);
87 buffer->needs_read_fill = 0; 91 buffer->needs_read_fill = 0;
88 BUG_ON(count > (ssize_t)PAGE_SIZE); 92 BUG_ON(count > (ssize_t)PAGE_SIZE);
@@ -348,12 +352,84 @@ static int sysfs_release(struct inode * inode, struct file * filp)
348 return 0; 352 return 0;
349} 353}
350 354
355/* Sysfs attribute files are pollable. The idea is that you read
356 * the content and then you use 'poll' or 'select' to wait for
357 * the content to change. When the content changes (assuming the
358 * manager for the kobject supports notification), poll will
359 * return POLLERR|POLLPRI, and select will return the fd whether
360 * it is waiting for read, write, or exceptions.
361 * Once poll/select indicates that the value has changed, you
362 * need to close and re-open the file, as simply seeking and reading
363 * again will not get new data, or reset the state of 'poll'.
364 * Reminder: this only works for attributes which actively support
365 * it, and it is not possible to test an attribute from userspace
366 * to see if it supports poll (Nether 'poll' or 'select' return
367 * an appropriate error code). When in doubt, set a suitable timeout value.
368 */
369static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
370{
371 struct sysfs_buffer * buffer = filp->private_data;
372 struct kobject * kobj = to_kobj(filp->f_dentry->d_parent);
373 struct sysfs_dirent * sd = filp->f_dentry->d_fsdata;
374 int res = 0;
375
376 poll_wait(filp, &kobj->poll, wait);
377
378 if (buffer->event != atomic_read(&sd->s_event)) {
379 res = POLLERR|POLLPRI;
380 buffer->needs_read_fill = 1;
381 }
382
383 return res;
384}
385
386
387static struct dentry *step_down(struct dentry *dir, const char * name)
388{
389 struct dentry * de;
390
391 if (dir == NULL || dir->d_inode == NULL)
392 return NULL;
393
394 mutex_lock(&dir->d_inode->i_mutex);
395 de = lookup_one_len(name, dir, strlen(name));
396 mutex_unlock(&dir->d_inode->i_mutex);
397 dput(dir);
398 if (IS_ERR(de))
399 return NULL;
400 if (de->d_inode == NULL) {
401 dput(de);
402 return NULL;
403 }
404 return de;
405}
406
407void sysfs_notify(struct kobject * k, char *dir, char *attr)
408{
409 struct dentry *de = k->dentry;
410 if (de)
411 dget(de);
412 if (de && dir)
413 de = step_down(de, dir);
414 if (de && attr)
415 de = step_down(de, attr);
416 if (de) {
417 struct sysfs_dirent * sd = de->d_fsdata;
418 if (sd)
419 atomic_inc(&sd->s_event);
420 wake_up_interruptible(&k->poll);
421 dput(de);
422 }
423}
424EXPORT_SYMBOL_GPL(sysfs_notify);
425
351const struct file_operations sysfs_file_operations = { 426const struct file_operations sysfs_file_operations = {
352 .read = sysfs_read_file, 427 .read = sysfs_read_file,
353 .write = sysfs_write_file, 428 .write = sysfs_write_file,
354 .llseek = generic_file_llseek, 429 .llseek = generic_file_llseek,
355 .open = sysfs_open_file, 430 .open = sysfs_open_file,
356 .release = sysfs_release, 431 .release = sysfs_release,
432 .poll = sysfs_poll,
357}; 433};
358 434
359 435
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 32958a7c50e9..3651ffb5ec09 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -11,6 +11,7 @@ extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
11 11
12extern int sysfs_add_file(struct dentry *, const struct attribute *, int); 12extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
13extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); 13extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
14extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
14 15
15extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); 16extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
16extern void sysfs_remove_subdir(struct dentry *); 17extern void sysfs_remove_subdir(struct dentry *);