tracing: Updates coming for 5.6 rc release
Subsystems (5)
Steven Rostedt
maintainercover tracing: Updates coming for 5.6 rc release
Some updates coming with 5.6 rc:
Change in API of bootconfig (before it comes live in a release)
- Have a magic value "BOOTCONFIG" in initrd to know a bootconfig exists
- Set CONFIG_BOOT_CONFIG to 'n' by default
- Show error if "bootconfig" on cmdline but not compiled in
- Prevent redefining the same value
- Have a way to append values
Synthetic event fixes:
- Switch to raw_smp_processor_id() for recording CPU value in preempt section. (No care for what the value actually is)
- Fix samples always recording u64 values
- Fix endianess
- Check number of values matches number of fields
- Fix a printing bug
Fix of trace_printk() breaking postponed start up tests
Make a function static that is only used in a single file.
Masami Hiramatsu (8):
tracing: Clear trace_state when starting trace
bootconfig: Set CONFIG_BOOT_CONFIG=n by default
bootconfig: Add bootconfig magic word for indicating bootconfig explicitly tools/bootconfig: Remove unneeded error message silencer
bootconfig: Reject subkey and value on same parent key
bootconfig: Print array as multiple commands for legacy command line
bootconfig: Prohibit re-defining value on same key
bootconfig: Add append value operator support
Qiujun Huang (1):
bootconfig: Mark boot_config_checksum() static
Steven Rostedt (VMware) (2):
tracing: Have synthetic event test use raw_smp_processor_id()
tracing: Disable trace_printk() on post poned tests
Tom Zanussi (4):
tracing: Make sure synth_event_trace() example always uses u64
tracing: Make synth_event trace functions endian-correct
tracing: Check that number of vals matches number of synth event fields
tracing: Fix number printing bug in print_synth_event()
----
Documentation/admin-guide/bootconfig.rst | 34 +++++++- include/linux/bootconfig.h | 3 + init/Kconfig | 3 +- init/main.c | 38 +++++---- kernel/trace/Kconfig | 3 +- kernel/trace/synth_event_gen_test.c | 44 +++++------ kernel/trace/trace.c | 2 + kernel/trace/trace_events_hist.c | 112 ++++++++++++++++++++++++--- lib/bootconfig.c | 36 ++++++--- tools/bootconfig/include/linux/printk.h | 5 +- tools/bootconfig/main.c | 51 +++++++----- tools/bootconfig/samples/bad-mixed-kv1.bconf | 3 + tools/bootconfig/samples/bad-mixed-kv2.bconf | 3 + tools/bootconfig/samples/bad-samekey.bconf | 6 ++ tools/bootconfig/test-bootconfig.sh | 18 ++++- 15 files changed, 271 insertions(+), 90 deletions(-) create mode 100644 tools/bootconfig/samples/bad-mixed-kv1.bconf create mode 100644 tools/bootconfig/samples/bad-mixed-kv2.bconf create mode 100644 tools/bootconfig/samples/bad-samekey.bconf
Steven Rostedt
maintainerPATCH 1/15 tracing: Make sure synth_event_trace() example always uses u64
From: Tom Zanussi <[email protected]>
synth_event_trace() is the varargs version of synth_event_trace_array(), which takes an array of u64, as do synth_event_add_val() et al.
To not only be consistent with those, but also to address the fact that synth_event_trace() expects every arg to be of the same type since it doesn't also pass in e.g. a format string, the caller needs to make sure all args are of the same type, u64. u64 is used because it needs to accomodate the largest type available in synthetic events, which is u64.
This fixes the bug reported by the kernel test robot/Rong Chen.
--- kernel/trace/synth_event_gen_test.c | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-)
kernel/trace/synth_event_gen_test.c +17 -17
@@ -111,11 +111,11 @@ static int __init test_gen_synth_cmd(void)/* Create some bogus values just for testing */ vals[0 ] =777 ;/* next_pid_field */ - vals[1 ] = (u64 )"hula hoops" ;/* next_comm_field */ + vals[1 ] = (u64 )(long )"hula hoops" ;/* next_comm_field */ vals[2 ] =1000000 ;/* ts_ns */ vals[3 ] =1000 ;/* ts_ms */ vals[4 ] =smp_processor_id ();/* cpu */ - vals[5 ] = (u64 )"thneed" ;/* my_string_field */ + vals[5 ] = (u64 )(long )"thneed" ;/* my_string_field */ vals[6 ] =598 ;/* my_int_field */ /* Now generate a gen_synth_test event */
@@ -218,11 +218,11 @@ static int __init test_empty_synth_event(void)/* Create some bogus values just for testing */ vals[0 ] =777 ;/* next_pid_field */ - vals[1 ] = (u64 )"tiddlywinks" ;/* next_comm_field */ + vals[1 ] = (u64 )(long )"tiddlywinks" ;/* next_comm_field */ vals[2 ] =1000000 ;/* ts_ns */ vals[3 ] =1000 ;/* ts_ms */ vals[4 ] =smp_processor_id ();/* cpu */ - vals[5 ] = (u64 )"thneed_2.0" ;/* my_string_field */ + vals[5 ] = (u64 )(long )"thneed_2.0" ;/* my_string_field */ vals[6 ] =399 ;/* my_int_field */ /* Now trace an empty_synth_test event */
@@ -290,11 +290,11 @@ static int __init test_create_synth_event(void)/* Create some bogus values just for testing */ vals[0 ] =777 ;/* next_pid_field */ - vals[1 ] = (u64 )"tiddlywinks" ;/* next_comm_field */ + vals[1 ] = (u64 )(long )"tiddlywinks" ;/* next_comm_field */ vals[2 ] =1000000 ;/* ts_ns */ vals[3 ] =1000 ;/* ts_ms */ vals[4 ] =smp_processor_id ();/* cpu */ - vals[5 ] = (u64 )"thneed" ;/* my_string_field */ + vals[5 ] = (u64 )(long )"thneed" ;/* my_string_field */ vals[6 ] =398 ;/* my_int_field */ /* Now generate a create_synth_test event */
@@ -330,7 +330,7 @@ static int __init test_add_next_synth_val(void) goto out;/* next_comm_field */ - ret =synth_event_add_next_val ((u64 )"slinky" , &trace_state); + ret =synth_event_add_next_val ((u64 )(long )"slinky" , &trace_state);if (ret) goto out;
@@ -350,7 +350,7 @@ static int __init test_add_next_synth_val(void) goto out;/* my_string_field */ - ret =synth_event_add_next_val ((u64 )"thneed_2.01" , &trace_state); + ret =synth_event_add_next_val ((u64 )(long )"thneed_2.01" , &trace_state);if (ret) goto out;
@@ -396,12 +396,12 @@ static int __init test_add_synth_val(void)if (ret) goto out; - ret =synth_event_add_val ("next_comm_field" , (u64 )"silly putty" , + ret =synth_event_add_val ("next_comm_field" , (u64 )(long )"silly putty" , &trace_state);if (ret) goto out; - ret =synth_event_add_val ("my_string_field" , (u64 )"thneed_9" , + ret =synth_event_add_val ("my_string_field" , (u64 )(long )"thneed_9" , &trace_state);if (ret) goto out;
@@ -423,13 +423,13 @@ static int __init test_trace_synth_event(void)/* Trace some bogus values just for testing */ ret =synth_event_trace (create_synth_test,7 ,/* number of values */ -444 ,/* next_pid_field */ - (u64 )"clackers" ,/* next_comm_field */ -1000000 ,/* ts_ns */ -1000 ,/* ts_ms */ -smp_processor_id (),/* cpu */ - (u64 )"Thneed" ,/* my_string_field */ -999 );/* my_int_field */ + (u64 )444 ,/* next_pid_field */ + (u64 )(long )"clackers" ,/* next_comm_field */ + (u64 )1000000 ,/* ts_ns */ + (u64 )1000 ,/* ts_ms */ + (u64 )smp_processor_id (),/* cpu */ + (u64 )(long )"Thneed" ,/* my_string_field */ + (u64 )999 );/* my_int_field */ return ret; }
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 2/15 tracing: Make synth_event trace functions endian-correct
In reply to Steven RostedtFrom: Tom Zanussi <[email protected]>
synth_event_trace(), synth_event_trace_array() and __synth_event_add_val() write directly into the trace buffer and need to take endianness into account, like trace_event_raw_event_synth() does.
--- kernel/trace/trace_events_hist.c | 62 +++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-)
kernel/trace/trace_events_hist.c +58 -4
@@ -1891,7 +1891,25 @@ int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...)strscpy (str_field, str_val,STR_VAR_LEN_MAX ); n_u64 +=STR_VAR_LEN_MAX /sizeof (u64); }else { - state.entry->fields[n_u64] = val; +struct synth_field *field = state.event->fields[i]; + +switch (field->size) { +case 1 : + *(u8 *)&state.entry->fields[n_u64] = (u8 )val; +break ; + +case 2 : + *(u16 *)&state.entry->fields[n_u64] = (u16 )val; +break ; + +case 4 : + *(u32 *)&state.entry->fields[n_u64] = (u32 )val; +break ; + +default : + state.entry->fields[n_u64] = val; +break ; + } n_u64++; } }
@@ -1943,7 +1961,26 @@ int synth_event_trace_array(struct trace_event_file *file, u64 *vals,strscpy (str_field, str_val,STR_VAR_LEN_MAX ); n_u64 +=STR_VAR_LEN_MAX /sizeof (u64); }else { - state.entry->fields[n_u64] = vals[i]; +struct synth_field *field = state.event->fields[i]; +u64 val = vals[i]; + +switch (field->size) { +case 1 : + *(u8 *)&state.entry->fields[n_u64] = (u8 )val; +break ; + +case 2 : + *(u16 *)&state.entry->fields[n_u64] = (u16 )val; +break ; + +case 4 : + *(u32 *)&state.entry->fields[n_u64] = (u32 )val; +break ; + +default : + state.entry->fields[n_u64] = val; +break ; + } n_u64++; } }
@@ -2062,8 +2099,25 @@ static int __synth_event_add_val(const char *field_name, u64 val, str_field = (char *)&entry->fields[field->offset];strscpy (str_field, str_val,STR_VAR_LEN_MAX ); - }else - entry->fields[field->offset] = val; + }else { +switch (field->size) { +case 1 : + *(u8 *)&trace_state->entry->fields[field->offset] = (u8 )val; +break ; + +case 2 : + *(u16 *)&trace_state->entry->fields[field->offset] = (u16 )val; +break ; + +case 4 : + *(u32 *)&trace_state->entry->fields[field->offset] = (u32 )val; +break ; + +default : + trace_state->entry->fields[field->offset] = val; +break ; + } + } out:return ret; }
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 3/15 tracing: Check that number of vals matches number of synth event fields
In reply to Steven RostedtFrom: Tom Zanussi <[email protected]>
Commit 7276531d4036('tracing: Consolidate trace() functions') inadvertently dropped the synth_event_trace() and synth_event_trace_array() checks that verify the number of values passed in matches the number of fields in the synthetic event being traced, so add them back.
--- kernel/trace/trace_events_hist.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
kernel/trace/trace_events_hist.c +12 -2
@@ -1878,6 +1878,11 @@ int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...)return ret; } +if (n_vals != state.event->n_fields) { + ret = -EINVAL ; + goto out; + } +va_start (args, n_vals);for (i =0 , n_u64 =0 ; i < state.event->n_fields; i++) {u64 val;
@@ -1914,7 +1919,7 @@ int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...) } }va_end (args); - +out:__synth_event_trace_end (&state);return ret;
@@ -1953,6 +1958,11 @@ int synth_event_trace_array(struct trace_event_file *file, u64 *vals,return ret; } +if (n_vals != state.event->n_fields) { + ret = -EINVAL ; + goto out; + } +for (i =0 , n_u64 =0 ; i < state.event->n_fields; i++) {if (state.event->fields[i]->is_string) {char *str_val = (char *)(long )vals[i];
@@ -1984,7 +1994,7 @@ int synth_event_trace_array(struct trace_event_file *file, u64 *vals, n_u64++; } } - +out:__synth_event_trace_end (&state);return ret;
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 4/15 tracing: Fix number printing bug in print_synth_event()
In reply to Steven RostedtFrom: Tom Zanussi <[email protected]>
Fix a varargs-related bug in print_synth_event() which resulted in strange output and oopses on 32-bit x86 systems. The problem is that trace_seq_printf() expects the varargs to match the format string, but print_synth_event() was always passing u64 values regardless. This results in unspecified behavior when unpacking with va_arg() in trace_seq_printf().
Add a function that takes the size into account when calling trace_seq_printf().
Before:
modprobe-1731 [003] .... 919.039758: gen_synth_test: next_pid_field=777(null)next_comm_field=hula hoops ts_ns=1000000 ts_ms=1000 cpu=3(null)my_string_field=thneed my_int_field=598(null)
After:
insmod-1136 [001] .... 36.634590: gen_synth_test: next_pid_field=777 next_comm_field=hula hoops ts_ns=1000000 ts_ms=1000 cpu=1 my_string_field=thneed my_int_field=598
--- kernel/trace/trace_events_hist.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-)
kernel/trace/trace_events_hist.c +29 -3
@@ -820,6 +820,29 @@ static const char *synth_field_fmt(char *type)return fmt; } +static void print_synth_event_num_val (struct trace_seq *s, +char *print_fmt,char *name, +int size,u64 val,char *space) +{ +switch (size) { +case 1 : +trace_seq_printf (s, print_fmt, name, (u8 )val, space); +break ; + +case 2 : +trace_seq_printf (s, print_fmt, name, (u16 )val, space); +break ; + +case 4 : +trace_seq_printf (s, print_fmt, name, (u32 )val, space); +break ; + +default : +trace_seq_printf (s, print_fmt, name, val, space); +break ; + } +} +static enum print_line_t print_synth_event (struct trace_iterator *iter,int flags,struct trace_event *event)
@@ -858,10 +881,13 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter, }else {struct trace_print_flags __flags[] = { __def_gfpflag_names, {-1 ,NULL } }; +char *space = (i == se->n_fields -1 ?"" :" " ); -trace_seq_printf (s, print_fmt, se->fields[i]->name, - entry->fields[n_u64], - i == se->n_fields -1 ?"" :" " ); +print_synth_event_num_val (s, print_fmt, + se->fields[i]->name, + se->fields[i]->size, + entry->fields[n_u64], + space);if (strcmp (se->fields[i]->type,"gfp_t" ) ==0 ) {trace_seq_puts (s," (" );
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 5/15 tracing: Have synthetic event test use raw_smp_processor_id()
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
The test code that tests synthetic event creation pushes in as one of its test fields the current CPU using "smp_processor_id()". As this is just something to see if the value is correctly passed in, and the actual CPU used does not matter, use raw_smp_processor_id(), otherwise with debug preemption enabled, a warning happens as the smp_processor_id() is called without preemption enabled.
--- kernel/trace/synth_event_gen_test.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
kernel/trace/synth_event_gen_test.c +6 -6
@@ -114,7 +114,7 @@ static int __init test_gen_synth_cmd(void) vals[1 ] = (u64 )(long )"hula hoops" ;/* next_comm_field */ vals[2 ] =1000000 ;/* ts_ns */ vals[3 ] =1000 ;/* ts_ms */ - vals[4 ] =smp_processor_id ();/* cpu */ + vals[4 ] =raw_smp_processor_id ();/* cpu */ vals[5 ] = (u64 )(long )"thneed" ;/* my_string_field */ vals[6 ] =598 ;/* my_int_field */
@@ -221,7 +221,7 @@ static int __init test_empty_synth_event(void) vals[1 ] = (u64 )(long )"tiddlywinks" ;/* next_comm_field */ vals[2 ] =1000000 ;/* ts_ns */ vals[3 ] =1000 ;/* ts_ms */ - vals[4 ] =smp_processor_id ();/* cpu */ + vals[4 ] =raw_smp_processor_id ();/* cpu */ vals[5 ] = (u64 )(long )"thneed_2.0" ;/* my_string_field */ vals[6 ] =399 ;/* my_int_field */
@@ -293,7 +293,7 @@ static int __init test_create_synth_event(void) vals[1 ] = (u64 )(long )"tiddlywinks" ;/* next_comm_field */ vals[2 ] =1000000 ;/* ts_ns */ vals[3 ] =1000 ;/* ts_ms */ - vals[4 ] =smp_processor_id ();/* cpu */ + vals[4 ] =raw_smp_processor_id ();/* cpu */ vals[5 ] = (u64 )(long )"thneed" ;/* my_string_field */ vals[6 ] =398 ;/* my_int_field */
@@ -345,7 +345,7 @@ static int __init test_add_next_synth_val(void) goto out;/* cpu */ - ret =synth_event_add_next_val (smp_processor_id (), &trace_state); + ret =synth_event_add_next_val (raw_smp_processor_id (), &trace_state);if (ret) goto out;
@@ -388,7 +388,7 @@ static int __init test_add_synth_val(void)if (ret) goto out; - ret =synth_event_add_val ("cpu" ,smp_processor_id (), &trace_state); + ret =synth_event_add_val ("cpu" ,raw_smp_processor_id (), &trace_state);if (ret) goto out;
@@ -427,7 +427,7 @@ static int __init test_trace_synth_event(void) (u64 )(long )"clackers" ,/* next_comm_field */ (u64 )1000000 ,/* ts_ns */ (u64 )1000 ,/* ts_ms */ - (u64 )smp_processor_id (),/* cpu */ + (u64 )raw_smp_processor_id (),/* cpu */ (u64 )(long )"Thneed" ,/* my_string_field */ (u64)999); /* my_int_field */return ret;
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 6/15 tracing: Disable trace_printk() on post poned tests
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
The tracing seftests checks various aspects of the tracing infrastructure, and one is filtering. If trace_printk() is active during a self test, it can cause the filtering to fail, which will disable that part of the trace.
To keep the selftests from failing because of trace_printk() calls, trace_printk() checks the variable tracing_selftest_running, and if set, it does not write to the tracing buffer.
As some tracers were registered earlier in boot, the selftest they triggered would fail because not all the infrastructure was set up for the full selftest. Thus, some of the tests were post poned to when their infrastructure was ready (namely file system code). The postpone code did not set the tracing_seftest_running variable, and could fail if a trace_printk() was added and executed during their run.
--- kernel/trace/trace.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/trace/trace.c +2 -0
@@ -1837,6 +1837,7 @@ static __init int init_trace_selftests(void)pr_info ("Running postponed tracer tests:\n" ); + tracing_selftest_running = true;list_for_each_entry_safe (p, n, &postponed_selftests, list) {/* This loop can take minutes when sanitizers are enabled, so * lets make sure we allow RCU processing.
@@ -1859,6 +1860,7 @@ static __init int init_trace_selftests(void)list_del (&p->list);kfree (p); } + tracing_selftest_running = false; out:mutex_unlock (&trace_types_lock);
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 7/15 bootconfig: Mark boot_config_checksum() static
In reply to Steven RostedtFrom: Qiujun Huang <[email protected]>
In fact, this function is only used in this file, so mark it with 'static'.
--- init/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
init/main.c +1 -1
@@ -335,7 +335,7 @@ static char * __init xbc_make_cmdline(const char *key)return new_cmdline; } -u32 boot_config_checksum (unsigned char *p,u32 size) +static u32 boot_config_checksum (unsigned char *p,u32 size) {u32 ret =0 ;
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 8/15 tracing: Clear trace_state when starting trace
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Clear trace_state data structure when starting trace in __synth_event_trace_start() internal function.
Currently trace_state is initialized only in the synth_event_trace_start() API, but the trace_state in synth_event_trace() and synth_event_trace_array() are on the stack without initialization.
This means those APIs will see wrong parameters and wil skip closing process in __synth_event_trace_end() because trace_state->disabled may be !0.
--- kernel/trace/trace_events_hist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/trace/trace_events_hist.c +2 -2
@@ -1824,6 +1824,8 @@ __synth_event_trace_start(struct trace_event_file *file,int entry_size, fields_size =0 ;int ret =0 ; +memset (trace_state,'\0' ,sizeof (*trace_state)); +/* * Normal event tracing doesn't get called at all unless the * ENABLED bit is set (which attaches the probe thus allowing
@@ -2063,8 +2065,6 @@ int synth_event_trace_start(struct trace_event_file *file,if (!trace_state)return -EINVAL ; -memset (trace_state,'\0' ,sizeof (*trace_state)); - ret =__synth_event_trace_start (file, trace_state);if (ret == -ENOENT ) ret =0 ;/* just disabled, not really an error */
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 9/15 bootconfig: Set CONFIG_BOOT_CONFIG=n by default
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Set CONFIG_BOOT_CONFIG=n by default. This also warns user if CONFIG_BOOT_CONFIG=n but "bootconfig" is given in the kernel command line.
--- init/Kconfig | 1 - init/main.c | 8 ++++++++ kernel/trace/Kconfig | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-)
init/Kconfig +0 -1
@@ -1218,7 +1218,6 @@ endif config BOOT_CONFIG bool "Boot config support" depends on BLK_DEV_INITRD - default y help Extra boot config allows system admin to pass a config file as complemental extension of kernel cmdline when booting.
init/main.c +8 -0
@@ -418,6 +418,14 @@ static void __init setup_boot_config(const char *cmdline) }#else #define setup_boot_config (cmdline) do { } while (0) + +static int __init warn_bootconfig (char *str) +{ +pr_warn ("WARNING: 'bootconfig' found on the kernel command line but CONFIG_BOOTCONFIG is not set.\n" ); +return 0 ; +} +early_param ("bootconfig" , warn_bootconfig); +#endif /* Change NUL term back to "=", to make "param" the whole string. */
kernel/trace/Kconfig +2 -1
@@ -143,7 +143,8 @@ if FTRACE config BOOTTIME_TRACING bool "Boot-time Tracing support" - depends on BOOT_CONFIG && TRACING + depends on TRACING + select BOOT_CONFIG default y help Enable developer to setup ftrace subsystem via supplemental
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 10/15 bootconfig: Add bootconfig magic word for indicating bootconfig explicitly
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Add bootconfig magic word to the end of bootconfig on initrd image for indicating explicitly the bootconfig is there. Also tools/bootconfig treats wrong size or wrong checksum or parse error as an error, because if there is a bootconfig magic word, there must be a bootconfig.
The bootconfig magic word is "#BOOTCONFIG\n", 12 bytes word. Thus the block image of the initrd file with bootconfig is as follows.
[Initrd][bootconfig][size][csum][#BOOTCONFIG\n]
--- Documentation/admin-guide/bootconfig.rst | 10 ++++-- include/linux/bootconfig.h | 3 ++ init/Kconfig | 2 +- init/main.c | 6 +++- tools/bootconfig/main.c | 43 ++++++++++++++++++------ tools/bootconfig/test-bootconfig.sh | 2 +- 6 files changed, 49 insertions(+), 17 deletions(-)
Documentation/admin-guide/bootconfig.rst +7 -3
@@ -102,9 +102,13 @@ Boot Kernel With a Boot Config ============================== Since the boot configuration file is loaded with initrd, it will be added -to the end of the initrd (initramfs) image file. The Linux kernel decodes -the last part of the initrd image in memory to get the boot configuration -data. +to the end of the initrd (initramfs) image file with size, checksum and +12-byte magic word as below. + +[initrd][bootconfig][size(u32)][checksum(u32)][#BOOTCONFIG\n] + +The Linux kernel decodes the last part of the initrd image in memory to +get the boot configuration data. Because of this "piggyback" method, there is no need to change or update the boot loader and the kernel image itself.
include/linux/bootconfig.h +3 -0
@@ -10,6 +10,9 @@#include <linux/kernel.h> #include <linux/types.h> +#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n" +#define BOOTCONFIG_MAGIC_LEN 12 +/* XBC tree node */ struct xbc_node {u16 next;
init/Kconfig +1 -1
@@ -1222,7 +1222,7 @@ config BOOT_CONFIG Extra boot config allows system admin to pass a config file as complemental extension of kernel cmdline when booting. The boot config file must be attached at the end of initramfs - with checksum and size. + with checksum, size and magic word. See <file:Documentation/admin-guide/bootconfig.rst> for details. If unsure, say Y.
init/main.c +5 -1
@@ -374,7 +374,11 @@ static void __init setup_boot_config(const char *cmdline)if (!initrd_end) goto not_found; - hdr = (u32 *)(initrd_end -8 ); + data = (char *)initrd_end -BOOTCONFIG_MAGIC_LEN ; +if (memcmp (data,BOOTCONFIG_MAGIC ,BOOTCONFIG_MAGIC_LEN )) + goto not_found; + + hdr = (u32 *)(data -8 ); size = hdr[0 ]; csum = hdr[1 ];
tools/bootconfig/main.c +32 -11
88 lines not on this page · raw message
tools/bootconfig/test-bootconfig.sh +1 -1
@@ -49,7 +49,7 @@ xpass $BOOTCONF -a $TEMPCONF $INITRD new_size=$(stat -c %s $INITRD) echo "File size check" -xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9) +xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9 + 12) echo "Apply command repeat test" xpass $BOOTCONF -a $TEMPCONF $INITRD
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 11/15 tools/bootconfig: Remove unneeded error message silencer
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Remove error message silent knob, we don't need it anymore because we can check if there is a bootconfig by checking the magic word.
If there is a magic word, but failed to load a bootconfig from initrd, there is a real problem.
--- tools/bootconfig/include/linux/printk.h | 5 +---- tools/bootconfig/main.c | 8 -------- 2 files changed, 1 insertion(+), 12 deletions(-)
tools/bootconfig/include/linux/printk.h +1 -4
@@ -4,10 +4,7 @@#include <stdio.h> -/* controllable printf */ -extern int pr_output; -#define printk (fmt, ...) \ - (pr_output ? printf(fmt, ##__VA_ARGS__) : 0) +#define printk (fmt, ...) printf(fmt, ##__VA_ARGS__)#define pr_err printk#define pr_warn printk
tools/bootconfig/main.c +0 -8
@@ -14,8 +14,6 @@#include <linux/kernel.h> #include <linux/bootconfig.h> -int pr_output =1 ; -static int xbc_show_array (struct xbc_node *node) {const char *val;
@@ -227,13 +225,7 @@ int delete_xbc(const char *path)return -errno; } -/* -* Suppress error messages in xbc_init() because it can be just a -* data which concidentally matches the size and checksum footer. -*/ - pr_output =0 ; size =load_xbc_from_initrd (fd, &buf); - pr_output =1 ;if (size <0 ) { ret = size;pr_err ("Failed to load a boot config from initrd: %d\n" , ret);
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 12/15 bootconfig: Reject subkey and value on same parent key
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Reject if a value node is mixed with subkey node on same parent key node.
A value node can not co-exist with subkey node under some key node, e.g.
key = value
key.subkey = another-value
This is not be allowed because bootconfig API is not designed to handle such case.
--- Documentation/admin-guide/bootconfig.rst | 7 +++++++ lib/bootconfig.c | 16 ++++++++++++---- tools/bootconfig/samples/bad-mixed-kv1.bconf | 3 +++ tools/bootconfig/samples/bad-mixed-kv2.bconf | 3 +++ 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 tools/bootconfig/samples/bad-mixed-kv1.bconf create mode 100644 tools/bootconfig/samples/bad-mixed-kv2.bconf
Documentation/admin-guide/bootconfig.rst +7 -0
@@ -62,6 +62,13 @@ Or more shorter, written as following:: In both styles, same key words are automatically merged when parsing it at boot time. So you can append similar trees or key-values. +Note that a sub-key and a value can not co-exist under a parent key. +For example, following config is NOT allowed.:: + + foo = value1 + foo.bar = value2 # !ERROR! subkey "bar" and value "value1" can NOT co-exist + + Comments --------
lib/bootconfig.c +12 -4
@@ -533,7 +533,7 @@ struct xbc_node *find_match_node(struct xbc_node *node, char *k)static int __init __xbc_add_key (char *k) { -struct xbc_node *node; +struct xbc_node *node, *child;if (!xbc_valid_keyword (k))return xbc_parse_error ("Invalid keyword" , k);
@@ -543,8 +543,12 @@ static int __init __xbc_add_key(char *k)if (!last_parent)/* the first level */ node =find_match_node (xbc_nodes, k); -else - node =find_match_node (xbc_node_get_child (last_parent), k); +else { + child =xbc_node_get_child (last_parent); +if (child &&xbc_node_is_value (child)) +return xbc_parse_error ("Subkey is mixed with value" , k); + node =find_match_node (child, k); + }if (node) last_parent = node;
@@ -577,7 +581,7 @@ static int __init __xbc_parse_keys(char *k)static int __init xbc_parse_kv (char **k,char *v) {struct xbc_node *prev_parent = last_parent; -struct xbc_node *node; +struct xbc_node *node, *child;char *next;int c, ret;
@@ -585,6 +589,10 @@ static int __init xbc_parse_kv(char **k, char *v)if (ret)return ret; + child =xbc_node_get_child (last_parent); +if (child &&xbc_node_is_key (child)) +return xbc_parse_error ("Value is mixed with subkey" , v); + c =__xbc_parse_value (&v, &next);if (c <0 )return c;
tools/bootconfig/samples/bad-mixed-kv1.bconf new file +3 -0
@@ -0,0 +1,3 @@ +# value -> subkey pattern +key = value +key.subkey = another-value
tools/bootconfig/samples/bad-mixed-kv2.bconf new file +3 -0
@@ -0,0 +1,3 @@ +# subkey -> value pattern +key.subkey = value +key = another-value
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 13/15 bootconfig: Print array as multiple commands for legacy command line
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Print arraied values as multiple same options for legacy kernel command line. With this rule, if the "kernel.*" and "init.*" array entries in bootconfig are printed out as multiple same options, e.g.
kernel {
console = "ttyS0,115200"
console += "tty0"
}
will be correctly converted to
console="ttyS0,115200" console="tty0"
in the kernel command line.
--- init/main.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-)
init/main.c +8 -14
@@ -268,7 +268,6 @@ static int __init xbc_snprint_cmdline(char *buf, size_t size, {struct xbc_node *knode, *vnode;char *end = buf + size; -char c ='\"' ;const char *val;int ret;
@@ -279,25 +278,20 @@ static int __init xbc_snprint_cmdline(char *buf, size_t size,return ret; vnode =xbc_node_get_child (knode); - ret =snprintf (buf,rest (buf, end),"%s%c" , xbc_namebuf, - vnode ?'=' :' ' ); -if (ret <0 ) -return ret; - buf += ret; -if (!vnode) +if (!vnode) { + ret =snprintf (buf,rest (buf, end),"%s " , xbc_namebuf); +if (ret <0 ) +return ret; + buf += ret;continue ; - - c ='\"' ; + }xbc_array_for_each_value (vnode, val) { - ret =snprintf (buf,rest (buf, end),"%c%s" , c, val); + ret =snprintf (buf,rest (buf, end),"%s=\"%s\" " , + xbc_namebuf, val);if (ret <0 )return ret; buf += ret; - c =',' ; } -if (rest (buf, end) >2 ) -strcpy (buf,"\" " ); - buf +=2 ; }return buf - (end - size);
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 14/15 bootconfig: Prohibit re-defining value on same key
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Currently, bootconfig adds a new value on the existing key to the tail of an array. But this looks a bit confusing because an admin can easily rewrite the original value in the same config file.
This rejects the following value re-definition.
key = value1
...
key = value2
You should rewrite value1 to value2 in this case.
--- Documentation/admin-guide/bootconfig.rst | 11 ++++++++++- lib/bootconfig.c | 13 ++++++++----- tools/bootconfig/samples/bad-samekey.bconf | 6 ++++++ 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 tools/bootconfig/samples/bad-samekey.bconf
Documentation/admin-guide/bootconfig.rst +10 -1
@@ -62,7 +62,16 @@ Or more shorter, written as following:: In both styles, same key words are automatically merged when parsing it at boot time. So you can append similar trees or key-values. -Note that a sub-key and a value can not co-exist under a parent key. +Same-key Values +--------------- + +It is prohibited that two or more values or arrays share a same-key. +For example,:: + + foo = bar, baz + foo = qux # !ERROR! we can not re-define same key + +Also, a sub-key and a value can not co-exist under a parent key. For example, following config is NOT allowed.:: foo = value1
lib/bootconfig.c +8 -5
@@ -581,7 +581,7 @@ static int __init __xbc_parse_keys(char *k)static int __init xbc_parse_kv (char **k,char *v) {struct xbc_node *prev_parent = last_parent; -struct xbc_node *node, *child; +struct xbc_node *child;char *next;int c, ret;
@@ -590,15 +590,18 @@ static int __init xbc_parse_kv(char **k, char *v)return ret; child =xbc_node_get_child (last_parent); -if (child &&xbc_node_is_key (child)) -return xbc_parse_error ("Value is mixed with subkey" , v); +if (child) { +if (xbc_node_is_key (child)) +return xbc_parse_error ("Value is mixed with subkey" , v); +else +return xbc_parse_error ("Value is redefined" , v); + } c =__xbc_parse_value (&v, &next);if (c <0 )return c; - node =xbc_add_sibling (v,XBC_VALUE ); -if (!node) +if (!xbc_add_sibling (v,XBC_VALUE ))return -ENOMEM ;if (c ==',' ) {/* Array */
tools/bootconfig/samples/bad-samekey.bconf new file +6 -0
@@ -0,0 +1,6 @@ +# Same key value is not allowed +key { + foo = value + bar = value2 +} +key.foo = value
Signature · 1 line
2.25.0
Steven Rostedt
maintainerPATCH 15/15 bootconfig: Add append value operator support
In reply to Steven RostedtFrom: Masami Hiramatsu <[email protected]>
Add append value operator "+=" support to bootconfig syntax. With this operator, user can add new value to the key as an entry of array instead of overwriting.
For example,
foo = bar
...
foo += baz
Then the key "foo" has "bar" and "baz" values as an array.
--- Documentation/admin-guide/bootconfig.rst | 10 +++++++++- lib/bootconfig.c | 15 +++++++++++---- tools/bootconfig/test-bootconfig.sh | 16 ++++++++++++++-- 3 files changed, 34 insertions(+), 7 deletions(-)
Documentation/admin-guide/bootconfig.rst +9 -1
@@ -71,7 +71,15 @@ For example,:: foo = bar, baz foo = qux # !ERROR! we can not re-define same key -Also, a sub-key and a value can not co-exist under a parent key. +If you want to append the value to existing key as an array member, +you can use ``+=`` operator. For example:: + + foo = bar, baz + foo += qux + +In this case, the key ``foo`` has ``bar``, ``baz`` and ``qux``. + +However, a sub-key and a value can not co-exist under a parent key. For example, following config is NOT allowed.:: foo = value1
lib/bootconfig.c +11 -4
@@ -578,7 +578,7 @@ static int __init __xbc_parse_keys(char *k)return __xbc_add_key (k); } -static int __init xbc_parse_kv (char **k,char *v) +static int __init xbc_parse_kv (char **k,char *v,int op) {struct xbc_node *prev_parent = last_parent;struct xbc_node *child;
@@ -593,7 +593,7 @@ static int __init xbc_parse_kv(char **k, char *v)if (child) {if (xbc_node_is_key (child))return xbc_parse_error ("Value is mixed with subkey" , v); -else +else if (op =='=' )return xbc_parse_error ("Value is redefined" , v); }
@@ -774,7 +774,7 @@ int __init xbc_init(char *buf) p = buf; do { - q = strpbrk(p, "{}=;\n#"); + q = strpbrk(p, "{}=+;\n#"); if (!q) { p = skip_spaces(p); if (*p != '\0')
@@ -785,8 +785,15 @@ int __init xbc_init(char *buf) c = *q; *q++ ='\0' ;switch (c) { +case '+' : +if (*q++ !='=' ) { + ret =xbc_parse_error ("Wrong '+' operator" , + q -2 ); +break ; + } +/* Fall through */ case '=' : - ret =xbc_parse_kv (&p, q); + ret =xbc_parse_kv (&p, q, c);break ;case '{' : ret =xbc_open_brace (&p, q);
tools/bootconfig/test-bootconfig.sh +14 -2
@@ -9,7 +9,7 @@ TEMPCONF=`mktemp temp-XXXX.bconf` NG=0 cleanup() { - rm -f $INITRD $TEMPCONF + rm -f $INITRD $TEMPCONF $OUTFILE exit $NG }
@@ -71,7 +71,6 @@ printf " \0\0\0 \0\0\0" >> $INITRD $BOOTCONF -a $TEMPCONF $INITRD > $OUTFILE 2>&1 xfail grep -i "failed" $OUTFILE xfail grep -i "error" $OUTFILE -rm $OUTFILE echo "Max node number check"
@@ -96,6 +95,19 @@ truncate -s 32764 $TEMPCONF echo "\"" >> $TEMPCONF # add 2 bytes + terminal ('\"\n\0') xpass $BOOTCONF -a $TEMPCONF $INITRD +echo "Adding same-key values" +cat > $TEMPCONF << EOF +key = bar, baz +key += qux +EOF +echo > $INITRD + +xpass $BOOTCONF -a $TEMPCONF $INITRD +$BOOTCONF $INITRD > $OUTFILE +xpass grep -q "bar" $OUTFILE +xpass grep -q "baz" $OUTFILE +xpass grep -q "qux" $OUTFILE + echo "=== expected failure cases ===" for i in samples/bad-* ; do xfail $BOOTCONF -a $i $INITRD
Signature · 1 line
2.25.0