diff options
Diffstat (limited to 'kernel/softirq.c')
| -rw-r--r-- | kernel/softirq.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c index ea23ec087ee9..d105a82543d0 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
| @@ -21,8 +21,10 @@ | |||
| 21 | #include <linux/freezer.h> | 21 | #include <linux/freezer.h> |
| 22 | #include <linux/kthread.h> | 22 | #include <linux/kthread.h> |
| 23 | #include <linux/rcupdate.h> | 23 | #include <linux/rcupdate.h> |
| 24 | #include <linux/ftrace.h> | ||
| 24 | #include <linux/smp.h> | 25 | #include <linux/smp.h> |
| 25 | #include <linux/tick.h> | 26 | #include <linux/tick.h> |
| 27 | #include <trace/irq.h> | ||
| 26 | 28 | ||
| 27 | #include <asm/irq.h> | 29 | #include <asm/irq.h> |
| 28 | /* | 30 | /* |
| @@ -52,6 +54,11 @@ static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp | |||
| 52 | 54 | ||
| 53 | static DEFINE_PER_CPU(struct task_struct *, ksoftirqd); | 55 | static DEFINE_PER_CPU(struct task_struct *, ksoftirqd); |
| 54 | 56 | ||
| 57 | char *softirq_to_name[NR_SOFTIRQS] = { | ||
| 58 | "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", | ||
| 59 | "TASKLET", "SCHED", "HRTIMER", "RCU" | ||
| 60 | }; | ||
| 61 | |||
| 55 | /* | 62 | /* |
| 56 | * we cannot loop indefinitely here to avoid userspace starvation, | 63 | * we cannot loop indefinitely here to avoid userspace starvation, |
| 57 | * but we also don't want to introduce a worst case 1/HZ latency | 64 | * but we also don't want to introduce a worst case 1/HZ latency |
| @@ -79,13 +86,23 @@ static void __local_bh_disable(unsigned long ip) | |||
| 79 | WARN_ON_ONCE(in_irq()); | 86 | WARN_ON_ONCE(in_irq()); |
| 80 | 87 | ||
| 81 | raw_local_irq_save(flags); | 88 | raw_local_irq_save(flags); |
| 82 | add_preempt_count(SOFTIRQ_OFFSET); | 89 | /* |
| 90 | * The preempt tracer hooks into add_preempt_count and will break | ||
| 91 | * lockdep because it calls back into lockdep after SOFTIRQ_OFFSET | ||
| 92 | * is set and before current->softirq_enabled is cleared. | ||
| 93 | * We must manually increment preempt_count here and manually | ||
| 94 | * call the trace_preempt_off later. | ||
| 95 | */ | ||
| 96 | preempt_count() += SOFTIRQ_OFFSET; | ||
| 83 | /* | 97 | /* |
| 84 | * Were softirqs turned off above: | 98 | * Were softirqs turned off above: |
| 85 | */ | 99 | */ |
| 86 | if (softirq_count() == SOFTIRQ_OFFSET) | 100 | if (softirq_count() == SOFTIRQ_OFFSET) |
| 87 | trace_softirqs_off(ip); | 101 | trace_softirqs_off(ip); |
| 88 | raw_local_irq_restore(flags); | 102 | raw_local_irq_restore(flags); |
| 103 | |||
| 104 | if (preempt_count() == SOFTIRQ_OFFSET) | ||
| 105 | trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1)); | ||
| 89 | } | 106 | } |
| 90 | #else /* !CONFIG_TRACE_IRQFLAGS */ | 107 | #else /* !CONFIG_TRACE_IRQFLAGS */ |
| 91 | static inline void __local_bh_disable(unsigned long ip) | 108 | static inline void __local_bh_disable(unsigned long ip) |
| @@ -169,6 +186,9 @@ EXPORT_SYMBOL(local_bh_enable_ip); | |||
| 169 | */ | 186 | */ |
| 170 | #define MAX_SOFTIRQ_RESTART 10 | 187 | #define MAX_SOFTIRQ_RESTART 10 |
| 171 | 188 | ||
| 189 | DEFINE_TRACE(softirq_entry); | ||
| 190 | DEFINE_TRACE(softirq_exit); | ||
| 191 | |||
| 172 | asmlinkage void __do_softirq(void) | 192 | asmlinkage void __do_softirq(void) |
| 173 | { | 193 | { |
| 174 | struct softirq_action *h; | 194 | struct softirq_action *h; |
| @@ -195,12 +215,14 @@ restart: | |||
| 195 | if (pending & 1) { | 215 | if (pending & 1) { |
| 196 | int prev_count = preempt_count(); | 216 | int prev_count = preempt_count(); |
| 197 | 217 | ||
| 218 | trace_softirq_entry(h, softirq_vec); | ||
| 198 | h->action(h); | 219 | h->action(h); |
| 199 | 220 | trace_softirq_exit(h, softirq_vec); | |
| 200 | if (unlikely(prev_count != preempt_count())) { | 221 | if (unlikely(prev_count != preempt_count())) { |
| 201 | printk(KERN_ERR "huh, entered softirq %td %p" | 222 | printk(KERN_ERR "huh, entered softirq %td %s %p" |
| 202 | "with preempt_count %08x," | 223 | "with preempt_count %08x," |
| 203 | " exited with %08x?\n", h - softirq_vec, | 224 | " exited with %08x?\n", h - softirq_vec, |
| 225 | softirq_to_name[h - softirq_vec], | ||
| 204 | h->action, prev_count, preempt_count()); | 226 | h->action, prev_count, preempt_count()); |
| 205 | preempt_count() = prev_count; | 227 | preempt_count() = prev_count; |
| 206 | } | 228 | } |
