diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-02-22 16:34:17 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-02-26 00:40:44 -0500 |
commit | 5d00837b90340af9106dcd93af75fd664c8eb87f (patch) | |
tree | f537dc84421cf150d66b630e56ea8107078c07a8 /net/sunrpc/sched.c | |
parent | fda1393938035559b417dd5b26b9cc293a7aee00 (diff) |
SUNRPC: Run rpc timeout functions as callbacks instead of in softirqs
An audit of the current RPC timeout functions shows that they don't really
ever need to run in the softirq context. As long as the softirq is
able to signal that the wakeup is due to a timeout (which it can do by
setting task->tk_status to -ETIMEDOUT) then the callback functions can just
run as standard task->tk_callback functions (in the rpciod/process
context).
The only possible border-line case would be xprt_timer() for the case of
UDP, when the callback is used to reduce the size of the transport
congestion window. In testing, however, the effect of moving that update
to a callback would appear to be minor.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/sched.c')
-rw-r--r-- | net/sunrpc/sched.c | 50 |
1 files changed, 15 insertions, 35 deletions
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 35acdc39bfcb..caf12fd6b6af 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -56,29 +56,18 @@ struct workqueue_struct *rpciod_workqueue; | |||
56 | * queue->lock and bh_disabled in order to avoid races within | 56 | * queue->lock and bh_disabled in order to avoid races within |
57 | * rpc_run_timer(). | 57 | * rpc_run_timer(). |
58 | */ | 58 | */ |
59 | static inline void | 59 | static void |
60 | __rpc_disable_timer(struct rpc_task *task) | 60 | __rpc_disable_timer(struct rpc_task *task) |
61 | { | 61 | { |
62 | dprintk("RPC: %5u disabling timer\n", task->tk_pid); | 62 | dprintk("RPC: %5u disabling timer\n", task->tk_pid); |
63 | task->tk_timeout_fn = NULL; | ||
64 | task->tk_timeout = 0; | 63 | task->tk_timeout = 0; |
65 | } | 64 | } |
66 | 65 | ||
67 | /* | 66 | /* |
68 | * Default timeout handler if none specified by user | ||
69 | */ | ||
70 | static void | ||
71 | __rpc_default_timer(struct rpc_task *task) | ||
72 | { | ||
73 | dprintk("RPC: %5u timeout (default timer)\n", task->tk_pid); | ||
74 | task->tk_status = -ETIMEDOUT; | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Set up a timer for the current task. | 67 | * Set up a timer for the current task. |
79 | */ | 68 | */ |
80 | static inline void | 69 | static void |
81 | __rpc_add_timer(struct rpc_task *task, rpc_action timer) | 70 | __rpc_add_timer(struct rpc_task *task) |
82 | { | 71 | { |
83 | if (!task->tk_timeout) | 72 | if (!task->tk_timeout) |
84 | return; | 73 | return; |
@@ -86,10 +75,6 @@ __rpc_add_timer(struct rpc_task *task, rpc_action timer) | |||
86 | dprintk("RPC: %5u setting alarm for %lu ms\n", | 75 | dprintk("RPC: %5u setting alarm for %lu ms\n", |
87 | task->tk_pid, task->tk_timeout * 1000 / HZ); | 76 | task->tk_pid, task->tk_timeout * 1000 / HZ); |
88 | 77 | ||
89 | if (timer) | ||
90 | task->tk_timeout_fn = timer; | ||
91 | else | ||
92 | task->tk_timeout_fn = __rpc_default_timer; | ||
93 | set_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate); | 78 | set_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate); |
94 | mod_timer(&task->tk_timer, jiffies + task->tk_timeout); | 79 | mod_timer(&task->tk_timer, jiffies + task->tk_timeout); |
95 | } | 80 | } |
@@ -297,7 +282,6 @@ EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); | |||
297 | */ | 282 | */ |
298 | static void rpc_make_runnable(struct rpc_task *task) | 283 | static void rpc_make_runnable(struct rpc_task *task) |
299 | { | 284 | { |
300 | BUG_ON(task->tk_timeout_fn); | ||
301 | rpc_clear_queued(task); | 285 | rpc_clear_queued(task); |
302 | if (rpc_test_and_set_running(task)) | 286 | if (rpc_test_and_set_running(task)) |
303 | return; | 287 | return; |
@@ -327,7 +311,7 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
327 | * as it's on a wait queue. | 311 | * as it's on a wait queue. |
328 | */ | 312 | */ |
329 | static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | 313 | static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, |
330 | rpc_action action, rpc_action timer) | 314 | rpc_action action) |
331 | { | 315 | { |
332 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", | 316 | dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", |
333 | task->tk_pid, rpc_qname(q), jiffies); | 317 | task->tk_pid, rpc_qname(q), jiffies); |
@@ -341,11 +325,11 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
341 | 325 | ||
342 | BUG_ON(task->tk_callback != NULL); | 326 | BUG_ON(task->tk_callback != NULL); |
343 | task->tk_callback = action; | 327 | task->tk_callback = action; |
344 | __rpc_add_timer(task, timer); | 328 | __rpc_add_timer(task); |
345 | } | 329 | } |
346 | 330 | ||
347 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | 331 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, |
348 | rpc_action action, rpc_action timer) | 332 | rpc_action action) |
349 | { | 333 | { |
350 | /* Mark the task as being activated if so needed */ | 334 | /* Mark the task as being activated if so needed */ |
351 | rpc_set_active(task); | 335 | rpc_set_active(task); |
@@ -354,7 +338,7 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
354 | * Protect the queue operations. | 338 | * Protect the queue operations. |
355 | */ | 339 | */ |
356 | spin_lock_bh(&q->lock); | 340 | spin_lock_bh(&q->lock); |
357 | __rpc_sleep_on(q, task, action, timer); | 341 | __rpc_sleep_on(q, task, action); |
358 | spin_unlock_bh(&q->lock); | 342 | spin_unlock_bh(&q->lock); |
359 | } | 343 | } |
360 | EXPORT_SYMBOL_GPL(rpc_sleep_on); | 344 | EXPORT_SYMBOL_GPL(rpc_sleep_on); |
@@ -559,20 +543,15 @@ EXPORT_SYMBOL_GPL(rpc_wake_up_status); | |||
559 | static void rpc_run_timer(unsigned long ptr) | 543 | static void rpc_run_timer(unsigned long ptr) |
560 | { | 544 | { |
561 | struct rpc_task *task = (struct rpc_task *)ptr; | 545 | struct rpc_task *task = (struct rpc_task *)ptr; |
562 | void (*callback)(struct rpc_task *); | 546 | struct rpc_wait_queue *queue = task->tk_waitqueue; |
563 | 547 | ||
564 | if (RPC_IS_QUEUED(task)) { | 548 | spin_lock(&queue->lock); |
565 | struct rpc_wait_queue *queue = task->tk_waitqueue; | 549 | if (RPC_IS_QUEUED(task) && task->tk_waitqueue == queue) { |
566 | callback = task->tk_timeout_fn; | 550 | dprintk("RPC: %5u timeout\n", task->tk_pid); |
567 | 551 | task->tk_status = -ETIMEDOUT; | |
568 | dprintk("RPC: %5u running timer\n", task->tk_pid); | ||
569 | if (callback != NULL) | ||
570 | callback(task); | ||
571 | /* Note: we're already in a bh-safe context */ | ||
572 | spin_lock(&queue->lock); | ||
573 | rpc_wake_up_task_queue_locked(queue, task); | 552 | rpc_wake_up_task_queue_locked(queue, task); |
574 | spin_unlock(&queue->lock); | ||
575 | } | 553 | } |
554 | spin_unlock(&queue->lock); | ||
576 | smp_mb__before_clear_bit(); | 555 | smp_mb__before_clear_bit(); |
577 | clear_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate); | 556 | clear_bit(RPC_TASK_HAS_TIMER, &task->tk_runstate); |
578 | smp_mb__after_clear_bit(); | 557 | smp_mb__after_clear_bit(); |
@@ -580,6 +559,7 @@ static void rpc_run_timer(unsigned long ptr) | |||
580 | 559 | ||
581 | static void __rpc_atrun(struct rpc_task *task) | 560 | static void __rpc_atrun(struct rpc_task *task) |
582 | { | 561 | { |
562 | task->tk_status = 0; | ||
583 | } | 563 | } |
584 | 564 | ||
585 | /* | 565 | /* |
@@ -588,7 +568,7 @@ static void __rpc_atrun(struct rpc_task *task) | |||
588 | void rpc_delay(struct rpc_task *task, unsigned long delay) | 568 | void rpc_delay(struct rpc_task *task, unsigned long delay) |
589 | { | 569 | { |
590 | task->tk_timeout = delay; | 570 | task->tk_timeout = delay; |
591 | rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun); | 571 | rpc_sleep_on(&delay_queue, task, __rpc_atrun); |
592 | } | 572 | } |
593 | EXPORT_SYMBOL_GPL(rpc_delay); | 573 | EXPORT_SYMBOL_GPL(rpc_delay); |
594 | 574 | ||