diff options
-rw-r--r-- | include/linux/relay.h | 3 | ||||
-rw-r--r-- | kernel/relay.c | 35 |
2 files changed, 18 insertions, 20 deletions
diff --git a/include/linux/relay.h b/include/linux/relay.h index 759a0f97bec2..6cd8c4425fc7 100644 --- a/include/linux/relay.h +++ b/include/linux/relay.h | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/timer.h> | ||
15 | #include <linux/wait.h> | 16 | #include <linux/wait.h> |
16 | #include <linux/list.h> | 17 | #include <linux/list.h> |
17 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
@@ -38,7 +39,7 @@ struct rchan_buf | |||
38 | size_t subbufs_consumed; /* count of sub-buffers consumed */ | 39 | size_t subbufs_consumed; /* count of sub-buffers consumed */ |
39 | struct rchan *chan; /* associated channel */ | 40 | struct rchan *chan; /* associated channel */ |
40 | wait_queue_head_t read_wait; /* reader wait queue */ | 41 | wait_queue_head_t read_wait; /* reader wait queue */ |
41 | struct delayed_work wake_readers; /* reader wake-up work struct */ | 42 | struct timer_list timer; /* reader wake-up timer */ |
42 | struct dentry *dentry; /* channel file dentry */ | 43 | struct dentry *dentry; /* channel file dentry */ |
43 | struct kref kref; /* channel buffer refcount */ | 44 | struct kref kref; /* channel buffer refcount */ |
44 | struct page **page_array; /* array of current buffer pages */ | 45 | struct page **page_array; /* array of current buffer pages */ |
diff --git a/kernel/relay.c b/kernel/relay.c index 577f251c7e28..e804589c863c 100644 --- a/kernel/relay.c +++ b/kernel/relay.c | |||
@@ -310,16 +310,13 @@ static struct rchan_callbacks default_channel_callbacks = { | |||
310 | 310 | ||
311 | /** | 311 | /** |
312 | * wakeup_readers - wake up readers waiting on a channel | 312 | * wakeup_readers - wake up readers waiting on a channel |
313 | * @work: work struct that contains the the channel buffer | 313 | * @data: contains the the channel buffer |
314 | * | 314 | * |
315 | * This is the work function used to defer reader waking. The | 315 | * This is the timer function used to defer reader waking. |
316 | * reason waking is deferred is that calling directly from write | ||
317 | * causes problems if you're writing from say the scheduler. | ||
318 | */ | 316 | */ |
319 | static void wakeup_readers(struct work_struct *work) | 317 | static void wakeup_readers(unsigned long data) |
320 | { | 318 | { |
321 | struct rchan_buf *buf = | 319 | struct rchan_buf *buf = (struct rchan_buf *)data; |
322 | container_of(work, struct rchan_buf, wake_readers.work); | ||
323 | wake_up_interruptible(&buf->read_wait); | 320 | wake_up_interruptible(&buf->read_wait); |
324 | } | 321 | } |
325 | 322 | ||
@@ -337,11 +334,9 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init) | |||
337 | if (init) { | 334 | if (init) { |
338 | init_waitqueue_head(&buf->read_wait); | 335 | init_waitqueue_head(&buf->read_wait); |
339 | kref_init(&buf->kref); | 336 | kref_init(&buf->kref); |
340 | INIT_DELAYED_WORK(&buf->wake_readers, NULL); | 337 | setup_timer(&buf->timer, wakeup_readers, (unsigned long)buf); |
341 | } else { | 338 | } else |
342 | cancel_delayed_work(&buf->wake_readers); | 339 | del_timer_sync(&buf->timer); |
343 | flush_scheduled_work(); | ||
344 | } | ||
345 | 340 | ||
346 | buf->subbufs_produced = 0; | 341 | buf->subbufs_produced = 0; |
347 | buf->subbufs_consumed = 0; | 342 | buf->subbufs_consumed = 0; |
@@ -447,8 +442,7 @@ end: | |||
447 | static void relay_close_buf(struct rchan_buf *buf) | 442 | static void relay_close_buf(struct rchan_buf *buf) |
448 | { | 443 | { |
449 | buf->finalized = 1; | 444 | buf->finalized = 1; |
450 | cancel_delayed_work(&buf->wake_readers); | 445 | del_timer_sync(&buf->timer); |
451 | flush_scheduled_work(); | ||
452 | kref_put(&buf->kref, relay_remove_buf); | 446 | kref_put(&buf->kref, relay_remove_buf); |
453 | } | 447 | } |
454 | 448 | ||
@@ -608,11 +602,14 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) | |||
608 | buf->dentry->d_inode->i_size += buf->chan->subbuf_size - | 602 | buf->dentry->d_inode->i_size += buf->chan->subbuf_size - |
609 | buf->padding[old_subbuf]; | 603 | buf->padding[old_subbuf]; |
610 | smp_mb(); | 604 | smp_mb(); |
611 | if (waitqueue_active(&buf->read_wait)) { | 605 | if (waitqueue_active(&buf->read_wait)) |
612 | PREPARE_DELAYED_WORK(&buf->wake_readers, | 606 | /* |
613 | wakeup_readers); | 607 | * Calling wake_up_interruptible() from here |
614 | schedule_delayed_work(&buf->wake_readers, 1); | 608 | * will deadlock if we happen to be logging |
615 | } | 609 | * from the scheduler (trying to re-grab |
610 | * rq->lock), so defer it. | ||
611 | */ | ||
612 | __mod_timer(&buf->timer, jiffies + 1); | ||
616 | } | 613 | } |
617 | 614 | ||
618 | old = buf->data; | 615 | old = buf->data; |