summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (VMware) <rostedt@goodmis.org>2017-04-19 22:39:44 -0400
committerSteven Rostedt (VMware) <rostedt@goodmis.org>2017-04-20 22:06:46 -0400
commit6e4443199e5354255e8a4c1e8e5cfc8ef064c3ce (patch)
treeb0e7181d739a1207606bce8f60be5f305e27ea6b
parent7b60f3d8761561d95d7e962522d6338143fc2329 (diff)
tracing/ftrace: Add a better way to pass data via the probe functions
With the redesign of the registration and execution of the function probes (triggers), data can now be passed from the setup of the probe to the probe callers that are specific to the trace_array it is on. Although, all probes still only affect the toplevel trace array, this change will allow for instances to have their own probes separated from other instances and the top array. That is, something like the stacktrace probe can be set to trace only in an instance and not the toplevel trace array. This isn't implement yet, but this change sets the ground work for the change. When a probe callback is triggered (someone writes the probe format into set_ftrace_filter), it calls register_ftrace_function_probe() passing in init_data that will be used to initialize the probe. Then for every matching function, register_ftrace_function_probe() will call the probe_ops->init() function with the init data that was passed to it, as well as an address to a place holder that is associated with the probe and the instance. The first occurrence will have a NULL in the pointer. The init() function will then initialize it. If other probes are added, or more functions are part of the probe, the place holder will be passed to the init() function with the place holder data that it was initialized to the last time. Then this place_holder is passed to each of the other probe_ops functions, where it can be used in the function callback. When the probe_ops free() function is called, it can be called either with the rip of the function that is being removed from the probe, or zero, indicating that there are no more functions attached to the probe, and the place holder is about to be freed. This gives the probe_ops a way to free the data it assigned to the place holder if it was allocade during the first init call. Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-rw-r--r--kernel/trace/ftrace.c25
-rw-r--r--kernel/trace/trace.c38
-rw-r--r--kernel/trace/trace.h8
-rw-r--r--kernel/trace/trace_events.c110
-rw-r--r--kernel/trace/trace_functions.c79
5 files changed, 153 insertions, 107 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 8fdc18500c61..774e9108e5dc 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1106,6 +1106,7 @@ struct ftrace_func_probe {
1106 struct ftrace_ops ops; 1106 struct ftrace_ops ops;
1107 struct trace_array *tr; 1107 struct trace_array *tr;
1108 struct list_head list; 1108 struct list_head list;
1109 void *data;
1109 int ref; 1110 int ref;
1110}; 1111};
1111 1112
@@ -3187,7 +3188,7 @@ t_probe_show(struct seq_file *m, struct ftrace_iterator *iter)
3187 probe_ops = probe->probe_ops; 3188 probe_ops = probe->probe_ops;
3188 3189
3189 if (probe_ops->print) 3190 if (probe_ops->print)
3190 return probe_ops->print(m, probe_entry->ip, probe_ops, NULL); 3191 return probe_ops->print(m, probe_entry->ip, probe_ops, probe->data);
3191 3192
3192 seq_printf(m, "%ps:%ps\n", (void *)probe_entry->ip, 3193 seq_printf(m, "%ps:%ps\n", (void *)probe_entry->ip,
3193 (void *)probe_ops->func); 3194 (void *)probe_ops->func);
@@ -3814,7 +3815,7 @@ static void function_trace_probe_call(unsigned long ip, unsigned long parent_ip,
3814 * on the hash. rcu_read_lock is too dangerous here. 3815 * on the hash. rcu_read_lock is too dangerous here.
3815 */ 3816 */
3816 preempt_disable_notrace(); 3817 preempt_disable_notrace();
3817 probe_ops->func(ip, parent_ip, probe->tr, probe_ops, NULL); 3818 probe_ops->func(ip, parent_ip, probe->tr, probe_ops, probe->data);
3818 preempt_enable_notrace(); 3819 preempt_enable_notrace();
3819} 3820}
3820 3821
@@ -3972,6 +3973,12 @@ static void release_probe(struct ftrace_func_probe *probe)
3972 3973
3973 if (!probe->ref) { 3974 if (!probe->ref) {
3974 probe_ops = probe->probe_ops; 3975 probe_ops = probe->probe_ops;
3976 /*
3977 * Sending zero as ip tells probe_ops to free
3978 * the probe->data itself
3979 */
3980 if (probe_ops->free)
3981 probe_ops->free(probe_ops, probe->tr, 0, probe->data);
3975 list_del(&probe->list); 3982 list_del(&probe->list);
3976 kfree(probe); 3983 kfree(probe);
3977 } 3984 }
@@ -4060,9 +4067,15 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
4060 */ 4067 */
4061 if (probe_ops->init) { 4068 if (probe_ops->init) {
4062 ret = probe_ops->init(probe_ops, tr, 4069 ret = probe_ops->init(probe_ops, tr,
4063 entry->ip, data); 4070 entry->ip, data,
4064 if (ret < 0) 4071 &probe->data);
4072 if (ret < 0) {
4073 if (probe_ops->free && count)
4074 probe_ops->free(probe_ops, tr,
4075 0, probe->data);
4076 probe->data = NULL;
4065 goto out; 4077 goto out;
4078 }
4066 } 4079 }
4067 count++; 4080 count++;
4068 } 4081 }
@@ -4109,7 +4122,7 @@ register_ftrace_function_probe(char *glob, struct trace_array *tr,
4109 hlist_for_each_entry(entry, &hash->buckets[i], hlist) { 4122 hlist_for_each_entry(entry, &hash->buckets[i], hlist) {
4110 if (ftrace_lookup_ip(old_hash, entry->ip)) 4123 if (ftrace_lookup_ip(old_hash, entry->ip))
4111 continue; 4124 continue;
4112 probe_ops->free(probe_ops, tr, entry->ip, NULL); 4125 probe_ops->free(probe_ops, tr, entry->ip, probe->data);
4113 } 4126 }
4114 } 4127 }
4115 goto out_unlock; 4128 goto out_unlock;
@@ -4227,7 +4240,7 @@ unregister_ftrace_function_probe_func(char *glob, struct trace_array *tr,
4227 hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) { 4240 hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) {
4228 hlist_del(&entry->hlist); 4241 hlist_del(&entry->hlist);
4229 if (probe_ops->free) 4242 if (probe_ops->free)
4230 probe_ops->free(probe_ops, tr, entry->ip, NULL); 4243 probe_ops->free(probe_ops, tr, entry->ip, probe->data);
4231 kfree(entry); 4244 kfree(entry);
4232 } 4245 }
4233 mutex_unlock(&ftrace_lock); 4246 mutex_unlock(&ftrace_lock);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index e61610e5e6e3..18256cd7ad2c 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6737,7 +6737,7 @@ static const struct file_operations tracing_dyn_info_fops = {
6737static void 6737static void
6738ftrace_snapshot(unsigned long ip, unsigned long parent_ip, 6738ftrace_snapshot(unsigned long ip, unsigned long parent_ip,
6739 struct trace_array *tr, struct ftrace_probe_ops *ops, 6739 struct trace_array *tr, struct ftrace_probe_ops *ops,
6740 void **data) 6740 void *data)
6741{ 6741{
6742 tracing_snapshot(); 6742 tracing_snapshot();
6743} 6743}
@@ -6745,9 +6745,9 @@ ftrace_snapshot(unsigned long ip, unsigned long parent_ip,
6745static void 6745static void
6746ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip, 6746ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip,
6747 struct trace_array *tr, struct ftrace_probe_ops *ops, 6747 struct trace_array *tr, struct ftrace_probe_ops *ops,
6748 void **data) 6748 void *data)
6749{ 6749{
6750 struct ftrace_func_mapper *mapper = ops->private_data; 6750 struct ftrace_func_mapper *mapper = data;
6751 long *count = NULL; 6751 long *count = NULL;
6752 6752
6753 if (mapper) 6753 if (mapper)
@@ -6768,7 +6768,7 @@ static int
6768ftrace_snapshot_print(struct seq_file *m, unsigned long ip, 6768ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
6769 struct ftrace_probe_ops *ops, void *data) 6769 struct ftrace_probe_ops *ops, void *data)
6770{ 6770{
6771 struct ftrace_func_mapper *mapper = ops->private_data; 6771 struct ftrace_func_mapper *mapper = data;
6772 long *count = NULL; 6772 long *count = NULL;
6773 6773
6774 seq_printf(m, "%ps:", (void *)ip); 6774 seq_printf(m, "%ps:", (void *)ip);
@@ -6788,18 +6788,32 @@ ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
6788 6788
6789static int 6789static int
6790ftrace_snapshot_init(struct ftrace_probe_ops *ops, struct trace_array *tr, 6790ftrace_snapshot_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
6791 unsigned long ip, void *data) 6791 unsigned long ip, void *init_data, void **data)
6792{ 6792{
6793 struct ftrace_func_mapper *mapper = ops->private_data; 6793 struct ftrace_func_mapper *mapper = *data;
6794
6795 if (!mapper) {
6796 mapper = allocate_ftrace_func_mapper();
6797 if (!mapper)
6798 return -ENOMEM;
6799 *data = mapper;
6800 }
6794 6801
6795 return ftrace_func_mapper_add_ip(mapper, ip, data); 6802 return ftrace_func_mapper_add_ip(mapper, ip, init_data);
6796} 6803}
6797 6804
6798static void 6805static void
6799ftrace_snapshot_free(struct ftrace_probe_ops *ops, struct trace_array *tr, 6806ftrace_snapshot_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
6800 unsigned long ip, void **data) 6807 unsigned long ip, void *data)
6801{ 6808{
6802 struct ftrace_func_mapper *mapper = ops->private_data; 6809 struct ftrace_func_mapper *mapper = data;
6810
6811 if (!ip) {
6812 if (!mapper)
6813 return;
6814 free_ftrace_func_mapper(mapper, NULL);
6815 return;
6816 }
6803 6817
6804 ftrace_func_mapper_remove_ip(mapper, ip); 6818 ftrace_func_mapper_remove_ip(mapper, ip);
6805} 6819}
@@ -6842,12 +6856,6 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,
6842 if (!strlen(number)) 6856 if (!strlen(number))
6843 goto out_reg; 6857 goto out_reg;
6844 6858
6845 if (!ops->private_data) {
6846 ops->private_data = allocate_ftrace_func_mapper();
6847 if (!ops->private_data)
6848 return -ENOMEM;
6849 }
6850
6851 /* 6859 /*
6852 * We use the callback data field (which is a pointer) 6860 * We use the callback data field (which is a pointer)
6853 * as our counter. 6861 * as our counter.
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index e978ecd257b8..8f6754fba778 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -943,18 +943,18 @@ struct ftrace_probe_ops {
943 unsigned long parent_ip, 943 unsigned long parent_ip,
944 struct trace_array *tr, 944 struct trace_array *tr,
945 struct ftrace_probe_ops *ops, 945 struct ftrace_probe_ops *ops,
946 void **data); 946 void *data);
947 int (*init)(struct ftrace_probe_ops *ops, 947 int (*init)(struct ftrace_probe_ops *ops,
948 struct trace_array *tr, 948 struct trace_array *tr,
949 unsigned long ip, void *data); 949 unsigned long ip, void *init_data,
950 void **data);
950 void (*free)(struct ftrace_probe_ops *ops, 951 void (*free)(struct ftrace_probe_ops *ops,
951 struct trace_array *tr, 952 struct trace_array *tr,
952 unsigned long ip, void **data); 953 unsigned long ip, void *data);
953 int (*print)(struct seq_file *m, 954 int (*print)(struct seq_file *m,
954 unsigned long ip, 955 unsigned long ip,
955 struct ftrace_probe_ops *ops, 956 struct ftrace_probe_ops *ops,
956 void *data); 957 void *data);
957 void *private_data;
958}; 958};
959 959
960struct ftrace_func_mapper; 960struct ftrace_func_mapper;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 48c7f70cbac7..e7973e10398c 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2471,54 +2471,54 @@ static void update_event_probe(struct event_probe_data *data)
2471static void 2471static void
2472event_enable_probe(unsigned long ip, unsigned long parent_ip, 2472event_enable_probe(unsigned long ip, unsigned long parent_ip,
2473 struct trace_array *tr, struct ftrace_probe_ops *ops, 2473 struct trace_array *tr, struct ftrace_probe_ops *ops,
2474 void **_data) 2474 void *data)
2475{ 2475{
2476 struct ftrace_func_mapper *mapper = ops->private_data; 2476 struct ftrace_func_mapper *mapper = data;
2477 struct event_probe_data *data; 2477 struct event_probe_data *edata;
2478 void **pdata; 2478 void **pdata;
2479 2479
2480 pdata = ftrace_func_mapper_find_ip(mapper, ip); 2480 pdata = ftrace_func_mapper_find_ip(mapper, ip);
2481 if (!pdata || !*pdata) 2481 if (!pdata || !*pdata)
2482 return; 2482 return;
2483 2483
2484 data = *pdata; 2484 edata = *pdata;
2485 update_event_probe(data); 2485 update_event_probe(edata);
2486} 2486}
2487 2487
2488static void 2488static void
2489event_enable_count_probe(unsigned long ip, unsigned long parent_ip, 2489event_enable_count_probe(unsigned long ip, unsigned long parent_ip,
2490 struct trace_array *tr, struct ftrace_probe_ops *ops, 2490 struct trace_array *tr, struct ftrace_probe_ops *ops,
2491 void **_data) 2491 void *data)
2492{ 2492{
2493 struct ftrace_func_mapper *mapper = ops->private_data; 2493 struct ftrace_func_mapper *mapper = data;
2494 struct event_probe_data *data; 2494 struct event_probe_data *edata;
2495 void **pdata; 2495 void **pdata;
2496 2496
2497 pdata = ftrace_func_mapper_find_ip(mapper, ip); 2497 pdata = ftrace_func_mapper_find_ip(mapper, ip);
2498 if (!pdata || !*pdata) 2498 if (!pdata || !*pdata)
2499 return; 2499 return;
2500 2500
2501 data = *pdata; 2501 edata = *pdata;
2502 2502
2503 if (!data->count) 2503 if (!edata->count)
2504 return; 2504 return;
2505 2505
2506 /* Skip if the event is in a state we want to switch to */ 2506 /* Skip if the event is in a state we want to switch to */
2507 if (data->enable == !(data->file->flags & EVENT_FILE_FL_SOFT_DISABLED)) 2507 if (edata->enable == !(edata->file->flags & EVENT_FILE_FL_SOFT_DISABLED))
2508 return; 2508 return;
2509 2509
2510 if (data->count != -1) 2510 if (edata->count != -1)
2511 (data->count)--; 2511 (edata->count)--;
2512 2512
2513 update_event_probe(data); 2513 update_event_probe(edata);
2514} 2514}
2515 2515
2516static int 2516static int
2517event_enable_print(struct seq_file *m, unsigned long ip, 2517event_enable_print(struct seq_file *m, unsigned long ip,
2518 struct ftrace_probe_ops *ops, void *_data) 2518 struct ftrace_probe_ops *ops, void *data)
2519{ 2519{
2520 struct ftrace_func_mapper *mapper = ops->private_data; 2520 struct ftrace_func_mapper *mapper = data;
2521 struct event_probe_data *data; 2521 struct event_probe_data *edata;
2522 void **pdata; 2522 void **pdata;
2523 2523
2524 pdata = ftrace_func_mapper_find_ip(mapper, ip); 2524 pdata = ftrace_func_mapper_find_ip(mapper, ip);
@@ -2526,62 +2526,84 @@ event_enable_print(struct seq_file *m, unsigned long ip,
2526 if (WARN_ON_ONCE(!pdata || !*pdata)) 2526 if (WARN_ON_ONCE(!pdata || !*pdata))
2527 return 0; 2527 return 0;
2528 2528
2529 data = *pdata; 2529 edata = *pdata;
2530 2530
2531 seq_printf(m, "%ps:", (void *)ip); 2531 seq_printf(m, "%ps:", (void *)ip);
2532 2532
2533 seq_printf(m, "%s:%s:%s", 2533 seq_printf(m, "%s:%s:%s",
2534 data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR, 2534 edata->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
2535 data->file->event_call->class->system, 2535 edata->file->event_call->class->system,
2536 trace_event_name(data->file->event_call)); 2536 trace_event_name(edata->file->event_call));
2537 2537
2538 if (data->count == -1) 2538 if (edata->count == -1)
2539 seq_puts(m, ":unlimited\n"); 2539 seq_puts(m, ":unlimited\n");
2540 else 2540 else
2541 seq_printf(m, ":count=%ld\n", data->count); 2541 seq_printf(m, ":count=%ld\n", edata->count);
2542 2542
2543 return 0; 2543 return 0;
2544} 2544}
2545 2545
2546static int 2546static int
2547event_enable_init(struct ftrace_probe_ops *ops, struct trace_array *tr, 2547event_enable_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
2548 unsigned long ip, void *_data) 2548 unsigned long ip, void *init_data, void **data)
2549{ 2549{
2550 struct ftrace_func_mapper *mapper = ops->private_data; 2550 struct ftrace_func_mapper *mapper = *data;
2551 struct event_probe_data *data = _data; 2551 struct event_probe_data *edata = init_data;
2552 int ret; 2552 int ret;
2553 2553
2554 ret = ftrace_func_mapper_add_ip(mapper, ip, data); 2554 if (!mapper) {
2555 mapper = allocate_ftrace_func_mapper();
2556 if (!mapper)
2557 return -ENODEV;
2558 *data = mapper;
2559 }
2560
2561 ret = ftrace_func_mapper_add_ip(mapper, ip, edata);
2555 if (ret < 0) 2562 if (ret < 0)
2556 return ret; 2563 return ret;
2557 2564
2558 data->ref++; 2565 edata->ref++;
2566
2567 return 0;
2568}
2569
2570static int free_probe_data(void *data)
2571{
2572 struct event_probe_data *edata = data;
2559 2573
2574 edata->ref--;
2575 if (!edata->ref) {
2576 /* Remove the SOFT_MODE flag */
2577 __ftrace_event_enable_disable(edata->file, 0, 1);
2578 module_put(edata->file->event_call->mod);
2579 kfree(edata);
2580 }
2560 return 0; 2581 return 0;
2561} 2582}
2562 2583
2563static void 2584static void
2564event_enable_free(struct ftrace_probe_ops *ops, struct trace_array *tr, 2585event_enable_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
2565 unsigned long ip, void **_data) 2586 unsigned long ip, void *data)
2566{ 2587{
2567 struct ftrace_func_mapper *mapper = ops->private_data; 2588 struct ftrace_func_mapper *mapper = data;
2568 struct event_probe_data *data; 2589 struct event_probe_data *edata;
2590
2591 if (!ip) {
2592 if (!mapper)
2593 return;
2594 free_ftrace_func_mapper(mapper, free_probe_data);
2595 return;
2596 }
2569 2597
2570 data = ftrace_func_mapper_remove_ip(mapper, ip); 2598 edata = ftrace_func_mapper_remove_ip(mapper, ip);
2571 2599
2572 if (WARN_ON_ONCE(!data)) 2600 if (WARN_ON_ONCE(!edata))
2573 return; 2601 return;
2574 2602
2575 if (WARN_ON_ONCE(data->ref <= 0)) 2603 if (WARN_ON_ONCE(edata->ref <= 0))
2576 return; 2604 return;
2577 2605
2578 data->ref--; 2606 free_probe_data(edata);
2579 if (!data->ref) {
2580 /* Remove the SOFT_MODE flag */
2581 __ftrace_event_enable_disable(data->file, 0, 1);
2582 module_put(data->file->event_call->mod);
2583 kfree(data);
2584 }
2585} 2607}
2586 2608
2587static struct ftrace_probe_ops event_enable_probe_ops = { 2609static struct ftrace_probe_ops event_enable_probe_ops = {
@@ -2659,12 +2681,6 @@ event_enable_func(struct trace_array *tr, struct ftrace_hash *hash,
2659 2681
2660 ret = -ENOMEM; 2682 ret = -ENOMEM;
2661 2683
2662 if (!ops->private_data) {
2663 ops->private_data = allocate_ftrace_func_mapper();
2664 if (!ops->private_data)
2665 goto out;
2666 }
2667
2668 data = kzalloc(sizeof(*data), GFP_KERNEL); 2684 data = kzalloc(sizeof(*data), GFP_KERNEL);
2669 if (!data) 2685 if (!data)
2670 goto out; 2686 goto out;
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index b95f56ba9744..7775e1ca5bad 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -268,9 +268,10 @@ static struct tracer function_trace __tracer_data =
268 268
269#ifdef CONFIG_DYNAMIC_FTRACE 269#ifdef CONFIG_DYNAMIC_FTRACE
270static void update_traceon_count(struct ftrace_probe_ops *ops, 270static void update_traceon_count(struct ftrace_probe_ops *ops,
271 unsigned long ip, bool on) 271 unsigned long ip, bool on,
272 void *data)
272{ 273{
273 struct ftrace_func_mapper *mapper = ops->private_data; 274 struct ftrace_func_mapper *mapper = data;
274 long *count; 275 long *count;
275 long old_count; 276 long old_count;
276 277
@@ -329,23 +330,23 @@ static void update_traceon_count(struct ftrace_probe_ops *ops,
329static void 330static void
330ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, 331ftrace_traceon_count(unsigned long ip, unsigned long parent_ip,
331 struct trace_array *tr, struct ftrace_probe_ops *ops, 332 struct trace_array *tr, struct ftrace_probe_ops *ops,
332 void **data) 333 void *data)
333{ 334{
334 update_traceon_count(ops, ip, 1); 335 update_traceon_count(ops, ip, 1, data);
335} 336}
336 337
337static void 338static void
338ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, 339ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip,
339 struct trace_array *tr, struct ftrace_probe_ops *ops, 340 struct trace_array *tr, struct ftrace_probe_ops *ops,
340 void **data) 341 void *data)
341{ 342{
342 update_traceon_count(ops, ip, 0); 343 update_traceon_count(ops, ip, 0, data);
343} 344}
344 345
345static void 346static void
346ftrace_traceon(unsigned long ip, unsigned long parent_ip, 347ftrace_traceon(unsigned long ip, unsigned long parent_ip,
347 struct trace_array *tr, struct ftrace_probe_ops *ops, 348 struct trace_array *tr, struct ftrace_probe_ops *ops,
348 void **data) 349 void *data)
349{ 350{
350 if (tracing_is_on()) 351 if (tracing_is_on())
351 return; 352 return;
@@ -356,7 +357,7 @@ ftrace_traceon(unsigned long ip, unsigned long parent_ip,
356static void 357static void
357ftrace_traceoff(unsigned long ip, unsigned long parent_ip, 358ftrace_traceoff(unsigned long ip, unsigned long parent_ip,
358 struct trace_array *tr, struct ftrace_probe_ops *ops, 359 struct trace_array *tr, struct ftrace_probe_ops *ops,
359 void **data) 360 void *data)
360{ 361{
361 if (!tracing_is_on()) 362 if (!tracing_is_on())
362 return; 363 return;
@@ -376,7 +377,7 @@ ftrace_traceoff(unsigned long ip, unsigned long parent_ip,
376static void 377static void
377ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, 378ftrace_stacktrace(unsigned long ip, unsigned long parent_ip,
378 struct trace_array *tr, struct ftrace_probe_ops *ops, 379 struct trace_array *tr, struct ftrace_probe_ops *ops,
379 void **data) 380 void *data)
380{ 381{
381 trace_dump_stack(STACK_SKIP); 382 trace_dump_stack(STACK_SKIP);
382} 383}
@@ -384,9 +385,9 @@ ftrace_stacktrace(unsigned long ip, unsigned long parent_ip,
384static void 385static void
385ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, 386ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
386 struct trace_array *tr, struct ftrace_probe_ops *ops, 387 struct trace_array *tr, struct ftrace_probe_ops *ops,
387 void **data) 388 void *data)
388{ 389{
389 struct ftrace_func_mapper *mapper = ops->private_data; 390 struct ftrace_func_mapper *mapper = data;
390 long *count; 391 long *count;
391 long old_count; 392 long old_count;
392 long new_count; 393 long new_count;
@@ -423,9 +424,10 @@ ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
423 } while (new_count != old_count); 424 } while (new_count != old_count);
424} 425}
425 426
426static int update_count(struct ftrace_probe_ops *ops, unsigned long ip) 427static int update_count(struct ftrace_probe_ops *ops, unsigned long ip,
428 void *data)
427{ 429{
428 struct ftrace_func_mapper *mapper = ops->private_data; 430 struct ftrace_func_mapper *mapper = data;
429 long *count = NULL; 431 long *count = NULL;
430 432
431 if (mapper) 433 if (mapper)
@@ -443,9 +445,9 @@ static int update_count(struct ftrace_probe_ops *ops, unsigned long ip)
443static void 445static void
444ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, 446ftrace_dump_probe(unsigned long ip, unsigned long parent_ip,
445 struct trace_array *tr, struct ftrace_probe_ops *ops, 447 struct trace_array *tr, struct ftrace_probe_ops *ops,
446 void **data) 448 void *data)
447{ 449{
448 if (update_count(ops, ip)) 450 if (update_count(ops, ip, data))
449 ftrace_dump(DUMP_ALL); 451 ftrace_dump(DUMP_ALL);
450} 452}
451 453
@@ -453,17 +455,18 @@ ftrace_dump_probe(unsigned long ip, unsigned long parent_ip,
453static void 455static void
454ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip, 456ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip,
455 struct trace_array *tr, struct ftrace_probe_ops *ops, 457 struct trace_array *tr, struct ftrace_probe_ops *ops,
456 void **data) 458 void *data)
457{ 459{
458 if (update_count(ops, ip)) 460 if (update_count(ops, ip, data))
459 ftrace_dump(DUMP_ORIG); 461 ftrace_dump(DUMP_ORIG);
460} 462}
461 463
462static int 464static int
463ftrace_probe_print(const char *name, struct seq_file *m, 465ftrace_probe_print(const char *name, struct seq_file *m,
464 unsigned long ip, struct ftrace_probe_ops *ops) 466 unsigned long ip, struct ftrace_probe_ops *ops,
467 void *data)
465{ 468{
466 struct ftrace_func_mapper *mapper = ops->private_data; 469 struct ftrace_func_mapper *mapper = data;
467 long *count = NULL; 470 long *count = NULL;
468 471
469 seq_printf(m, "%ps:%s", (void *)ip, name); 472 seq_printf(m, "%ps:%s", (void *)ip, name);
@@ -484,52 +487,64 @@ ftrace_traceon_print(struct seq_file *m, unsigned long ip,
484 struct ftrace_probe_ops *ops, 487 struct ftrace_probe_ops *ops,
485 void *data) 488 void *data)
486{ 489{
487 return ftrace_probe_print("traceon", m, ip, ops); 490 return ftrace_probe_print("traceon", m, ip, ops, data);
488} 491}
489 492
490static int 493static int
491ftrace_traceoff_print(struct seq_file *m, unsigned long ip, 494ftrace_traceoff_print(struct seq_file *m, unsigned long ip,
492 struct ftrace_probe_ops *ops, void *data) 495 struct ftrace_probe_ops *ops, void *data)
493{ 496{
494 return ftrace_probe_print("traceoff", m, ip, ops); 497 return ftrace_probe_print("traceoff", m, ip, ops, data);
495} 498}
496 499
497static int 500static int
498ftrace_stacktrace_print(struct seq_file *m, unsigned long ip, 501ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
499 struct ftrace_probe_ops *ops, void *data) 502 struct ftrace_probe_ops *ops, void *data)
500{ 503{
501 return ftrace_probe_print("stacktrace", m, ip, ops); 504 return ftrace_probe_print("stacktrace", m, ip, ops, data);
502} 505}
503 506
504static int 507static int
505ftrace_dump_print(struct seq_file *m, unsigned long ip, 508ftrace_dump_print(struct seq_file *m, unsigned long ip,
506 struct ftrace_probe_ops *ops, void *data) 509 struct ftrace_probe_ops *ops, void *data)
507{ 510{
508 return ftrace_probe_print("dump", m, ip, ops); 511 return ftrace_probe_print("dump", m, ip, ops, data);
509} 512}
510 513
511static int 514static int
512ftrace_cpudump_print(struct seq_file *m, unsigned long ip, 515ftrace_cpudump_print(struct seq_file *m, unsigned long ip,
513 struct ftrace_probe_ops *ops, void *data) 516 struct ftrace_probe_ops *ops, void *data)
514{ 517{
515 return ftrace_probe_print("cpudump", m, ip, ops); 518 return ftrace_probe_print("cpudump", m, ip, ops, data);
516} 519}
517 520
518 521
519static int 522static int
520ftrace_count_init(struct ftrace_probe_ops *ops, struct trace_array *tr, 523ftrace_count_init(struct ftrace_probe_ops *ops, struct trace_array *tr,
521 unsigned long ip, void *data) 524 unsigned long ip, void *init_data, void **data)
522{ 525{
523 struct ftrace_func_mapper *mapper = ops->private_data; 526 struct ftrace_func_mapper *mapper = *data;
527
528 if (!mapper) {
529 mapper = allocate_ftrace_func_mapper();
530 if (!mapper)
531 return -ENOMEM;
532 *data = mapper;
533 }
524 534
525 return ftrace_func_mapper_add_ip(mapper, ip, data); 535 return ftrace_func_mapper_add_ip(mapper, ip, init_data);
526} 536}
527 537
528static void 538static void
529ftrace_count_free(struct ftrace_probe_ops *ops, struct trace_array *tr, 539ftrace_count_free(struct ftrace_probe_ops *ops, struct trace_array *tr,
530 unsigned long ip, void **_data) 540 unsigned long ip, void *data)
531{ 541{
532 struct ftrace_func_mapper *mapper = ops->private_data; 542 struct ftrace_func_mapper *mapper = data;
543
544 if (!ip) {
545 free_ftrace_func_mapper(mapper, NULL);
546 return;
547 }
533 548
534 ftrace_func_mapper_remove_ip(mapper, ip); 549 ftrace_func_mapper_remove_ip(mapper, ip);
535} 550}
@@ -607,12 +622,6 @@ ftrace_trace_probe_callback(struct trace_array *tr,
607 if (!strlen(number)) 622 if (!strlen(number))
608 goto out_reg; 623 goto out_reg;
609 624
610 if (!ops->private_data) {
611 ops->private_data = allocate_ftrace_func_mapper();
612 if (!ops->private_data)
613 return -ENOMEM;
614 }
615
616 /* 625 /*
617 * We use the callback data field (which is a pointer) 626 * We use the callback data field (which is a pointer)
618 * as our counter. 627 * as our counter.