Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568// SPDX-License-Identifier: GPL-2.0/* Include in trace.c */
#include <uapi/linux/sched/types.h>#include <linux/stringify.h>#include <linux/kthread.h>#include <linux/delay.h>#include <linux/slab.h>
static inline int trace_valid_entry(struct trace_entry *entry){ switch (entry->type) { case TRACE_FN: case TRACE_CTX: case TRACE_WAKE: case TRACE_STACK: case TRACE_PRINT: case TRACE_BRANCH: case TRACE_GRAPH_ENT: case TRACE_GRAPH_RETADDR_ENT: case TRACE_GRAPH_RET: return 1; } return 0;}
static int trace_test_buffer_cpu(struct array_buffer *buf, int cpu){ struct ring_buffer_event *event; struct trace_entry *entry; unsigned int loops = 0;
while ((event = ring_buffer_consume(buf->buffer, cpu, NULL, NULL))) { entry = ring_buffer_event_data(event);
/* * The ring buffer is a size of trace_buf_size, if * we loop more than the size, there's something wrong * with the ring buffer. */ if (loops++ > trace_buf_size) { printk(KERN_CONT ".. bad ring buffer "); goto failed; } if (!trace_valid_entry(entry)) { printk(KERN_CONT ".. invalid entry %d ", entry->type); goto failed; } } return 0;
failed: /* disable tracing */ tracing_disabled = 1; printk(KERN_CONT ".. corrupted trace buffer .. "); return -1;}
/* * Test the trace buffer to see if all the elements * are still sane. */static int __maybe_unused trace_test_buffer(struct array_buffer *buf, unsigned long *count){ unsigned long flags, cnt = 0; int cpu, ret = 0;
/* Don't allow flipping of max traces now */ local_irq_save(flags); arch_spin_lock(&buf->tr->max_lock);
cnt = ring_buffer_entries(buf->buffer);
/* * The trace_test_buffer_cpu runs a while loop to consume all data. * If the calling tracer is broken, and is constantly filling * the buffer, this will run forever, and hard lock the box. * We disable the ring buffer while we do this test to prevent * a hard lock up. */ tracing_off(); for_each_possible_cpu(cpu) { ret = trace_test_buffer_cpu(buf, cpu); if (ret) break; } tracing_on(); arch_spin_unlock(&buf->tr->max_lock); local_irq_restore(flags);
if (count) *count = cnt;
return ret;}
static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret){ printk(KERN_WARNING "Failed to init %s tracer, init returned %d\n", trace->name, init_ret);}#ifdef CONFIG_FUNCTION_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
static int trace_selftest_test_probe1_cnt;static void trace_selftest_test_probe1_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct ftrace_regs *fregs){ trace_selftest_test_probe1_cnt++;}
static int trace_selftest_test_probe2_cnt;static void trace_selftest_test_probe2_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct ftrace_regs *fregs){ trace_selftest_test_probe2_cnt++;}
static int trace_selftest_test_probe3_cnt;static void trace_selftest_test_probe3_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct ftrace_regs *fregs){ trace_selftest_test_probe3_cnt++;}
static int trace_selftest_test_global_cnt;static void trace_selftest_test_global_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct ftrace_regs *fregs){ trace_selftest_test_global_cnt++;}
static int trace_selftest_test_dyn_cnt;static void trace_selftest_test_dyn_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct ftrace_regs *fregs){ trace_selftest_test_dyn_cnt++;}
static struct ftrace_ops test_probe1 = { .func = trace_selftest_test_probe1_func,};
static struct ftrace_ops test_probe2 = { .func = trace_selftest_test_probe2_func,};
static struct ftrace_ops test_probe3 = { .func = trace_selftest_test_probe3_func,};
static void print_counts(void){ printk("(%d %d %d %d %d) ", trace_selftest_test_probe1_cnt, trace_selftest_test_probe2_cnt, trace_selftest_test_probe3_cnt, trace_selftest_test_global_cnt, trace_selftest_test_dyn_cnt);}
static void reset_counts(void){ trace_selftest_test_probe1_cnt = 0; trace_selftest_test_probe2_cnt = 0; trace_selftest_test_probe3_cnt = 0; trace_selftest_test_global_cnt = 0; trace_selftest_test_dyn_cnt = 0;}
static int trace_selftest_ops(struct trace_array *tr, int cnt){ int save_ftrace_enabled = ftrace_enabled; struct ftrace_ops *dyn_ops; char *func1_name; char *func2_name; int len1; int len2; int ret = -1;
printk(KERN_CONT "PASSED\n"); pr_info("Testing dynamic ftrace ops #%d: ", cnt);
ftrace_enabled = 1; reset_counts();
/* Handle PPC64 '.' name */ func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME); func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2); len1 = strlen(func1_name); len2 = strlen(func2_name);
/* * Probe 1 will trace function 1. * Probe 2 will trace function 2. * Probe 3 will trace functions 1 and 2. */ ftrace_set_filter(&test_probe1, func1_name, len1, 1); ftrace_set_filter(&test_probe2, func2_name, len2, 1); ftrace_set_filter(&test_probe3, func1_name, len1, 1); ftrace_set_filter(&test_probe3, func2_name, len2, 0);
register_ftrace_function(&test_probe1); register_ftrace_function(&test_probe2); register_ftrace_function(&test_probe3); /* First time we are running with main function */ if (cnt > 1) { ftrace_init_array_ops(tr, trace_selftest_test_global_func); register_ftrace_function(tr->ops); }
DYN_FTRACE_TEST_NAME();
print_counts();
if (trace_selftest_test_probe1_cnt != 1) goto out; if (trace_selftest_test_probe2_cnt != 0) goto out; if (trace_selftest_test_probe3_cnt != 1) goto out; if (cnt > 1) { if (trace_selftest_test_global_cnt == 0) goto out; }
DYN_FTRACE_TEST_NAME2();
print_counts();
if (trace_selftest_test_probe1_cnt != 1) goto out; if (trace_selftest_test_probe2_cnt != 1) goto out; if (trace_selftest_test_probe3_cnt != 2) goto out;
/* Add a dynamic probe */ dyn_ops = kzalloc_obj(*dyn_ops); if (!dyn_ops) { printk("MEMORY ERROR "); goto out; }
dyn_ops->func = trace_selftest_test_dyn_func;
register_ftrace_function(dyn_ops);
trace_selftest_test_global_cnt = 0;
DYN_FTRACE_TEST_NAME();
print_counts();
if (trace_selftest_test_probe1_cnt != 2) goto out_free; if (trace_selftest_test_probe2_cnt != 1) goto out_free; if (trace_selftest_test_probe3_cnt != 3) goto out_free; if (cnt > 1) { if (trace_selftest_test_global_cnt == 0) goto out_free; } if (trace_selftest_test_dyn_cnt == 0) goto out_free;
DYN_FTRACE_TEST_NAME2();
print_counts();
if (trace_selftest_test_probe1_cnt != 2) goto out_free; if (trace_selftest_test_probe2_cnt != 2) goto out_free; if (trace_selftest_test_probe3_cnt != 4) goto out_free;
/* Remove trace function from probe 3 */ func1_name = "!" __stringify(DYN_FTRACE_TEST_NAME); len1 = strlen(func1_name);
ftrace_set_filter(&test_probe3, func1_name, len1, 0);
DYN_FTRACE_TEST_NAME();
print_counts();
if (trace_selftest_test_probe1_cnt != 3) goto out_free; if (trace_selftest_test_probe2_cnt != 2) goto out_free; if (trace_selftest_test_probe3_cnt != 4) goto out_free; if (cnt > 1) { if (trace_selftest_test_global_cnt == 0) goto out_free; } if (trace_selftest_test_dyn_cnt == 0) goto out_free;
DYN_FTRACE_TEST_NAME2();
print_counts();
if (trace_selftest_test_probe1_cnt != 3) goto out_free; if (trace_selftest_test_probe2_cnt != 3) goto out_free; if (trace_selftest_test_probe3_cnt != 5) goto out_free;
ret = 0; out_free: unregister_ftrace_function(dyn_ops); kfree(dyn_ops);
out: /* Purposely unregister in the same order */ unregister_ftrace_function(&test_probe1); unregister_ftrace_function(&test_probe2); unregister_ftrace_function(&test_probe3); if (cnt > 1) unregister_ftrace_function(tr->ops); ftrace_reset_array_ops(tr);
/* Make sure everything is off */ reset_counts(); DYN_FTRACE_TEST_NAME(); DYN_FTRACE_TEST_NAME();
if (trace_selftest_test_probe1_cnt || trace_selftest_test_probe2_cnt || trace_selftest_test_probe3_cnt || trace_selftest_test_global_cnt || trace_selftest_test_dyn_cnt) ret = -1;
ftrace_enabled = save_ftrace_enabled;
return ret;}
/* Test dynamic code modification and ftrace filters */static int trace_selftest_startup_dynamic_tracing(struct tracer *trace, struct trace_array *tr, int (*func)(void)){ int save_ftrace_enabled = ftrace_enabled; unsigned long count; char *func_name; int ret;
/* The ftrace test PASSED */ printk(KERN_CONT "PASSED\n"); pr_info("Testing dynamic ftrace: ");
/* enable tracing, and record the filter function */ ftrace_enabled = 1;
/* passed in by parameter to fool gcc from optimizing */ func();
/* * Some archs *cough*PowerPC*cough* add characters to the * start of the function names. We simply put a '*' to * accommodate them. */ func_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
/* filter only on our function */ ftrace_set_global_filter(func_name, strlen(func_name), 1);
/* enable tracing */ ret = tracer_init(trace, tr); if (ret) { warn_failed_init_tracer(trace, ret); goto out; }
/* Sleep for a 1/10 of a second */ msleep(100);
/* we should have nothing in the buffer */ ret = trace_test_buffer(&tr->array_buffer, &count); if (ret) goto out;
if (count) { ret = -1; printk(KERN_CONT ".. filter did not filter .. "); goto out; }
/* call our function again */ func();
/* sleep again */ msleep(100);
/* stop the tracing. */ tracing_stop(); ftrace_enabled = 0;
/* check the trace buffer */ ret = trace_test_buffer(&tr->array_buffer, &count);
ftrace_enabled = 1; tracing_start();
/* we should only have one item */ if (!ret && count != 1) { trace->reset(tr); printk(KERN_CONT ".. filter failed count=%ld ..", count); ret = -1; goto out; }
/* Test the ops with global tracing running */ ret = trace_selftest_ops(tr, 1); trace->reset(tr);
out: ftrace_enabled = save_ftrace_enabled;
/* Enable tracing on all functions again */ ftrace_set_global_filter(NULL, 0, 1);
/* Test the ops with global tracing off */ if (!ret) ret = trace_selftest_ops(tr, 2);
return ret;}
static int trace_selftest_recursion_cnt;static void trace_selftest_test_recursion_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct ftrace_regs *fregs){ /* * This function is registered without the recursion safe flag. * The ftrace infrastructure should provide the recursion * protection. If not, this will crash the kernel! */ if (trace_selftest_recursion_cnt++ > 10) return; DYN_FTRACE_TEST_NAME();}
static void trace_selftest_test_recursion_safe_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct ftrace_regs *fregs){ /* * We said we would provide our own recursion. By calling * this function again, we should recurse back into this function * and count again. But this only happens if the arch supports * all of ftrace features and nothing else is using the function * tracing utility. */ if (trace_selftest_recursion_cnt++) return; DYN_FTRACE_TEST_NAME();}
static struct ftrace_ops test_rec_probe = { .func = trace_selftest_test_recursion_func, .flags = FTRACE_OPS_FL_RECURSION,};
static struct ftrace_ops test_recsafe_probe = { .func = trace_selftest_test_recursion_safe_func,};
static inttrace_selftest_function_recursion(void){ int save_ftrace_enabled = ftrace_enabled; char *func_name; int len; int ret;
/* The previous test PASSED */ pr_cont("PASSED\n"); pr_info("Testing ftrace recursion: ");
/* enable tracing, and record the filter function */ ftrace_enabled = 1;
/* Handle PPC64 '.' name */ func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); len = strlen(func_name);
ret = ftrace_set_filter(&test_rec_probe, func_name, len, 1); if (ret) { pr_cont("*Could not set filter* "); goto out; }
ret = register_ftrace_function(&test_rec_probe); if (ret) { pr_cont("*could not register callback* "); goto out; }
DYN_FTRACE_TEST_NAME();
unregister_ftrace_function(&test_rec_probe);
ret = -1; /* * Recursion allows for transitions between context, * and may call the callback twice. */ if (trace_selftest_recursion_cnt != 1 && trace_selftest_recursion_cnt != 2) { pr_cont("*callback not called once (or twice) (%d)* ", trace_selftest_recursion_cnt); goto out; }
trace_selftest_recursion_cnt = 1;
pr_cont("PASSED\n"); pr_info("Testing ftrace recursion safe: ");
ret = ftrace_set_filter(&test_recsafe_probe, func_name, len, 1); if (ret) { pr_cont("*Could not set filter* "); goto out; }
ret = register_ftrace_function(&test_recsafe_probe); if (ret) { pr_cont("*could not register callback* "); goto out; }
DYN_FTRACE_TEST_NAME();
unregister_ftrace_function(&test_recsafe_probe);
ret = -1; if (trace_selftest_recursion_cnt != 2) { pr_cont("*callback not called expected 2 times (%d)* ", trace_selftest_recursion_cnt); goto out; }
ret = 0;out: ftrace_enabled = save_ftrace_enabled;
return ret;}#else# define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })# define trace_selftest_function_recursion() ({ 0; })#endif /* CONFIG_DYNAMIC_FTRACE */
static enum { TRACE_SELFTEST_REGS_START, TRACE_SELFTEST_REGS_FOUND, TRACE_SELFTEST_REGS_NOT_FOUND,} trace_selftest_regs_stat;
static void trace_selftest_test_regs_func(unsigned long ip, unsigned long pip, struct ftrace_ops *op, struct ftrace_regs *fregs){ struct pt_regs *regs = ftrace_get_regs(fregs);
if (regs) trace_selftest_regs_stat = TRACE_SELFTEST_REGS_FOUND; else trace_selftest_regs_stat = TRACE_SELFTEST_REGS_NOT_FOUND;}
static struct ftrace_ops test_regs_probe = { .func = trace_selftest_test_regs_func, .flags = FTRACE_OPS_FL_SAVE_REGS,};
static inttrace_selftest_function_regs(void){ int save_ftrace_enabled = ftrace_enabled; char *func_name; int len; int ret; int supported = 0;
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS supported = 1;#endif
/* The previous test PASSED */ pr_cont("PASSED\n"); pr_info("Testing ftrace regs%s: ", !supported ? "(no arch support)" : "");
/* enable tracing, and record the filter function */ ftrace_enabled = 1;
/* Handle PPC64 '.' name */ func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); len = strlen(func_name);
ret = ftrace_set_filter(&test_regs_probe, func_name, len, 1); /* * If DYNAMIC_FTRACE is not set, then we just trace all functions. * This test really doesn't care. */ if (ret && ret != -ENODEV) { pr_cont("*Could not set filter* "); goto out; }
ret = register_ftrace_function(&test_regs_probe); /* * Now if the arch does not support passing regs, then this should * have failed. */ if (!supported) { if (!ret) { pr_cont("*registered save-regs without arch support* "); goto out; } test_regs_probe.flags |= FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED; ret = register_ftrace_function(&test_regs_probe); } if (ret) { pr_cont("*could not register callback* "); goto out; }
DYN_FTRACE_TEST_NAME();
unregister_ftrace_function(&test_regs_probe);
ret = -1;
switch (trace_selftest_regs_stat) { case TRACE_SELFTEST_REGS_START: pr_cont("*callback never called* "); goto out;
case TRACE_SELFTEST_REGS_FOUND: if (supported) break; pr_cont("*callback received regs without arch support* "); goto out;
case TRACE_SELFTEST_REGS_NOT_FOUND: if (!supported) break; pr_cont("*callback received NULL regs* "); goto out; }
ret = 0;out: ftrace_enabled = save_ftrace_enabled;
return ret;}
/* * Simple verification test of ftrace function tracer. * Enable ftrace, sleep 1/10 second, and then read the trace * buffer to see if all is in order. */__init inttrace_selftest_startup_function(struct tracer *trace, struct trace_array *tr){ int save_ftrace_enabled = ftrace_enabled; unsigned long count; int ret;
#ifdef CONFIG_DYNAMIC_FTRACE if (ftrace_filter_param) { printk(KERN_CONT " ... kernel command line filter set: force PASS ... "); return 0; }#endif
/* make sure msleep has been recorded */ msleep(1);
/* start the tracing */ ftrace_enabled = 1;
ret = tracer_init(trace, tr); if (ret) { warn_failed_init_tracer(trace, ret); goto out; }
/* Sleep for a 1/10 of a second */ msleep(100); /* stop the tracing. */ tracing_stop(); ftrace_enabled = 0;
/* check the trace buffer */ ret = trace_test_buffer(&tr->array_buffer, &count);
ftrace_enabled = 1; trace->reset(tr); tracing_start();
if (!ret && !count) { printk(KERN_CONT ".. no entries found .."); ret = -1; goto out; }
ret = trace_selftest_startup_dynamic_tracing(trace, tr, DYN_FTRACE_TEST_NAME); if (ret) goto out;
ret = trace_selftest_function_recursion(); if (ret) goto out;
ret = trace_selftest_function_regs(); out: ftrace_enabled = save_ftrace_enabled;
/* kill ftrace totally if we failed */ if (ret) ftrace_kill();
return ret;}#endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
#define CHAR_NUMBER 123#define SHORT_NUMBER 12345#define WORD_NUMBER 1234567890#define LONG_NUMBER 1234567890123456789LL#define ERRSTR_BUFLEN 128
struct fgraph_fixture { struct fgraph_ops gops; int store_size; const char *store_type_name; char error_str_buf[ERRSTR_BUFLEN]; char *error_str;};
static __init int store_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, struct ftrace_regs *fregs){ struct fgraph_fixture *fixture = container_of(gops, struct fgraph_fixture, gops); const char *type = fixture->store_type_name; int size = fixture->store_size; void *p;
p = fgraph_reserve_data(gops->idx, size); if (!p) { snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "Failed to reserve %s\n", type); return 0; }
switch (size) { case 1: *(char *)p = CHAR_NUMBER; break; case 2: *(short *)p = SHORT_NUMBER; break; case 4: *(int *)p = WORD_NUMBER; break; case 8: *(long long *)p = LONG_NUMBER; break; }
return 1;}
static __init void store_return(struct ftrace_graph_ret *trace, struct fgraph_ops *gops, struct ftrace_regs *fregs){ struct fgraph_fixture *fixture = container_of(gops, struct fgraph_fixture, gops); const char *type = fixture->store_type_name; long long expect = 0; long long found = -1; int size; char *p;
p = fgraph_retrieve_data(gops->idx, &size); if (!p) { snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "Failed to retrieve %s\n", type); return; } if (fixture->store_size > size) { snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "Retrieved size %d is smaller than expected %d\n", size, (int)fixture->store_size); return; }
switch (fixture->store_size) { case 1: expect = CHAR_NUMBER; found = *(char *)p; break; case 2: expect = SHORT_NUMBER; found = *(short *)p; break; case 4: expect = WORD_NUMBER; found = *(int *)p; break; case 8: expect = LONG_NUMBER; found = *(long long *)p; break; }
if (found != expect) { snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "%s returned not %lld but %lld\n", type, expect, found); return; } fixture->error_str = NULL;}
static int __init init_fgraph_fixture(struct fgraph_fixture *fixture){ char *func_name; int len;
snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "Failed to execute storage %s\n", fixture->store_type_name); fixture->error_str = fixture->error_str_buf;
func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); len = strlen(func_name);
return ftrace_set_filter(&fixture->gops.ops, func_name, len, 1);}
/* Test fgraph storage for each size */static int __init test_graph_storage_single(struct fgraph_fixture *fixture){ int size = fixture->store_size; int ret;
pr_cont("PASSED\n"); pr_info("Testing fgraph storage of %d byte%s: ", size, str_plural(size));
ret = init_fgraph_fixture(fixture); if (ret && ret != -ENODEV) { pr_cont("*Could not set filter* "); return -1; }
ret = register_ftrace_graph(&fixture->gops); if (ret) { pr_warn("Failed to init store_bytes fgraph tracing\n"); return -1; }
DYN_FTRACE_TEST_NAME();
unregister_ftrace_graph(&fixture->gops);
if (fixture->error_str) { pr_cont("*** %s ***", fixture->error_str); return -1; }
return 0;}
static struct fgraph_fixture store_bytes[4] __initdata = { [0] = { .gops = { .entryfunc = store_entry, .retfunc = store_return, }, .store_size = 1, .store_type_name = "byte", }, [1] = { .gops = { .entryfunc = store_entry, .retfunc = store_return, }, .store_size = 2, .store_type_name = "short", }, [2] = { .gops = { .entryfunc = store_entry, .retfunc = store_return, }, .store_size = 4, .store_type_name = "word", }, [3] = { .gops = { .entryfunc = store_entry, .retfunc = store_return, }, .store_size = 8, .store_type_name = "long long", },};
static __init int test_graph_storage_multi(void){ struct fgraph_fixture *fixture; bool printed = false; int i, j, ret;
pr_cont("PASSED\n"); pr_info("Testing multiple fgraph storage on a function: ");
for (i = 0; i < ARRAY_SIZE(store_bytes); i++) { fixture = &store_bytes[i]; ret = init_fgraph_fixture(fixture); if (ret && ret != -ENODEV) { pr_cont("*Could not set filter* "); printed = true; goto out2; } }
for (j = 0; j < ARRAY_SIZE(store_bytes); j++) { fixture = &store_bytes[j]; ret = register_ftrace_graph(&fixture->gops); if (ret) { pr_warn("Failed to init store_bytes fgraph tracing\n"); printed = true; goto out1; } }
DYN_FTRACE_TEST_NAME();out1: while (--j >= 0) { fixture = &store_bytes[j]; unregister_ftrace_graph(&fixture->gops);
if (fixture->error_str && !printed) { pr_cont("*** %s ***", fixture->error_str); printed = true; } }out2: while (--i >= 0) { fixture = &store_bytes[i]; ftrace_free_filter(&fixture->gops.ops);
if (fixture->error_str && !printed) { pr_cont("*** %s ***", fixture->error_str); printed = true; } } return printed ? -1 : 0;}
/* Test the storage passed across function_graph entry and return */static __init int test_graph_storage(void){ int ret;
ret = test_graph_storage_single(&store_bytes[0]); if (ret) return ret; ret = test_graph_storage_single(&store_bytes[1]); if (ret) return ret; ret = test_graph_storage_single(&store_bytes[2]); if (ret) return ret; ret = test_graph_storage_single(&store_bytes[3]); if (ret) return ret; ret = test_graph_storage_multi(); if (ret) return ret; return 0;}#elsestatic inline int test_graph_storage(void) { return 0; }#endif /* CONFIG_DYNAMIC_FTRACE */
/* Maximum number of functions to trace before diagnosing a hang */#define GRAPH_MAX_FUNC_TEST 100000000
static unsigned int graph_hang_thresh;
/* Wrap the real function entry probe to avoid possible hanging */static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace, struct fgraph_ops *gops, struct ftrace_regs *fregs){ /* This is harmlessly racy, we want to approximately detect a hang */ if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) { ftrace_graph_stop(); printk(KERN_WARNING "BUG: Function graph tracer hang!\n"); if (ftrace_dump_on_oops_enabled()) { ftrace_dump(DUMP_ALL); /* ftrace_dump() disables tracing */ tracing_on(); } return 0; }
return trace_graph_entry(trace, gops, fregs);}
static struct fgraph_ops fgraph_ops __initdata = { .entryfunc = &trace_graph_entry_watchdog, .retfunc = &trace_graph_return,};
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLSstatic struct ftrace_ops direct;#endif
/* * Pretty much the same than for the function tracer from which the selftest * has been borrowed. */__init inttrace_selftest_startup_function_graph(struct tracer *trace, struct trace_array *tr){ int ret; unsigned long count; char *func_name __maybe_unused;
#ifdef CONFIG_DYNAMIC_FTRACE if (ftrace_filter_param) { printk(KERN_CONT " ... kernel command line filter set: force PASS ... "); return 0; }#endif
/* * Simulate the init() callback but we attach a watchdog callback * to detect and recover from possible hangs */ tracing_reset_online_cpus(&tr->array_buffer); fgraph_ops.private = tr; ret = register_ftrace_graph(&fgraph_ops); if (ret) { warn_failed_init_tracer(trace, ret); goto out; } tracing_start_cmdline_record();
/* Sleep for a 1/10 of a second */ msleep(100);
/* Have we just recovered from a hang? */ if (graph_hang_thresh > GRAPH_MAX_FUNC_TEST) { disable_tracing_selftest("recovering from a hang"); ret = -1; goto out; }
tracing_stop();
/* check the trace buffer */ ret = trace_test_buffer(&tr->array_buffer, &count);
/* Need to also simulate the tr->reset to remove this fgraph_ops */ tracing_stop_cmdline_record(); unregister_ftrace_graph(&fgraph_ops);
tracing_start();
if (!ret && !count) { printk(KERN_CONT ".. no entries found .."); ret = -1; goto out; }
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS /* * These tests can take some time to run. Make sure on non PREEMPT * kernels, we do not trigger the softlockup detector. */ cond_resched();
tracing_reset_online_cpus(&tr->array_buffer); fgraph_ops.private = tr;
/* * Some archs *cough*PowerPC*cough* add characters to the * start of the function names. We simply put a '*' to * accommodate them. */ func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); ftrace_set_global_filter(func_name, strlen(func_name), 1);
/* * Register direct function together with graph tracer * and make sure we get graph trace. */ ftrace_set_filter_ip(&direct, (unsigned long)DYN_FTRACE_TEST_NAME, 0, 0); ret = register_ftrace_direct(&direct, (unsigned long)ftrace_stub_direct_tramp); if (ret) goto out;
cond_resched();
ret = register_ftrace_graph(&fgraph_ops); if (ret) { warn_failed_init_tracer(trace, ret); goto out; }
DYN_FTRACE_TEST_NAME();
count = 0;
tracing_stop(); /* check the trace buffer */ ret = trace_test_buffer(&tr->array_buffer, &count);
unregister_ftrace_graph(&fgraph_ops);
ret = unregister_ftrace_direct(&direct, (unsigned long)ftrace_stub_direct_tramp, true); if (ret) goto out;
cond_resched();
tracing_start();
if (!ret && !count) { ret = -1; goto out; }
/* Enable tracing on all functions again */ ftrace_set_global_filter(NULL, 0, 1);#endif
ret = test_graph_storage();
/* Don't test dynamic tracing, the function tracer already did */out: /* Stop it if we failed */ if (ret) ftrace_graph_stop();
return ret;}#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
#ifdef CONFIG_IRQSOFF_TRACERinttrace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr){ unsigned long save_max = tr->max_latency; unsigned long count; int ret;
/* start the tracing */ ret = tracer_init(trace, tr); if (ret) { warn_failed_init_tracer(trace, ret); return ret; }
/* reset the max latency */ tr->max_latency = 0; /* disable interrupts for a bit */ local_irq_disable(); udelay(100); local_irq_enable();
/* * Stop the tracer to avoid a warning subsequent * to buffer flipping failure because tracing_stop() * disables the tr and max buffers, making flipping impossible * in case of parallels max irqs off latencies. */ trace->stop(tr); /* stop the tracing. */ tracing_stop(); /* check both trace buffers */ ret = trace_test_buffer(&tr->array_buffer, NULL); if (!ret) ret = trace_test_buffer(&tr->snapshot_buffer, &count); trace->reset(tr); tracing_start();
if (!ret && !count) { printk(KERN_CONT ".. no entries found .."); ret = -1; }
tr->max_latency = save_max;
return ret;}#endif /* CONFIG_IRQSOFF_TRACER */
#ifdef CONFIG_PREEMPT_TRACERinttrace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr){ unsigned long save_max = tr->max_latency; unsigned long count; int ret;
/* * Now that the big kernel lock is no longer preemptible, * and this is called with the BKL held, it will always * fail. If preemption is already disabled, simply * pass the test. When the BKL is removed, or becomes * preemptible again, we will once again test this, * so keep it in. */ if (preempt_count()) { printk(KERN_CONT "can not test ... force "); return 0; }
/* start the tracing */ ret = tracer_init(trace, tr); if (ret) { warn_failed_init_tracer(trace, ret); return ret; }
/* reset the max latency */ tr->max_latency = 0; /* disable preemption for a bit */ preempt_disable(); udelay(100); preempt_enable();
/* * Stop the tracer to avoid a warning subsequent * to buffer flipping failure because tracing_stop() * disables the tr and max buffers, making flipping impossible * in case of parallels max preempt off latencies. */ trace->stop(tr); /* stop the tracing. */ tracing_stop(); /* check both trace buffers */ ret = trace_test_buffer(&tr->array_buffer, NULL); if (!ret) ret = trace_test_buffer(&tr->snapshot_buffer, &count); trace->reset(tr); tracing_start();
if (!ret && !count) { printk(KERN_CONT ".. no entries found .."); ret = -1; }
tr->max_latency = save_max;
return ret;}#endif /* CONFIG_PREEMPT_TRACER */
#if defined(CONFIG_IRQSOFF_TRACER) && defined(CONFIG_PREEMPT_TRACER)inttrace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *tr){ unsigned long save_max = tr->max_latency; unsigned long count; int ret;
/* * Now that the big kernel lock is no longer preemptible, * and this is called with the BKL held, it will always * fail. If preemption is already disabled, simply * pass the test. When the BKL is removed, or becomes * preemptible again, we will once again test this, * so keep it in. */ if (preempt_count()) { printk(KERN_CONT "can not test ... force "); return 0; }
/* start the tracing */ ret = tracer_init(trace, tr); if (ret) { warn_failed_init_tracer(trace, ret); goto out_no_start; }
/* reset the max latency */ tr->max_latency = 0;
/* disable preemption and interrupts for a bit */ preempt_disable(); local_irq_disable(); udelay(100); preempt_enable(); /* reverse the order of preempt vs irqs */ local_irq_enable();
/* * Stop the tracer to avoid a warning subsequent * to buffer flipping failure because tracing_stop() * disables the tr and max buffers, making flipping impossible * in case of parallels max irqs/preempt off latencies. */ trace->stop(tr); /* stop the tracing. */ tracing_stop(); /* check both trace buffers */ ret = trace_test_buffer(&tr->array_buffer, NULL); if (ret) goto out;
ret = trace_test_buffer(&tr->snapshot_buffer, &count); if (ret) goto out;
if (!ret && !count) { printk(KERN_CONT ".. no entries found .."); ret = -1; goto out; }
/* do the test by disabling interrupts first this time */ tr->max_latency = 0; tracing_start(); trace->start(tr);
preempt_disable(); local_irq_disable(); udelay(100); preempt_enable(); /* reverse the order of preempt vs irqs */ local_irq_enable();
trace->stop(tr); /* stop the tracing. */ tracing_stop(); /* check both trace buffers */ ret = trace_test_buffer(&tr->array_buffer, NULL); if (ret) goto out;
ret = trace_test_buffer(&tr->snapshot_buffer, &count);
if (!ret && !count) { printk(KERN_CONT ".. no entries found .."); ret = -1; goto out; }
out: tracing_start();out_no_start: trace->reset(tr); tr->max_latency = save_max;
return ret;}#endif /* CONFIG_IRQSOFF_TRACER && CONFIG_PREEMPT_TRACER */
#ifdef CONFIG_NOP_TRACERinttrace_selftest_startup_nop(struct tracer *trace, struct trace_array *tr){ /* What could possibly go wrong? */ return 0;}#endif
#ifdef CONFIG_SCHED_TRACER
struct wakeup_test_data { struct completion is_ready; int go;};
static int trace_wakeup_test_thread(void *data){ /* Make this a -deadline thread */ static const struct sched_attr attr = { .sched_policy = SCHED_DEADLINE, .sched_runtime = 100000ULL, .sched_deadline = 10000000ULL, .sched_period = 10000000ULL }; struct wakeup_test_data *x = data;
sched_setattr(current, &attr);
/* Make it know we have a new prio */ complete(&x->is_ready);
/* now go to sleep and let the test wake us up */ set_current_state(TASK_INTERRUPTIBLE); while (!x->go) { schedule(); set_current_state(TASK_INTERRUPTIBLE); }
complete(&x->is_ready);
set_current_state(TASK_INTERRUPTIBLE);
/* we are awake, now wait to disappear */ while (!kthread_should_stop()) { schedule(); set_current_state(TASK_INTERRUPTIBLE); }
__set_current_state(TASK_RUNNING);
return 0;}inttrace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr){ unsigned long save_max = tr->max_latency; struct task_struct *p; struct wakeup_test_data data; unsigned long count; int ret;
memset(&data, 0, sizeof(data));
init_completion(&data.is_ready);
/* create a -deadline thread */ p = kthread_run(trace_wakeup_test_thread, &data, "ftrace-test"); if (IS_ERR(p)) { printk(KERN_CONT "Failed to create ftrace wakeup test thread "); return -1; }
/* make sure the thread is running at -deadline policy */ wait_for_completion(&data.is_ready);
/* start the tracing */ ret = tracer_init(trace, tr); if (ret) { warn_failed_init_tracer(trace, ret); return ret; }
/* reset the max latency */ tr->max_latency = 0;
while (task_is_runnable(p)) { /* * Sleep to make sure the -deadline thread is asleep too. * On virtual machines we can't rely on timings, * but we want to make sure this test still works. */ msleep(100); }
init_completion(&data.is_ready);
data.go = 1; /* memory barrier is in the wake_up_process() */
wake_up_process(p);
/* Wait for the task to wake up */ wait_for_completion(&data.is_ready);
/* stop the tracing. */ tracing_stop(); /* check both trace buffers */ ret = trace_test_buffer(&tr->array_buffer, NULL); if (!ret) ret = trace_test_buffer(&tr->snapshot_buffer, &count);
trace->reset(tr); tracing_start();
tr->max_latency = save_max;
/* kill the thread */ kthread_stop(p);
if (!ret && !count) { printk(KERN_CONT ".. no entries found .."); ret = -1; }
return ret;}#endif /* CONFIG_SCHED_TRACER */
#ifdef CONFIG_BRANCH_TRACERinttrace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr){ unsigned long count; int ret;
/* start the tracing */ ret = tracer_init(trace, tr); if (ret) { warn_failed_init_tracer(trace, ret); return ret; }
/* Sleep for a 1/10 of a second */ msleep(100); /* stop the tracing. */ tracing_stop(); /* check the trace buffer */ ret = trace_test_buffer(&tr->array_buffer, &count); trace->reset(tr); tracing_start();
if (!ret && !count) { printk(KERN_CONT ".. no entries found .."); ret = -1; }
return ret;}#endif /* CONFIG_BRANCH_TRACER */