diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-01-06 15:33:30 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-07 04:45:14 -0500 |
commit | ff288b274a9b383046fdbda4be3067daba4d5fe8 (patch) | |
tree | 9b140f23d6e3bf325ed4f8978a3ddc14c8ccd16d | |
parent | 431aa3fbf5bbe3be79809c7e603c2ed2ac64b015 (diff) |
tracing/ftrace: fix a memory leak in stat tracing
Impact: fix memory leak
This patch fixes a memory leak inside reset_stat_list(). The freeing
loop iterated only once.
Also turn the stat_list into a simple struct list_head, which
simplify the code and avoid an unused static pointer.
Reported-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | kernel/trace/trace_stat.c | 39 |
1 files changed, 15 insertions, 24 deletions
diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c index 6f194a33a64a..4cb4ff27646d 100644 --- a/kernel/trace/trace_stat.c +++ b/kernel/trace/trace_stat.c | |||
@@ -21,7 +21,7 @@ struct trace_stat_list { | |||
21 | void *stat; | 21 | void *stat; |
22 | }; | 22 | }; |
23 | 23 | ||
24 | static struct trace_stat_list stat_list; | 24 | static LIST_HEAD(stat_list); |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * This is a copy of the current tracer to avoid racy | 27 | * This is a copy of the current tracer to avoid racy |
@@ -39,22 +39,12 @@ static DEFINE_MUTEX(stat_list_mutex); | |||
39 | 39 | ||
40 | static void reset_stat_list(void) | 40 | static void reset_stat_list(void) |
41 | { | 41 | { |
42 | struct trace_stat_list *node; | 42 | struct trace_stat_list *node, *next; |
43 | struct list_head *next; | ||
44 | 43 | ||
45 | if (list_empty(&stat_list.list)) | 44 | list_for_each_entry_safe(node, next, &stat_list, list) |
46 | return; | ||
47 | |||
48 | node = list_entry(stat_list.list.next, struct trace_stat_list, list); | ||
49 | next = node->list.next; | ||
50 | |||
51 | while (&node->list != next) { | ||
52 | kfree(node); | 45 | kfree(node); |
53 | node = list_entry(next, struct trace_stat_list, list); | ||
54 | } | ||
55 | kfree(node); | ||
56 | 46 | ||
57 | INIT_LIST_HEAD(&stat_list.list); | 47 | INIT_LIST_HEAD(&stat_list); |
58 | } | 48 | } |
59 | 49 | ||
60 | void init_tracer_stat(struct tracer *trace) | 50 | void init_tracer_stat(struct tracer *trace) |
@@ -107,7 +97,7 @@ static int stat_seq_init(void) | |||
107 | } | 97 | } |
108 | 98 | ||
109 | INIT_LIST_HEAD(&new_entry->list); | 99 | INIT_LIST_HEAD(&new_entry->list); |
110 | list_add(&new_entry->list, &stat_list.list); | 100 | list_add(&new_entry->list, &stat_list); |
111 | new_entry->stat = current_tracer.stat_start(); | 101 | new_entry->stat = current_tracer.stat_start(); |
112 | 102 | ||
113 | prev_stat = new_entry->stat; | 103 | prev_stat = new_entry->stat; |
@@ -130,7 +120,7 @@ static int stat_seq_init(void) | |||
130 | if (!new_entry->stat) | 120 | if (!new_entry->stat) |
131 | break; | 121 | break; |
132 | 122 | ||
133 | list_for_each_entry(iter_entry, &stat_list.list, list) { | 123 | list_for_each_entry(iter_entry, &stat_list, list) { |
134 | /* Insertion with a descendent sorting */ | 124 | /* Insertion with a descendent sorting */ |
135 | if (current_tracer.stat_cmp(new_entry->stat, | 125 | if (current_tracer.stat_cmp(new_entry->stat, |
136 | iter_entry->stat) > 0) { | 126 | iter_entry->stat) > 0) { |
@@ -141,7 +131,7 @@ static int stat_seq_init(void) | |||
141 | 131 | ||
142 | /* The current smaller value */ | 132 | /* The current smaller value */ |
143 | } else if (list_is_last(&iter_entry->list, | 133 | } else if (list_is_last(&iter_entry->list, |
144 | &stat_list.list)) { | 134 | &stat_list)) { |
145 | list_add(&new_entry->list, &iter_entry->list); | 135 | list_add(&new_entry->list, &iter_entry->list); |
146 | break; | 136 | break; |
147 | } | 137 | } |
@@ -162,7 +152,7 @@ exit_free_list: | |||
162 | 152 | ||
163 | static void *stat_seq_start(struct seq_file *s, loff_t *pos) | 153 | static void *stat_seq_start(struct seq_file *s, loff_t *pos) |
164 | { | 154 | { |
165 | struct trace_stat_list *l = (struct trace_stat_list *)s->private; | 155 | struct list_head *l = (struct list_head *)s->private; |
166 | 156 | ||
167 | /* Prevent from tracer switch or stat_list modification */ | 157 | /* Prevent from tracer switch or stat_list modification */ |
168 | mutex_lock(&stat_list_mutex); | 158 | mutex_lock(&stat_list_mutex); |
@@ -171,14 +161,14 @@ static void *stat_seq_start(struct seq_file *s, loff_t *pos) | |||
171 | if (!*pos && current_tracer.stat_headers) | 161 | if (!*pos && current_tracer.stat_headers) |
172 | current_tracer.stat_headers(s); | 162 | current_tracer.stat_headers(s); |
173 | 163 | ||
174 | return seq_list_start(&l->list, *pos); | 164 | return seq_list_start(l, *pos); |
175 | } | 165 | } |
176 | 166 | ||
177 | static void *stat_seq_next(struct seq_file *s, void *p, loff_t *pos) | 167 | static void *stat_seq_next(struct seq_file *s, void *p, loff_t *pos) |
178 | { | 168 | { |
179 | struct trace_stat_list *l = (struct trace_stat_list *)s->private; | 169 | struct list_head *l = (struct list_head *)s->private; |
180 | 170 | ||
181 | return seq_list_next(p, &l->list, pos); | 171 | return seq_list_next(p, l, pos); |
182 | } | 172 | } |
183 | 173 | ||
184 | static void stat_seq_stop(struct seq_file *m, void *p) | 174 | static void stat_seq_stop(struct seq_file *m, void *p) |
@@ -188,8 +178,10 @@ static void stat_seq_stop(struct seq_file *m, void *p) | |||
188 | 178 | ||
189 | static int stat_seq_show(struct seq_file *s, void *v) | 179 | static int stat_seq_show(struct seq_file *s, void *v) |
190 | { | 180 | { |
191 | struct trace_stat_list *l = list_entry(v, struct trace_stat_list, list); | 181 | struct trace_stat_list *entry = |
192 | return current_tracer.stat_show(s, l->stat); | 182 | list_entry(v, struct trace_stat_list, list); |
183 | |||
184 | return current_tracer.stat_show(s, entry->stat); | ||
193 | } | 185 | } |
194 | 186 | ||
195 | static const struct seq_operations trace_stat_seq_ops = { | 187 | static const struct seq_operations trace_stat_seq_ops = { |
@@ -237,7 +229,6 @@ static int __init tracing_stat_init(void) | |||
237 | struct dentry *d_tracing; | 229 | struct dentry *d_tracing; |
238 | struct dentry *entry; | 230 | struct dentry *entry; |
239 | 231 | ||
240 | INIT_LIST_HEAD(&stat_list.list); | ||
241 | d_tracing = tracing_init_dentry(); | 232 | d_tracing = tracing_init_dentry(); |
242 | 233 | ||
243 | entry = debugfs_create_file("trace_stat", 0444, d_tracing, | 234 | entry = debugfs_create_file("trace_stat", 0444, d_tracing, |