Commit 4508a7a734b111b8b7e39986237d84acb1168dd0

Authored by NeilBrown
Committed by Greg Kroah-Hartman
1 parent f043ca43c1

[PATCH] sysfs: Allow sysfs attribute files to be pollable

It works like this:
  Open the file
  Read all the contents.
  Call poll requesting POLLERR or POLLPRI (so select/exceptfds works)
  When poll returns,
     close the file and go to top of loop.
   or lseek to start of file and go back to the 'read'.

Events are signaled by an object manager calling
   sysfs_notify(kobj, dir, attr);

If the dir is non-NULL, it is used to find a subdirectory which
contains the attribute (presumably created by sysfs_create_group).

This has a cost of one int  per attribute, one wait_queuehead per kobject,
one int per open file.

The name "sysfs_notify" may be confused with the inotify
functionality.  Maybe it would be nice to support inotify for sysfs
attributes as well?

This patch also uses sysfs_notify to allow /sys/block/md*/md/sync_action
to be pollable

Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Showing 7 changed files with 88 additions and 0 deletions Side-by-side Diff

... ... @@ -163,6 +163,7 @@
163 163 {
164 164 atomic_inc(&md_event_count);
165 165 wake_up(&md_event_waiters);
  166 + sysfs_notify(&mddev->kobj, NULL, "sync_action");
166 167 }
167 168 EXPORT_SYMBOL_GPL(md_new_event);
168 169  
... ... @@ -43,6 +43,7 @@
43 43  
44 44 memset(sd, 0, sizeof(*sd));
45 45 atomic_set(&sd->s_count, 1);
  46 + atomic_set(&sd->s_event, 0);
46 47 INIT_LIST_HEAD(&sd->s_children);
47 48 list_add(&sd->s_sibling, &parent_sd->s_children);
48 49 sd->s_element = element;
... ... @@ -6,6 +6,7 @@
6 6 #include <linux/fsnotify.h>
7 7 #include <linux/kobject.h>
8 8 #include <linux/namei.h>
  9 +#include <linux/poll.h>
9 10 #include <asm/uaccess.h>
10 11 #include <asm/semaphore.h>
11 12  
... ... @@ -57,6 +58,7 @@
57 58 struct sysfs_ops * ops;
58 59 struct semaphore sem;
59 60 int needs_read_fill;
  61 + int event;
60 62 };
61 63  
62 64  
... ... @@ -72,6 +74,7 @@
72 74 */
73 75 static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
74 76 {
  77 + struct sysfs_dirent * sd = dentry->d_fsdata;
75 78 struct attribute * attr = to_attr(dentry);
76 79 struct kobject * kobj = to_kobj(dentry->d_parent);
77 80 struct sysfs_ops * ops = buffer->ops;
... ... @@ -83,6 +86,7 @@
83 86 if (!buffer->page)
84 87 return -ENOMEM;
85 88  
  89 + buffer->event = atomic_read(&sd->s_event);
86 90 count = ops->show(kobj,attr,buffer->page);
87 91 buffer->needs_read_fill = 0;
88 92 BUG_ON(count > (ssize_t)PAGE_SIZE);
89 93  
... ... @@ -348,12 +352,84 @@
348 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 + */
  369 +static 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 +
  387 +static 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 +
  407 +void 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 +}
  424 +EXPORT_SYMBOL_GPL(sysfs_notify);
  425 +
351 426 const struct file_operations sysfs_file_operations = {
352 427 .read = sysfs_read_file,
353 428 .write = sysfs_write_file,
354 429 .llseek = generic_file_llseek,
355 430 .open = sysfs_open_file,
356 431 .release = sysfs_release,
  432 + .poll = sysfs_poll,
357 433 };
358 434  
359 435  
... ... @@ -11,6 +11,7 @@
11 11  
12 12 extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
13 13 extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
  14 +extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
14 15  
15 16 extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
16 17 extern void sysfs_remove_subdir(struct dentry *);
include/linux/kobject.h
... ... @@ -24,6 +24,7 @@
24 24 #include <linux/rwsem.h>
25 25 #include <linux/kref.h>
26 26 #include <linux/kernel.h>
  27 +#include <linux/wait.h>
27 28 #include <asm/atomic.h>
28 29  
29 30 #define KOBJ_NAME_LEN 20
... ... @@ -56,6 +57,7 @@
56 57 struct kset * kset;
57 58 struct kobj_type * ktype;
58 59 struct dentry * dentry;
  60 + wait_queue_head_t poll;
59 61 };
60 62  
61 63 extern int kobject_set_name(struct kobject *, const char *, ...)
include/linux/sysfs.h
... ... @@ -74,6 +74,7 @@
74 74 umode_t s_mode;
75 75 struct dentry * s_dentry;
76 76 struct iattr * s_iattr;
  77 + atomic_t s_event;
77 78 };
78 79  
79 80 #define SYSFS_ROOT 0x0001
... ... @@ -117,6 +118,7 @@
117 118  
118 119 int sysfs_create_group(struct kobject *, const struct attribute_group *);
119 120 void sysfs_remove_group(struct kobject *, const struct attribute_group *);
  121 +void sysfs_notify(struct kobject * k, char *dir, char *attr);
120 122  
121 123 #else /* CONFIG_SYSFS */
122 124  
... ... @@ -183,6 +185,10 @@
183 185 static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g)
184 186 {
185 187 ;
  188 +}
  189 +
  190 +static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
  191 +{
186 192 }
187 193  
188 194 #endif /* CONFIG_SYSFS */
... ... @@ -128,6 +128,7 @@
128 128 {
129 129 kref_init(&kobj->kref);
130 130 INIT_LIST_HEAD(&kobj->entry);
  131 + init_waitqueue_head(&kobj->poll);
131 132 kobj->kset = kset_get(kobj->kset);
132 133 }
133 134