lkml.org 
[lkml]   [2020]   [Feb]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH v2 3/9] rcu,tracing: Create trace_rcu_{enter,exit}()
    To facilitate tracers that need RCU, add some helpers to wrap the
    magic required.

    The problem is that we can call into tracers (trace events and
    function tracing) while RCU isn't watching and this can happen from
    any context, including NMI.

    It is this latter that is causing most of the trouble; we must make
    sure in_nmi() returns true before we land in anything tracing,
    otherwise we cannot recover.

    These helpers are macros because of header-hell; they're placed here
    because of the proximity to nmi_{enter,exit{().

    Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
    ---
    include/linux/hardirq.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
    1 file changed, 48 insertions(+)

    --- a/include/linux/hardirq.h
    +++ b/include/linux/hardirq.h
    @@ -89,4 +89,52 @@ extern void irq_exit(void);
    arch_nmi_exit(); \
    } while (0)

    +/*
    + * Tracing vs RCU
    + * --------------
    + *
    + * tracepoints and function-tracing can happen when RCU isn't watching (idle,
    + * or early IRQ/NMI entry).
    + *
    + * When it happens during idle or early during IRQ entry, tracing will have
    + * to inform RCU that it ought to pay attention, this is done by calling
    + * rcu_irq_enter_irqsave().
    + *
    + * On NMI entry, we must be very careful that tracing only happens after we've
    + * incremented preempt_count(), otherwise we cannot tell we're in NMI and take
    + * the special path.
    + */
    +
    +#define __TR_IRQ 1
    +#define __TR_NMI 2
    +
    +#define trace_rcu_enter() \
    +({ \
    + unsigned long state = 0; \
    + if (!rcu_is_watching()) { \
    + if (in_nmi()) { \
    + state = __TR_NMI; \
    + rcu_nmi_enter(); \
    + } else { \
    + state = __TR_IRQ; \
    + rcu_irq_enter_irqsave(); \
    + } \
    + } \
    + state; \
    +})
    +
    +#define trace_rcu_exit(state) \
    +do { \
    + switch (state) { \
    + case __TR_IRQ: \
    + rcu_irq_exit_irqsave(); \
    + break; \
    + case __TR_NMI: \
    + rcu_nmi_exit(); \
    + break; \
    + default: \
    + break; \
    + } \
    +} while (0)
    +
    #endif /* LINUX_HARDIRQ_H */

    \
     
     \ /
      Last update: 2020-02-12 22:14    [W:4.132 / U:0.120 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site