Commit 43175623 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'trace-v5.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull more tracing updates from Steven Rostedt:

 - Add migrate-disable counter to tracing header

 - Fix error handling in event probes

 - Fix missed unlock in osnoise in error path

 - Fix merge issue with tools/bootconfig

 - Clean up bootconfig data when init memory is removed

 - Fix bootconfig to loop only on subkeys

 - Have kernel command lines override bootconfig options

 - Increase field counts for synthetic events

 - Have histograms dynamic allocate event elements to save space

 - Fixes in testing and documentation

* tag 'trace-v5.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  tracing/boot: Fix to loop on only subkeys
  selftests/ftrace: Exclude "(fault)" in testing add/remove eprobe events
  tracing: Dynamically allocate the per-elt hist_elt_data array
  tracing: synth events: increase max fields count
  tools/bootconfig: Show whole test command for each test case
  bootconfig: Fix missing return check of xbc_node_compose_key function
  tools/bootconfig: Fix tracing_on option checking in ftrace2bconf.sh
  docs: bootconfig: Add how to use bootconfig for kernel parameters
  init/bootconfig: Reorder init parameter from bootconfig and cmdline
  init: bootconfig: Remove all bootconfig data when the init memory is removed
  tracing/osnoise: Fix missed cpus_read_unlock() in start_per_cpu_kthreads()
  tracing: Fix some alloc_event_probe() error handling bugs
  tracing: Add migrate-disabled counter to tracing output.
parents f154c806 cfd79983
...@@ -178,7 +178,7 @@ update the boot loader and the kernel image itself as long as the boot ...@@ -178,7 +178,7 @@ update the boot loader and the kernel image itself as long as the boot
loader passes the correct initrd file size. If by any chance, the boot loader passes the correct initrd file size. If by any chance, the boot
loader passes a longer size, the kernel fails to find the bootconfig data. loader passes a longer size, the kernel fails to find the bootconfig data.
To do this operation, Linux kernel provides "bootconfig" command under To do this operation, Linux kernel provides ``bootconfig`` command under
tools/bootconfig, which allows admin to apply or delete the config file tools/bootconfig, which allows admin to apply or delete the config file
to/from initrd image. You can build it by the following command:: to/from initrd image. You can build it by the following command::
...@@ -196,6 +196,43 @@ To remove the config from the image, you can use -d option as below:: ...@@ -196,6 +196,43 @@ To remove the config from the image, you can use -d option as below::
Then add "bootconfig" on the normal kernel command line to tell the Then add "bootconfig" on the normal kernel command line to tell the
kernel to look for the bootconfig at the end of the initrd file. kernel to look for the bootconfig at the end of the initrd file.
Kernel parameters via Boot Config
=================================
In addition to the kernel command line, the boot config can be used for
passing the kernel parameters. All the key-value pairs under ``kernel``
key will be passed to kernel cmdline directly. Moreover, the key-value
pairs under ``init`` will be passed to init process via the cmdline.
The parameters are concatinated with user-given kernel cmdline string
as the following order, so that the command line parameter can override
bootconfig parameters (this depends on how the subsystem handles parameters
but in general, earlier parameter will be overwritten by later one.)::
[bootconfig params][cmdline params] -- [bootconfig init params][cmdline init params]
Here is an example of the bootconfig file for kernel/init parameters.::
kernel {
root = 01234567-89ab-cdef-0123-456789abcd
}
init {
splash
}
This will be copied into the kernel cmdline string as the following::
root="01234567-89ab-cdef-0123-456789abcd" -- splash
If user gives some other command line like,::
ro bootconfig -- quiet
The final kernel cmdline will be the following::
root="01234567-89ab-cdef-0123-456789abcd" ro bootconfig -- splash quiet
Config File Limitation Config File Limitation
====================== ======================
......
...@@ -153,10 +153,10 @@ static char *extra_init_args; ...@@ -153,10 +153,10 @@ static char *extra_init_args;
#ifdef CONFIG_BOOT_CONFIG #ifdef CONFIG_BOOT_CONFIG
/* Is bootconfig on command line? */ /* Is bootconfig on command line? */
static bool bootconfig_found; static bool bootconfig_found;
static bool initargs_found; static size_t initargs_offs;
#else #else
# define bootconfig_found false # define bootconfig_found false
# define initargs_found false # define initargs_offs 0
#endif #endif
static char *execute_command; static char *execute_command;
...@@ -422,9 +422,9 @@ static void __init setup_boot_config(void) ...@@ -422,9 +422,9 @@ static void __init setup_boot_config(void)
if (IS_ERR(err) || !bootconfig_found) if (IS_ERR(err) || !bootconfig_found)
return; return;
/* parse_args() stops at '--' and returns an address */ /* parse_args() stops at the next param of '--' and returns an address */
if (err) if (err)
initargs_found = true; initargs_offs = err - tmp_cmdline;
if (!data) { if (!data) {
pr_err("'bootconfig' found on command line, but no bootconfig found\n"); pr_err("'bootconfig' found on command line, but no bootconfig found\n");
...@@ -468,7 +468,12 @@ static void __init setup_boot_config(void) ...@@ -468,7 +468,12 @@ static void __init setup_boot_config(void)
return; return;
} }
#else static void __init exit_boot_config(void)
{
xbc_destroy_all();
}
#else /* !CONFIG_BOOT_CONFIG */
static void __init setup_boot_config(void) static void __init setup_boot_config(void)
{ {
...@@ -481,7 +486,11 @@ static int __init warn_bootconfig(char *str) ...@@ -481,7 +486,11 @@ static int __init warn_bootconfig(char *str)
pr_warn("WARNING: 'bootconfig' found on the kernel command line but CONFIG_BOOT_CONFIG is not set.\n"); pr_warn("WARNING: 'bootconfig' found on the kernel command line but CONFIG_BOOT_CONFIG is not set.\n");
return 0; return 0;
} }
#endif
#define exit_boot_config() do {} while (0)
#endif /* CONFIG_BOOT_CONFIG */
early_param("bootconfig", warn_bootconfig); early_param("bootconfig", warn_bootconfig);
/* Change NUL term back to "=", to make "param" the whole string. */ /* Change NUL term back to "=", to make "param" the whole string. */
...@@ -646,17 +655,22 @@ static void __init setup_command_line(char *command_line) ...@@ -646,17 +655,22 @@ static void __init setup_command_line(char *command_line)
* Append supplemental init boot args to saved_command_line * Append supplemental init boot args to saved_command_line
* so that user can check what command line options passed * so that user can check what command line options passed
* to init. * to init.
* The order should always be
* " -- "[bootconfig init-param][cmdline init-param]
*/ */
len = strlen(saved_command_line); if (initargs_offs) {
if (initargs_found) { len = xlen + initargs_offs;
saved_command_line[len++] = ' '; strcpy(saved_command_line + len, extra_init_args);
len += ilen - 4; /* strlen(extra_init_args) */
strcpy(saved_command_line + len,
boot_command_line + initargs_offs - 1);
} else { } else {
len = strlen(saved_command_line);
strcpy(saved_command_line + len, " -- "); strcpy(saved_command_line + len, " -- ");
len += 4; len += 4;
}
strcpy(saved_command_line + len, extra_init_args); strcpy(saved_command_line + len, extra_init_args);
} }
}
} }
/* /*
...@@ -1494,6 +1508,7 @@ static int __ref kernel_init(void *unused) ...@@ -1494,6 +1508,7 @@ static int __ref kernel_init(void *unused)
kprobe_free_init_mem(); kprobe_free_init_mem();
ftrace_free_init_mem(); ftrace_free_init_mem();
kgdb_free_init_mem(); kgdb_free_init_mem();
exit_boot_config();
free_initmem(); free_initmem();
mark_readonly(); mark_readonly();
......
...@@ -2603,6 +2603,15 @@ enum print_line_t trace_handle_return(struct trace_seq *s) ...@@ -2603,6 +2603,15 @@ enum print_line_t trace_handle_return(struct trace_seq *s)
} }
EXPORT_SYMBOL_GPL(trace_handle_return); EXPORT_SYMBOL_GPL(trace_handle_return);
static unsigned short migration_disable_value(void)
{
#if defined(CONFIG_SMP)
return current->migration_disabled;
#else
return 0;
#endif
}
unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status) unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status)
{ {
unsigned int trace_flags = irqs_status; unsigned int trace_flags = irqs_status;
...@@ -2621,7 +2630,8 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status) ...@@ -2621,7 +2630,8 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status)
trace_flags |= TRACE_FLAG_NEED_RESCHED; trace_flags |= TRACE_FLAG_NEED_RESCHED;
if (test_preempt_need_resched()) if (test_preempt_need_resched())
trace_flags |= TRACE_FLAG_PREEMPT_RESCHED; trace_flags |= TRACE_FLAG_PREEMPT_RESCHED;
return (trace_flags << 16) | (pc & 0xff); return (trace_flags << 16) | (min_t(unsigned int, pc & 0xff, 0xf)) |
(min_t(unsigned int, migration_disable_value(), 0xf)) << 4;
} }
struct ring_buffer_event * struct ring_buffer_event *
...@@ -4189,9 +4199,10 @@ static void print_lat_help_header(struct seq_file *m) ...@@ -4189,9 +4199,10 @@ static void print_lat_help_header(struct seq_file *m)
"# | / _----=> need-resched \n" "# | / _----=> need-resched \n"
"# || / _---=> hardirq/softirq \n" "# || / _---=> hardirq/softirq \n"
"# ||| / _--=> preempt-depth \n" "# ||| / _--=> preempt-depth \n"
"# |||| / delay \n" "# |||| / _-=> migrate-disable \n"
"# cmd pid ||||| time | caller \n" "# ||||| / delay \n"
"# \\ / ||||| \\ | / \n"); "# cmd pid |||||| time | caller \n"
"# \\ / |||||| \\ | / \n");
} }
static void print_event_info(struct array_buffer *buf, struct seq_file *m) static void print_event_info(struct array_buffer *buf, struct seq_file *m)
...@@ -4229,9 +4240,10 @@ static void print_func_help_header_irq(struct array_buffer *buf, struct seq_file ...@@ -4229,9 +4240,10 @@ static void print_func_help_header_irq(struct array_buffer *buf, struct seq_file
seq_printf(m, "# %.*s / _----=> need-resched\n", prec, space); seq_printf(m, "# %.*s / _----=> need-resched\n", prec, space);
seq_printf(m, "# %.*s| / _---=> hardirq/softirq\n", prec, space); seq_printf(m, "# %.*s| / _---=> hardirq/softirq\n", prec, space);
seq_printf(m, "# %.*s|| / _--=> preempt-depth\n", prec, space); seq_printf(m, "# %.*s|| / _--=> preempt-depth\n", prec, space);
seq_printf(m, "# %.*s||| / delay\n", prec, space); seq_printf(m, "# %.*s||| / _-=> migrate-disable\n", prec, space);
seq_printf(m, "# TASK-PID %.*s CPU# |||| TIMESTAMP FUNCTION\n", prec, " TGID "); seq_printf(m, "# %.*s|||| / delay\n", prec, space);
seq_printf(m, "# | | %.*s | |||| | |\n", prec, " | "); seq_printf(m, "# TASK-PID %.*s CPU# ||||| TIMESTAMP FUNCTION\n", prec, " TGID ");
seq_printf(m, "# | | %.*s | ||||| | |\n", prec, " | ");
} }
void void
......
...@@ -522,14 +522,14 @@ trace_boot_init_events(struct trace_array *tr, struct xbc_node *node) ...@@ -522,14 +522,14 @@ trace_boot_init_events(struct trace_array *tr, struct xbc_node *node)
if (!node) if (!node)
return; return;
/* per-event key starts with "event.GROUP.EVENT" */ /* per-event key starts with "event.GROUP.EVENT" */
xbc_node_for_each_child(node, gnode) { xbc_node_for_each_subkey(node, gnode) {
data = xbc_node_get_data(gnode); data = xbc_node_get_data(gnode);
if (!strcmp(data, "enable")) { if (!strcmp(data, "enable")) {
enable_all = true; enable_all = true;
continue; continue;
} }
enable = false; enable = false;
xbc_node_for_each_child(gnode, enode) { xbc_node_for_each_subkey(gnode, enode) {
data = xbc_node_get_data(enode); data = xbc_node_get_data(enode);
if (!strcmp(data, "enable")) { if (!strcmp(data, "enable")) {
enable = true; enable = true;
...@@ -625,7 +625,7 @@ trace_boot_init_instances(struct xbc_node *node) ...@@ -625,7 +625,7 @@ trace_boot_init_instances(struct xbc_node *node)
if (!node) if (!node)
return; return;
xbc_node_for_each_child(node, inode) { xbc_node_for_each_subkey(node, inode) {
p = xbc_node_get_data(inode); p = xbc_node_get_data(inode);
if (!p || *p == '\0') if (!p || *p == '\0')
continue; continue;
......
...@@ -151,7 +151,7 @@ static struct trace_eprobe *alloc_event_probe(const char *group, ...@@ -151,7 +151,7 @@ static struct trace_eprobe *alloc_event_probe(const char *group,
ep = kzalloc(struct_size(ep, tp.args, nargs), GFP_KERNEL); ep = kzalloc(struct_size(ep, tp.args, nargs), GFP_KERNEL);
if (!ep) { if (!ep) {
trace_event_put_ref(ep->event); trace_event_put_ref(event);
goto error; goto error;
} }
ep->event = event; ep->event = event;
...@@ -851,7 +851,8 @@ static int __trace_eprobe_create(int argc, const char *argv[]) ...@@ -851,7 +851,8 @@ static int __trace_eprobe_create(int argc, const char *argv[])
ret = PTR_ERR(ep); ret = PTR_ERR(ep);
/* This must return -ENOMEM, else there is a bug */ /* This must return -ENOMEM, else there is a bug */
WARN_ON_ONCE(ret != -ENOMEM); WARN_ON_ONCE(ret != -ENOMEM);
goto error; /* We know ep is not allocated */ ep = NULL;
goto error;
} }
argc -= 2; argv += 2; argc -= 2; argv += 2;
......
...@@ -181,6 +181,7 @@ static int trace_define_common_fields(void) ...@@ -181,6 +181,7 @@ static int trace_define_common_fields(void)
__common_field(unsigned short, type); __common_field(unsigned short, type);
__common_field(unsigned char, flags); __common_field(unsigned char, flags);
/* Holds both preempt_count and migrate_disable */
__common_field(unsigned char, preempt_count); __common_field(unsigned char, preempt_count);
__common_field(int, pid); __common_field(int, pid);
......
...@@ -508,7 +508,8 @@ struct track_data { ...@@ -508,7 +508,8 @@ struct track_data {
struct hist_elt_data { struct hist_elt_data {
char *comm; char *comm;
u64 *var_ref_vals; u64 *var_ref_vals;
char *field_var_str[SYNTH_FIELDS_MAX]; char **field_var_str;
int n_field_var_str;
}; };
struct snapshot_context { struct snapshot_context {
...@@ -1401,9 +1402,11 @@ static void hist_elt_data_free(struct hist_elt_data *elt_data) ...@@ -1401,9 +1402,11 @@ static void hist_elt_data_free(struct hist_elt_data *elt_data)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < SYNTH_FIELDS_MAX; i++) for (i = 0; i < elt_data->n_field_var_str; i++)
kfree(elt_data->field_var_str[i]); kfree(elt_data->field_var_str[i]);
kfree(elt_data->field_var_str);
kfree(elt_data->comm); kfree(elt_data->comm);
kfree(elt_data); kfree(elt_data);
} }
...@@ -1451,6 +1454,13 @@ static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt) ...@@ -1451,6 +1454,13 @@ static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt)
size = STR_VAR_LEN_MAX; size = STR_VAR_LEN_MAX;
elt_data->field_var_str = kcalloc(n_str, sizeof(char *), GFP_KERNEL);
if (!elt_data->field_var_str) {
hist_elt_data_free(elt_data);
return -EINVAL;
}
elt_data->n_field_var_str = n_str;
for (i = 0; i < n_str; i++) { for (i = 0; i < n_str; i++) {
elt_data->field_var_str[i] = kzalloc(size, GFP_KERNEL); elt_data->field_var_str[i] = kzalloc(size, GFP_KERNEL);
if (!elt_data->field_var_str[i]) { if (!elt_data->field_var_str[i]) {
......
...@@ -1548,7 +1548,7 @@ static int start_kthread(unsigned int cpu) ...@@ -1548,7 +1548,7 @@ static int start_kthread(unsigned int cpu)
static int start_per_cpu_kthreads(struct trace_array *tr) static int start_per_cpu_kthreads(struct trace_array *tr)
{ {
struct cpumask *current_mask = &save_cpumask; struct cpumask *current_mask = &save_cpumask;
int retval; int retval = 0;
int cpu; int cpu;
cpus_read_lock(); cpus_read_lock();
...@@ -1568,13 +1568,13 @@ static int start_per_cpu_kthreads(struct trace_array *tr) ...@@ -1568,13 +1568,13 @@ static int start_per_cpu_kthreads(struct trace_array *tr)
retval = start_kthread(cpu); retval = start_kthread(cpu);
if (retval) { if (retval) {
stop_per_cpu_kthreads(); stop_per_cpu_kthreads();
return retval; break;
} }
} }
cpus_read_unlock(); cpus_read_unlock();
return 0; return retval;
} }
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
......
...@@ -492,8 +492,13 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry) ...@@ -492,8 +492,13 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
trace_seq_printf(s, "%c%c%c", trace_seq_printf(s, "%c%c%c",
irqs_off, need_resched, hardsoft_irq); irqs_off, need_resched, hardsoft_irq);
if (entry->preempt_count) if (entry->preempt_count & 0xf)
trace_seq_printf(s, "%x", entry->preempt_count); trace_seq_printf(s, "%x", entry->preempt_count & 0xf);
else
trace_seq_putc(s, '.');
if (entry->preempt_count & 0xf0)
trace_seq_printf(s, "%x", entry->preempt_count >> 4);
else else
trace_seq_putc(s, '.'); trace_seq_putc(s, '.');
...@@ -656,7 +661,7 @@ int trace_print_lat_context(struct trace_iterator *iter) ...@@ -656,7 +661,7 @@ int trace_print_lat_context(struct trace_iterator *iter)
trace_seq_printf( trace_seq_printf(
s, "%16s %7d %3d %d %08x %08lx ", s, "%16s %7d %3d %d %08x %08lx ",
comm, entry->pid, iter->cpu, entry->flags, comm, entry->pid, iter->cpu, entry->flags,
entry->preempt_count, iter->idx); entry->preempt_count & 0xf, iter->idx);
} else { } else {
lat_print_generic(s, entry, iter->cpu); lat_print_generic(s, entry, iter->cpu);
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#include "trace_dynevent.h" #include "trace_dynevent.h"
#define SYNTH_SYSTEM "synthetic" #define SYNTH_SYSTEM "synthetic"
#define SYNTH_FIELDS_MAX 32 #define SYNTH_FIELDS_MAX 64
#define STR_VAR_LEN_MAX MAX_FILTER_STR_VAL /* must be multiple of sizeof(u64) */ #define STR_VAR_LEN_MAX MAX_FILTER_STR_VAL /* must be multiple of sizeof(u64) */
......
...@@ -111,9 +111,11 @@ static void xbc_show_list(void) ...@@ -111,9 +111,11 @@ static void xbc_show_list(void)
char key[XBC_KEYLEN_MAX]; char key[XBC_KEYLEN_MAX];
struct xbc_node *leaf; struct xbc_node *leaf;
const char *val; const char *val;
int ret;
xbc_for_each_key_value(leaf, val) { xbc_for_each_key_value(leaf, val) {
if (xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX) < 0) { ret = xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX);
if (ret < 0) {
fprintf(stderr, "Failed to compose key %d\n", ret); fprintf(stderr, "Failed to compose key %d\n", ret);
break; break;
} }
......
...@@ -239,8 +239,8 @@ instance_options() { # [instance-name] ...@@ -239,8 +239,8 @@ instance_options() { # [instance-name]
emit_kv $PREFIX.cpumask = $val emit_kv $PREFIX.cpumask = $val
fi fi
val=`cat $INSTANCE/tracing_on` val=`cat $INSTANCE/tracing_on`
if [ `echo $val | sed -e s/f//g`x != x ]; then if [ "$val" = "0" ]; then
emit_kv $PREFIX.tracing_on = $val emit_kv $PREFIX.tracing_on = 0
fi fi
val=`cat $INSTANCE/current_tracer` val=`cat $INSTANCE/current_tracer`
......
...@@ -26,7 +26,7 @@ trap cleanup EXIT TERM ...@@ -26,7 +26,7 @@ trap cleanup EXIT TERM
NO=1 NO=1
xpass() { # pass test command xpass() { # pass test command
echo "test case $NO ($3)... " echo "test case $NO ($*)... "
if ! ($@ && echo "\t\t[OK]"); then if ! ($@ && echo "\t\t[OK]"); then
echo "\t\t[NG]"; NG=$((NG + 1)) echo "\t\t[NG]"; NG=$((NG + 1))
fi fi
...@@ -34,7 +34,7 @@ xpass() { # pass test command ...@@ -34,7 +34,7 @@ xpass() { # pass test command
} }
xfail() { # fail test command xfail() { # fail test command
echo "test case $NO ($3)... " echo "test case $NO ($*)... "
if ! (! $@ && echo "\t\t[OK]"); then if ! (! $@ && echo "\t\t[OK]"); then
echo "\t\t[NG]"; NG=$((NG + 1)) echo "\t\t[NG]"; NG=$((NG + 1))
fi fi
......
...@@ -22,7 +22,7 @@ ls ...@@ -22,7 +22,7 @@ ls
echo 0 > events/eprobes/$EPROBE/enable echo 0 > events/eprobes/$EPROBE/enable
content=`grep '^ *ls-' trace | grep 'file='` content=`grep '^ *ls-' trace | grep 'file='`
nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."'` || true nocontent=`grep '^ *ls-' trace | grep 'file=' | grep -v -e '"/' -e '"."' -e '(fault)' ` || true
if [ -z "$content" ]; then if [ -z "$content" ]; then
exit_fail exit_fail
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment