diff options
| author | Li Zefan <lizf@cn.fujitsu.com> | 2009-05-05 22:33:04 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-05-06 04:38:19 -0400 |
| commit | 2df75e415709ad12862028916c772c1f377f6a7c (patch) | |
| tree | 3374a78cb06fe096e82d9e4d03ad03d048784967 | |
| parent | 96d17980fabeb757706d2d6db5a28580a6156bfc (diff) | |
tracing/events: fix memory leak when unloading module
When unloading a module, memory allocated by init_preds() and
trace_define_field() is not freed.
[ Impact: fix memory leak ]
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <4A00F6E0.3040503@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | include/linux/ftrace_event.h | 1 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 18 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 22 |
3 files changed, 34 insertions, 7 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 5fff40c9ff59..662c1becf367 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
| @@ -116,6 +116,7 @@ struct ftrace_event_call { | |||
| 116 | #define MAX_FILTER_STR_VAL 128 | 116 | #define MAX_FILTER_STR_VAL 128 |
| 117 | 117 | ||
| 118 | extern int init_preds(struct ftrace_event_call *call); | 118 | extern int init_preds(struct ftrace_event_call *call); |
| 119 | extern void destroy_preds(struct ftrace_event_call *call); | ||
| 119 | extern int filter_match_preds(struct ftrace_event_call *call, void *rec); | 120 | extern int filter_match_preds(struct ftrace_event_call *call, void *rec); |
| 120 | extern int filter_current_check_discard(struct ftrace_event_call *call, | 121 | extern int filter_current_check_discard(struct ftrace_event_call *call, |
| 121 | void *rec, | 122 | void *rec, |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index f789ca540fe1..f251a150e75e 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -60,6 +60,22 @@ err: | |||
| 60 | } | 60 | } |
| 61 | EXPORT_SYMBOL_GPL(trace_define_field); | 61 | EXPORT_SYMBOL_GPL(trace_define_field); |
| 62 | 62 | ||
| 63 | #ifdef CONFIG_MODULES | ||
| 64 | |||
| 65 | static void trace_destroy_fields(struct ftrace_event_call *call) | ||
| 66 | { | ||
| 67 | struct ftrace_event_field *field, *next; | ||
| 68 | |||
| 69 | list_for_each_entry_safe(field, next, &call->fields, link) { | ||
| 70 | list_del(&field->link); | ||
| 71 | kfree(field->type); | ||
| 72 | kfree(field->name); | ||
| 73 | kfree(field); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | #endif /* CONFIG_MODULES */ | ||
| 78 | |||
| 63 | static void ftrace_clear_events(void) | 79 | static void ftrace_clear_events(void) |
| 64 | { | 80 | { |
| 65 | struct ftrace_event_call *call; | 81 | struct ftrace_event_call *call; |
| @@ -925,6 +941,8 @@ static void trace_module_remove_events(struct module *mod) | |||
| 925 | unregister_ftrace_event(call->event); | 941 | unregister_ftrace_event(call->event); |
| 926 | debugfs_remove_recursive(call->dir); | 942 | debugfs_remove_recursive(call->dir); |
| 927 | list_del(&call->list); | 943 | list_del(&call->list); |
| 944 | trace_destroy_fields(call); | ||
| 945 | destroy_preds(call); | ||
| 928 | } | 946 | } |
| 929 | } | 947 | } |
| 930 | 948 | ||
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index f49486687ee2..ce07b8186710 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
| @@ -346,6 +346,20 @@ static void filter_disable_preds(struct ftrace_event_call *call) | |||
| 346 | filter->preds[i]->fn = filter_pred_none; | 346 | filter->preds[i]->fn = filter_pred_none; |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | void destroy_preds(struct ftrace_event_call *call) | ||
| 350 | { | ||
| 351 | struct event_filter *filter = call->filter; | ||
| 352 | int i; | ||
| 353 | |||
| 354 | for (i = 0; i < MAX_FILTER_PRED; i++) { | ||
| 355 | if (filter->preds[i]) | ||
| 356 | filter_free_pred(filter->preds[i]); | ||
| 357 | } | ||
| 358 | kfree(filter->preds); | ||
| 359 | kfree(filter); | ||
| 360 | call->filter = NULL; | ||
| 361 | } | ||
| 362 | |||
| 349 | int init_preds(struct ftrace_event_call *call) | 363 | int init_preds(struct ftrace_event_call *call) |
| 350 | { | 364 | { |
| 351 | struct event_filter *filter; | 365 | struct event_filter *filter; |
| @@ -374,13 +388,7 @@ int init_preds(struct ftrace_event_call *call) | |||
| 374 | return 0; | 388 | return 0; |
| 375 | 389 | ||
| 376 | oom: | 390 | oom: |
| 377 | for (i = 0; i < MAX_FILTER_PRED; i++) { | 391 | destroy_preds(call); |
| 378 | if (filter->preds[i]) | ||
| 379 | filter_free_pred(filter->preds[i]); | ||
| 380 | } | ||
| 381 | kfree(filter->preds); | ||
| 382 | kfree(call->filter); | ||
| 383 | call->filter = NULL; | ||
| 384 | 392 | ||
| 385 | return -ENOMEM; | 393 | return -ENOMEM; |
| 386 | } | 394 | } |
