Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'ftrace-v6.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull ftrace fixes from Steven Rostedt:
"A couple of fixes to function graph infrastructure:

- Fix allocation of idle shadow stack allocation during hotplug

If function graph tracing is started when a CPU is offline, if it
were come online during the trace then the idle task that
represents the CPU will not get a shadow stack allocated for it.
This means all function graph hooks that happen while that idle
task is running (including in interrupt mode) will have all its
events dropped.

Switch over to the CPU hotplug mechanism that will have any newly
brought on line CPU get a callback that can allocate the shadow
stack for its idle task.

- Fix allocation size of the ret_stack_list array

When function graph tracing converted over to allowing more than
one user at a time, it had to convert its shadow stack from an
array of ret_stack structures to an array of unsigned longs. The
shadow stacks are allocated in batches of 32 at a time and assigned
to every running task. The batch is held by the ret_stack_list
array.

But when the conversion happened, instead of allocating an array of
32 pointers, it was allocated as a ret_stack itself (PAGE_SIZE).
This ret_stack_list gets passed to a function that iterates over
what it believes is its size defined by the
FTRACE_RETSTACK_ALLOC_SIZE macro (which is 32).

Luckily (PAGE_SIZE) is greater than 32 * sizeof(long), otherwise
this would have been an array overflow. This still should be fixed
and the ret_stack_list should be allocated to the size it is
expected to be as someday it may end up being bigger than
SHADOW_STACK_SIZE"

* tag 'ftrace-v6.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
fgraph: Allocate ret_stack_list with proper size
fgraph: Use CPU hotplug mechanism to initialize idle shadow stacks

+23 -8
+23 -8
kernel/trace/fgraph.c
··· 1160 1160 static int start_graph_tracing(void) 1161 1161 { 1162 1162 unsigned long **ret_stack_list; 1163 - int ret, cpu; 1163 + int ret; 1164 1164 1165 - ret_stack_list = kmalloc(SHADOW_STACK_SIZE, GFP_KERNEL); 1165 + ret_stack_list = kcalloc(FTRACE_RETSTACK_ALLOC_SIZE, 1166 + sizeof(*ret_stack_list), GFP_KERNEL); 1166 1167 1167 1168 if (!ret_stack_list) 1168 1169 return -ENOMEM; 1169 - 1170 - /* The cpu_boot init_task->ret_stack will never be freed */ 1171 - for_each_online_cpu(cpu) { 1172 - if (!idle_task(cpu)->ret_stack) 1173 - ftrace_graph_init_idle_task(idle_task(cpu), cpu); 1174 - } 1175 1170 1176 1171 do { 1177 1172 ret = alloc_retstack_tasklist(ret_stack_list); ··· 1237 1242 fgraph_direct_gops = &fgraph_stub; 1238 1243 } 1239 1244 1245 + /* The cpu_boot init_task->ret_stack will never be freed */ 1246 + static int fgraph_cpu_init(unsigned int cpu) 1247 + { 1248 + if (!idle_task(cpu)->ret_stack) 1249 + ftrace_graph_init_idle_task(idle_task(cpu), cpu); 1250 + return 0; 1251 + } 1252 + 1240 1253 int register_ftrace_graph(struct fgraph_ops *gops) 1241 1254 { 1255 + static bool fgraph_initialized; 1242 1256 int command = 0; 1243 1257 int ret = 0; 1244 1258 int i = -1; 1245 1259 1246 1260 mutex_lock(&ftrace_lock); 1261 + 1262 + if (!fgraph_initialized) { 1263 + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "fgraph_idle_init", 1264 + fgraph_cpu_init, NULL); 1265 + if (ret < 0) { 1266 + pr_warn("fgraph: Error to init cpu hotplug support\n"); 1267 + return ret; 1268 + } 1269 + fgraph_initialized = true; 1270 + ret = 0; 1271 + } 1247 1272 1248 1273 if (!fgraph_array[0]) { 1249 1274 /* The array must always have real data on it */