]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: convert FBT blacklist to RB-tree
authorKris Van Hees <kris.van.hees@oracle.com>
Mon, 12 Jun 2017 13:29:16 +0000 (09:29 -0400)
committerKris Van Hees <kris.van.hees@oracle.com>
Mon, 26 Jun 2017 22:18:55 +0000 (18:18 -0400)
The blacklist for FBT was implemented as a sorted list, populated from
a static list of functions.  In order to allow functions to be added
from other places (i.e. programmatically), it has been converted to an
RB-tree with an API to add functions and to traverse the list.  It is
still possible to add functions by address or to add them by symbol
name, to be resolved into the corresponding address.

Orabug: 26190412
Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com>
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Acked-by: Nick Alcock <nick.alcock@oracle.com>
arch/sparc/kernel/dtrace_fbt.c
arch/x86/kernel/dtrace_fbt.c
arch/x86/kernel/fbt_blacklist.h
include/linux/dtrace_fbt.h
kernel/dtrace/Makefile
kernel/dtrace/dtrace_fbt_core.c [new file with mode: 0644]

index 2178e7736f7f39ff5b89a02ad59bbaac3b1eed67..e1c07b24b189332c809bd4896c747f704cb67417 100644 (file)
 #undef BL_DENTRY
 #undef BL_SENTRY
 
-typedef struct _bl_entry {
-       void *addr;
-       const char *name;
-} bl_entry;
-
-static bl_entry blacklist[] = {
-#define BL_SENTRY(tp, nm)      { (void *)&nm, __stringify(nm) },
-#define BL_DENTRY(tp, nm)      { NULL, __stringify(nm) },
+static void
+dtrace_fbt_populate_bl(void)
+{
+#define BL_SENTRY(tp, nm)      dtrace_fbt_bl_add((unsigned long)&nm, __stringify(nm));
+#define BL_DENTRY(tp, nm)      dtrace_fbt_bl_add(0, __stringify(nm));
 #include "fbt_blacklist.h"
 #undef BL_DENTRY
 #undef BL_SENTRY
 };
-static int     blacklist_len = ARRAY_SIZE(blacklist);
-
-static int bl_entry_cmp(const void *xx, const void *yy)
-{
-       bl_entry        *x = (bl_entry *)xx;
-       bl_entry        *y = (bl_entry *)yy;
-
-       return x->addr > y->addr ? 1
-                                : x->addr < y->addr ? -1 : 0;
-}
 
 void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe)
 {
@@ -159,18 +146,14 @@ void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe)
        struct kallsym_iter     sym;
        size_t                  blpos = 0;
        asm_instr_t             *paddr = NULL;
+       dt_fbt_bl_entry_t       *blent = NULL;
 
        /*
         * Look up any unresolved symbols in the blacklist, and sort the list
         * by ascending address.
         */
-       for (pos = 0; pos < blacklist_len; pos++) {
-               bl_entry        *be = &blacklist[pos];
-
-               if (!be->addr)
-                       be->addr = (void *)kallsyms_lookup_name(be->name);
-       }
-       sort(blacklist, blacklist_len, sizeof(bl_entry), bl_entry_cmp, NULL);
+       dtrace_fbt_populate_bl();
+       blent = dtrace_fbt_bl_first();
 
        pos = 0;
        kallsyms_iter_reset(&sym, 0);
@@ -201,15 +184,15 @@ void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe)
                        continue;
 
                /*
-                * See if the symbol is on the blacklist.  Since both lists are
-                * sorted by ascending address we can use concurrent traversal
-                * of both lists.
+                * See if the symbol is on the FBT's blacklist.  Since both
+                * iterators are workng in sort order by ascending address we
+                * can use concurrent traversal.
                 */
-               while (blpos < blacklist_len &&
-                      blacklist[blpos].addr < (void *)sym.value)
-                       blpos++;
-
-               if (blacklist[blpos].addr == (void *)sym.value)
+               while (blent != NULL &&
+                      dtrace_fbt_bl_entry_addr(blent) < sym.value) {
+                       blent = dtrace_fbt_bl_next(blent);
+               }
+               if (dtrace_fbt_bl_entry_addr(blent) == sym.value)
                        continue;
 
                /*
index 97ee749665c8a2e116d0402b0132704e14b173d4..6786a7dbcac0d7a2ff722b51772c198e5996470b 100644 (file)
 #undef BL_DENTRY
 #undef BL_SENTRY
 
-typedef struct _bl_entry {
-       void *addr;
-       const char *name;
-} bl_entry;
-
-static bl_entry        blacklist[] = {
-#define BL_SENTRY(tp, nm)      { (void *)&nm, __stringify(nm) },
-#define BL_DENTRY(tp, nm)      { NULL, __stringify(nm) },
+static void
+dtrace_fbt_populate_bl(void)
+{
+#define        BL_SENTRY(tp, nm)       dtrace_fbt_bl_add((unsigned long)&nm, __stringify(nm));
+#define BL_DENTRY(tp, nm)      dtrace_fbt_bl_add(0, __stringify(nm));
 #include "fbt_blacklist.h"
-#undef BL_DENTRY
 #undef BL_SENTRY
-};
-static int     blacklist_len = ARRAY_SIZE(blacklist);
-
-static int bl_entry_cmp(const void *xx, const void *yy)
-{
-       bl_entry        *x = (bl_entry *)xx;
-       bl_entry        *y = (bl_entry *)yy;
-
-       if (x->addr > y->addr)
-               return 1;
-       else if (x->addr < y->addr)
-               return -1;
-       else
-               return 0;
+#undef BL_DENTRY
 }
 
 void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe)
 {
        loff_t                  pos;
        struct kallsym_iter     sym;
-       size_t                  blpos = 0;
        asm_instr_t             *paddr = NULL;
+       dt_fbt_bl_entry_t       *blent = NULL;
 
        /*
         * Look up any unresolved symbols in the blacklist, and sort the list
         * by ascending address.
         */
-       for (pos = 0; pos < blacklist_len; pos++) {
-               bl_entry        *be = &blacklist[pos];
-
-               if (!be->addr)
-                       be->addr = (void *)kallsyms_lookup_name(be->name);
-       }
-       sort(blacklist, blacklist_len, sizeof(bl_entry), bl_entry_cmp, NULL);
+       dtrace_fbt_populate_bl();
+       blent = dtrace_fbt_bl_first();
 
        pos = 0;
        kallsyms_iter_reset(&sym, 0);
@@ -99,15 +77,18 @@ void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe)
                if (!core_kernel_text(sym.value))
                        continue;
 
+               /* TODO: Jumplabel blacklist ? */
+
                /*
-                * See if the symbol is on the blacklist.  Since both lists are
-                * sorted by ascending address we can use concurrent traversal
-                * of both lists.
+                * See if the symbol is on the FBT's blacklist.  Since both
+                * iterators are workng in sort order by ascending address we
+                * can use concurrent traversal.
                 */
-               while (blpos < blacklist_len &&
-                      blacklist[blpos].addr < (void *)sym.value)
-                       blpos++;
-               if (blacklist[blpos].addr == (void *)sym.value)
+               while (blent != NULL &&
+                      dtrace_fbt_bl_entry_addr(blent) < sym.value) {
+                       blent = dtrace_fbt_bl_next(blent);
+               }
+               if (dtrace_fbt_bl_entry_addr(blent) == sym.value)
                        continue;
 
                /*
index 3294cd428a45c302458751a8a5fda577e3b064b3..41b7244199cb854c04a8ef4fc77e6ece5e51cadf 100644 (file)
@@ -1,16 +1,61 @@
+/*
+ * Functions used in die notifier chain calling.
+ */
+BL_SENTRY(void *, notify_die)
 BL_DENTRY(void *, notifier_call_chain)
 BL_SENTRY(typeof(__atomic_notifier_call_chain), __atomic_notifier_call_chain)
 BL_SENTRY(typeof(atomic_notifier_call_chain), atomic_notifier_call_chain)
 BL_SENTRY(typeof(__raw_notifier_call_chain), __raw_notifier_call_chain)
 BL_SENTRY(typeof(raw_notifier_call_chain), raw_notifier_call_chain)
-BL_SENTRY(typeof(idr_find_slowpath), idr_find_slowpath)
 BL_DENTRY(void *, hw_breakpoint_exceptions_notify)
 BL_DENTRY(void *, kprobe_exceptions_notify)
-BL_SENTRY(void *, notify_die)
-BL_DENTRY(void *, pvclock_clocksource_read)
+
+BL_SENTRY(typeof(idr_find_slowpath), idr_find_slowpath)
+
+/*
+ * Functions used to update vtime in probe context.
+ */
 BL_SENTRY(typeof(ktime_get_raw_fast_ns), ktime_get_raw_fast_ns)
+/* xen_clocksource */
+BL_DENTRY(void *, xen_clocksource_get_cycles)
+BL_DENTRY(void *, xen_clocksource_read)
+BL_DENTRY(void *, pvclock_clocksource_read)
+BL_DENTRY(void *, pvclock_touch_watchdogs)
+BL_DENTRY(void *, touch_softlockup_watchdog_sync)
+BL_DENTRY(void *, clocksource_touch_watchdog)
+BL_DENTRY(void *, clocksource_resume_watchdog)
+BL_DENTRY(void *, reset_hung_task_detector)
+/* clocksource_tsc */
+BL_DENTRY(void *, read_tsc)
+BL_DENTRY(void *, get_cycles)
+/* clocksource_hpet */
+BL_DENTRY(void *, read_hpet)
+BL_DENTRY(void *, hpet_readl)
+/* kvm_clock */
+BL_DENTRY(void *, kvm_clock_get_cycles)
+BL_DENTRY(void *, kvm_clock_read)
+
+/*
+ * Functions used in trap handling.
+ */
 BL_DENTRY(void *, fixup_exception)
+BL_DENTRY(void *, paranoid_entry)
+BL_DENTRY(void *, kgdb_ll_trap)
+BL_DENTRY(void *, error_entry)
+BL_DENTRY(void *, xen_int3)
+BL_DENTRY(void *, ftrace_int3_handler)
+BL_SENTRY(typeof(poke_int3_handler), poke_int3_handler)
+BL_DENTRY(void *, fixup_bad_iret)
+BL_DENTRY(void *, xen_adjust_exception_frame)
+BL_DENTRY(void *, paravirt_nop)
+BL_DENTRY(void *, ist_enter)
+BL_DENTRY(void *, rcu_nmi_enter)
+BL_DENTRY(void *, rcu_nmi_exit)
+BL_DENTRY(void *, ist_exit)
 
+/*
+ * Functions used in page fault handling.
+ */
 BL_SENTRY(void *, do_page_fault)
 BL_DENTRY(void *, __do_page_fault)
 BL_DENTRY(void *, down_read_trylock)
index a7789eb84ec090ba5105915c1385f5053ffc635f..75c1e8745f2c687fd625e974f5e0643c0545a54f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015 Oracle, Inc. */
+/* Copyright (C) 2015, 2017, Oracle and/or its affiliates. All rights reserved. */
 
 #ifndef _LINUX_DTRACE_FBT_H
 #define _LINUX_DTRACE_FBT_H
@@ -29,4 +29,15 @@ typedef void *(*fbt_add_probe_fn)(struct module *, char *, int, int,
                                  asm_instr_t *, uintptr_t, void *);
 extern void dtrace_fbt_init(fbt_add_probe_fn);
 
+/*
+ * Dynamic blacklist routines.
+ */
+typedef struct dt_fbt_bl_entry dt_fbt_bl_entry_t;
+
+extern dt_fbt_bl_entry_t *dtrace_fbt_bl_add(unsigned long, const char *);
+extern dt_fbt_bl_entry_t *dtrace_fbt_bl_first(void);
+extern dt_fbt_bl_entry_t *dtrace_fbt_bl_next(dt_fbt_bl_entry_t *);
+extern unsigned long dtrace_fbt_bl_entry_addr(dt_fbt_bl_entry_t *);
+extern const char *dtrace_fbt_bl_entry_name(dt_fbt_bl_entry_t *);
+
 #endif /* _LINUX_DTRACE_FBT_H */
index e0d84ccf91ef88035ab69f385bdf8f2c95168a33..066bbace957238a4dc64a004aa3f08b2db61d675 100644 (file)
@@ -10,6 +10,6 @@ DT_CORE_ARCH_OBJS             = $(addprefix ../../arch/$(SRCARCH)/kernel/, \
 
 ifdef CONFIG_DT_CORE
 obj-y                          += cyclic.o dtrace_os.o dtrace_cpu.o \
-                                  dtrace_sdt_core.o \
+                                  dtrace_sdt_core.o dtrace_fbt_core.o \
                                   $(DT_CORE_ARCH_OBJS)
 endif
diff --git a/kernel/dtrace/dtrace_fbt_core.c b/kernel/dtrace/dtrace_fbt_core.c
new file mode 100644 (file)
index 0000000..3b2ca44
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * FILE:        dtrace_fbt_core.c
+ * DESCRIPTION: Dynamic Tracing: FBT common code
+ *
+ * Copyright (C) 2017, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kallsyms.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+#include <linux/dtrace_fbt.h>
+
+struct dt_fbt_bl_entry {
+       struct rb_node          dfbe_node;
+       unsigned long           dfbe_addr;
+       const char              *dfbe_name;
+};
+
+static struct rb_root dt_fbt_root = RB_ROOT;
+
+dt_fbt_bl_entry_t *
+dtrace_fbt_bl_add(unsigned long addr, const char *name)
+{
+       struct rb_node **p = &dt_fbt_root.rb_node;
+       struct rb_node *parent = NULL;
+       struct dt_fbt_bl_entry *entry;
+
+       /*
+        * If no address was given, we need to do a symbol name lookup:
+        *  - If no symbol name was given, we cannot add anything.
+        *  - If the lookup failed, we cannot add anything.
+        */
+       if (addr == 0) {
+               if (name == NULL)
+                       return NULL;
+
+               addr = kallsyms_lookup_name(name);
+
+               if (addr == 0)
+                       return NULL;
+       }
+
+       /* Find place in the tree. */
+       while (*p) {
+               parent = *p;
+               entry = rb_entry(parent, dt_fbt_bl_entry_t, dfbe_node);
+
+               if (addr > entry->dfbe_addr)
+                       p = &parent->rb_right;
+               else if (addr < entry->dfbe_addr)
+                       p = &parent->rb_left;
+               else
+                       return NULL;            /* no duplicates please */
+       }
+
+       /* Create a new blacklist entry. */
+       if ((entry = kmalloc(sizeof(*entry), GFP_KERNEL)) == NULL)
+               return NULL;
+
+       entry->dfbe_name = name;
+       entry->dfbe_addr = addr;
+
+       /* Update the tree. */
+       rb_link_node(&entry->dfbe_node, parent, p);
+       rb_insert_color(&entry->dfbe_node, &dt_fbt_root);
+
+       return entry;
+}
+
+/*
+ * Iterators for blacklisted symbols. The iteration happens in sort order by
+ * virtual memory address. Symbols with pending resolution are inored.
+ */
+dt_fbt_bl_entry_t *
+dtrace_fbt_bl_first(void)
+{
+       struct rb_node *node = rb_first(&dt_fbt_root);
+
+       if (node == NULL)
+               return (NULL);
+
+       return (rb_entry(node, dt_fbt_bl_entry_t, dfbe_node));
+}
+
+dt_fbt_bl_entry_t *
+dtrace_fbt_bl_next(dt_fbt_bl_entry_t *entry)
+{
+       struct rb_node *node = rb_next(&entry->dfbe_node);
+
+       if (node == NULL)
+               return (NULL);
+
+       return (rb_entry(node, dt_fbt_bl_entry_t, dfbe_node));
+}
+
+unsigned long
+dtrace_fbt_bl_entry_addr(dt_fbt_bl_entry_t *entry)
+{
+       if (entry == NULL)
+               return (0);
+
+       return (entry->dfbe_addr);
+}
+
+const char *
+dtrace_fbt_bl_entry_name(dt_fbt_bl_entry_t *entry)
+{
+       if (entry == NULL)
+               return (NULL);
+
+       return (entry->dfbe_name);
+}