diff options
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b13ba94cf8ac..c05f9618b2dc 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -62,6 +62,8 @@ static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; | |||
62 | 62 | ||
63 | struct sysfs_open_dirent { | 63 | struct sysfs_open_dirent { |
64 | atomic_t refcnt; | 64 | atomic_t refcnt; |
65 | atomic_t event; | ||
66 | wait_queue_head_t poll; | ||
65 | struct list_head buffers; /* goes through sysfs_buffer.list */ | 67 | struct list_head buffers; /* goes through sysfs_buffer.list */ |
66 | }; | 68 | }; |
67 | 69 | ||
@@ -104,7 +106,7 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
104 | if (!sysfs_get_active_two(attr_sd)) | 106 | if (!sysfs_get_active_two(attr_sd)) |
105 | return -ENODEV; | 107 | return -ENODEV; |
106 | 108 | ||
107 | buffer->event = atomic_read(&attr_sd->s_event); | 109 | buffer->event = atomic_read(&attr_sd->s_attr.open->event); |
108 | count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); | 110 | count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); |
109 | 111 | ||
110 | sysfs_put_active_two(attr_sd); | 112 | sysfs_put_active_two(attr_sd); |
@@ -301,6 +303,8 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, | |||
301 | return -ENOMEM; | 303 | return -ENOMEM; |
302 | 304 | ||
303 | atomic_set(&new_od->refcnt, 0); | 305 | atomic_set(&new_od->refcnt, 0); |
306 | atomic_set(&new_od->event, 1); | ||
307 | init_waitqueue_head(&new_od->poll); | ||
304 | INIT_LIST_HEAD(&new_od->buffers); | 308 | INIT_LIST_HEAD(&new_od->buffers); |
305 | goto retry; | 309 | goto retry; |
306 | } | 310 | } |
@@ -443,17 +447,17 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait) | |||
443 | { | 447 | { |
444 | struct sysfs_buffer * buffer = filp->private_data; | 448 | struct sysfs_buffer * buffer = filp->private_data; |
445 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; | 449 | struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; |
446 | struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; | 450 | struct sysfs_open_dirent *od = attr_sd->s_attr.open; |
447 | 451 | ||
448 | /* need parent for the kobj, grab both */ | 452 | /* need parent for the kobj, grab both */ |
449 | if (!sysfs_get_active_two(attr_sd)) | 453 | if (!sysfs_get_active_two(attr_sd)) |
450 | goto trigger; | 454 | goto trigger; |
451 | 455 | ||
452 | poll_wait(filp, &kobj->poll, wait); | 456 | poll_wait(filp, &od->poll, wait); |
453 | 457 | ||
454 | sysfs_put_active_two(attr_sd); | 458 | sysfs_put_active_two(attr_sd); |
455 | 459 | ||
456 | if (buffer->event != atomic_read(&attr_sd->s_event)) | 460 | if (buffer->event != atomic_read(&od->event)) |
457 | goto trigger; | 461 | goto trigger; |
458 | 462 | ||
459 | return 0; | 463 | return 0; |
@@ -474,8 +478,17 @@ void sysfs_notify(struct kobject *k, char *dir, char *attr) | |||
474 | if (sd && attr) | 478 | if (sd && attr) |
475 | sd = sysfs_find_dirent(sd, attr); | 479 | sd = sysfs_find_dirent(sd, attr); |
476 | if (sd) { | 480 | if (sd) { |
477 | atomic_inc(&sd->s_event); | 481 | struct sysfs_open_dirent *od; |
478 | wake_up_interruptible(&k->poll); | 482 | |
483 | spin_lock(&sysfs_open_dirent_lock); | ||
484 | |||
485 | od = sd->s_attr.open; | ||
486 | if (od) { | ||
487 | atomic_inc(&od->event); | ||
488 | wake_up_interruptible(&od->poll); | ||
489 | } | ||
490 | |||
491 | spin_unlock(&sysfs_open_dirent_lock); | ||
479 | } | 492 | } |
480 | 493 | ||
481 | mutex_unlock(&sysfs_mutex); | 494 | mutex_unlock(&sysfs_mutex); |