linux/lib/dynamic_debug.c

1457 lines
37 KiB
C
Raw Normal View History

/*
* lib/dynamic_debug.c
*
* make pr_debug()/dev_dbg() calls runtime configurable based upon their
* source module.
*
* Copyright (C) 2008 Jason Baron <jbaron@redhat.com>
* By Greg Banks <gnb@melbourne.sgi.com>
* Copyright (c) 2008 Silicon Graphics Inc. All Rights Reserved.
* Copyright (C) 2011 Bart Van Assche. All Rights Reserved.
* Copyright (C) 2013 Du, Changbin <changbin.du@gmail.com>
*/
#define pr_fmt(fmt) "dyndbg: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kallsyms.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <linux/sysctl.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/parser.h>
#include <linux/string_helpers.h>
#include <linux/uaccess.h>
#include <linux/dynamic_debug.h>
#include <linux/debugfs.h>
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
#include <linux/slab.h>
#include <linux/jump_label.h>
#include <linux/hardirq.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/netdevice.h>
#include <rdma/ib_verbs.h>
extern struct _ddebug __start___dyndbg[];
extern struct _ddebug __stop___dyndbg[];
extern struct ddebug_class_map __start___dyndbg_classes[];
extern struct ddebug_class_map __stop___dyndbg_classes[];
struct ddebug_table {
struct list_head link, maps;
const char *mod_name;
unsigned int num_ddebugs;
struct _ddebug *ddebugs;
};
struct ddebug_query {
const char *filename;
const char *module;
const char *function;
const char *format;
const char *class_string;
unsigned int first_lineno, last_lineno;
};
struct ddebug_iter {
struct ddebug_table *table;
int idx;
};
struct flag_settings {
unsigned int flags;
unsigned int mask;
};
static DEFINE_MUTEX(ddebug_lock);
static LIST_HEAD(ddebug_tables);
static int verbose;
module_param(verbose, int, 0644);
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
MODULE_PARM_DESC(verbose, " dynamic_debug/control processing "
"( 0 = off (default), 1 = module add/rm, 2 = >control summary, 3 = parsing, 4 = per-site changes)");
/* Return the path relative to source root */
static inline const char *trim_prefix(const char *path)
{
int skip = strlen(__FILE__) - strlen("lib/dynamic_debug.c");
if (strncmp(path, __FILE__, skip))
skip = 0; /* prefix mismatch, don't skip */
return path + skip;
}
static struct { unsigned flag:8; char opt_char; } opt_array[] = {
{ _DPRINTK_FLAGS_PRINT, 'p' },
{ _DPRINTK_FLAGS_INCL_MODNAME, 'm' },
{ _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' },
{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
{ _DPRINTK_FLAGS_INCL_TID, 't' },
{ _DPRINTK_FLAGS_NONE, '_' },
};
struct flagsbuf { char buf[ARRAY_SIZE(opt_array)+1]; };
/* format a string into buf[] which describes the _ddebug's flags */
static char *ddebug_describe_flags(unsigned int flags, struct flagsbuf *fb)
{
char *p = fb->buf;
int i;
for (i = 0; i < ARRAY_SIZE(opt_array); ++i)
if (flags & opt_array[i].flag)
*p++ = opt_array[i].opt_char;
if (p == fb->buf)
*p++ = '_';
*p = '\0';
return fb->buf;
}
#define vnpr_info(lvl, fmt, ...) \
do { \
if (verbose >= lvl) \
pr_info(fmt, ##__VA_ARGS__); \
} while (0)
#define vpr_info(fmt, ...) vnpr_info(1, fmt, ##__VA_ARGS__)
#define v2pr_info(fmt, ...) vnpr_info(2, fmt, ##__VA_ARGS__)
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
#define v3pr_info(fmt, ...) vnpr_info(3, fmt, ##__VA_ARGS__)
#define v4pr_info(fmt, ...) vnpr_info(4, fmt, ##__VA_ARGS__)
static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
{
/* trim any trailing newlines */
int fmtlen = 0;
if (query->format) {
fmtlen = strlen(query->format);
while (fmtlen && query->format[fmtlen - 1] == '\n')
fmtlen--;
}
v3pr_info("%s: func=\"%s\" file=\"%s\" module=\"%s\" format=\"%.*s\" lineno=%u-%u class=%s\n",
msg,
query->function ?: "",
query->filename ?: "",
query->module ?: "",
fmtlen, query->format ?: "",
query->first_lineno, query->last_lineno, query->class_string);
}
static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
const char *class_string, int *class_id)
{
struct ddebug_class_map *map;
int idx;
list_for_each_entry(map, &dt->maps, link) {
idx = match_string(map->class_names, map->length, class_string);
if (idx >= 0) {
*class_id = idx + map->base;
return map;
}
}
*class_id = -ENOENT;
return NULL;
}
#define __outvar /* filled by callee */
/*
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
* Search the tables for _ddebug's which match the given `query' and
* apply the `flags' and `mask' to them. Returns number of matching
* callsites, normally the same as number of changes. If verbose,
* logs the changes. Takes ddebug_lock.
*/
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
static int ddebug_change(const struct ddebug_query *query,
struct flag_settings *modifiers)
{
int i;
struct ddebug_table *dt;
unsigned int newflags;
unsigned int nfound = 0;
struct flagsbuf fbuf, nbuf;
struct ddebug_class_map *map = NULL;
int __outvar valid_class;
/* search for matching ddebugs */
mutex_lock(&ddebug_lock);
list_for_each_entry(dt, &ddebug_tables, link) {
/* match against the module name */
if (query->module &&
!match_wildcard(query->module, dt->mod_name))
continue;
if (query->class_string) {
map = ddebug_find_valid_class(dt, query->class_string, &valid_class);
if (!map)
continue;
} else {
/* constrain query, do not touch class'd callsites */
valid_class = _DPRINTK_CLASS_DFLT;
}
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = &dt->ddebugs[i];
/* match site against query-class */
if (dp->class_id != valid_class)
continue;
/* match against the source filename */
if (query->filename &&
!match_wildcard(query->filename, dp->filename) &&
!match_wildcard(query->filename,
kbasename(dp->filename)) &&
!match_wildcard(query->filename,
trim_prefix(dp->filename)))
continue;
/* match against the function */
if (query->function &&
!match_wildcard(query->function, dp->function))
continue;
/* match against the format */
if (query->format) {
if (*query->format == '^') {
char *p;
/* anchored search. match must be at beginning */
p = strstr(dp->format, query->format+1);
if (p != dp->format)
continue;
} else if (!strstr(dp->format, query->format))
continue;
}
/* match against the line number range */
if (query->first_lineno &&
dp->lineno < query->first_lineno)
continue;
if (query->last_lineno &&
dp->lineno > query->last_lineno)
continue;
nfound++;
newflags = (dp->flags & modifiers->mask) | modifiers->flags;
if (newflags == dp->flags)
continue;
#ifdef CONFIG_JUMP_LABEL
if (dp->flags & _DPRINTK_FLAGS_PRINT) {
if (!(newflags & _DPRINTK_FLAGS_PRINT))
static_branch_disable(&dp->key.dd_key_true);
} else if (newflags & _DPRINTK_FLAGS_PRINT) {
static_branch_enable(&dp->key.dd_key_true);
}
#endif
v4pr_info("changed %s:%d [%s]%s %s => %s\n",
trim_prefix(dp->filename), dp->lineno,
dt->mod_name, dp->function,
ddebug_describe_flags(dp->flags, &fbuf),
ddebug_describe_flags(newflags, &nbuf));
dp->flags = newflags;
}
}
mutex_unlock(&ddebug_lock);
if (!nfound && verbose)
pr_info("no matches for query\n");
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
return nfound;
}
/*
* Split the buffer `buf' into space-separated words.
* Handles simple " and ' quoting, i.e. without nested,
* embedded or escaped \". Return the number of words
* or <0 on error.
*/
static int ddebug_tokenize(char *buf, char *words[], int maxwords)
{
int nwords = 0;
while (*buf) {
char *end;
/* Skip leading whitespace */
tree-wide: convert open calls to remove spaces to skip_spaces() lib function Makes use of skip_spaces() defined in lib/string.c for removing leading spaces from strings all over the tree. It decreases lib.a code size by 47 bytes and reuses the function tree-wide: text data bss dec hex filename 64688 584 592 65864 10148 (TOTALS-BEFORE) 64641 584 592 65817 10119 (TOTALS-AFTER) Also, while at it, if we see (*str && isspace(*str)), we can be sure to remove the first condition (*str) as the second one (isspace(*str)) also evaluates to 0 whenever *str == 0, making it redundant. In other words, "a char equals zero is never a space". Julia Lawall tried the semantic patch (http://coccinelle.lip6.fr) below, and found occurrences of this pattern on 3 more files: drivers/leds/led-class.c drivers/leds/ledtrig-timer.c drivers/video/output.c @@ expression str; @@ ( // ignore skip_spaces cases while (*str && isspace(*str)) { \(str++;\|++str;\) } | - *str && isspace(*str) ) Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com> Cc: Julia Lawall <julia@diku.dk> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Jeff Dike <jdike@addtoit.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Richard Purdie <rpurdie@rpsys.net> Cc: Neil Brown <neilb@suse.de> Cc: Kyle McMartin <kyle@mcmartin.ca> Cc: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Cc: David Howells <dhowells@redhat.com> Cc: <linux-ext4@vger.kernel.org> Cc: Samuel Ortiz <samuel@sortiz.org> Cc: Patrick McHardy <kaber@trash.net> Cc: Takashi Iwai <tiwai@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-12-15 10:01:06 +08:00
buf = skip_spaces(buf);
if (!*buf)
break; /* oh, it was trailing whitespace */
if (*buf == '#')
break; /* token starts comment, skip rest of line */
/* find `end' of word, whitespace separated or quoted */
if (*buf == '"' || *buf == '\'') {
int quote = *buf++;
for (end = buf; *end && *end != quote; end++)
;
if (!*end) {
pr_err("unclosed quote: %s\n", buf);
return -EINVAL; /* unclosed quote */
}
} else {
for (end = buf; *end && !isspace(*end); end++)
;
BUG_ON(end == buf);
}
/* `buf' is start of word, `end' is one past its end */
if (nwords == maxwords) {
pr_err("too many words, legal max <=%d\n", maxwords);
return -EINVAL; /* ran out of words[] before bytes */
}
if (*end)
*end++ = '\0'; /* terminate the word */
words[nwords++] = buf;
buf = end;
}
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
if (verbose >= 3) {
int i;
pr_info("split into words:");
for (i = 0; i < nwords; i++)
pr_cont(" \"%s\"", words[i]);
pr_cont("\n");
}
return nwords;
}
/*
* Parse a single line number. Note that the empty string ""
* is treated as a special case and converted to zero, which
* is later treated as a "don't care" value.
*/
static inline int parse_lineno(const char *str, unsigned int *val)
{
BUG_ON(str == NULL);
if (*str == '\0') {
*val = 0;
return 0;
}
if (kstrtouint(str, 10, val) < 0) {
pr_err("bad line-number: %s\n", str);
return -EINVAL;
}
return 0;
}
static int parse_linerange(struct ddebug_query *query, const char *first)
{
char *last = strchr(first, '-');
if (query->first_lineno || query->last_lineno) {
pr_err("match-spec: line used 2x\n");
return -EINVAL;
}
if (last)
*last++ = '\0';
if (parse_lineno(first, &query->first_lineno) < 0)
return -EINVAL;
if (last) {
/* range <first>-<last> */
if (parse_lineno(last, &query->last_lineno) < 0)
return -EINVAL;
/* special case for last lineno not specified */
if (query->last_lineno == 0)
query->last_lineno = UINT_MAX;
if (query->last_lineno < query->first_lineno) {
pr_err("last-line:%d < 1st-line:%d\n",
query->last_lineno,
query->first_lineno);
return -EINVAL;
}
} else {
query->last_lineno = query->first_lineno;
}
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
v3pr_info("parsed line %d-%d\n", query->first_lineno,
query->last_lineno);
return 0;
}
static int check_set(const char **dest, char *src, char *name)
{
int rc = 0;
if (*dest) {
rc = -EINVAL;
pr_err("match-spec:%s val:%s overridden by %s\n",
name, *dest, src);
}
*dest = src;
return rc;
}
/*
* Parse words[] as a ddebug query specification, which is a series
* of (keyword, value) pairs chosen from these possibilities:
*
* func <function-name>
* file <full-pathname>
* file <base-filename>
* module <module-name>
* format <escaped-string-to-find-in-format>
* line <lineno>
* line <first-lineno>-<last-lineno> // where either may be empty
*
* Only 1 of each type is allowed.
* Returns 0 on success, <0 on error.
*/
static int ddebug_parse_query(char *words[], int nwords,
struct ddebug_query *query, const char *modname)
{
unsigned int i;
int rc = 0;
char *fline;
/* check we have an even number of words */
if (nwords % 2 != 0) {
pr_err("expecting pairs of match-spec <value>\n");
return -EINVAL;
}
for (i = 0; i < nwords; i += 2) {
char *keyword = words[i];
char *arg = words[i+1];
if (!strcmp(keyword, "func")) {
rc = check_set(&query->function, arg, "func");
} else if (!strcmp(keyword, "file")) {
if (check_set(&query->filename, arg, "file"))
return -EINVAL;
/* tail :$info is function or line-range */
fline = strchr(query->filename, ':');
if (!fline)
continue;
*fline++ = '\0';
if (isalpha(*fline) || *fline == '*' || *fline == '?') {
/* take as function name */
if (check_set(&query->function, fline, "func"))
return -EINVAL;
} else {
if (parse_linerange(query, fline))
return -EINVAL;
}
} else if (!strcmp(keyword, "module")) {
rc = check_set(&query->module, arg, "module");
} else if (!strcmp(keyword, "format")) {
string_unescape_inplace(arg, UNESCAPE_SPACE |
UNESCAPE_OCTAL |
UNESCAPE_SPECIAL);
rc = check_set(&query->format, arg, "format");
} else if (!strcmp(keyword, "line")) {
if (parse_linerange(query, arg))
return -EINVAL;
} else if (!strcmp(keyword, "class")) {
rc = check_set(&query->class_string, arg, "class");
} else {
pr_err("unknown keyword \"%s\"\n", keyword);
return -EINVAL;
}
if (rc)
return rc;
}
if (!query->module && modname)
/*
* support $modname.dyndbg=<multiple queries>, when
* not given in the query itself
*/
query->module = modname;
vpr_info_dq(query, "parsed");
return 0;
}
/*
* Parse `str' as a flags specification, format [-+=][p]+.
* Sets up *maskp and *flagsp to be used when changing the
* flags fields of matched _ddebug's. Returns 0 on success
* or <0 on error.
*/
static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
{
int op, i;
switch (*str) {
case '+':
case '-':
case '=':
op = *str++;
break;
default:
pr_err("bad flag-op %c, at start of %s\n", *str, str);
return -EINVAL;
}
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
v3pr_info("op='%c'\n", op);
for (; *str ; ++str) {
for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
if (*str == opt_array[i].opt_char) {
modifiers->flags |= opt_array[i].flag;
break;
}
}
if (i < 0) {
pr_err("unknown flag '%c'\n", *str);
return -EINVAL;
}
}
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
v3pr_info("flags=0x%x\n", modifiers->flags);
/* calculate final flags, mask based upon op */
switch (op) {
case '=':
/* modifiers->flags already set */
modifiers->mask = 0;
break;
case '+':
modifiers->mask = ~0U;
break;
case '-':
modifiers->mask = ~modifiers->flags;
modifiers->flags = 0;
break;
}
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
v3pr_info("*flagsp=0x%x *maskp=0x%x\n", modifiers->flags, modifiers->mask);
return 0;
}
static int ddebug_exec_query(char *query_string, const char *modname)
{
struct flag_settings modifiers = {};
struct ddebug_query query = {};
#define MAXWORDS 9
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
int nwords, nfound;
char *words[MAXWORDS];
nwords = ddebug_tokenize(query_string, words, MAXWORDS);
if (nwords <= 0) {
pr_err("tokenize failed\n");
return -EINVAL;
}
/* check flags 1st (last arg) so query is pairs of spec,val */
if (ddebug_parse_flags(words[nwords-1], &modifiers)) {
pr_err("flags parse failed\n");
return -EINVAL;
}
if (ddebug_parse_query(words, nwords-1, &query, modname)) {
pr_err("query parse failed\n");
return -EINVAL;
}
/* actually go and implement the change */
nfound = ddebug_change(&query, &modifiers);
vpr_info_dq(&query, nfound ? "applied" : "no-match");
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
return nfound;
}
/* handle multiple queries in query string, continue on error, return
last error or number of matching callsites. Module name is either
in param (for boot arg) or perhaps in query string.
*/
static int ddebug_exec_queries(char *query, const char *modname)
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
{
char *split;
int i, errs = 0, exitcode = 0, rc, nfound = 0;
for (i = 0; query; query = split) {
split = strpbrk(query, ";\n");
if (split)
*split++ = '\0';
query = skip_spaces(query);
if (!query || !*query || *query == '#')
continue;
vpr_info("query %d: \"%s\" mod:%s\n", i, query, modname ?: "*");
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
rc = ddebug_exec_query(query, modname);
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
if (rc < 0) {
errs++;
exitcode = rc;
} else {
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
nfound += rc;
}
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
i++;
}
if (i)
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
v2pr_info("processed %d queries, with %d matches, %d errs\n",
i, nfound, errs);
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
if (exitcode)
return exitcode;
return nfound;
}
dyndbg: add drm.debug style (drm/parameters/debug) bitmap support Add kernel_param_ops and callbacks to use a class-map to validate and apply input to a sysfs-node, which allows users to control classes defined in that class-map. This supports uses like: echo 0x3 > /sys/module/drm/parameters/debug IE add these: - int param_set_dyndbg_classes() - int param_get_dyndbg_classes() - struct kernel_param_ops param_ops_dyndbg_classes Following the model of kernel/params.c STANDARD_PARAM_DEFS, these are non-static and exported. This might be unnecessary here. get/set use an augmented kernel_param; the arg refs a new struct ddebug_class_param, which contains: - A ptr to user's state-store; a union of &ulong for drm.debug, &int for nouveau level debug. By ref'g the client's bit-state _var, code coordinates with existing code (like drm_debug_enabled) which uses it, so existing/remaining calls can work unchanged. Changing drm.debug to a ulong allows use of BIT() etc. - FLAGS: dyndbg.flags toggled by changes to bitmap. Usually just "p". - MAP: a pointer to struct ddebug_classes_map, which maps those class-names to .class_ids 0..N that the module is using. This class-map is declared & initialized by DECLARE_DYNDBG_CLASSMAP. - map-type: 4 enums DD_CLASS_TYPE_* select 2 input forms and 2 meanings. numeric input: DD_CLASS_TYPE_DISJOINT_BITS integer input, independent bits. ie: drm.debug DD_CLASS_TYPE_LEVEL_NUM integer input, 0..N levels classnames-list (comma separated) input: DD_CLASS_TYPE_DISJOINT_NAMES each name affects a bit, others preserved DD_CLASS_TYPE_LEVEL_NAMES names have level meanings, like kern_levels.h _NAMES - comma-separated classnames (with optional +-) _NUM - numeric input, 0-N expected _BITS - numeric input, 0x1F bitmap form expected _DISJOINT - bits are independent _LEVEL - (x<y) on bit-pos. _DISJOINT treats input like a bit-vector (ala drm.debug), and sets each bit accordingly. LEVEL is layered on top of this. _LEVEL treats input like a bit-pos:N, then sets bits(0..N)=1, and bits(N+1..max)=0. This applies (bit<N) semantics on top of disjoint bits. USAGES: A potentially typical _DISJOINT_NAMES use: echo +DRM_UT_CORE,+DRM_UT_KMS,-DRM_UT_DRIVER,-DRM_UT_ATOMIC \ > /sys/module/drm/parameters/debug_catnames A naive _LEVEL_NAMES use, with one class, that sets all in the class-map according to (x<y): : problem seen echo +L7 > /sys/module/test_dynamic_debug/parameters/p_level_names : problem solved echo -L1 > /sys/module/test_dynamic_debug/parameters/p_level_names Note this artifact: : this is same as prev cmd (due to +/-) echo L0 > /sys/module/test_dynamic_debug/parameters/p_level_names : this is "even-more" off, but same wo __pr_debug_class(L0, ".."). echo -L0 > /sys/module/test_dynamic_debug/parameters/p_level_names A stress-test/make-work usage (kid toggling a light switch): echo +L7,L0,L7,L0,L7,L0,L7,L0,L7,L0,L7,L0,L7 \ > /sys/module/test_dynamic_debug/parameters/p_level_names ddebug_apply_class_bitmap(): inside-fn, works on bitmaps, receives new-bits, finds diffs vs client-bitvector holding "current" state, and issues exec_query to commit the adjustment. param_set_dyndbg_classes(): interface fn, sends _NAMES to param_set_dyndbg_classnames() and returns, falls thru to handle _BITS, _NUM internally, and calls ddebug_apply_class_bitmap(). Finishes by updating state. param_set_dyndbg_classnames(): handles classnames-list in loop, calls ddebug_apply_class_bitmap for each, then updates state. NOTES: _LEVEL_ is overlay on _DISJOINT_; inputs are converted to a bitmask, by the callbacks. IOW this is possible, and possibly confusing: echo class V3 +p > control echo class V1 -p > control IMO thats ok, relative verbosity is an interface property. _LEVEL_NUM maps still need class-names, even though the names are not usable at the sysfs interface (unlike with _NAMES style). The names are the only way to >control the classes. - It must have a "V0" name, something below "V1" to turn "V1" off. __pr_debug_cls(V0,..) is printk, don't do that. - "class names" is required at the >control interface. - relative levels are not enforced at >control _LEVEL_NAMES bear +/- signs, which alters the on-bit-pos by 1. IOW, +L2 means L0,L1,L2, and -L2 means just L0,L1. This kinda spoils the readback fidelity, since the L0 bit gets turned on by any use of any L*, except "-L0". All the interface uncertainty here pertains to the _NAMES features. Nobody has actually asked for this, so its practical (if a little tedious) to split it out. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-21-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:57 +08:00
/* apply a new bitmap to the sys-knob's current bit-state */
static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
unsigned long *new_bits, unsigned long *old_bits)
{
#define QUERY_SIZE 128
char query[QUERY_SIZE];
const struct ddebug_class_map *map = dcp->map;
int matches = 0;
int bi, ct;
v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits);
for (bi = 0; bi < map->length; bi++) {
if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
continue;
snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
test_bit(bi, new_bits) ? '+' : '-', dcp->flags);
ct = ddebug_exec_queries(query, NULL);
matches += ct;
v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
ct, map->class_names[bi], *new_bits);
}
return matches;
}
/* stub to later conditionally add "$module." prefix where not already done */
#define KP_NAME(kp) kp->name
#define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
/* accept comma-separated-list of [+-] classnames */
static int param_set_dyndbg_classnames(const char *instr, const struct kernel_param *kp)
{
const struct ddebug_class_param *dcp = kp->arg;
const struct ddebug_class_map *map = dcp->map;
unsigned long curr_bits, old_bits;
char *cl_str, *p, *tmp;
int cls_id, totct = 0;
bool wanted;
cl_str = tmp = kstrdup(instr, GFP_KERNEL);
p = strchr(cl_str, '\n');
if (p)
*p = '\0';
/* start with previously set state-bits, then modify */
curr_bits = old_bits = *dcp->bits;
vpr_info("\"%s\" > %s:0x%lx\n", cl_str, KP_NAME(kp), curr_bits);
for (; cl_str; cl_str = p) {
p = strchr(cl_str, ',');
if (p)
*p++ = '\0';
if (*cl_str == '-') {
wanted = false;
cl_str++;
} else {
wanted = true;
if (*cl_str == '+')
cl_str++;
}
cls_id = match_string(map->class_names, map->length, cl_str);
if (cls_id < 0) {
pr_err("%s unknown to %s\n", cl_str, KP_NAME(kp));
continue;
}
/* have one or more valid class_ids of one *_NAMES type */
switch (map->map_type) {
case DD_CLASS_TYPE_DISJOINT_NAMES:
/* the +/- pertains to a single bit */
if (test_bit(cls_id, &curr_bits) == wanted) {
v3pr_info("no change on %s\n", cl_str);
continue;
}
curr_bits ^= BIT(cls_id);
totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits);
*dcp->bits = curr_bits;
v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
map->class_names[cls_id]);
break;
case DD_CLASS_TYPE_LEVEL_NAMES:
/* cls_id = N in 0..max. wanted +/- determines N or N-1 */
old_bits = CLASSMAP_BITMASK(*dcp->lvl);
curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits);
*dcp->lvl = (cls_id + (wanted ? 1 : 0));
v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
map->class_names[cls_id], old_bits, curr_bits);
break;
default:
pr_err("illegal map-type value %d\n", map->map_type);
}
}
kfree(tmp);
vpr_info("total matches: %d\n", totct);
return 0;
}
/**
* param_set_dyndbg_classes - class FOO >control
* @instr: string echo>d to sysfs, input depends on map_type
* @kp: kp->arg has state: bits/lvl, map, map_type
*
* Enable/disable prdbgs by their class, as given in the arguments to
* DECLARE_DYNDBG_CLASSMAP. For LEVEL map-types, enforce relative
* levels by bitpos.
*
* Returns: 0 or <0 if error.
*/
int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
{
const struct ddebug_class_param *dcp = kp->arg;
const struct ddebug_class_map *map = dcp->map;
unsigned long inrep, new_bits, old_bits;
int rc, totct = 0;
switch (map->map_type) {
case DD_CLASS_TYPE_DISJOINT_NAMES:
case DD_CLASS_TYPE_LEVEL_NAMES:
/* handle [+-]classnames list separately, we are done here */
return param_set_dyndbg_classnames(instr, kp);
case DD_CLASS_TYPE_DISJOINT_BITS:
case DD_CLASS_TYPE_LEVEL_NUM:
/* numeric input, accept and fall-thru */
rc = kstrtoul(instr, 0, &inrep);
if (rc) {
pr_err("expecting numeric input: %s > %s\n", instr, KP_NAME(kp));
return -EINVAL;
}
break;
default:
pr_err("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
return -EINVAL;
}
/* only _BITS,_NUM (numeric) map-types get here */
switch (map->map_type) {
case DD_CLASS_TYPE_DISJOINT_BITS:
/* expect bits. mask and warn if too many */
if (inrep & ~CLASSMAP_BITMASK(map->length)) {
pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n",
KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
inrep &= CLASSMAP_BITMASK(map->length);
}
v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits);
*dcp->bits = inrep;
break;
case DD_CLASS_TYPE_LEVEL_NUM:
/* input is bitpos, of highest verbosity to be enabled */
if (inrep > map->length) {
pr_warn("%s: level:%ld exceeds max:%d, clamping\n",
KP_NAME(kp), inrep, map->length);
inrep = map->length;
}
old_bits = CLASSMAP_BITMASK(*dcp->lvl);
new_bits = CLASSMAP_BITMASK(inrep);
v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits);
*dcp->lvl = inrep;
break;
default:
pr_warn("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
}
vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct);
return 0;
}
EXPORT_SYMBOL(param_set_dyndbg_classes);
/**
* param_get_dyndbg_classes - classes reader
* @buffer: string description of controlled bits -> classes
* @kp: kp->arg has state: bits, map
*
* Reads last written state, underlying prdbg state may have been
* altered by direct >control. Displays 0x for DISJOINT, 0-N for
* LEVEL Returns: #chars written or <0 on error
*/
int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
{
const struct ddebug_class_param *dcp = kp->arg;
const struct ddebug_class_map *map = dcp->map;
switch (map->map_type) {
case DD_CLASS_TYPE_DISJOINT_NAMES:
case DD_CLASS_TYPE_DISJOINT_BITS:
return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits);
case DD_CLASS_TYPE_LEVEL_NAMES:
case DD_CLASS_TYPE_LEVEL_NUM:
return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
default:
return -1;
}
}
EXPORT_SYMBOL(param_get_dyndbg_classes);
const struct kernel_param_ops param_ops_dyndbg_classes = {
.set = param_set_dyndbg_classes,
.get = param_get_dyndbg_classes,
};
EXPORT_SYMBOL(param_ops_dyndbg_classes);
#define PREFIX_SIZE 64
static int remaining(int wrote)
{
if (PREFIX_SIZE - wrote > 0)
return PREFIX_SIZE - wrote;
return 0;
}
static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
{
int pos_after_tid;
int pos = 0;
if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {
if (in_interrupt())
pos += snprintf(buf + pos, remaining(pos), "<intr> ");
else
pos += snprintf(buf + pos, remaining(pos), "[%d] ",
task_pid_vnr(current));
}
pos_after_tid = pos;
if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)
pos += snprintf(buf + pos, remaining(pos), "%s:",
desc->modname);
if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
pos += snprintf(buf + pos, remaining(pos), "%s:",
desc->function);
if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
pos += snprintf(buf + pos, remaining(pos), "%d:",
desc->lineno);
if (pos - pos_after_tid)
pos += snprintf(buf + pos, remaining(pos), " ");
if (pos >= PREFIX_SIZE)
buf[PREFIX_SIZE - 1] = '\0';
return buf;
}
static inline char *dynamic_emit_prefix(struct _ddebug *desc, char *buf)
{
if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_ANY))
return __dynamic_emit_prefix(desc, buf);
return buf;
}
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
{
va_list args;
struct va_format vaf;
char buf[PREFIX_SIZE] = "";
BUG_ON(!descriptor);
BUG_ON(!fmt);
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
printk(KERN_DEBUG "%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf);
va_end(args);
}
EXPORT_SYMBOL(__dynamic_pr_debug);
void __dynamic_dev_dbg(struct _ddebug *descriptor,
const struct device *dev, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
BUG_ON(!descriptor);
BUG_ON(!fmt);
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
if (!dev) {
printk(KERN_DEBUG "(NULL device *): %pV", &vaf);
} else {
char buf[PREFIX_SIZE] = "";
dev_printk_emit(LOGLEVEL_DEBUG, dev, "%s%s %s: %pV",
dynamic_emit_prefix(descriptor, buf),
dev_driver_string(dev), dev_name(dev),
&vaf);
}
va_end(args);
}
EXPORT_SYMBOL(__dynamic_dev_dbg);
#ifdef CONFIG_NET
void __dynamic_netdev_dbg(struct _ddebug *descriptor,
const struct net_device *dev, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
BUG_ON(!descriptor);
BUG_ON(!fmt);
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
if (dev && dev->dev.parent) {
char buf[PREFIX_SIZE] = "";
dev_printk_emit(LOGLEVEL_DEBUG, dev->dev.parent,
"%s%s %s %s%s: %pV",
dynamic_emit_prefix(descriptor, buf),
dev_driver_string(dev->dev.parent),
dev_name(dev->dev.parent),
netdev_name(dev), netdev_reg_state(dev),
&vaf);
} else if (dev) {
printk(KERN_DEBUG "%s%s: %pV", netdev_name(dev),
netdev_reg_state(dev), &vaf);
} else {
printk(KERN_DEBUG "(NULL net_device): %pV", &vaf);
}
va_end(args);
}
EXPORT_SYMBOL(__dynamic_netdev_dbg);
#endif
#if IS_ENABLED(CONFIG_INFINIBAND)
void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
const struct ib_device *ibdev, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
if (ibdev && ibdev->dev.parent) {
char buf[PREFIX_SIZE] = "";
dev_printk_emit(LOGLEVEL_DEBUG, ibdev->dev.parent,
"%s%s %s %s: %pV",
dynamic_emit_prefix(descriptor, buf),
dev_driver_string(ibdev->dev.parent),
dev_name(ibdev->dev.parent),
dev_name(&ibdev->dev),
&vaf);
} else if (ibdev) {
printk(KERN_DEBUG "%s: %pV", dev_name(&ibdev->dev), &vaf);
} else {
printk(KERN_DEBUG "(NULL ib_device): %pV", &vaf);
}
va_end(args);
}
EXPORT_SYMBOL(__dynamic_ibdev_dbg);
#endif
/*
* Install a noop handler to make dyndbg look like a normal kernel cli param.
* This avoids warnings about dyndbg being an unknown cli param when supplied
* by a user.
*/
static __init int dyndbg_setup(char *str)
{
return 1;
}
__setup("dyndbg=", dyndbg_setup);
/*
* File_ops->write method for <debugfs>/dynamic_debug/control. Gathers the
* command text from userspace, parses and executes it.
*/
#define USER_BUF_PAGE 4096
static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
char *tmpbuf;
int ret;
if (len == 0)
return 0;
if (len > USER_BUF_PAGE - 1) {
pr_warn("expected <%d bytes into control\n", USER_BUF_PAGE);
return -E2BIG;
}
tmpbuf = memdup_user_nul(ubuf, len);
if (IS_ERR(tmpbuf))
return PTR_ERR(tmpbuf);
dyndbg: refine verbosity 1-4 summary-detail adjust current v*pr_info() calls to fit an overview..detail scheme: 1- module level activity: add/remove, etc 2- command ingest, splitting, summary of effects. per >control write 3- command parsing: op, flags, search terms 4- per-site change msg can yield ~3k x 2 logs per echo "+p;-p" > command. Summarize these 4 levels in MODULE_PARM_DESC, and update verbose=3 in Doc. 2- is new, to isolate a problem where a stress-test script (which feeds ~4kb multi-command strings) would produce short writes, truncating last command and causing parsing errors, which confused test results. The script fix was to use syswrite, to deliver full proper commands. 4- gets per-callsite "changed:" pr-infos, which are very noisy during stress tests, and formerly obscured v1-3 messages, and overwhelmed the static-key workload being tested. The verbose parameter has previously seen adjustment: commit 481c0e33f1e7 ("dyndbg: refine debug verbosity; 1 is basic, 2 more chatty") The script driving these adjustments is: !/usr/bin/perl -w =for Doc 1st purpose was to benchmark the effect of wildcard queries on query performance; if wildcards are risk free cheap enough, we can deploy them in the (floating) format search. 1st finding: wildcards take 2x as long to process. 2nd purpose was to benchmark real static-key changes VS simple flag changes. Found ~100x decrease for the hard work. The script maximizes workload per >control by packing it a ~4kb string of "+p; -p;" commands; this uncovered some broken stuff. The 85th query failed, and appears to be truncated, so is gramatically incorrect. Its either an error here, or in the kernel. Its not happening atm, retest. Plot thickens: fail only happens doing +-p, not +-mf, likely load dependent. Error remains consistent. Looks like a short write, longer on writer than kernel-reader. Try syswrite on handle to control this. That fixed short write. =cut use Getopt::Std; getopts('vN:k:', \my %opts) or die <<EOH; $0 options: -v verbose -k=n kernel dyndbg verbosity -N=n number of loops.. tbrc EOH $opts{N} //= 10; # !undef, 0 tests too long. my $ctrl = '/proc/dynamic_debug/control'; vx($opts{k}) if defined $opts{k}; # works on -k0 open(my $CTL, '>', $ctrl) or die "cant open $ctrl for writing: $!\n"; sub vx { my $arg = shift; my $cmd = "echo $arg > /sys/module/dynamic_debug/parameters/verbose"; system($cmd); warn("vx problem: rc:$? err:$! qry: $cmd\n") if ($?); } sub qryOK { my $qry = shift; print "syntax test: <\n$qry>\n" if $opts{v}; my $bytes = syswrite $CTL, $qry; printf "short read: $bytes / %d\n", length $qry if $bytes < length $qry; if ($?) { warn "rc:$? err:$! qry: $qry\n"; return 0; } return 1; } sub build_queries { my ($cmd, $flags, $ct) = @_; # build experiment and reference queries my $cycle = " $cmd +$flags # on ; $cmd -$flags # off \n"; my $ref = " +$flags ; -$flags \n"; my $len = length $cycle; my $max = int(4096 / $len); # break/fit to buffer size $ct |= $max; print "qry: ct:$max x << \n$cycle >>\n"; return unless qryOK($ref); return unless qryOK($cycle); my $wild = $cycle x $ct; my $empty = $ref x $ct; printf "len: %d, %d\n", length $wild, length $empty; return { trial => $wild, ref => $empty, probe => $cycle, zero => $ref, count => $ct, max => $max }; } my $query_set = build_queries(' file "*" module "*" func "*" ', "mf"); qryOK($query_set->{zero}); qryOK($query_set->{probe}); qryOK($query_set->{ref}); qryOK($query_set->{trial}); use Benchmark; sub dobatch { my ($cmd, $flags, $reps, $ct) = @_; $reps ||= $opts{N}; my $qs = build_queries($cmd, $flags, $ct); timethese($reps, { wildcards => sub { syswrite $CTL, $qs->{trial}; }, no_search => sub { syswrite $CTL, $qs->{ref}; } } ); } sub bench_static_key_toggle { vx 0; dobatch(' file "*" module "*" func "*" ', "mf"); dobatch(' file "*" module "*" func "*" ', "p"); } sub bench_verbose_levels { for my $i (0..4) { vx $i; dobatch(' file "*" module "*" func "*" ', "mf"); } } bench_static_key_toggle(); __END__ Heres how the test-script runs: :: verbose=3 parsing info [ 48.401646] dyndbg: query 95: "file "*" module "*" func "*" -mf # off " mod:* [ 48.402040] dyndbg: split into words: "file" "*" "module" "*" "func" "*" "-mf" [ 48.402456] dyndbg: op='-' [ 48.402615] dyndbg: flags=0x6 [ 48.402779] dyndbg: *flagsp=0x0 *maskp=0xfffffff9 [ 48.403033] dyndbg: parsed: func="*" file="*" module="*" format="" lineno=0-0 [ 48.403674] dyndbg: applied: func="*" file="*" module="*" format="" lineno=0-0 :: verbose=2 >control summary. ~300k site matches/changes per 4kb command [ 48.404063] dyndbg: processed 96 queries, with 296160 matches, 0 errs :: 2 queries against each other, no-search vs all-wildcard-search qry: ct:48 x << file "*" module "*" func "*" +mf # on ; file "*" module "*" func "*" -mf # off >> len: 4080, 576 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 0 wallclock secs ( 0.00 usr + 0.03 sys = 0.03 CPU) @ 333.33/s (n=10) (warning: too few iterations for a reliable count) wildcards: 0 wallclock secs ( 0.00 usr + 0.09 sys = 0.09 CPU) @ 111.11/s (n=10) (warning: too few iterations for a reliable count) :: 2 queries, both doing real work / changing stati-key states. qry: ct:49 x << file "*" module "*" func "*" +p # on ; file "*" module "*" func "*" -p # off >> len: 4067, 490 Benchmark: timing 10 iterations of no_search, wildcards... no_search: 20 wallclock secs ( 0.00 usr + 20.36 sys = 20.36 CPU) @ 0.49/s (n=10) wildcards: 21 wallclock secs ( 0.00 usr + 21.08 sys = 21.08 CPU) @ 0.47/s (n=10) bash-5.1# Thats 150k static-key-toggles / sec ~600x slower than simple flags on qemu --smp 3 run Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20211019210746.185307-1-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-10-20 05:07:46 +08:00
v2pr_info("read %zu bytes from userspace\n", len);
ret = ddebug_exec_queries(tmpbuf, NULL);
kfree(tmpbuf);
dynamic_debug: process multiple debug-queries on a line Insert ddebug_exec_queries() in place of ddebug_exec_query(). It splits the query string on [;\n], and calls ddebug_exec_query() on each. All queries are processed independent of errors, allowing a query to fail, for example when a module is not installed. Empty lines and comments are skipped. Errors are counted, and the last error seen (negative) or the number of callsites found (0 or positive) is returned. Return code checks are altered accordingly. With this, multiple queries can be given in ddebug_query, allowing more selective enabling of callsites. As a side effect, a set of commands can be batched in: cat cmd-file > $DBGMT/dynamic_debug/control We dont want a ddebug_query syntax error to kill the dynamic debug facility, so dynamic_debug_init() zeros ddebug_exec_queries()'s return code after logging the appropriate message, so that ddebug tables are preserved and $DBGMT/dynamic_debug/control file is created. This would be appropriate even without accepting multiple queries. This patch also alters ddebug_change() to return number of callsites matched (which typically is the same as number of callsites changed). ddebug_exec_query() also returns the number found, or a negative value if theres a parse error on the query. Splitting on [;\n] prevents their use in format-specs, but selecting callsites on punctuation is brittle anyway, meaningful and selective substrings are more typical. Note: splitting queries on ';' before handling trailing #comments means that a ';' also terminates a comment, and text after the ';' is treated as another query. This trailing query will almost certainly result in a parse error and thus have no effect other than the error message. The double corner case with unexpected results is: ddebug_query="func foo +p # enable foo ; +p" Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Signed-off-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-12-20 06:13:21 +08:00
if (ret < 0)
return ret;
*offp += len;
return len;
}
/*
* Set the iterator to point to the first _ddebug object
* and return a pointer to that first object. Returns
* NULL if there are no _ddebugs at all.
*/
static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
{
if (list_empty(&ddebug_tables)) {
iter->table = NULL;
return NULL;
}
iter->table = list_entry(ddebug_tables.next,
struct ddebug_table, link);
iter->idx = iter->table->num_ddebugs;
return &iter->table->ddebugs[--iter->idx];
}
/*
* Advance the iterator to point to the next _ddebug
* object from the one the iterator currently points at,
* and returns a pointer to the new _ddebug. Returns
* NULL if the iterator has seen all the _ddebugs.
*/
static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
{
if (iter->table == NULL)
return NULL;
if (--iter->idx < 0) {
/* iterate to next table */
if (list_is_last(&iter->table->link, &ddebug_tables)) {
iter->table = NULL;
return NULL;
}
iter->table = list_entry(iter->table->link.next,
struct ddebug_table, link);
iter->idx = iter->table->num_ddebugs;
--iter->idx;
}
return &iter->table->ddebugs[iter->idx];
}
/*
* Seq_ops start method. Called at the start of every
* read() call from userspace. Takes the ddebug_lock and
* seeks the seq_file's iterator to the given position.
*/
static void *ddebug_proc_start(struct seq_file *m, loff_t *pos)
{
struct ddebug_iter *iter = m->private;
struct _ddebug *dp;
int n = *pos;
mutex_lock(&ddebug_lock);
if (!n)
return SEQ_START_TOKEN;
if (n < 0)
return NULL;
dp = ddebug_iter_first(iter);
while (dp != NULL && --n > 0)
dp = ddebug_iter_next(iter);
return dp;
}
/*
* Seq_ops next method. Called several times within a read()
* call from userspace, with ddebug_lock held. Walks to the
* next _ddebug object with a special case for the header line.
*/
static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
{
struct ddebug_iter *iter = m->private;
struct _ddebug *dp;
if (p == SEQ_START_TOKEN)
dp = ddebug_iter_first(iter);
else
dp = ddebug_iter_next(iter);
++*pos;
return dp;
}
#define class_in_range(class_id, map) \
(class_id >= map->base && class_id < map->base + map->length)
static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
{
struct ddebug_class_map *map;
list_for_each_entry(map, &iter->table->maps, link)
if (class_in_range(dp->class_id, map))
return map->class_names[dp->class_id - map->base];
return NULL;
}
/*
* Seq_ops show method. Called several times within a read()
* call from userspace, with ddebug_lock held. Formats the
* current _ddebug as a single human-readable line, with a
* special case for the header line.
*/
static int ddebug_proc_show(struct seq_file *m, void *p)
{
struct ddebug_iter *iter = m->private;
struct _ddebug *dp = p;
struct flagsbuf flags;
char const *class;
if (p == SEQ_START_TOKEN) {
seq_puts(m,
"# filename:lineno [module]function flags format\n");
return 0;
}
seq_printf(m, "%s:%u [%s]%s =%s \"",
trim_prefix(dp->filename), dp->lineno,
iter->table->mod_name, dp->function,
ddebug_describe_flags(dp->flags, &flags));
seq_escape_str(m, dp->format, ESCAPE_SPACE, "\t\r\n\"");
seq_puts(m, "\"");
if (dp->class_id != _DPRINTK_CLASS_DFLT) {
class = ddebug_class_name(iter, dp);
if (class)
seq_printf(m, " class:%s", class);
else
seq_printf(m, " class unknown, _id:%d", dp->class_id);
}
seq_puts(m, "\n");
return 0;
}
/*
* Seq_ops stop method. Called at the end of each read()
* call from userspace. Drops ddebug_lock.
*/
static void ddebug_proc_stop(struct seq_file *m, void *p)
{
mutex_unlock(&ddebug_lock);
}
static const struct seq_operations ddebug_proc_seqops = {
.start = ddebug_proc_start,
.next = ddebug_proc_next,
.show = ddebug_proc_show,
.stop = ddebug_proc_stop
};
static int ddebug_proc_open(struct inode *inode, struct file *file)
{
return seq_open_private(file, &ddebug_proc_seqops,
sizeof(struct ddebug_iter));
}
static const struct file_operations ddebug_proc_fops = {
.owner = THIS_MODULE,
.open = ddebug_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
.write = ddebug_proc_write
};
static const struct proc_ops proc_fops = {
.proc_open = ddebug_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = seq_release_private,
.proc_write = ddebug_proc_write
};
static void ddebug_attach_module_classes(struct ddebug_table *dt,
struct ddebug_class_map *classes,
int num_classes)
{
struct ddebug_class_map *cm;
int i, j, ct = 0;
for (cm = classes, i = 0; i < num_classes; i++, cm++) {
if (!strcmp(cm->mod_name, dt->mod_name)) {
v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i,
cm->mod_name, cm->base, cm->length, cm->map_type);
for (j = 0; j < cm->length; j++)
v3pr_info(" %d: %d %s\n", j + cm->base, j,
cm->class_names[j]);
list_add(&cm->link, &dt->maps);
ct++;
}
}
if (ct)
vpr_info("module:%s attached %d classes\n", dt->mod_name, ct);
}
/*
* Allocate a new ddebug_table for the given module
* and add it to the global list.
*/
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
static int __ddebug_add_module(struct _ddebug_info *di, unsigned int base,
const char *modname)
{
struct ddebug_table *dt;
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
if (!di->num_descs) {
v3pr_info(" skip %s\n", modname);
return 0;
}
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
if (dt == NULL) {
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
pr_err("error adding module: %s\n", modname);
return -ENOMEM;
}
/*
* For built-in modules, name lives in .rodata and is
* immortal. For loaded modules, name points at the name[]
* member of struct module, which lives at least as long as
* this struct ddebug_table.
*/
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
dt->mod_name = modname;
dt->ddebugs = di->descs;
dt->num_ddebugs = di->num_descs;
INIT_LIST_HEAD(&dt->link);
INIT_LIST_HEAD(&dt->maps);
if (di->classes && di->num_classes)
ddebug_attach_module_classes(dt, di->classes, di->num_classes);
mutex_lock(&ddebug_lock);
list_add_tail(&dt->link, &ddebug_tables);
mutex_unlock(&ddebug_lock);
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
return 0;
}
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
int ddebug_add_module(struct _ddebug_info *di, const char *modname)
{
return __ddebug_add_module(di, 0, modname);
}
/* helper for ddebug_dyndbg_(boot|module)_param_cb */
static int ddebug_dyndbg_param_cb(char *param, char *val,
const char *modname, int on_err)
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
{
char *sep;
sep = strchr(param, '.');
if (sep) {
/* needed only for ddebug_dyndbg_boot_param_cb */
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
*sep = '\0';
modname = param;
param = sep + 1;
}
if (strcmp(param, "dyndbg"))
return on_err; /* determined by caller */
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
ddebug_exec_queries((val ? val : "+p"), modname);
return 0; /* query failure shouldn't stop module load */
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
}
/* handle both dyndbg and $module.dyndbg params at boot */
static int ddebug_dyndbg_boot_param_cb(char *param, char *val,
module: add extra argument for parse_params() callback This adds an extra argument onto parse_params() to be used as a way to make the unused callback a bit more useful and generic by allowing the caller to pass on a data structure of its choice. An example use case is to allow us to easily make module parameters for every module which we will do next. @ parse @ identifier name, args, params, num, level_min, level_max; identifier unknown, param, val, doing; type s16; @@ extern char *parse_args(const char *name, char *args, const struct kernel_param *params, unsigned num, s16 level_min, s16 level_max, + void *arg, int (*unknown)(char *param, char *val, const char *doing + , void *arg )); @ parse_mod @ identifier name, args, params, num, level_min, level_max; identifier unknown, param, val, doing; type s16; @@ char *parse_args(const char *name, char *args, const struct kernel_param *params, unsigned num, s16 level_min, s16 level_max, + void *arg, int (*unknown)(char *param, char *val, const char *doing + , void *arg )) { ... } @ parse_args_found @ expression R, E1, E2, E3, E4, E5, E6; identifier func; @@ ( R = parse_args(E1, E2, E3, E4, E5, E6, + NULL, func); | R = parse_args(E1, E2, E3, E4, E5, E6, + NULL, &func); | R = parse_args(E1, E2, E3, E4, E5, E6, + NULL, NULL); | parse_args(E1, E2, E3, E4, E5, E6, + NULL, func); | parse_args(E1, E2, E3, E4, E5, E6, + NULL, &func); | parse_args(E1, E2, E3, E4, E5, E6, + NULL, NULL); ) @ parse_args_unused depends on parse_args_found @ identifier parse_args_found.func; @@ int func(char *param, char *val, const char *unused + , void *arg ) { ... } @ mod_unused depends on parse_args_found @ identifier parse_args_found.func; expression A1, A2, A3; @@ - func(A1, A2, A3); + func(A1, A2, A3, NULL); Generated-by: Coccinelle SmPL Cc: cocci@systeme.lip6.fr Cc: Tejun Heo <tj@kernel.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Christoph Hellwig <hch@infradead.org> Cc: Felipe Contreras <felipe.contreras@gmail.com> Cc: Ewan Milne <emilne@redhat.com> Cc: Jean Delvare <jdelvare@suse.de> Cc: Hannes Reinecke <hare@suse.de> Cc: Jani Nikula <jani.nikula@intel.com> Cc: linux-kernel@vger.kernel.org Reviewed-by: Tejun Heo <tj@kernel.org> Acked-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-31 07:20:03 +08:00
const char *unused, void *arg)
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
{
vpr_info("%s=\"%s\"\n", param, val);
return ddebug_dyndbg_param_cb(param, val, NULL, 0);
}
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
/*
* modprobe foo finds foo.params in boot-args, strips "foo.", and
* passes them to load_module(). This callback gets unknown params,
* processes dyndbg params, rejects others.
*/
int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *module)
{
vpr_info("module: %s %s=\"%s\"\n", module, param, val);
return ddebug_dyndbg_param_cb(param, val, module, -ENOENT);
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
}
static void ddebug_table_free(struct ddebug_table *dt)
{
list_del_init(&dt->link);
kfree(dt);
}
/*
* Called in response to a module being unloaded. Removes
* any ddebug_table's which point at the module.
*/
int ddebug_remove_module(const char *mod_name)
{
struct ddebug_table *dt, *nextdt;
int ret = -ENOENT;
mutex_lock(&ddebug_lock);
list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
if (dt->mod_name == mod_name) {
ddebug_table_free(dt);
ret = 0;
break;
}
}
mutex_unlock(&ddebug_lock);
if (!ret)
v2pr_info("removed module \"%s\"\n", mod_name);
return ret;
}
static void ddebug_remove_all_tables(void)
{
mutex_lock(&ddebug_lock);
while (!list_empty(&ddebug_tables)) {
struct ddebug_table *dt = list_entry(ddebug_tables.next,
struct ddebug_table,
link);
ddebug_table_free(dt);
}
mutex_unlock(&ddebug_lock);
}
Dynamic Debug: Initialize dynamic debug earlier via arch_initcall Having the ddebug_query= boot parameter it makes sense to set up dynamic debug as soon as possible. I expect sysfs files cannot be set up via an arch_initcall, because this one is even before fs_initcall. Therefore I splitted the dynamic_debug_init function into an early one and a later one providing /sys/../dynamic_debug/control file. Possibly dynamic_debug can be initialized even earlier, not sure whether this still makes sense then. I picked up arch_initcall as it covers quite a lot already. Dynamic debug needs to allocate memory, therefore it's not easily possible to set it up even before the command line gets parsed. Therefore the boot param query string is stored in a temp string which is applied when dynamic debug gets set up. This has been tested with ddebug_query="file ec.c +p" and I could retrieve pr_debug() messages early at boot during ACPI setup: ACPI: EC: Look up EC in DSDT ACPI: EC: ---> status = 0x08 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 ACPI: EC: ~~~> interrupt ACPI: EC: ---> status = 0x08 ACPI: EC: <--- data = 0xa4 ... ACPI: Interpreter enabled ACPI: (supports S0 S3 S4 S5) ACPI: Using IOAPIC for interrupt routing ACPI: EC: ---> status = 0x00 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: jbaron@redhat.com Acked-by: Pekka Enberg <penberg@cs.helsinki.fi> CC: linux-acpi@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-08-06 22:11:03 +08:00
static __initdata int ddebug_init_success;
static int __init dynamic_debug_init_control(void)
{
struct proc_dir_entry *procfs_dir;
struct dentry *debugfs_dir;
Dynamic Debug: Initialize dynamic debug earlier via arch_initcall Having the ddebug_query= boot parameter it makes sense to set up dynamic debug as soon as possible. I expect sysfs files cannot be set up via an arch_initcall, because this one is even before fs_initcall. Therefore I splitted the dynamic_debug_init function into an early one and a later one providing /sys/../dynamic_debug/control file. Possibly dynamic_debug can be initialized even earlier, not sure whether this still makes sense then. I picked up arch_initcall as it covers quite a lot already. Dynamic debug needs to allocate memory, therefore it's not easily possible to set it up even before the command line gets parsed. Therefore the boot param query string is stored in a temp string which is applied when dynamic debug gets set up. This has been tested with ddebug_query="file ec.c +p" and I could retrieve pr_debug() messages early at boot during ACPI setup: ACPI: EC: Look up EC in DSDT ACPI: EC: ---> status = 0x08 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 ACPI: EC: ~~~> interrupt ACPI: EC: ---> status = 0x08 ACPI: EC: <--- data = 0xa4 ... ACPI: Interpreter enabled ACPI: (supports S0 S3 S4 S5) ACPI: Using IOAPIC for interrupt routing ACPI: EC: ---> status = 0x00 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: jbaron@redhat.com Acked-by: Pekka Enberg <penberg@cs.helsinki.fi> CC: linux-acpi@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-08-06 22:11:03 +08:00
if (!ddebug_init_success)
return -ENODEV;
/* Create the control file in debugfs if it is enabled */
if (debugfs_initialized()) {
debugfs_dir = debugfs_create_dir("dynamic_debug", NULL);
debugfs_create_file("control", 0644, debugfs_dir, NULL,
&ddebug_proc_fops);
}
/* Also create the control file in procfs */
procfs_dir = proc_mkdir("dynamic_debug", NULL);
if (procfs_dir)
proc_create("control", 0644, procfs_dir, &proc_fops);
Dynamic Debug: Initialize dynamic debug earlier via arch_initcall Having the ddebug_query= boot parameter it makes sense to set up dynamic debug as soon as possible. I expect sysfs files cannot be set up via an arch_initcall, because this one is even before fs_initcall. Therefore I splitted the dynamic_debug_init function into an early one and a later one providing /sys/../dynamic_debug/control file. Possibly dynamic_debug can be initialized even earlier, not sure whether this still makes sense then. I picked up arch_initcall as it covers quite a lot already. Dynamic debug needs to allocate memory, therefore it's not easily possible to set it up even before the command line gets parsed. Therefore the boot param query string is stored in a temp string which is applied when dynamic debug gets set up. This has been tested with ddebug_query="file ec.c +p" and I could retrieve pr_debug() messages early at boot during ACPI setup: ACPI: EC: Look up EC in DSDT ACPI: EC: ---> status = 0x08 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 ACPI: EC: ~~~> interrupt ACPI: EC: ---> status = 0x08 ACPI: EC: <--- data = 0xa4 ... ACPI: Interpreter enabled ACPI: (supports S0 S3 S4 S5) ACPI: Using IOAPIC for interrupt routing ACPI: EC: ---> status = 0x00 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: jbaron@redhat.com Acked-by: Pekka Enberg <penberg@cs.helsinki.fi> CC: linux-acpi@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-08-06 22:11:03 +08:00
return 0;
}
static int __init dynamic_debug_init(void)
{
struct _ddebug *iter, *iter_mod_start;
int ret, i, mod_sites, mod_ct;
const char *modname;
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
char *cmdline;
Dynamic Debug: Initialize dynamic debug earlier via arch_initcall Having the ddebug_query= boot parameter it makes sense to set up dynamic debug as soon as possible. I expect sysfs files cannot be set up via an arch_initcall, because this one is even before fs_initcall. Therefore I splitted the dynamic_debug_init function into an early one and a later one providing /sys/../dynamic_debug/control file. Possibly dynamic_debug can be initialized even earlier, not sure whether this still makes sense then. I picked up arch_initcall as it covers quite a lot already. Dynamic debug needs to allocate memory, therefore it's not easily possible to set it up even before the command line gets parsed. Therefore the boot param query string is stored in a temp string which is applied when dynamic debug gets set up. This has been tested with ddebug_query="file ec.c +p" and I could retrieve pr_debug() messages early at boot during ACPI setup: ACPI: EC: Look up EC in DSDT ACPI: EC: ---> status = 0x08 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 ACPI: EC: ~~~> interrupt ACPI: EC: ---> status = 0x08 ACPI: EC: <--- data = 0xa4 ... ACPI: Interpreter enabled ACPI: (supports S0 S3 S4 S5) ACPI: Using IOAPIC for interrupt routing ACPI: EC: ---> status = 0x00 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: jbaron@redhat.com Acked-by: Pekka Enberg <penberg@cs.helsinki.fi> CC: linux-acpi@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-08-06 22:11:03 +08:00
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
struct _ddebug_info di = {
.descs = __start___dyndbg,
.classes = __start___dyndbg_classes,
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
.num_descs = __stop___dyndbg - __start___dyndbg,
.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
};
if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n");
return 1;
}
pr_info("Ignore empty _ddebug table in a CONFIG_DYNAMIC_DEBUG_CORE build\n");
ddebug_init_success = 1;
return 0;
}
iter = iter_mod_start = __start___dyndbg;
modname = iter->modname;
i = mod_sites = mod_ct = 0;
for (; iter < __stop___dyndbg; iter++, i++, mod_sites++) {
if (strcmp(modname, iter->modname)) {
mod_ct++;
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
di.num_descs = mod_sites;
di.descs = iter_mod_start;
ret = __ddebug_add_module(&di, i - mod_sites, modname);
if (ret)
goto out_err;
mod_sites = 0;
modname = iter->modname;
iter_mod_start = iter;
}
}
dyndbg: gather __dyndbg[] state into struct _ddebug_info This new struct composes the linker provided (vector,len) section, and provides a place to add other __dyndbg[] state-data later: descs - the vector of descriptors in __dyndbg section. num_descs - length of the data/section. Use it, in several different ways, as follows: In lib/dynamic_debug.c: ddebug_add_module(): Alter params-list, replacing 2 args (array,index) with a struct _ddebug_info * containing them both, with room for expansion. This helps future-proof the function prototype against the looming addition of class-map info into the dyndbg-state, by providing a place to add more member fields later. NB: later add static struct _ddebug_info builtins_state declaration, not needed yet. ddebug_add_module() is called in 2 contexts: In dynamic_debug_init(), declare, init a struct _ddebug_info di auto-var to use as a cursor. Then iterate over the prdbg blocks of the builtin modules, and update the di cursor before calling _add_module for each. Its called from kernel/module/main.c:load_info() for each loaded module: In internal.h, alter struct load_info, replacing the dyndbg array,len fields with an embedded _ddebug_info containing them both; and populate its members in find_module_sections(). The 2 calling contexts differ in that _init deals with contiguous subranges of __dyndbgs[] section, packed together, while loadable modules are added one at a time. So rename ddebug_add_module() into outer/__inner fns, call __inner from _init, and provide the offset into the builtin __dyndbgs[] where the module's prdbgs reside. The cursor provides start, len of the subrange for each. The offset will be used later to pack the results of builtin __dyndbg_sites[] de-duplication, and is 0 and unneeded for loadable modules, Note: kernel/module/main.c includes <dynamic_debug.h> for struct _ddeubg_info. This might be prone to include loops, since its also included by printk.h. Nothing has broken in robot-land on this. cc: Luis Chamberlain <mcgrof@kernel.org> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> Link: https://lore.kernel.org/r/20220904214134.408619-12-jim.cromie@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-05 05:40:48 +08:00
di.num_descs = mod_sites;
di.descs = iter_mod_start;
ret = __ddebug_add_module(&di, i - mod_sites, modname);
if (ret)
goto out_err;
ddebug_init_success = 1;
vpr_info("%d prdebugs in %d modules, %d KiB in ddebug tables, %d kiB in __dyndbg section\n",
i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
(int)((i * sizeof(struct _ddebug)) >> 10));
if (di.num_classes)
v2pr_info(" %d builtin ddebug class-maps\n", di.num_classes);
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
/* now that ddebug tables are loaded, process all boot args
* again to find and activate queries given in dyndbg params.
* While this has already been done for known boot params, it
* ignored the unknown ones (dyndbg in particular). Reusing
* parse_args avoids ad-hoc parsing. This will also attempt
* to activate queries for not-yet-loaded modules, which is
* slightly noisy if verbose, but harmless.
*/
cmdline = kstrdup(saved_command_line, GFP_KERNEL);
parse_args("dyndbg params", cmdline, NULL,
module: add extra argument for parse_params() callback This adds an extra argument onto parse_params() to be used as a way to make the unused callback a bit more useful and generic by allowing the caller to pass on a data structure of its choice. An example use case is to allow us to easily make module parameters for every module which we will do next. @ parse @ identifier name, args, params, num, level_min, level_max; identifier unknown, param, val, doing; type s16; @@ extern char *parse_args(const char *name, char *args, const struct kernel_param *params, unsigned num, s16 level_min, s16 level_max, + void *arg, int (*unknown)(char *param, char *val, const char *doing + , void *arg )); @ parse_mod @ identifier name, args, params, num, level_min, level_max; identifier unknown, param, val, doing; type s16; @@ char *parse_args(const char *name, char *args, const struct kernel_param *params, unsigned num, s16 level_min, s16 level_max, + void *arg, int (*unknown)(char *param, char *val, const char *doing + , void *arg )) { ... } @ parse_args_found @ expression R, E1, E2, E3, E4, E5, E6; identifier func; @@ ( R = parse_args(E1, E2, E3, E4, E5, E6, + NULL, func); | R = parse_args(E1, E2, E3, E4, E5, E6, + NULL, &func); | R = parse_args(E1, E2, E3, E4, E5, E6, + NULL, NULL); | parse_args(E1, E2, E3, E4, E5, E6, + NULL, func); | parse_args(E1, E2, E3, E4, E5, E6, + NULL, &func); | parse_args(E1, E2, E3, E4, E5, E6, + NULL, NULL); ) @ parse_args_unused depends on parse_args_found @ identifier parse_args_found.func; @@ int func(char *param, char *val, const char *unused + , void *arg ) { ... } @ mod_unused depends on parse_args_found @ identifier parse_args_found.func; expression A1, A2, A3; @@ - func(A1, A2, A3); + func(A1, A2, A3, NULL); Generated-by: Coccinelle SmPL Cc: cocci@systeme.lip6.fr Cc: Tejun Heo <tj@kernel.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Christoph Hellwig <hch@infradead.org> Cc: Felipe Contreras <felipe.contreras@gmail.com> Cc: Ewan Milne <emilne@redhat.com> Cc: Jean Delvare <jdelvare@suse.de> Cc: Hannes Reinecke <hare@suse.de> Cc: Jani Nikula <jani.nikula@intel.com> Cc: linux-kernel@vger.kernel.org Reviewed-by: Tejun Heo <tj@kernel.org> Acked-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Luis R. Rodriguez <mcgrof@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-31 07:20:03 +08:00
0, 0, 0, NULL, &ddebug_dyndbg_boot_param_cb);
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
kfree(cmdline);
return 0;
out_err:
ddebug_remove_all_tables();
return 0;
}
Dynamic Debug: Initialize dynamic debug earlier via arch_initcall Having the ddebug_query= boot parameter it makes sense to set up dynamic debug as soon as possible. I expect sysfs files cannot be set up via an arch_initcall, because this one is even before fs_initcall. Therefore I splitted the dynamic_debug_init function into an early one and a later one providing /sys/../dynamic_debug/control file. Possibly dynamic_debug can be initialized even earlier, not sure whether this still makes sense then. I picked up arch_initcall as it covers quite a lot already. Dynamic debug needs to allocate memory, therefore it's not easily possible to set it up even before the command line gets parsed. Therefore the boot param query string is stored in a temp string which is applied when dynamic debug gets set up. This has been tested with ddebug_query="file ec.c +p" and I could retrieve pr_debug() messages early at boot during ACPI setup: ACPI: EC: Look up EC in DSDT ACPI: EC: ---> status = 0x08 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 ACPI: EC: ~~~> interrupt ACPI: EC: ---> status = 0x08 ACPI: EC: <--- data = 0xa4 ... ACPI: Interpreter enabled ACPI: (supports S0 S3 S4 S5) ACPI: Using IOAPIC for interrupt routing ACPI: EC: ---> status = 0x00 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: jbaron@redhat.com Acked-by: Pekka Enberg <penberg@cs.helsinki.fi> CC: linux-acpi@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-08-06 22:11:03 +08:00
/* Allow early initialization for boot messages via boot param */
early_initcall(dynamic_debug_init);
dynamic_debug: make dynamic-debug work for module initialization This introduces a fake module param $module.dyndbg. Its based upon Thomas Renninger's $module.ddebug boot-time debugging patch from https://lkml.org/lkml/2010/9/15/397 The 'fake' module parameter is provided for all modules, whether or not they need it. It is not explicitly added to each module, but is implemented in callbacks invoked from parse_args. For builtin modules, dynamic_debug_init() now directly calls parse_args(..., &ddebug_dyndbg_boot_params_cb), to process the params undeclared in the modules, just after the ddebug tables are processed. While its slightly weird to reprocess the boot params, parse_args() is already called repeatedly by do_initcall_levels(). More importantly, the dyndbg queries (given in ddebug_query or dyndbg params) cannot be activated until after the ddebug tables are ready, and reusing parse_args is cleaner than doing an ad-hoc parse. This reparse would break options like inc_verbosity, but they probably should be params, like verbosity=3. ddebug_dyndbg_boot_params_cb() handles both bare dyndbg (aka: ddebug_query) and module-prefixed dyndbg params, and ignores all other parameters. For example, the following will enable pr_debug()s in 4 builtin modules, in the order given: dyndbg="module params +p; module aio +p" module.dyndbg=+p pci.dyndbg For loadable modules, parse_args() in load_module() calls ddebug_dyndbg_module_params_cb(). This handles bare dyndbg params as passed from modprobe, and errors on other unknown params. Note that modprobe reads /proc/cmdline, so "modprobe foo" grabs all foo.params, strips the "foo.", and passes these to the kernel. ddebug_dyndbg_module_params_cb() is again called for the unknown params; it handles dyndbg, and errors on others. The "doing" arg added previously contains the module name. For non CONFIG_DYNAMIC_DEBUG builds, the stub function accepts and ignores $module.dyndbg params, other unknowns get -ENOENT. If no param value is given (as in pci.dyndbg example above), "+p" is assumed, which enables all pr_debug callsites in the module. The dyndbg fake parameter is not shown in /sys/module/*/parameters, thus it does not use any resources. Changes to it are made via the control file. Also change pr_info in ddebug_exec_queries to vpr_info, no need to see it all the time. Signed-off-by: Jim Cromie <jim.cromie@gmail.com> CC: Thomas Renninger <trenn@suse.de> CC: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Jason Baron <jbaron@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2012-04-28 04:30:35 +08:00
Dynamic Debug: Initialize dynamic debug earlier via arch_initcall Having the ddebug_query= boot parameter it makes sense to set up dynamic debug as soon as possible. I expect sysfs files cannot be set up via an arch_initcall, because this one is even before fs_initcall. Therefore I splitted the dynamic_debug_init function into an early one and a later one providing /sys/../dynamic_debug/control file. Possibly dynamic_debug can be initialized even earlier, not sure whether this still makes sense then. I picked up arch_initcall as it covers quite a lot already. Dynamic debug needs to allocate memory, therefore it's not easily possible to set it up even before the command line gets parsed. Therefore the boot param query string is stored in a temp string which is applied when dynamic debug gets set up. This has been tested with ddebug_query="file ec.c +p" and I could retrieve pr_debug() messages early at boot during ACPI setup: ACPI: EC: Look up EC in DSDT ACPI: EC: ---> status = 0x08 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 ACPI: EC: ~~~> interrupt ACPI: EC: ---> status = 0x08 ACPI: EC: <--- data = 0xa4 ... ACPI: Interpreter enabled ACPI: (supports S0 S3 S4 S5) ACPI: Using IOAPIC for interrupt routing ACPI: EC: ---> status = 0x00 ACPI: EC: transaction start ACPI: EC: <--- command = 0x80 Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: jbaron@redhat.com Acked-by: Pekka Enberg <penberg@cs.helsinki.fi> CC: linux-acpi@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-08-06 22:11:03 +08:00
/* Debugfs setup must be done later */
fs_initcall(dynamic_debug_init_control);