diff options
Diffstat (limited to 'kernel/tracepoint.c')
| -rw-r--r-- | kernel/tracepoint.c | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 1ef5d3a601c7..9489a0a9b1be 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/tracepoint.h> | 24 | #include <linux/tracepoint.h> |
| 25 | #include <linux/err.h> | 25 | #include <linux/err.h> |
| 26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 27 | #include <linux/sched.h> | ||
| 27 | 28 | ||
| 28 | extern struct tracepoint __start___tracepoints[]; | 29 | extern struct tracepoint __start___tracepoints[]; |
| 29 | extern struct tracepoint __stop___tracepoints[]; | 30 | extern struct tracepoint __stop___tracepoints[]; |
| @@ -242,6 +243,11 @@ static void set_tracepoint(struct tracepoint_entry **entry, | |||
| 242 | { | 243 | { |
| 243 | WARN_ON(strcmp((*entry)->name, elem->name) != 0); | 244 | WARN_ON(strcmp((*entry)->name, elem->name) != 0); |
| 244 | 245 | ||
| 246 | if (elem->regfunc && !elem->state && active) | ||
| 247 | elem->regfunc(); | ||
| 248 | else if (elem->unregfunc && elem->state && !active) | ||
| 249 | elem->unregfunc(); | ||
| 250 | |||
| 245 | /* | 251 | /* |
| 246 | * rcu_assign_pointer has a smp_wmb() which makes sure that the new | 252 | * rcu_assign_pointer has a smp_wmb() which makes sure that the new |
| 247 | * probe callbacks array is consistent before setting a pointer to it. | 253 | * probe callbacks array is consistent before setting a pointer to it. |
| @@ -261,6 +267,9 @@ static void set_tracepoint(struct tracepoint_entry **entry, | |||
| 261 | */ | 267 | */ |
| 262 | static void disable_tracepoint(struct tracepoint *elem) | 268 | static void disable_tracepoint(struct tracepoint *elem) |
| 263 | { | 269 | { |
| 270 | if (elem->unregfunc && elem->state) | ||
| 271 | elem->unregfunc(); | ||
| 272 | |||
| 264 | elem->state = 0; | 273 | elem->state = 0; |
| 265 | rcu_assign_pointer(elem->funcs, NULL); | 274 | rcu_assign_pointer(elem->funcs, NULL); |
| 266 | } | 275 | } |
| @@ -554,9 +563,6 @@ int tracepoint_module_notify(struct notifier_block *self, | |||
| 554 | 563 | ||
| 555 | switch (val) { | 564 | switch (val) { |
| 556 | case MODULE_STATE_COMING: | 565 | case MODULE_STATE_COMING: |
| 557 | tracepoint_update_probe_range(mod->tracepoints, | ||
| 558 | mod->tracepoints + mod->num_tracepoints); | ||
| 559 | break; | ||
| 560 | case MODULE_STATE_GOING: | 566 | case MODULE_STATE_GOING: |
| 561 | tracepoint_update_probe_range(mod->tracepoints, | 567 | tracepoint_update_probe_range(mod->tracepoints, |
| 562 | mod->tracepoints + mod->num_tracepoints); | 568 | mod->tracepoints + mod->num_tracepoints); |
| @@ -577,3 +583,41 @@ static int init_tracepoints(void) | |||
| 577 | __initcall(init_tracepoints); | 583 | __initcall(init_tracepoints); |
| 578 | 584 | ||
| 579 | #endif /* CONFIG_MODULES */ | 585 | #endif /* CONFIG_MODULES */ |
| 586 | |||
| 587 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS | ||
| 588 | |||
| 589 | /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ | ||
| 590 | static int sys_tracepoint_refcount; | ||
| 591 | |||
| 592 | void syscall_regfunc(void) | ||
| 593 | { | ||
| 594 | unsigned long flags; | ||
| 595 | struct task_struct *g, *t; | ||
| 596 | |||
| 597 | if (!sys_tracepoint_refcount) { | ||
| 598 | read_lock_irqsave(&tasklist_lock, flags); | ||
| 599 | do_each_thread(g, t) { | ||
| 600 | /* Skip kernel threads. */ | ||
| 601 | if (t->mm) | ||
| 602 | set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); | ||
| 603 | } while_each_thread(g, t); | ||
| 604 | read_unlock_irqrestore(&tasklist_lock, flags); | ||
| 605 | } | ||
| 606 | sys_tracepoint_refcount++; | ||
| 607 | } | ||
| 608 | |||
| 609 | void syscall_unregfunc(void) | ||
| 610 | { | ||
| 611 | unsigned long flags; | ||
| 612 | struct task_struct *g, *t; | ||
| 613 | |||
| 614 | sys_tracepoint_refcount--; | ||
| 615 | if (!sys_tracepoint_refcount) { | ||
| 616 | read_lock_irqsave(&tasklist_lock, flags); | ||
| 617 | do_each_thread(g, t) { | ||
| 618 | clear_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT); | ||
| 619 | } while_each_thread(g, t); | ||
| 620 | read_unlock_irqrestore(&tasklist_lock, flags); | ||
| 621 | } | ||
| 622 | } | ||
| 623 | #endif | ||
