Skip to content

Commit e7901af

Browse files
committed
Merge tag 'trace-fixes-v4.0-rc2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull seq-buf/ftrace fixes from Steven Rostedt: "This includes fixes for seq_buf_bprintf() truncation issue. It also contains fixes to ftrace when /proc/sys/kernel/ftrace_enabled and function tracing are started. Doing the following causes some issues: # echo 0 > /proc/sys/kernel/ftrace_enabled # echo function_graph > /sys/kernel/debug/tracing/current_tracer # echo 1 > /proc/sys/kernel/ftrace_enabled # echo nop > /sys/kernel/debug/tracing/current_tracer # echo function_graph > /sys/kernel/debug/tracing/current_tracer As well as with function tracing too. Pratyush Anand first reported this issue to me and supplied a patch. When I tested this on my x86 test box, it caused thousands of backtraces and warnings to appear in dmesg, which also caused a denial of service (a warning for every function that was listed). I applied Pratyush's patch but it did not fix the issue for me. I looked into it and found a slight problem with trampoline accounting. I fixed it and sent Pratyush a patch, but he said that it did not fix the issue for him. I later learned tha Pratyush was using an ARM64 server, and when I tested on my ARM board, I was able to reproduce the same issue as Pratyush. After applying his patch, it fixed the problem. The above test uncovered two different bugs, one in x86 and one in ARM and ARM64. As this looked like it would affect PowerPC, I tested it on my PPC64 box. It too broke, but neither the patch that fixed ARM or x86 fixed this box (the changes were all in generic code!). The above test, uncovered two more bugs that affected PowerPC. Again, the changes were only done to generic code. It's the way the arch code expected things to be done that was different between the archs. Some where more sensitive than others. The rest of this series fixes the PPC bugs as well" * tag 'trace-fixes-v4.0-rc2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: ftrace: Fix ftrace enable ordering of sysctl ftrace_enabled ftrace: Fix en(dis)able graph caller when en(dis)abling record via sysctl ftrace: Clear REGS_EN and TRAMP_EN flags on disabling record via sysctl seq_buf: Fix seq_buf_bprintf() truncation seq_buf: Fix seq_buf_vprintf() truncation
2 parents 36bef88 + 524a386 commit e7901af

File tree

2 files changed

+32
-12
lines changed

2 files changed

+32
-12
lines changed

kernel/trace/ftrace.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,12 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
10591059

10601060
static struct pid * const ftrace_swapper_pid = &init_struct_pid;
10611061

1062+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1063+
static int ftrace_graph_active;
1064+
#else
1065+
# define ftrace_graph_active 0
1066+
#endif
1067+
10621068
#ifdef CONFIG_DYNAMIC_FTRACE
10631069

10641070
static struct ftrace_ops *removed_ops;
@@ -2041,8 +2047,12 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
20412047
if (!ftrace_rec_count(rec))
20422048
rec->flags = 0;
20432049
else
2044-
/* Just disable the record (keep REGS state) */
2045-
rec->flags &= ~FTRACE_FL_ENABLED;
2050+
/*
2051+
* Just disable the record, but keep the ops TRAMP
2052+
* and REGS states. The _EN flags must be disabled though.
2053+
*/
2054+
rec->flags &= ~(FTRACE_FL_ENABLED | FTRACE_FL_TRAMP_EN |
2055+
FTRACE_FL_REGS_EN);
20462056
}
20472057

20482058
return FTRACE_UPDATE_MAKE_NOP;
@@ -2688,24 +2698,36 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
26882698

26892699
static void ftrace_startup_sysctl(void)
26902700
{
2701+
int command;
2702+
26912703
if (unlikely(ftrace_disabled))
26922704
return;
26932705

26942706
/* Force update next time */
26952707
saved_ftrace_func = NULL;
26962708
/* ftrace_start_up is true if we want ftrace running */
2697-
if (ftrace_start_up)
2698-
ftrace_run_update_code(FTRACE_UPDATE_CALLS);
2709+
if (ftrace_start_up) {
2710+
command = FTRACE_UPDATE_CALLS;
2711+
if (ftrace_graph_active)
2712+
command |= FTRACE_START_FUNC_RET;
2713+
ftrace_startup_enable(command);
2714+
}
26992715
}
27002716

27012717
static void ftrace_shutdown_sysctl(void)
27022718
{
2719+
int command;
2720+
27032721
if (unlikely(ftrace_disabled))
27042722
return;
27052723

27062724
/* ftrace_start_up is true if ftrace is running */
2707-
if (ftrace_start_up)
2708-
ftrace_run_update_code(FTRACE_DISABLE_CALLS);
2725+
if (ftrace_start_up) {
2726+
command = FTRACE_DISABLE_CALLS;
2727+
if (ftrace_graph_active)
2728+
command |= FTRACE_STOP_FUNC_RET;
2729+
ftrace_run_update_code(command);
2730+
}
27092731
}
27102732

27112733
static cycle_t ftrace_update_time;
@@ -5558,12 +5580,12 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
55585580

55595581
if (ftrace_enabled) {
55605582

5561-
ftrace_startup_sysctl();
5562-
55635583
/* we are starting ftrace again */
55645584
if (ftrace_ops_list != &ftrace_list_end)
55655585
update_ftrace_function();
55665586

5587+
ftrace_startup_sysctl();
5588+
55675589
} else {
55685590
/* stopping ftrace calls (just send to ftrace_stub) */
55695591
ftrace_trace_function = ftrace_stub;
@@ -5590,8 +5612,6 @@ static struct ftrace_ops graph_ops = {
55905612
ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)
55915613
};
55925614

5593-
static int ftrace_graph_active;
5594-
55955615
int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
55965616
{
55975617
return 0;

lib/seq_buf.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
6161

6262
if (s->len < s->size) {
6363
len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
64-
if (seq_buf_can_fit(s, len)) {
64+
if (s->len + len < s->size) {
6565
s->len += len;
6666
return 0;
6767
}
@@ -118,7 +118,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
118118

119119
if (s->len < s->size) {
120120
ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
121-
if (seq_buf_can_fit(s, ret)) {
121+
if (s->len + ret < s->size) {
122122
s->len += ret;
123123
return 0;
124124
}

0 commit comments

Comments
 (0)