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(); |
