relay: use plain timer instead of delayed work
PATCH 1/1 relay: use plain timer instead of delayed work
Patch updated to include changes suggested by Oleg Nesterov and Satyam Sharma.
---
relay doesn't need to use schedule_delayed_work() for waking readers when a simple timer will do.
Signed-off-by Tom Zanussi <[email protected]>
---
include/linux/relay.h | 3 ++- kernel/relay.c | 35 ++++++++++++++++------------------- 2 files changed, 18 insertions(+), 20 deletions(-)
include/linux/relay.h +2 -1
@@ -12,6 +12,7 @@#include <linux/types.h> #include <linux/sched.h> +#include <linux/timer.h> #include <linux/wait.h> #include <linux/list.h> #include <linux/fs.h>
@@ -38,7 +39,7 @@ struct rchan_bufsize_t subbufs_consumed;/* count of sub-buffers consumed */ struct rchan *chan;/* associated channel */ wait_queue_head_t read_wait;/* reader wait queue */ -struct delayed_work wake_readers;/* reader wake-up work struct */ +struct timer_list timer;/* reader wake-up timer */ struct dentry *dentry;/* channel file dentry */ struct kref kref;/* channel buffer refcount */ struct page **page_array;/* array of current buffer pages */
kernel/relay.c +16 -19
@@ -310,16 +310,13 @@ static struct rchan_callbacks default_channel_callbacks = {/** * wakeup_readers - wake up readers waiting on a channel -* @work: work struct that contains the the channel buffer +* @data: contains the the channel buffer * -* This is the work function used to defer reader waking. The -* reason waking is deferred is that calling directly from write -* causes problems if you're writing from say the scheduler. +* This is the timer function used to defer reader waking. */ -static void wakeup_readers (struct work_struct *work) +static void wakeup_readers (unsigned long data) { -struct rchan_buf *buf = - container_of(work, struct rchan_buf, wake_readers.work); +struct rchan_buf *buf = (struct rchan_buf *)data;wake_up_interruptible (&buf->read_wait); }
@@ -337,11 +334,9 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)if (init) {init_waitqueue_head (&buf->read_wait);kref_init (&buf->kref); -INIT_DELAYED_WORK (&buf->wake_readers,NULL ); - }else { -cancel_delayed_work (&buf->wake_readers); -flush_scheduled_work (); - } +setup_timer (&buf->timer, wakeup_readers, (unsigned long )buf); + }else +del_timer_sync (&buf->timer); buf->subbufs_produced =0 ; buf->subbufs_consumed =0 ;
@@ -447,8 +442,7 @@ end:static void relay_close_buf (struct rchan_buf *buf) { buf->finalized =1 ; -cancel_delayed_work (&buf->wake_readers); -flush_scheduled_work (); +del_timer_sync (&buf->timer);kref_put (&buf->kref, relay_remove_buf); }
@@ -608,11 +602,14 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) buf->dentry->d_inode->i_size += buf->chan->subbuf_size - buf->padding[old_subbuf];smp_mb (); -if (waitqueue_active (&buf->read_wait)) { -PREPARE_DELAYED_WORK (&buf->wake_readers, - wakeup_readers); -schedule_delayed_work (&buf->wake_readers,1 ); - } +if (waitqueue_active (&buf->read_wait)) +/* +* Calling wake_up_interruptible() from here +* will deadlock if we happen to be logging +* from the scheduler (trying to re-grab +* rq->lock), so defer it. +*/ +__mod_timer (&buf->timer, jiffies +1 ); } old = buf->data;