diff options
author | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-10 14:47:26 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-10 14:47:26 -0400 |
commit | f0cd91a68acdc9b49d7f6738b514a426da627649 (patch) | |
tree | 8ad73564015794197583b094217ae0a71e71e753 /fs/sysfs/file.c | |
parent | 60eef25701d25e99c991dd0f4a9f3832a0c3ad3e (diff) | |
parent | 128e6ced247cda88f96fa9f2e4ba8b2c4a681560 (diff) |
Merge ../linux-2.6
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 76 |
1 files changed, 76 insertions, 0 deletions
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 | */ |
73 | static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) | 75 | static 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 | */ | ||
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 | const struct file_operations sysfs_file_operations = { | 426 | const 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 | ||