diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index fcdc744c245eb..369efc569238f 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -762,28 +762,32 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) #define SHORT_NUMBER 12345 #define WORD_NUMBER 1234567890 #define LONG_NUMBER 1234567890123456789LL - -static int fgraph_store_size __initdata; -static const char *fgraph_store_type_name __initdata; -static char *fgraph_error_str __initdata; -static char fgraph_error_str_buf[128] __initdata; +#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) { - const char *type = fgraph_store_type_name; - int size = fgraph_store_size; + 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(fgraph_error_str_buf, sizeof(fgraph_error_str_buf), + snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "Failed to reserve %s\n", type); - fgraph_error_str = fgraph_error_str_buf; return 0; } - switch (fgraph_store_size) { + switch (size) { case 1: *(char *)p = BYTE_NUMBER; break; @@ -804,7 +808,8 @@ static __init int store_entry(struct ftrace_graph_ent *trace, static __init void store_return(struct ftrace_graph_ret *trace, struct fgraph_ops *gops) { - const char *type = fgraph_store_type_name; + 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; @@ -812,20 +817,18 @@ static __init void store_return(struct ftrace_graph_ret *trace, p = fgraph_retrieve_data(gops->idx, &size); if (!p) { - snprintf(fgraph_error_str_buf, sizeof(fgraph_error_str_buf), + snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "Failed to retrieve %s\n", type); - fgraph_error_str = fgraph_error_str_buf; return; } - if (fgraph_store_size > size) { - snprintf(fgraph_error_str_buf, sizeof(fgraph_error_str_buf), + if (fixture->store_size > size) { + snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "Retrieved size %d is smaller than expected %d\n", - size, (int)fgraph_store_size); - fgraph_error_str = fgraph_error_str_buf; + size, (int)fixture->store_size); return; } - switch (fgraph_store_size) { + switch (fixture->store_size) { case 1: expect = BYTE_NUMBER; found = *(char *)p; @@ -845,45 +848,44 @@ static __init void store_return(struct ftrace_graph_ret *trace, } if (found != expect) { - snprintf(fgraph_error_str_buf, sizeof(fgraph_error_str_buf), + snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, "%s returned not %lld but %lld\n", type, expect, found); - fgraph_error_str = fgraph_error_str_buf; return; } - fgraph_error_str = NULL; + fixture->error_str = NULL; } -static struct fgraph_ops store_bytes __initdata = { - .entryfunc = store_entry, - .retfunc = store_return, -}; - -static int __init test_graph_storage_type(const char *name, int size) +static int __init init_fgraph_fixture(struct fgraph_fixture *fixture) { char *func_name; int len; - int ret; - fgraph_store_type_name = name; - fgraph_store_size = size; + snprintf(fixture->error_str_buf, ERRSTR_BUFLEN, + "Failed to execute storage %s\n", fixture->store_type_name); + fixture->error_str = fixture->error_str_buf; - snprintf(fgraph_error_str_buf, sizeof(fgraph_error_str_buf), - "Failed to execute storage %s\n", name); - fgraph_error_str = fgraph_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, size > 1 ? "s" : ""); - func_name = "*" __stringify(DYN_FTRACE_TEST_NAME); - len = strlen(func_name); - - ret = ftrace_set_filter(&store_bytes.ops, func_name, len, 1); + ret = init_fgraph_fixture(fixture); if (ret && ret != -ENODEV) { pr_cont("*Could not set filter* "); return -1; } - ret = register_ftrace_graph(&store_bytes); + ret = register_ftrace_graph(&fixture->gops); if (ret) { pr_warn("Failed to init store_bytes fgraph tracing\n"); return -1; @@ -891,30 +893,109 @@ static int __init test_graph_storage_type(const char *name, int size) DYN_FTRACE_TEST_NAME(); - unregister_ftrace_graph(&store_bytes); + unregister_ftrace_graph(&fixture->gops); - if (fgraph_error_str) { - pr_cont("*** %s ***", fgraph_error_str); + 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, 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 out; + } + + ret = register_ftrace_graph(&fixture->gops); + if (ret) { + pr_warn("Failed to init store_bytes fgraph tracing\n"); + printed = true; + goto out; + } + } + + DYN_FTRACE_TEST_NAME(); +out: + while (--i >= 0) { + fixture = &store_bytes[i]; + unregister_ftrace_graph(&fixture->gops); + + 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_type("byte", 1); + 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_type("short", 2); + ret = test_graph_storage_single(&store_bytes[2]); if (ret) return ret; - ret = test_graph_storage_type("word", 4); + ret = test_graph_storage_single(&store_bytes[3]); if (ret) return ret; - ret = test_graph_storage_type("long long", 8); + ret = test_graph_storage_multi(); if (ret) return ret; return 0;