tracing fixes for v7.3:

- Fix NULL dereference when copying histogram field variable
 
   If event_hist_trigger_parse() creates an action that uses one of pseudo
   fields for its keys, the hist_data field element will have a NULL for its
   field member. When looking to match that key, the lookup uses
   key_field->field->name which will dereference a NULL pointer.
   Instead use the helper function that handles such cases: expr_field_str().
 
 - Take the trace_types_lock when dropping the buffer_meta reference
 
   The tracing_buffer_meta_open() error return drops the trace_array
   reference with __trace_array_put() instead of trace_array_put() where the
   former doesn't take the lock and the latter does.
 
 - Fix NULL pointer dereference when reading per_cpu/cpuN/buffer_meta
 
   These files are created for every possible CPU. But it only contains data
   for CPUs that have come online. If one is read for a CPU that hasn't come
   online yet, it triggers a NULL pointer dereference.
 
   Have reading of CPUs that have not come on line yet return -ENODEV.
 
 - Fix an out-of-bounds shift in the log2 histogram modifier
 
   Histograms can take a log2 modifier to have the buckets defined by log2
   increments. If a shift is greater than ULONG_MAX or above 2^63, the key
   falls into a lower order bucket.
 
   Use order_base_2() instead of "ilog2(n - 1) + 1" to have all overflowed
   keys go into the top bucket.
 
 - Fix the persistent ring buffer rb_meta_subbuf_idx() accounting
 
   The algorithm for finding the index of a sub-buffer in a persistent ring
   buffer buffer did not take into account the meta data at the beginning of
   the buffer causing the wrong index to be returned.
 
   As rb_subbufs_from_meta() does the proper accounting to find the first
   sub-buffer, use that function instead of repeating the logic (incorrectly)
   and make the calculations based off of that.
 
 - Fix the symbol name checks for the remote buffer code
 
   The remote ring buffer has a build time check to make sure its not using
   any code that will not be in the hypervisor. For various architectures,
   there has been false positive reports from this checker.
 
   Fix them.
 
 - Fix false warning in ring_buffer_map_get_reader()
 
   There is a WARN_ON() after rb_get_reader_page() if no reader is returned.
   But there are legitimate cases where this can happen. Remove the WARN_ON()
   and also a check that covers one of the legitimate cases that tries to
   exit out early. There's no need for the check if it just simply allows the
   return of NULL from rb_get_reader_page().
 
 - Fix the ignored return value from resize_buffer_duplicate_size()
 
   Some clean up of the code in tracing_snapshot_write() removed checking the
   return value of resize_buffer_duplicate_size() and if that failed it would
   not be detected.
 
 - Fix the histogram timestamps for buffered events
 
   The histogram timestamps are taken from the events that are recorded.
   It currently reads ring_buffer_event_time_stamp() but if the event is
   buffered it does not read it properly. Use tracing_event_time_stamp()
   which handles both buffered and normal events.
 
 - Do not initialize tracefs if tracing is disabled at boot
 
   If tracing fails to allocate or some other error is detected,
   tracing_disabled is set. Do not initialize tracefs in this case as it may
   expect data to be initialized but is not.
 
 - Free eventfs inode after an RCU grace period
 
   Currently eventfs_inodes are freed after a SRCU grace period as the
   iterations in the code use SRCU. There are locations that the inode may
   still be accessed from the VFS that uses RCU which does not have the same
   synchronization as SRCU. Add an RCU wait before free eventfs inodes.
 
 - Do not fail persistent and remote buffers under memory pressure
 
   As persistent and remote buffers have their own pre-allocated memory,
   there's no reason to check how much memory is available before created
   them. By checking the memory pressure, these buffers may fail to be
   created even though their memory is already present.
 
 - Account for subbuffer size when checking how much memory is available
 
   Before allocating a ring buffer, the size is checked against the current
   memory pressure of the system. But it assumes every sub-buffer is of page
   size. This is no longer the case. Use the actual sub-buffer size when
   calculating how much memory will be used.
 
 - Reject non-stack fields for synthetic stacktrace fields
 
   Stack traces are special fields and the checks currently do not do enough
   to make sure that the fields being processed as stack traces are indeed
   stack traces. Update the logic to properly detect what is or is not a
   stack trace.
 
 - Fix a crash in print_graph_function_event()
 
   When a tracer does not define static or default flags the
   tr->current_trace_flags is set to NULL. If the ring buffer is
   not cleared when switching tracers, the previous tracers events
   could be read. The function_graph entries will dereference the
   tr->current_trace_flags and cause a crash.
 
   Set the tr->current_trace_flags to a empty set of flags to prevent
   it from being NULL.
 
 - Separate tracing filter predicate count from allocation
 
   The amount allocated for the predicate program is the number of predicates
   defined plus two for adding "true" and "false" at the end. The nr_preds is
   incremented by two to accommodate the booleans but is then used as the
   limit check for number of predicates. This is incorrect as it is now two
   higher than what is expected.
 
   Use a separate variable for the size of the predicate array.
 
 - Fix the filter operator stack check
 
   The operator stack increments the pointer and then writes the content onto
   the stack. The check for overflow compared the current pointer to see if
   it was greater than the stack size before doing so. This is an off by 2
   error as the write will be at the size - 1 and the compare is done before
   the increment. Adjust the check accordingly.
 -----BEGIN PGP SIGNATURE-----
 
 iIoEABYKADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCatItoRQccm9zdGVkdEBn
 b29kbWlzLm9yZwAKCRAp5XQQmuv6qmfsAP9XviDyrl49/PBpuanB2qQzlMGqYQlb
 CwISmzgWoO1jKQEArNiSpKsIdPLfSJSLfIHAGxAZfmT42SugA4M5jqhW3Qc=
 =7KiP
 -----END PGP SIGNATURE-----

Merge tag 'trace-v7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing fixes from Steven Rostedt:

 - Fix NULL dereference when copying histogram field variable

   If event_hist_trigger_parse() creates an action that uses one of
   pseudo fields for its keys, the hist_data field element will have a
   NULL for its field member. When looking to match that key, the lookup
   uses key_field->field->name which will dereference a NULL pointer.
   Instead use the helper function that handles such cases:
   expr_field_str().

 - Take the trace_types_lock when dropping the buffer_meta reference

   The tracing_buffer_meta_open() error return drops the trace_array
   reference with __trace_array_put() instead of trace_array_put() where
   the former doesn't take the lock and the latter does.

 - Fix NULL pointer dereference when reading per_cpu/cpuN/buffer_meta

   These files are created for every possible CPU. But it only contains
   data for CPUs that have come online. If one is read for a CPU that
   hasn't come online yet, it triggers a NULL pointer dereference.

   Have reading of CPUs that have not come on line yet return -ENODEV.

 - Fix an out-of-bounds shift in the log2 histogram modifier

   Histograms can take a log2 modifier to have the buckets defined by
   log2 increments. If a shift is greater than ULONG_MAX or above 2^63,
   the key falls into a lower order bucket.

   Use order_base_2() instead of "ilog2(n - 1) + 1" to have all
   overflowed keys go into the top bucket.

 - Fix the persistent ring buffer rb_meta_subbuf_idx() accounting

   The algorithm for finding the index of a sub-buffer in a persistent
   ring buffer buffer did not take into account the meta data at the
   beginning of the buffer causing the wrong index to be returned.

   As rb_subbufs_from_meta() does the proper accounting to find the
   first sub-buffer, use that function instead of repeating the logic
   (incorrectly) and make the calculations based off of that.

 - Fix the symbol name checks for the remote buffer code

   The remote ring buffer has a build time check to make sure its not
   using any code that will not be in the hypervisor. For various
   architectures, there has been false positive reports from this
   checker.

   Fix them.

 - Fix false warning in ring_buffer_map_get_reader()

   There is a WARN_ON() after rb_get_reader_page() if no reader is
   returned. But there are legitimate cases where this can happen.
   Remove the WARN_ON() and also a check that covers one of the
   legitimate cases that tries to exit out early. There's no need for
   the check if it just simply allows the return of NULL from
   rb_get_reader_page().

 - Fix the ignored return value from resize_buffer_duplicate_size()

   Some clean up of the code in tracing_snapshot_write() removed
   checking the return value of resize_buffer_duplicate_size() and if
   that failed it would not be detected.

 - Fix the histogram timestamps for buffered events

   The histogram timestamps are taken from the events that are recorded.
   It currently reads ring_buffer_event_time_stamp() but if the event is
   buffered it does not read it properly. Use tracing_event_time_stamp()
   which handles both buffered and normal events.

 - Do not initialize tracefs if tracing is disabled at boot

   If tracing fails to allocate or some other error is detected,
   tracing_disabled is set. Do not initialize tracefs in this case as it
   may expect data to be initialized but is not.

 - Free eventfs inode after an RCU grace period

   Currently eventfs_inodes are freed after a SRCU grace period as the
   iterations in the code use SRCU. There are locations that the inode
   may still be accessed from the VFS that uses RCU which does not have
   the same synchronization as SRCU. Add an RCU wait before free eventfs
   inodes.

 - Do not fail persistent and remote buffers under memory pressure

   As persistent and remote buffers have their own pre-allocated memory,
   there's no reason to check how much memory is available before
   created them. By checking the memory pressure, these buffers may fail
   to be created even though their memory is already present.

 - Account for subbuffer size when checking how much memory is available

   Before allocating a ring buffer, the size is checked against the
   current memory pressure of the system. But it assumes every
   sub-buffer is of page size. This is no longer the case. Use the
   actual sub-buffer size when calculating how much memory will be used.

 - Reject non-stack fields for synthetic stacktrace fields

   Stack traces are special fields and the checks currently do not do
   enough to make sure that the fields being processed as stack traces
   are indeed stack traces. Update the logic to properly detect what is
   or is not a stack trace.

 - Fix a crash in print_graph_function_event()

   When a tracer does not define static or default flags the
   tr->current_trace_flags is set to NULL. If the ring buffer is not
   cleared when switching tracers, the previous tracers events could be
   read. The function_graph entries will dereference the
   tr->current_trace_flags and cause a crash.

   Set the tr->current_trace_flags to a empty set of flags to prevent it
   from being NULL.

 - Separate tracing filter predicate count from allocation

   The amount allocated for the predicate program is the number of
   predicates defined plus two for adding "true" and "false" at the end.
   The nr_preds is incremented by two to accommodate the booleans but is
   then used as the limit check for number of predicates. This is
   incorrect as it is now two higher than what is expected.

   Use a separate variable for the size of the predicate array.

 - Fix the filter operator stack check

   The operator stack increments the pointer and then writes the content
   onto the stack. The check for overflow compared the current pointer
   to see if it was greater than the stack size before doing so. This is
   an off by 2 error as the write will be at the size - 1 and the
   compare is done before the increment. Adjust the check accordingly.

* tag 'trace-v7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  tracing: Check operator stack capacity before pushing
  tracing: Keep the predicate limit separate from program capacity
  tracing: Fix crash in print_graph_function_event()
  tracing/histograms: Reject non-stacktrace fields for synthetic stacktrace fields
  ring-buffer: Use subbuf_order in available memory estimation
  ring-buffer: Skip si_mem_available() for persistent and remote buffers
  eventfs: Free the eventfs_inode after an rcu grace period too
  tracing: Do not initialize tracefs work if tracing is disabled
  tracing: Fix hist trigger timestamps for buffered events
  tracing: Fix ignored return value of resize_buffer_duplicate_size()
  ring-buffer: Fix false warning in ring_buffer_map_get_reader()
  tracing: Fix simple_ring_buffer undef check on sparc64
  tracing: Fix simple_ring_buffer undef check on parisc
  tracing: Fix empty symbol names in simple_ring_buffer undef check
  ring-buffer: Fix the sub-buffer array base in rb_meta_subbuf_idx()
  tracing: Fix the shift out of bounds in the log2 histogram modifier
  ring-buffer: Do not show buffer_meta for CPUs without a buffer
  tracing: Take trace_types_lock when dropping the buffer_meta reference
  tracing: Fix NULL dereference when copying keys for a field variable
This commit is contained in:
Linus Torvalds 2026-10-16 14:27:22 -10:00
commit e2c278bc37
7 changed files with 83 additions and 50 deletions

View File

@ -146,11 +146,12 @@ KASAN_SANITIZE_undefsyms_base.o := y
UNDEFINED_ALLOWLIST = __asan __gcov __kasan __kcsan __hwasan __sancov __sanitizer __tsan __ubsan __msan \
__aeabi_unwind_cpp __s390_indirect_jump __x86_indirect_thunk simple_ring_buffer \
$(shell $(NM) -u $(obj)/undefsyms_base.o 2>/dev/null | awk '{print $$2}')
current_thread_info_reg \
$(shell $(NM) -u $(obj)/undefsyms_base.o 2>/dev/null | awk '$$2 {print $$2}')
quiet_cmd_check_undefined = NM $<
cmd_check_undefined = \
undefsyms=$$($(NM) -u $< | grep -v $(addprefix -e , $(UNDEFINED_ALLOWLIST)) || true); \
undefsyms=$$($(NM) -u $< | awk '$$2 {print $$2}' | grep -v $(addprefix -e , $(UNDEFINED_ALLOWLIST)) || true); \
if [ -n "$$undefsyms" ]; then \
echo "Unexpected symbols in $<:" >&2; \
echo "$$undefsyms" >&2; \

View File

@ -2380,6 +2380,9 @@ int ring_buffer_meta_seq_init(struct file *file, struct trace_buffer *buffer, in
struct seq_file *m;
int ret;
if (!cpumask_test_cpu(cpu, buffer->cpumask))
return -ENODEV;
ret = seq_open(file, &rb_meta_seq_ops);
if (ret)
return ret;
@ -2440,22 +2443,33 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
unsigned long nr_pages, struct list_head *pages)
{
struct trace_buffer *buffer = cpu_buffer->buffer;
unsigned int subbuf_order = buffer->subbuf_order;
struct ring_buffer_cpu_meta *meta = NULL;
struct buffer_page *bpage, *tmp;
bool user_thread = current->mm != NULL;
struct ring_buffer_desc *desc = NULL;
bool user_thread = false;
long i;
/*
* Check if the available memory is there first.
* Note, si_mem_available() only gives us a rough estimate of available
* memory. It may not be accurate. But we don't care, we just want
* to prevent doing any allocation when it is obvious that it is
* not going to succeed.
*/
i = si_mem_available();
if (i < nr_pages)
return -ENOMEM;
if (buffer->range_addr_start) {
meta = rb_range_meta(buffer, nr_pages, cpu_buffer->cpu);
} else if (buffer->remote) {
desc = ring_buffer_desc(buffer->remote->desc, cpu_buffer->cpu);
if (!desc || WARN_ON(desc->nr_page_va != (nr_pages + 1)))
return -EINVAL;
} else {
/*
* Check if the available memory is there first.
* Note, si_mem_available() only gives us a rough estimate of available
* memory. It may not be accurate. But we don't care, we just want
* to prevent doing any allocation when it is obvious that it is
* not going to succeed.
*/
i = si_mem_available();
if (i < (nr_pages << subbuf_order))
return -ENOMEM;
user_thread = current->mm != NULL;
}
/*
* If a user thread allocates too much, and si_mem_available()
@ -2469,15 +2483,6 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
if (user_thread)
set_current_oom_origin();
if (buffer->range_addr_start)
meta = rb_range_meta(buffer, nr_pages, cpu_buffer->cpu);
if (buffer->remote) {
desc = ring_buffer_desc(buffer->remote->desc, cpu_buffer->cpu);
if (!desc || WARN_ON(desc->nr_page_va != (nr_pages + 1)))
return -EINVAL;
}
for (i = 0; i < nr_pages; i++) {
bpage = alloc_cpu_page(cpu_buffer->cpu);
@ -2513,12 +2518,11 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
bpage->id = i + 1;
cpu_buffer->subbuf_ids[i + 1] = bpage;
} else {
bpage->page = alloc_cpu_data(cpu_buffer->cpu,
cpu_buffer->buffer->subbuf_order);
bpage->page = alloc_cpu_data(cpu_buffer->cpu, subbuf_order);
if (!bpage->page)
goto free_pages;
}
bpage->order = cpu_buffer->buffer->subbuf_order;
bpage->order = subbuf_order;
if (user_thread && fatal_signal_pending(current))
goto free_pages;
@ -3627,10 +3631,8 @@ static void rb_inc_iter(struct ring_buffer_iter *iter)
/* Return the index into the sub-buffers for a given sub-buffer */
static int rb_meta_subbuf_idx(struct ring_buffer_cpu_meta *meta, void *subbuf)
{
void *subbuf_array;
void *subbuf_array = rb_subbufs_from_meta(meta);
subbuf_array = (void *)meta + sizeof(int) * meta->nr_subbufs;
subbuf_array = (void *)ALIGN((unsigned long)subbuf_array, meta->subbuf_size);
return (subbuf - subbuf_array) / meta->subbuf_size;
}
@ -7997,12 +7999,8 @@ int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu)
goto out;
}
/* Did the reader catch up with the writer? */
if (cpu_buffer->reader_page == cpu_buffer->commit_page)
goto out;
reader = rb_get_reader_page(cpu_buffer);
if (WARN_ON(!reader))
if (!reader)
goto out;
/* Check if any events were dropped */

View File

@ -99,6 +99,12 @@ struct tracers {
struct tracer_flags *flags;
};
/*
* Tracers that do not define their own flags use these empty flags,
* as tr->current_trace_flags must never be NULL.
*/
static struct tracer_flags no_tracer_flags;
/*
* To prevent the comm cache from being overwritten when no
* tracing is active, only save the comm when a trace event
@ -1318,7 +1324,12 @@ static int run_tracer_selftest(struct tracer *type)
tracing_reset_online_cpus(&tr->array_buffer);
tr->current_trace = type;
tr->current_trace_flags = type->flags ? : type->default_flags;
if (type->flags)
tr->current_trace_flags = type->flags;
else if (type->default_flags)
tr->current_trace_flags = type->default_flags;
else
tr->current_trace_flags = &no_tracer_flags;
#ifdef CONFIG_TRACER_MAX_TRACE
if (tracer_uses_snapshot(type)) {
@ -5089,7 +5100,12 @@ int tracing_set_tracer(struct trace_array *tr, const char *buf)
return ret;
}
tr->current_trace_flags = t->flags ? : t->tracer->flags;
if (t->flags)
tr->current_trace_flags = t->flags;
else if (t->tracer->flags)
tr->current_trace_flags = t->tracer->flags;
else
tr->current_trace_flags = &no_tracer_flags;
if (trace->init) {
ret = tracer_init(trace, tr);
@ -5881,7 +5897,7 @@ static int tracing_buffer_meta_open(struct inode *inode, struct file *filp)
ret = ring_buffer_meta_seq_init(filp, tr->array_buffer.buffer, cpu);
if (ret < 0)
__trace_array_put(tr);
trace_array_put(tr);
return ret;
}
@ -9287,6 +9303,12 @@ static struct notifier_block trace_module_nb = {
static __init void tracer_init_tracefs_work_func(struct work_struct *work)
{
/*
* Do not attempt to initialize tracefs if tracing was disabled or
* failed to allocate
*/
if (tracing_disabled)
return;
event_trace_init();

View File

@ -482,18 +482,17 @@ predicate_parse(const char *str, int nr_parens, int nr_preds,
int len;
int N = 0;
int i;
nr_preds += 2; /* For TRUE and FALSE */
int nr_preds_alloc = nr_preds + 2; /* For TRUE and FALSE */
op_stack = kmalloc_objs(*op_stack, nr_parens);
if (!op_stack)
return ERR_PTR(-ENOMEM);
prog_stack = kzalloc_objs(*prog_stack, nr_preds);
prog_stack = kzalloc_objs(*prog_stack, nr_preds_alloc);
if (!prog_stack) {
parse_error(pe, -ENOMEM, 0);
goto out_free;
}
inverts = kmalloc_array(nr_preds, sizeof(*inverts), GFP_KERNEL);
inverts = kmalloc_array(nr_preds_alloc, sizeof(*inverts), GFP_KERNEL);
if (!inverts) {
parse_error(pe, -ENOMEM, 0);
goto out_free;
@ -512,7 +511,7 @@ predicate_parse(const char *str, int nr_parens, int nr_preds,
switch (*next) {
case '(': /* #2 */
if (top - op_stack > nr_parens) {
if (top - op_stack >= nr_parens - 1) {
ret = -EINVAL;
goto out_free;
}

View File

@ -289,7 +289,7 @@ static u64 hist_field_log2(struct hist_field *hist_field,
u64 val = hist_fn_call(operand, elt, buffer, rbe, event);
return (u64) ilog2(roundup_pow_of_two(val));
return order_base_2(val);
}
static u64 hist_field_bucket(struct hist_field *hist_field,
@ -873,7 +873,7 @@ static u64 hist_field_timestamp(struct hist_field *hist_field,
struct hist_trigger_data *hist_data = hist_field->hist_data;
struct trace_array *tr = hist_data->event_file->tr;
u64 ts = ring_buffer_event_time_stamp(buffer, rbe);
u64 ts = tracing_event_time_stamp(buffer, rbe);
if (hist_data->attrs->ts_in_usecs && trace_clock_in_ns(tr))
ts = ns2usecs(ts);
@ -2121,7 +2121,8 @@ static int init_var_ref(struct hist_field *ref_field,
ref_field->size = var_field->size;
ref_field->is_signed = var_field->is_signed;
ref_field->flags |= var_field->flags &
(HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
(HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS |
HIST_FIELD_FL_STACKTRACE);
if (system) {
ref_field->system = kstrdup(system, GFP_KERNEL);
@ -3090,7 +3091,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
key_field = hist_data->fields[i];
if (!first)
seq_buf_putc(&s, ',');
seq_buf_puts(&s, key_field->field->name);
expr_field_str(key_field, &s);
first = false;
}
@ -3318,6 +3319,7 @@ static struct field_var *create_field_var(struct hist_trigger_data *hist_data,
ret = PTR_ERR(var);
goto err;
}
var->flags |= val->flags & HIST_FIELD_FL_STACKTRACE;
field_var = kzalloc_obj(struct field_var);
if (!field_var) {
@ -3946,7 +3948,10 @@ static int check_synth_field(struct synth_event *event,
&& field->is_dynamic)
return 0;
if (strstr(hist_field->type, "long[") && field->is_stack)
if (!!(hist_field->flags & HIST_FIELD_FL_STACKTRACE) != field->is_stack)
return -EINVAL;
if (field->is_stack)
return 0;
if (strcmp(field->type, hist_field->type) != 0) {
@ -4487,7 +4492,8 @@ static int create_var_field(struct hist_trigger_data *hist_data,
if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_EXECNAME)
update_var_execname(hist_data->fields[val_idx]);
if (!ret && hist_data->fields[val_idx]->flags &
if (!ret && !(hist_data->fields[val_idx]->flags & HIST_FIELD_FL_ALIAS) &&
hist_data->fields[val_idx]->flags &
(HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE))
hist_data->fields[val_idx]->var_str_idx = hist_data->n_var_str++;
@ -5228,7 +5234,8 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
if (hist_field->flags & HIST_FIELD_FL_VAR) {
var_idx = hist_field->var.idx;
if (hist_field->flags &
if (!(hist_field->flags & HIST_FIELD_FL_ALIAS) &&
hist_field->flags &
(HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) {
unsigned int str_start, var_str_idx, idx;
char *str, *val_str;

View File

@ -675,9 +675,12 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
if (iter->cpu_file != RING_BUFFER_ALL_CPUS)
return -EINVAL;
#endif
if (tr->allocated_snapshot)
if (tr->allocated_snapshot) {
ret = resize_buffer_duplicate_size(&tr->snapshot_buffer,
&tr->array_buffer, iter->cpu_file);
if (ret < 0)
return ret;
}
ret = tracing_arm_snapshot_locked(tr);
if (ret)

View File

@ -9,6 +9,7 @@
#include <linux/atomic.h>
#include <linux/string.h>
#include <asm/local.h>
#include <asm/page.h>
void undefsyms_base(void *p, int n);
@ -18,11 +19,13 @@ static char page[PAGE_SIZE] __aligned(PAGE_SIZE);
void undefsyms_base(void *p, int n)
{
char buffer[256] = { 0 };
u32 u = 0;
memset((char * volatile)page, 8, PAGE_SIZE);
memset((char * volatile)buffer, 8, sizeof(buffer));
memcpy((void * volatile)p, buffer, sizeof(buffer));
cmpxchg((u32 * volatile)&u, 0, 8);
cmpxchg((unsigned long *)p, 0, 8);
local_set((local_t *)p, 8);
WARN_ON(n == 0xdeadbeef);
}