aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVegard Nossum <vegard.nossum@gmail.com>2008-05-21 16:53:13 -0400
committerVegard Nossum <vegard.nossum@gmail.com>2009-06-13 04:02:24 -0400
commit7c692cbade8b8884f1c20500393bcc7cd6d24ef8 (patch)
tree2cf4353c684304dfdefb89e0a70bfbd7eeadf85b
parent8eae985f08138758e06503588f5f1196269bc415 (diff)
tasklets: new tasklet scheduling function
Rationale: kmemcheck needs to be able to schedule a tasklet without touching any dynamically allocated memory _at_ _all_ (since that would lead to a recursive page fault). This tasklet is used for writing the error reports to the kernel log. The new scheduling function avoids touching any other tasklets by inserting the new tasklist as the head of the "tasklet_hi" list instead of on the tail. Also don't wake up the softirq thread lest the scheduler access some tracked memory and we go down with a recursive page fault. In this case, we'd better just wait for the maximum time of 1/HZ for the message to appear. Signed-off-by: Vegard Nossum <vegard.nossum@gmail.com>
-rw-r--r--include/linux/interrupt.h14
-rw-r--r--kernel/softirq.c11
2 files changed, 25 insertions, 0 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index ff374ceface0..dd574d51bcaa 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -466,6 +466,20 @@ static inline void tasklet_hi_schedule(struct tasklet_struct *t)
466 __tasklet_hi_schedule(t); 466 __tasklet_hi_schedule(t);
467} 467}
468 468
469extern void __tasklet_hi_schedule_first(struct tasklet_struct *t);
470
471/*
472 * This version avoids touching any other tasklets. Needed for kmemcheck
473 * in order not to take any page faults while enqueueing this tasklet;
474 * consider VERY carefully whether you really need this or
475 * tasklet_hi_schedule()...
476 */
477static inline void tasklet_hi_schedule_first(struct tasklet_struct *t)
478{
479 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
480 __tasklet_hi_schedule_first(t);
481}
482
469 483
470static inline void tasklet_disable_nosync(struct tasklet_struct *t) 484static inline void tasklet_disable_nosync(struct tasklet_struct *t)
471{ 485{
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 258885a543db..b41fb710e114 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -382,6 +382,17 @@ void __tasklet_hi_schedule(struct tasklet_struct *t)
382 382
383EXPORT_SYMBOL(__tasklet_hi_schedule); 383EXPORT_SYMBOL(__tasklet_hi_schedule);
384 384
385void __tasklet_hi_schedule_first(struct tasklet_struct *t)
386{
387 BUG_ON(!irqs_disabled());
388
389 t->next = __get_cpu_var(tasklet_hi_vec).head;
390 __get_cpu_var(tasklet_hi_vec).head = t;
391 __raise_softirq_irqoff(HI_SOFTIRQ);
392}
393
394EXPORT_SYMBOL(__tasklet_hi_schedule_first);
395
385static void tasklet_action(struct softirq_action *a) 396static void tasklet_action(struct softirq_action *a)
386{ 397{
387 struct tasklet_struct *list; 398 struct tasklet_struct *list;