Various tracing fixes:
- Fix a crash when having function tracing and function stack tracing on the command line. The ftrace trampolines are created as executable and read only. But the stack tracer tries to modify them with text_poke() which expects all kernel text to still be writable at boot. Keep the trampolines writable at boot, and convert them to read-only with the rest of the kernel. - A selftest was triggering in the ring buffer iterator code, that is no longer valid with the update of keeping the ring buffer writable while a iterator is reading. Just bail after three failed attempts to get an event and remove the warning and disabling of the ring buffer. - While modifying the ring buffer code, decided to remove all the unnecessary BUG() calls. -----BEGIN PGP SIGNATURE----- iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCXr1CDhQccm9zdGVkdEBn b29kbWlzLm9yZwAKCRAp5XQQmuv6qsXcAQCoL229SBrtHsn4DUO7eAQRppUT3hNw RuKzvQ56+1GccQEAh8VGCeg89uMSK6imrTujEl6VmOUdbgrD5R96yiKoGQw= =vi+k -----END PGP SIGNATURE----- Merge tag 'trace-v5.7-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace Pull more tracing fixes from Steven Rostedt: "Various tracing fixes: - Fix a crash when having function tracing and function stack tracing on the command line. The ftrace trampolines are created as executable and read only. But the stack tracer tries to modify them with text_poke() which expects all kernel text to still be writable at boot. Keep the trampolines writable at boot, and convert them to read-only with the rest of the kernel. - A selftest was triggering in the ring buffer iterator code, that is no longer valid with the update of keeping the ring buffer writable while a iterator is reading. Just bail after three failed attempts to get an event and remove the warning and disabling of the ring buffer. - While modifying the ring buffer code, decided to remove all the unnecessary BUG() calls" * tag 'trace-v5.7-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: ring-buffer: Remove all BUG() calls ring-buffer: Don't deactivate the ring buffer on failed iterator reads x86/ftrace: Have ftrace trampolines turn read-only at the end of system boot up
This commit is contained in:
commit
f44d5c4890
|
@ -56,6 +56,12 @@ struct dyn_arch_ftrace {
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE)
|
||||||
|
extern void set_ftrace_ops_ro(void);
|
||||||
|
#else
|
||||||
|
static inline void set_ftrace_ops_ro(void) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
|
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
|
||||||
static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
|
static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -407,7 +407,8 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
||||||
|
|
||||||
set_vm_flush_reset_perms(trampoline);
|
set_vm_flush_reset_perms(trampoline);
|
||||||
|
|
||||||
set_memory_ro((unsigned long)trampoline, npages);
|
if (likely(system_state != SYSTEM_BOOTING))
|
||||||
|
set_memory_ro((unsigned long)trampoline, npages);
|
||||||
set_memory_x((unsigned long)trampoline, npages);
|
set_memory_x((unsigned long)trampoline, npages);
|
||||||
return (unsigned long)trampoline;
|
return (unsigned long)trampoline;
|
||||||
fail:
|
fail:
|
||||||
|
@ -415,6 +416,32 @@ fail:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_ftrace_ops_ro(void)
|
||||||
|
{
|
||||||
|
struct ftrace_ops *ops;
|
||||||
|
unsigned long start_offset;
|
||||||
|
unsigned long end_offset;
|
||||||
|
unsigned long npages;
|
||||||
|
unsigned long size;
|
||||||
|
|
||||||
|
do_for_each_ftrace_op(ops, ftrace_ops_list) {
|
||||||
|
if (!(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
|
||||||
|
start_offset = (unsigned long)ftrace_regs_caller;
|
||||||
|
end_offset = (unsigned long)ftrace_regs_caller_end;
|
||||||
|
} else {
|
||||||
|
start_offset = (unsigned long)ftrace_caller;
|
||||||
|
end_offset = (unsigned long)ftrace_epilogue;
|
||||||
|
}
|
||||||
|
size = end_offset - start_offset;
|
||||||
|
size = size + RET_SIZE + sizeof(void *);
|
||||||
|
npages = DIV_ROUND_UP(size, PAGE_SIZE);
|
||||||
|
set_memory_ro((unsigned long)ops->trampoline, npages);
|
||||||
|
} while_for_each_ftrace_op(ops);
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned long calc_trampoline_call_offset(bool save_regs)
|
static unsigned long calc_trampoline_call_offset(bool save_regs)
|
||||||
{
|
{
|
||||||
unsigned long start_offset;
|
unsigned long start_offset;
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
#include <asm/init.h>
|
#include <asm/init.h>
|
||||||
#include <asm/uv/uv.h>
|
#include <asm/uv/uv.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
|
#include <asm/ftrace.h>
|
||||||
|
|
||||||
#include "mm_internal.h"
|
#include "mm_internal.h"
|
||||||
|
|
||||||
|
@ -1291,6 +1292,8 @@ void mark_rodata_ro(void)
|
||||||
all_end = roundup((unsigned long)_brk_end, PMD_SIZE);
|
all_end = roundup((unsigned long)_brk_end, PMD_SIZE);
|
||||||
set_memory_nx(text_end, (all_end - text_end) >> PAGE_SHIFT);
|
set_memory_nx(text_end, (all_end - text_end) >> PAGE_SHIFT);
|
||||||
|
|
||||||
|
set_ftrace_ops_ro();
|
||||||
|
|
||||||
#ifdef CONFIG_CPA_DEBUG
|
#ifdef CONFIG_CPA_DEBUG
|
||||||
printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, end);
|
printk(KERN_INFO "Testing CPA: undo %lx-%lx\n", start, end);
|
||||||
set_memory_rw(start, (end-start) >> PAGE_SHIFT);
|
set_memory_rw(start, (end-start) >> PAGE_SHIFT);
|
||||||
|
|
|
@ -210,6 +210,29 @@ struct ftrace_ops {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern struct ftrace_ops __rcu *ftrace_ops_list;
|
||||||
|
extern struct ftrace_ops ftrace_list_end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Traverse the ftrace_global_list, invoking all entries. The reason that we
|
||||||
|
* can use rcu_dereference_raw_check() is that elements removed from this list
|
||||||
|
* are simply leaked, so there is no need to interact with a grace-period
|
||||||
|
* mechanism. The rcu_dereference_raw_check() calls are needed to handle
|
||||||
|
* concurrent insertions into the ftrace_global_list.
|
||||||
|
*
|
||||||
|
* Silly Alpha and silly pointer-speculation compiler optimizations!
|
||||||
|
*/
|
||||||
|
#define do_for_each_ftrace_op(op, list) \
|
||||||
|
op = rcu_dereference_raw_check(list); \
|
||||||
|
do
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optimized for just a single item in the list (as that is the normal case).
|
||||||
|
*/
|
||||||
|
#define while_for_each_ftrace_op(op) \
|
||||||
|
while (likely(op = rcu_dereference_raw_check((op)->next)) && \
|
||||||
|
unlikely((op) != &ftrace_list_end))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Type of the current tracing.
|
* Type of the current tracing.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,28 +4,6 @@
|
||||||
|
|
||||||
#ifdef CONFIG_FUNCTION_TRACER
|
#ifdef CONFIG_FUNCTION_TRACER
|
||||||
|
|
||||||
/*
|
|
||||||
* Traverse the ftrace_global_list, invoking all entries. The reason that we
|
|
||||||
* can use rcu_dereference_raw_check() is that elements removed from this list
|
|
||||||
* are simply leaked, so there is no need to interact with a grace-period
|
|
||||||
* mechanism. The rcu_dereference_raw_check() calls are needed to handle
|
|
||||||
* concurrent insertions into the ftrace_global_list.
|
|
||||||
*
|
|
||||||
* Silly Alpha and silly pointer-speculation compiler optimizations!
|
|
||||||
*/
|
|
||||||
#define do_for_each_ftrace_op(op, list) \
|
|
||||||
op = rcu_dereference_raw_check(list); \
|
|
||||||
do
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Optimized for just a single item in the list (as that is the normal case).
|
|
||||||
*/
|
|
||||||
#define while_for_each_ftrace_op(op) \
|
|
||||||
while (likely(op = rcu_dereference_raw_check((op)->next)) && \
|
|
||||||
unlikely((op) != &ftrace_list_end))
|
|
||||||
|
|
||||||
extern struct ftrace_ops __rcu *ftrace_ops_list;
|
|
||||||
extern struct ftrace_ops ftrace_list_end;
|
|
||||||
extern struct mutex ftrace_lock;
|
extern struct mutex ftrace_lock;
|
||||||
extern struct ftrace_ops global_ops;
|
extern struct ftrace_ops global_ops;
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,7 @@ rb_event_length(struct ring_buffer_event *event)
|
||||||
case RINGBUF_TYPE_DATA:
|
case RINGBUF_TYPE_DATA:
|
||||||
return rb_event_data_length(event);
|
return rb_event_data_length(event);
|
||||||
default:
|
default:
|
||||||
BUG();
|
WARN_ON_ONCE(1);
|
||||||
}
|
}
|
||||||
/* not hit */
|
/* not hit */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -249,7 +249,7 @@ rb_event_data(struct ring_buffer_event *event)
|
||||||
{
|
{
|
||||||
if (extended_time(event))
|
if (extended_time(event))
|
||||||
event = skip_time_extend(event);
|
event = skip_time_extend(event);
|
||||||
BUG_ON(event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
|
WARN_ON_ONCE(event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
|
||||||
/* If length is in len field, then array[0] has the data */
|
/* If length is in len field, then array[0] has the data */
|
||||||
if (event->type_len)
|
if (event->type_len)
|
||||||
return (void *)&event->array[0];
|
return (void *)&event->array[0];
|
||||||
|
@ -3727,7 +3727,7 @@ rb_update_read_stamp(struct ring_buffer_per_cpu *cpu_buffer,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
RB_WARN_ON(cpu_buffer, 1);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3757,7 +3757,7 @@ rb_update_iter_read_stamp(struct ring_buffer_iter *iter,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
RB_WARN_ON(iter->cpu_buffer, 1);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4020,7 +4020,7 @@ rb_buffer_peek(struct ring_buffer_per_cpu *cpu_buffer, u64 *ts,
|
||||||
return event;
|
return event;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
RB_WARN_ON(cpu_buffer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -4034,7 +4034,6 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
|
||||||
struct ring_buffer_per_cpu *cpu_buffer;
|
struct ring_buffer_per_cpu *cpu_buffer;
|
||||||
struct ring_buffer_event *event;
|
struct ring_buffer_event *event;
|
||||||
int nr_loops = 0;
|
int nr_loops = 0;
|
||||||
bool failed = false;
|
|
||||||
|
|
||||||
if (ts)
|
if (ts)
|
||||||
*ts = 0;
|
*ts = 0;
|
||||||
|
@ -4056,19 +4055,14 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We repeat when a time extend is encountered or we hit
|
* As the writer can mess with what the iterator is trying
|
||||||
* the end of the page. Since the time extend is always attached
|
* to read, just give up if we fail to get an event after
|
||||||
* to a data event, we should never loop more than three times.
|
* three tries. The iterator is not as reliable when reading
|
||||||
* Once for going to next page, once on time extend, and
|
* the ring buffer with an active write as the consumer is.
|
||||||
* finally once to get the event.
|
* Do not warn if the three failures is reached.
|
||||||
* We should never hit the following condition more than thrice,
|
|
||||||
* unless the buffer is very small, and there's a writer
|
|
||||||
* that is causing the reader to fail getting an event.
|
|
||||||
*/
|
*/
|
||||||
if (++nr_loops > 3) {
|
if (++nr_loops > 3)
|
||||||
RB_WARN_ON(cpu_buffer, !failed);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
if (rb_per_cpu_empty(cpu_buffer))
|
if (rb_per_cpu_empty(cpu_buffer))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -4079,10 +4073,8 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
event = rb_iter_head_event(iter);
|
event = rb_iter_head_event(iter);
|
||||||
if (!event) {
|
if (!event)
|
||||||
failed = true;
|
|
||||||
goto again;
|
goto again;
|
||||||
}
|
|
||||||
|
|
||||||
switch (event->type_len) {
|
switch (event->type_len) {
|
||||||
case RINGBUF_TYPE_PADDING:
|
case RINGBUF_TYPE_PADDING:
|
||||||
|
@ -4117,7 +4109,7 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
|
||||||
return event;
|
return event;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
RB_WARN_ON(cpu_buffer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Reference in a new issue