aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-05-12 15:20:48 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-23 14:54:04 -0400
commit37ad508419f0fdfda7b378756eb1f35cfd26d96d (patch)
tree53db6e201e605c1926adc74fa965b1a615066da8 /kernel/trace/ftrace.c
parent088b1e427dbba2af93cb6a7d39258c10ff58dd27 (diff)
ftrace - fix dynamic ftrace memory leak
The ftrace dynamic function update allocates a record to store the instruction pointers that are being modified. If the modified instruction pointer fails to update, then the record is marked as failed and nothing more is done. Worse, if the modification fails, but the record ip function is still called, it will allocate a new record and try again. In just a matter of time, will this cause a serious memory leak and crash the system. This patch plugs this memory leak. When a record fails, it is included back into the pool of records to be used. Now a record may fail over and over again, but the number of allocated records will not increase. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c45
1 files changed, 42 insertions, 3 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index a15e068535f8..8e02aa690b2b 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -188,6 +188,8 @@ static int ftraced_suspend;
188 188
189static int ftrace_record_suspend; 189static int ftrace_record_suspend;
190 190
191static struct dyn_ftrace *ftrace_free_records;
192
191static inline int 193static inline int
192notrace ftrace_ip_in_hash(unsigned long ip, unsigned long key) 194notrace ftrace_ip_in_hash(unsigned long ip, unsigned long key)
193{ 195{
@@ -211,8 +213,35 @@ ftrace_add_hash(struct dyn_ftrace *node, unsigned long key)
211 hlist_add_head(&node->node, &ftrace_hash[key]); 213 hlist_add_head(&node->node, &ftrace_hash[key]);
212} 214}
213 215
216static notrace void ftrace_free_rec(struct dyn_ftrace *rec)
217{
218 /* no locking, only called from kstop_machine */
219
220 rec->ip = (unsigned long)ftrace_free_records;
221 ftrace_free_records = rec;
222 rec->flags |= FTRACE_FL_FREE;
223}
224
214static notrace struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) 225static notrace struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
215{ 226{
227 struct dyn_ftrace *rec;
228
229 /* First check for freed records */
230 if (ftrace_free_records) {
231 rec = ftrace_free_records;
232
233 /* todo, disable tracing altogether on this warning */
234 if (unlikely(!(rec->flags & FTRACE_FL_FREE))) {
235 WARN_ON_ONCE(1);
236 ftrace_free_records = NULL;
237 return NULL;
238 }
239
240 ftrace_free_records = (void *)rec->ip;
241 memset(rec, 0, sizeof(*rec));
242 return rec;
243 }
244
216 if (ftrace_pages->index == ENTRIES_PER_PAGE) { 245 if (ftrace_pages->index == ENTRIES_PER_PAGE) {
217 if (!ftrace_pages->next) 246 if (!ftrace_pages->next)
218 return NULL; 247 return NULL;
@@ -356,8 +385,16 @@ __ftrace_replace_code(struct dyn_ftrace *rec,
356 } 385 }
357 386
358 failed = ftrace_modify_code(ip, old, new); 387 failed = ftrace_modify_code(ip, old, new);
359 if (failed) 388 if (failed) {
360 rec->flags |= FTRACE_FL_FAILED; 389 unsigned long key;
390 /* It is possible that the function hasn't been converted yet */
391 key = hash_long(ip, FTRACE_HASHBITS);
392 if (!ftrace_ip_in_hash(ip, key)) {
393 rec->flags |= FTRACE_FL_FAILED;
394 ftrace_free_rec(rec);
395 }
396
397 }
361} 398}
362 399
363static void notrace ftrace_replace_code(int enable) 400static void notrace ftrace_replace_code(int enable)
@@ -407,8 +444,10 @@ ftrace_code_disable(struct dyn_ftrace *rec)
407 call = ftrace_call_replace(ip, MCOUNT_ADDR); 444 call = ftrace_call_replace(ip, MCOUNT_ADDR);
408 445
409 failed = ftrace_modify_code(ip, call, nop); 446 failed = ftrace_modify_code(ip, call, nop);
410 if (failed) 447 if (failed) {
411 rec->flags |= FTRACE_FL_FAILED; 448 rec->flags |= FTRACE_FL_FAILED;
449 ftrace_free_rec(rec);
450 }
412} 451}
413 452
414static int notrace __ftrace_modify_code(void *data) 453static int notrace __ftrace_modify_code(void *data)