diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-14 20:07:57 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-14 20:07:57 -0400 |
| commit | 754a264c42178b85125a071299bb900b615c853b (patch) | |
| tree | 8cfc6d85e6725f90672b75314064ead9fd62e3c6 /fs/sysfs/file.c | |
| parent | f9814802dfec8feaf51ba873d7eac1a05ee65842 (diff) | |
| parent | 4f705ae3e94ffaafe8d35f71ff4d5c499bb06814 (diff) | |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6: (158 commits)
commit 4f705ae3e94ffaafe8d35f71ff4d5c499bb06814
Author: Bjorn Helgaas <bjorn.helgaas@hp.com>
Date: Mon Apr 3 17:09:22 2006 -0700
[PATCH] DMI: move dmi_scan.c from arch/i386 to drivers/firmware/
dmi_scan.c is arch-independent and is used by i386, x86_64, and ia64.
Currently all three arches compile it from arch/i386, which means that ia64
and x86_64 depend on things in arch/i386 that they wouldn't otherwise care
about.
This is simply "mv arch/i386/kernel/dmi_scan.c drivers/firmware/" (removing
trailing whitespace) and the associated Makefile changes. All three
architectures already set CONFIG_DMI in their top-level Kconfig files.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Cc: Andi Kleen <ak@muc.de>
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: Andrey Panin <pazke@orbita1.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
...
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 | ||
