ALSA: usb-audio: add support for Akai MPD16
[safe/jmp/linux-2.6] / kernel / tracepoint.c
index 94ac4e3..cc89be5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/tracepoint.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 
 extern struct tracepoint __start___tracepoints[];
 extern struct tracepoint __stop___tracepoints[];
@@ -47,7 +48,7 @@ static struct hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
 
 /*
  * Note about RCU :
- * It is used to to delay the free of multiple probes array until a quiescent
+ * It is used to delay the free of multiple probes array until a quiescent
  * state is reached.
  * Tracepoint entries modifications are protected by the tracepoints_mutex.
  */
@@ -242,6 +243,11 @@ static void set_tracepoint(struct tracepoint_entry **entry,
 {
        WARN_ON(strcmp((*entry)->name, elem->name) != 0);
 
+       if (elem->regfunc && !elem->state && active)
+               elem->regfunc();
+       else if (elem->unregfunc && elem->state && !active)
+               elem->unregfunc();
+
        /*
         * rcu_assign_pointer has a smp_wmb() which makes sure that the new
         * probe callbacks array is consistent before setting a pointer to it.
@@ -261,6 +267,9 @@ static void set_tracepoint(struct tracepoint_entry **entry,
  */
 static void disable_tracepoint(struct tracepoint *elem)
 {
+       if (elem->unregfunc && elem->state)
+               elem->unregfunc();
+
        elem->state = 0;
        rcu_assign_pointer(elem->funcs, NULL);
 }
@@ -272,12 +281,15 @@ static void disable_tracepoint(struct tracepoint *elem)
  *
  * Updates the probe callback corresponding to a range of tracepoints.
  */
-void tracepoint_update_probe_range(struct tracepoint *begin,
-       struct tracepoint *end)
+void
+tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end)
 {
        struct tracepoint *iter;
        struct tracepoint_entry *mark_entry;
 
+       if (!begin)
+               return;
+
        mutex_lock(&tracepoints_mutex);
        for (iter = begin; iter < end; iter++) {
                mark_entry = get_tracepoint(iter->name);
@@ -542,6 +554,8 @@ void tracepoint_iter_reset(struct tracepoint_iter *iter)
 }
 EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
 
+#ifdef CONFIG_MODULES
+
 int tracepoint_module_notify(struct notifier_block *self,
                             unsigned long val, void *data)
 {
@@ -549,9 +563,6 @@ int tracepoint_module_notify(struct notifier_block *self,
 
        switch (val) {
        case MODULE_STATE_COMING:
-               tracepoint_update_probe_range(mod->tracepoints,
-                       mod->tracepoints + mod->num_tracepoints);
-               break;
        case MODULE_STATE_GOING:
                tracepoint_update_probe_range(mod->tracepoints,
                        mod->tracepoints + mod->num_tracepoints);
@@ -570,3 +581,43 @@ static int init_tracepoints(void)
        return register_module_notifier(&tracepoint_module_nb);
 }
 __initcall(init_tracepoints);
+
+#endif /* CONFIG_MODULES */
+
+#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
+
+/* NB: reg/unreg are called while guarded with the tracepoints_mutex */
+static int sys_tracepoint_refcount;
+
+void syscall_regfunc(void)
+{
+       unsigned long flags;
+       struct task_struct *g, *t;
+
+       if (!sys_tracepoint_refcount) {
+               read_lock_irqsave(&tasklist_lock, flags);
+               do_each_thread(g, t) {
+                       /* Skip kernel threads. */
+                       if (t->mm)
+                               set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
+               } while_each_thread(g, t);
+               read_unlock_irqrestore(&tasklist_lock, flags);
+       }
+       sys_tracepoint_refcount++;
+}
+
+void syscall_unregfunc(void)
+{
+       unsigned long flags;
+       struct task_struct *g, *t;
+
+       sys_tracepoint_refcount--;
+       if (!sys_tracepoint_refcount) {
+               read_lock_irqsave(&tasklist_lock, flags);
+               do_each_thread(g, t) {
+                       clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
+               } while_each_thread(g, t);
+               read_unlock_irqrestore(&tasklist_lock, flags);
+       }
+}
+#endif