|
@@ -76,12 +76,22 @@ void wakeup_softirqd(void)
|
|
|
wake_up_process(tsk);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * preempt_count and SOFTIRQ_OFFSET usage:
|
|
|
+ * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
|
|
|
+ * softirq processing.
|
|
|
+ * - preempt_count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET)
|
|
|
+ * on local_bh_disable or local_bh_enable.
|
|
|
+ * This lets us distinguish between whether we are currently processing
|
|
|
+ * softirq and whether we just have bh disabled.
|
|
|
+ */
|
|
|
+
|
|
|
/*
|
|
|
* This one is for softirq.c-internal use,
|
|
|
* where hardirqs are disabled legitimately:
|
|
|
*/
|
|
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
|
|
-static void __local_bh_disable(unsigned long ip)
|
|
|
+static void __local_bh_disable(unsigned long ip, unsigned int cnt)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
|
|
@@ -95,32 +105,43 @@ static void __local_bh_disable(unsigned long ip)
|
|
|
* We must manually increment preempt_count here and manually
|
|
|
* call the trace_preempt_off later.
|
|
|
*/
|
|
|
- preempt_count() += SOFTIRQ_OFFSET;
|
|
|
+ preempt_count() += cnt;
|
|
|
/*
|
|
|
* Were softirqs turned off above:
|
|
|
*/
|
|
|
- if (softirq_count() == SOFTIRQ_OFFSET)
|
|
|
+ if (softirq_count() == cnt)
|
|
|
trace_softirqs_off(ip);
|
|
|
raw_local_irq_restore(flags);
|
|
|
|
|
|
- if (preempt_count() == SOFTIRQ_OFFSET)
|
|
|
+ if (preempt_count() == cnt)
|
|
|
trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1));
|
|
|
}
|
|
|
#else /* !CONFIG_TRACE_IRQFLAGS */
|
|
|
-static inline void __local_bh_disable(unsigned long ip)
|
|
|
+static inline void __local_bh_disable(unsigned long ip, unsigned int cnt)
|
|
|
{
|
|
|
- add_preempt_count(SOFTIRQ_OFFSET);
|
|
|
+ add_preempt_count(cnt);
|
|
|
barrier();
|
|
|
}
|
|
|
#endif /* CONFIG_TRACE_IRQFLAGS */
|
|
|
|
|
|
void local_bh_disable(void)
|
|
|
{
|
|
|
- __local_bh_disable((unsigned long)__builtin_return_address(0));
|
|
|
+ __local_bh_disable((unsigned long)__builtin_return_address(0),
|
|
|
+ SOFTIRQ_DISABLE_OFFSET);
|
|
|
}
|
|
|
|
|
|
EXPORT_SYMBOL(local_bh_disable);
|
|
|
|
|
|
+static void __local_bh_enable(unsigned int cnt)
|
|
|
+{
|
|
|
+ WARN_ON_ONCE(in_irq());
|
|
|
+ WARN_ON_ONCE(!irqs_disabled());
|
|
|
+
|
|
|
+ if (softirq_count() == cnt)
|
|
|
+ trace_softirqs_on((unsigned long)__builtin_return_address(0));
|
|
|
+ sub_preempt_count(cnt);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Special-case - softirqs can safely be enabled in
|
|
|
* cond_resched_softirq(), or by __do_softirq(),
|
|
@@ -128,12 +149,7 @@ EXPORT_SYMBOL(local_bh_disable);
|
|
|
*/
|
|
|
void _local_bh_enable(void)
|
|
|
{
|
|
|
- WARN_ON_ONCE(in_irq());
|
|
|
- WARN_ON_ONCE(!irqs_disabled());
|
|
|
-
|
|
|
- if (softirq_count() == SOFTIRQ_OFFSET)
|
|
|
- trace_softirqs_on((unsigned long)__builtin_return_address(0));
|
|
|
- sub_preempt_count(SOFTIRQ_OFFSET);
|
|
|
+ __local_bh_enable(SOFTIRQ_DISABLE_OFFSET);
|
|
|
}
|
|
|
|
|
|
EXPORT_SYMBOL(_local_bh_enable);
|
|
@@ -147,13 +163,13 @@ static inline void _local_bh_enable_ip(unsigned long ip)
|
|
|
/*
|
|
|
* Are softirqs going to be turned on now:
|
|
|
*/
|
|
|
- if (softirq_count() == SOFTIRQ_OFFSET)
|
|
|
+ if (softirq_count() == SOFTIRQ_DISABLE_OFFSET)
|
|
|
trace_softirqs_on(ip);
|
|
|
/*
|
|
|
* Keep preemption disabled until we are done with
|
|
|
* softirq processing:
|
|
|
*/
|
|
|
- sub_preempt_count(SOFTIRQ_OFFSET - 1);
|
|
|
+ sub_preempt_count(SOFTIRQ_DISABLE_OFFSET - 1);
|
|
|
|
|
|
if (unlikely(!in_interrupt() && local_softirq_pending()))
|
|
|
do_softirq();
|
|
@@ -198,7 +214,8 @@ asmlinkage void __do_softirq(void)
|
|
|
pending = local_softirq_pending();
|
|
|
account_system_vtime(current);
|
|
|
|
|
|
- __local_bh_disable((unsigned long)__builtin_return_address(0));
|
|
|
+ __local_bh_disable((unsigned long)__builtin_return_address(0),
|
|
|
+ SOFTIRQ_OFFSET);
|
|
|
lockdep_softirq_enter();
|
|
|
|
|
|
cpu = smp_processor_id();
|
|
@@ -245,7 +262,7 @@ restart:
|
|
|
lockdep_softirq_exit();
|
|
|
|
|
|
account_system_vtime(current);
|
|
|
- _local_bh_enable();
|
|
|
+ __local_bh_enable(SOFTIRQ_OFFSET);
|
|
|
}
|
|
|
|
|
|
#ifndef __ARCH_HAS_DO_SOFTIRQ
|