]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: FBT return probes on x86_64 run with in_irq() true
authorKris Van Hees <kris.van.hees@oracle.com>
Mon, 22 May 2017 15:16:45 +0000 (11:16 -0400)
committerKris Van Hees <kris.van.hees@oracle.com>
Tue, 23 May 2017 14:22:23 +0000 (10:22 -0400)
Because FBT return probes are imeplemented on x86_64 by means of a
breakpoint trap (int3), and because int3 (on Linux) causes HARDIRQ
to be incremented in the preempt counter, the DTrace core thinks
that the probe was triggered from IRQ context (which it may or may
not be).

This commit ensures that we can detect wether we're processing a
probe triggered using int3, and if so, it subtracts from the HARDIRQ
counter before testing it (to compensate for the int3-imposed
increment).

Orabug: 26089286
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Reviewed-by: Tomas Jedlicka <tomas.jedlicka@oracle.com>
dtrace/dtrace_dif.c
dtrace/fbt_x86_64.c

index 974d18284935d4bfcedf5edd6cb72b195c40c2e8..62a66c155f657b6c57d23e954bd828bee4a15454 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/vmalloc.h>
 #include <net/ipv6.h>
 #include <asm/byteorder.h>
+#include <asm/traps.h>
 
 #include <linux/mount.h>
 
@@ -1094,9 +1095,18 @@ void dtrace_difo_release(dtrace_difo_t *dp, dtrace_vstate_t *vstate)
  * no way for a global variable key signature to match a thread-local key
  * signature.
  */
+#ifdef CONFIG_X86_64
+# define DTRACE_IN_IRQ()                                               \
+       ((this_cpu_core->cpu_dtrace_regs &&                             \
+         this_cpu_core->cpu_dtrace_regs->orig_ax == X86_TRAP_BP)       \
+               ? (hardirq_count() - HARDIRQ_OFFSET)                    \
+               : in_irq())
+#else
+# define DTRACE_IN_IRQ()       in_irq()
+#endif
 #define DTRACE_TLS_THRKEY(where)                                       \
        {                                                               \
-               uint_t  intr = in_irq() ? 1 : 0;                        \
+               uint_t  intr = DTRACE_IN_IRQ() ? 1 : 0;                 \
                                                                        \
                (where) = ((current->pid + DIF_VARIABLE_MAX) &          \
                           (((uint64_t)1 << 63) - 1)) |                 \
index 7853963c91f699ee21cc3f71539be3f5c5a8c227..7b5611959fa583006a7b2c775fcc16cdefe7da1a 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <linux/dtrace_fbt.h>
+#include <asm/traps.h>
 #include <asm/dtrace_util.h>
 
 #include "dtrace.h"
@@ -41,15 +42,32 @@ static uint8_t fbt_invop(struct pt_regs *regs)
 
        for (; fbp != NULL; fbp = fbp->fbp_hashnext) {
                if ((uintptr_t)fbp->fbp_patchpoint == regs->ip) {
+                       unsigned long   orig_ax;
+
+                       /*
+                        * We (ab)use regs->orig_ax to store the trapno since
+                        * int3 (used for return probes) causes HARDIRQ to be
+                        * incremented in the preempt_count, which messes with
+                        * the TLS thread key calculation.
+                        *
+                        * This is not pretty, but neither is the fact that
+                        * int3 cause handlers to think they are called from
+                        * within an interrupt.
+                        */
                        this_cpu_core->cpu_dtrace_regs = regs;
+                       orig_ax = regs->orig_ax;
+
                        if (fbp->fbp_roffset == 0) {
+                               regs->orig_ax = X86_TRAP_UD;
                                dtrace_probe(fbp->fbp_id, regs->di, regs->si,
                                             regs->dx, regs->cx, regs->r8);
                        } else {
+                               regs->orig_ax = X86_TRAP_BP;
                                dtrace_probe(fbp->fbp_id, fbp->fbp_roffset,
                                             regs->ax, 0, 0, 0);
                        }
 
+                       regs->orig_ax = orig_ax;
                        this_cpu_core->cpu_dtrace_regs = NULL;
 
                        return fbp->fbp_rval;