diff options
Diffstat (limited to 'kernel/softirq.c')
-rw-r--r-- | kernel/softirq.c | 141 |
1 files changed, 122 insertions, 19 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c index 8f03e3b89b55..215541e26c1a 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
@@ -62,6 +62,119 @@ static inline void wakeup_softirqd(void) | |||
62 | } | 62 | } |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * This one is for softirq.c-internal use, | ||
66 | * where hardirqs are disabled legitimately: | ||
67 | */ | ||
68 | static void __local_bh_disable(unsigned long ip) | ||
69 | { | ||
70 | unsigned long flags; | ||
71 | |||
72 | WARN_ON_ONCE(in_irq()); | ||
73 | |||
74 | raw_local_irq_save(flags); | ||
75 | add_preempt_count(SOFTIRQ_OFFSET); | ||
76 | /* | ||
77 | * Were softirqs turned off above: | ||
78 | */ | ||
79 | if (softirq_count() == SOFTIRQ_OFFSET) | ||
80 | trace_softirqs_off(ip); | ||
81 | raw_local_irq_restore(flags); | ||
82 | } | ||
83 | |||
84 | void local_bh_disable(void) | ||
85 | { | ||
86 | __local_bh_disable((unsigned long)__builtin_return_address(0)); | ||
87 | } | ||
88 | |||
89 | EXPORT_SYMBOL(local_bh_disable); | ||
90 | |||
91 | void __local_bh_enable(void) | ||
92 | { | ||
93 | WARN_ON_ONCE(in_irq()); | ||
94 | |||
95 | /* | ||
96 | * softirqs should never be enabled by __local_bh_enable(), | ||
97 | * it always nests inside local_bh_enable() sections: | ||
98 | */ | ||
99 | WARN_ON_ONCE(softirq_count() == SOFTIRQ_OFFSET); | ||
100 | |||
101 | sub_preempt_count(SOFTIRQ_OFFSET); | ||
102 | } | ||
103 | EXPORT_SYMBOL_GPL(__local_bh_enable); | ||
104 | |||
105 | /* | ||
106 | * Special-case - softirqs can safely be enabled in | ||
107 | * cond_resched_softirq(), or by __do_softirq(), | ||
108 | * without processing still-pending softirqs: | ||
109 | */ | ||
110 | void _local_bh_enable(void) | ||
111 | { | ||
112 | WARN_ON_ONCE(in_irq()); | ||
113 | WARN_ON_ONCE(!irqs_disabled()); | ||
114 | |||
115 | if (softirq_count() == SOFTIRQ_OFFSET) | ||
116 | trace_softirqs_on((unsigned long)__builtin_return_address(0)); | ||
117 | sub_preempt_count(SOFTIRQ_OFFSET); | ||
118 | } | ||
119 | |||
120 | EXPORT_SYMBOL(_local_bh_enable); | ||
121 | |||
122 | void local_bh_enable(void) | ||
123 | { | ||
124 | unsigned long flags; | ||
125 | |||
126 | WARN_ON_ONCE(in_irq()); | ||
127 | WARN_ON_ONCE(irqs_disabled()); | ||
128 | |||
129 | local_irq_save(flags); | ||
130 | /* | ||
131 | * Are softirqs going to be turned on now: | ||
132 | */ | ||
133 | if (softirq_count() == SOFTIRQ_OFFSET) | ||
134 | trace_softirqs_on((unsigned long)__builtin_return_address(0)); | ||
135 | /* | ||
136 | * Keep preemption disabled until we are done with | ||
137 | * softirq processing: | ||
138 | */ | ||
139 | sub_preempt_count(SOFTIRQ_OFFSET - 1); | ||
140 | |||
141 | if (unlikely(!in_interrupt() && local_softirq_pending())) | ||
142 | do_softirq(); | ||
143 | |||
144 | dec_preempt_count(); | ||
145 | local_irq_restore(flags); | ||
146 | preempt_check_resched(); | ||
147 | } | ||
148 | EXPORT_SYMBOL(local_bh_enable); | ||
149 | |||
150 | void local_bh_enable_ip(unsigned long ip) | ||
151 | { | ||
152 | unsigned long flags; | ||
153 | |||
154 | WARN_ON_ONCE(in_irq()); | ||
155 | |||
156 | local_irq_save(flags); | ||
157 | /* | ||
158 | * Are softirqs going to be turned on now: | ||
159 | */ | ||
160 | if (softirq_count() == SOFTIRQ_OFFSET) | ||
161 | trace_softirqs_on(ip); | ||
162 | /* | ||
163 | * Keep preemption disabled until we are done with | ||
164 | * softirq processing: | ||
165 | */ | ||
166 | sub_preempt_count(SOFTIRQ_OFFSET - 1); | ||
167 | |||
168 | if (unlikely(!in_interrupt() && local_softirq_pending())) | ||
169 | do_softirq(); | ||
170 | |||
171 | dec_preempt_count(); | ||
172 | local_irq_restore(flags); | ||
173 | preempt_check_resched(); | ||
174 | } | ||
175 | EXPORT_SYMBOL(local_bh_enable_ip); | ||
176 | |||
177 | /* | ||
65 | * We restart softirq processing MAX_SOFTIRQ_RESTART times, | 178 | * We restart softirq processing MAX_SOFTIRQ_RESTART times, |
66 | * and we fall back to softirqd after that. | 179 | * and we fall back to softirqd after that. |
67 | * | 180 | * |
@@ -80,8 +193,11 @@ asmlinkage void __do_softirq(void) | |||
80 | int cpu; | 193 | int cpu; |
81 | 194 | ||
82 | pending = local_softirq_pending(); | 195 | pending = local_softirq_pending(); |
196 | account_system_vtime(current); | ||
197 | |||
198 | __local_bh_disable((unsigned long)__builtin_return_address(0)); | ||
199 | trace_softirq_enter(); | ||
83 | 200 | ||
84 | local_bh_disable(); | ||
85 | cpu = smp_processor_id(); | 201 | cpu = smp_processor_id(); |
86 | restart: | 202 | restart: |
87 | /* Reset the pending bitmask before enabling irqs */ | 203 | /* Reset the pending bitmask before enabling irqs */ |
@@ -109,7 +225,10 @@ restart: | |||
109 | if (pending) | 225 | if (pending) |
110 | wakeup_softirqd(); | 226 | wakeup_softirqd(); |
111 | 227 | ||
112 | __local_bh_enable(); | 228 | trace_softirq_exit(); |
229 | |||
230 | account_system_vtime(current); | ||
231 | _local_bh_enable(); | ||
113 | } | 232 | } |
114 | 233 | ||
115 | #ifndef __ARCH_HAS_DO_SOFTIRQ | 234 | #ifndef __ARCH_HAS_DO_SOFTIRQ |
@@ -136,23 +255,6 @@ EXPORT_SYMBOL(do_softirq); | |||
136 | 255 | ||
137 | #endif | 256 | #endif |
138 | 257 | ||
139 | void local_bh_enable(void) | ||
140 | { | ||
141 | WARN_ON(irqs_disabled()); | ||
142 | /* | ||
143 | * Keep preemption disabled until we are done with | ||
144 | * softirq processing: | ||
145 | */ | ||
146 | sub_preempt_count(SOFTIRQ_OFFSET - 1); | ||
147 | |||
148 | if (unlikely(!in_interrupt() && local_softirq_pending())) | ||
149 | do_softirq(); | ||
150 | |||
151 | dec_preempt_count(); | ||
152 | preempt_check_resched(); | ||
153 | } | ||
154 | EXPORT_SYMBOL(local_bh_enable); | ||
155 | |||
156 | #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED | 258 | #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED |
157 | # define invoke_softirq() __do_softirq() | 259 | # define invoke_softirq() __do_softirq() |
158 | #else | 260 | #else |
@@ -165,6 +267,7 @@ EXPORT_SYMBOL(local_bh_enable); | |||
165 | void irq_exit(void) | 267 | void irq_exit(void) |
166 | { | 268 | { |
167 | account_system_vtime(current); | 269 | account_system_vtime(current); |
270 | trace_hardirq_exit(); | ||
168 | sub_preempt_count(IRQ_EXIT_OFFSET); | 271 | sub_preempt_count(IRQ_EXIT_OFFSET); |
169 | if (!in_interrupt() && local_softirq_pending()) | 272 | if (!in_interrupt() && local_softirq_pending()) |
170 | invoke_softirq(); | 273 | invoke_softirq(); |