2009-02-05 16:51:38 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
2011-01-23 16:17:24 +00:00
|
|
|
* Copyright (C) 2011 Bart Van Assche. All Rights Reserved.
|
2014-01-23 23:54:14 +00:00
|
|
|
* Copyright (C) 2013 Du, Changbin <changbin.du@gmail.com>
|
2009-02-05 16:51:38 +00:00
|
|
|
*/
|
|
|
|
|
2020-07-19 23:10:57 +00:00
|
|
|
#define pr_fmt(fmt) "dyndbg: " fmt
|
2011-08-11 18:36:33 +00:00
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
2012-05-07 23:47:32 +00:00
|
|
|
#include <linux/moduleparam.h>
|
|
|
|
#include <linux/kallsyms.h>
|
|
|
|
#include <linux/types.h>
|
2009-02-05 16:51:38 +00:00
|
|
|
#include <linux/mutex.h>
|
2012-05-07 23:47:32 +00:00
|
|
|
#include <linux/proc_fs.h>
|
2009-02-05 16:51:38 +00:00
|
|
|
#include <linux/seq_file.h>
|
2012-05-07 23:47:32 +00:00
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/sysctl.h>
|
2009-02-05 16:51:38 +00:00
|
|
|
#include <linux/ctype.h>
|
2012-05-07 23:47:32 +00:00
|
|
|
#include <linux/string.h>
|
2014-01-23 23:54:14 +00:00
|
|
|
#include <linux/parser.h>
|
2013-04-30 22:27:32 +00:00
|
|
|
#include <linux/string_helpers.h>
|
2012-05-07 23:47:32 +00:00
|
|
|
#include <linux/uaccess.h>
|
2009-02-05 16:51:38 +00:00
|
|
|
#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 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2012-05-07 23:47:32 +00:00
|
|
|
#include <linux/jump_label.h>
|
2011-01-23 16:17:24 +00:00
|
|
|
#include <linux/hardirq.h>
|
2011-02-03 23:59:58 +00:00
|
|
|
#include <linux/sched.h>
|
2012-05-07 23:47:32 +00:00
|
|
|
#include <linux/device.h>
|
2011-08-11 18:36:48 +00:00
|
|
|
#include <linux/netdevice.h>
|
2009-02-05 16:51:38 +00:00
|
|
|
|
2019-05-01 10:48:13 +00:00
|
|
|
#include <rdma/ib_verbs.h>
|
|
|
|
|
2020-07-19 23:10:45 +00:00
|
|
|
extern struct _ddebug __start___dyndbg[];
|
|
|
|
extern struct _ddebug __stop___dyndbg[];
|
2022-09-04 21:40:52 +00:00
|
|
|
extern struct ddebug_class_map __start___dyndbg_classes[];
|
|
|
|
extern struct ddebug_class_map __stop___dyndbg_classes[];
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
struct ddebug_table {
|
dyndbg: add ddebug_attach_module_classes
Add ddebug_attach_module_classes(), call it from ddebug_add_module().
It scans the classes/section its given, finds records where the
module-name matches the module being added, and adds them to the
module's maps list. No locking here, since the record
isn't yet linked into the ddebug_tables list.
It is called indirectly from 2 sources:
- from load_module(), where it scans the module's __dyndbg_classes
section, which contains DYNAMIC_DEBUG_CLASSES definitions from just
the module.
- from dynamic_debug_init(), where all DYNAMIC_DEBUG_CLASSES
definitions of each builtin module have been packed together.
This is why ddebug_attach_module_classes() checks module-name.
NOTES
Its (highly) likely that builtin classes will be ordered by module
name (just like prdbg descriptors are in the __dyndbg section). So
the list can be replaced by a vector (ptr + length), which will work
for loaded modules too. This would imitate whats currently done for
the _ddebug descriptors.
That said, converting to vector,len is close to pointless; a small
minority of modules will ever define a class-map, and almost all of
them will have only 1 or 2 class-maps, so theres only a couple dozen
pointers to save. TODO: re-evaluate for lines removable.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-17-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:53 +00:00
|
|
|
struct list_head link, maps;
|
2015-11-07 00:30:15 +00:00
|
|
|
const char *mod_name;
|
2009-02-05 16:51:38 +00:00
|
|
|
unsigned int num_ddebugs;
|
|
|
|
struct _ddebug *ddebugs;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ddebug_query {
|
|
|
|
const char *filename;
|
|
|
|
const char *module;
|
|
|
|
const char *function;
|
|
|
|
const char *format;
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
const char *class_string;
|
2009-02-05 16:51:38 +00:00
|
|
|
unsigned int first_lineno, last_lineno;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ddebug_iter {
|
|
|
|
struct ddebug_table *table;
|
2022-09-04 21:40:42 +00:00
|
|
|
int idx;
|
2009-02-05 16:51:38 +00:00
|
|
|
};
|
|
|
|
|
2020-07-19 23:10:55 +00:00
|
|
|
struct flag_settings {
|
|
|
|
unsigned int flags;
|
|
|
|
unsigned int mask;
|
|
|
|
};
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
static DEFINE_MUTEX(ddebug_lock);
|
|
|
|
static LIST_HEAD(ddebug_tables);
|
2012-12-05 21:48:26 +00:00
|
|
|
static int verbose;
|
2011-12-19 22:12:24 +00:00
|
|
|
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-19 21:07:46 +00: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)");
|
2009-02-05 16:51:38 +00:00
|
|
|
|
2011-12-19 22:13:12 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2023-07-09 21:17:58 +00:00
|
|
|
static const struct { unsigned flag:8; char opt_char; } opt_array[] = {
|
2011-01-23 16:17:24 +00:00
|
|
|
{ _DPRINTK_FLAGS_PRINT, 'p' },
|
|
|
|
{ _DPRINTK_FLAGS_INCL_MODNAME, 'm' },
|
|
|
|
{ _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' },
|
|
|
|
{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
|
|
|
|
{ _DPRINTK_FLAGS_INCL_TID, 't' },
|
2011-12-19 22:12:44 +00:00
|
|
|
{ _DPRINTK_FLAGS_NONE, '_' },
|
2011-01-23 16:17:24 +00:00
|
|
|
};
|
|
|
|
|
2020-07-19 23:10:47 +00:00
|
|
|
struct flagsbuf { char buf[ARRAY_SIZE(opt_array)+1]; };
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
/* format a string into buf[] which describes the _ddebug's flags */
|
2020-07-19 23:10:47 +00:00
|
|
|
static char *ddebug_describe_flags(unsigned int flags, struct flagsbuf *fb)
|
2009-02-05 16:51:38 +00:00
|
|
|
{
|
2020-07-19 23:10:47 +00:00
|
|
|
char *p = fb->buf;
|
2011-01-23 16:17:24 +00:00
|
|
|
int i;
|
2009-02-05 16:51:38 +00:00
|
|
|
|
2011-01-23 16:17:24 +00:00
|
|
|
for (i = 0; i < ARRAY_SIZE(opt_array); ++i)
|
2020-07-19 23:10:47 +00:00
|
|
|
if (flags & opt_array[i].flag)
|
2011-01-23 16:17:24 +00:00
|
|
|
*p++ = opt_array[i].opt_char;
|
2020-07-19 23:10:47 +00:00
|
|
|
if (p == fb->buf)
|
2011-12-19 22:12:44 +00:00
|
|
|
*p++ = '_';
|
2009-02-05 16:51:38 +00:00
|
|
|
*p = '\0';
|
|
|
|
|
2020-07-19 23:10:47 +00:00
|
|
|
return fb->buf;
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
|
|
|
|
2020-07-19 23:10:44 +00:00
|
|
|
#define vnpr_info(lvl, fmt, ...) \
|
2012-04-27 20:30:32 +00:00
|
|
|
do { \
|
2020-07-19 23:10:44 +00:00
|
|
|
if (verbose >= lvl) \
|
2012-12-05 21:48:26 +00:00
|
|
|
pr_info(fmt, ##__VA_ARGS__); \
|
2011-12-19 22:13:16 +00:00
|
|
|
} while (0)
|
|
|
|
|
2020-07-19 23:10:44 +00:00
|
|
|
#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-19 21:07:46 +00:00
|
|
|
#define v3pr_info(fmt, ...) vnpr_info(3, fmt, ##__VA_ARGS__)
|
|
|
|
#define v4pr_info(fmt, ...) vnpr_info(4, fmt, ##__VA_ARGS__)
|
2020-07-19 23:10:44 +00:00
|
|
|
|
2012-12-05 21:48:26 +00:00
|
|
|
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--;
|
|
|
|
}
|
|
|
|
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
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);
|
2012-12-05 21:48:26 +00:00
|
|
|
}
|
|
|
|
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
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 */
|
2009-02-05 16:51:38 +00:00
|
|
|
/*
|
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-19 22:13:21 +00: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.
|
2009-02-05 16:51:38 +00:00
|
|
|
*/
|
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-19 22:13:21 +00:00
|
|
|
static int ddebug_change(const struct ddebug_query *query,
|
2020-07-19 23:10:55 +00:00
|
|
|
struct flag_settings *modifiers)
|
2009-02-05 16:51:38 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct ddebug_table *dt;
|
|
|
|
unsigned int newflags;
|
|
|
|
unsigned int nfound = 0;
|
2022-09-04 21:40:40 +00:00
|
|
|
struct flagsbuf fbuf, nbuf;
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
struct ddebug_class_map *map = NULL;
|
|
|
|
int __outvar valid_class;
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
/* search for matching ddebugs */
|
|
|
|
mutex_lock(&ddebug_lock);
|
|
|
|
list_for_each_entry(dt, &ddebug_tables, link) {
|
|
|
|
|
|
|
|
/* match against the module name */
|
2014-01-23 23:54:14 +00:00
|
|
|
if (query->module &&
|
|
|
|
!match_wildcard(query->module, dt->mod_name))
|
2009-02-05 16:51:38 +00:00
|
|
|
continue;
|
|
|
|
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-12-05 21:48:26 +00:00
|
|
|
for (i = 0; i < dt->num_ddebugs; i++) {
|
2009-02-05 16:51:38 +00:00
|
|
|
struct _ddebug *dp = &dt->ddebugs[i];
|
|
|
|
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
/* match site against query-class */
|
|
|
|
if (dp->class_id != valid_class)
|
|
|
|
continue;
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
/* match against the source filename */
|
2011-12-19 22:12:39 +00:00
|
|
|
if (query->filename &&
|
2014-01-23 23:54:14 +00:00
|
|
|
!match_wildcard(query->filename, dp->filename) &&
|
|
|
|
!match_wildcard(query->filename,
|
|
|
|
kbasename(dp->filename)) &&
|
|
|
|
!match_wildcard(query->filename,
|
|
|
|
trim_prefix(dp->filename)))
|
2009-02-05 16:51:38 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* match against the function */
|
2011-12-19 22:12:39 +00:00
|
|
|
if (query->function &&
|
2014-01-23 23:54:14 +00:00
|
|
|
!match_wildcard(query->function, dp->function))
|
2009-02-05 16:51:38 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* match against the format */
|
2020-07-19 23:10:56 +00:00
|
|
|
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;
|
|
|
|
}
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
/* 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++;
|
|
|
|
|
2020-07-19 23:10:55 +00:00
|
|
|
newflags = (dp->flags & modifiers->mask) | modifiers->flags;
|
2009-02-05 16:51:38 +00:00
|
|
|
if (newflags == dp->flags)
|
|
|
|
continue;
|
2018-12-30 15:14:15 +00:00
|
|
|
#ifdef CONFIG_JUMP_LABEL
|
2016-08-03 20:46:39 +00:00
|
|
|
if (dp->flags & _DPRINTK_FLAGS_PRINT) {
|
2022-09-04 21:40:38 +00:00
|
|
|
if (!(newflags & _DPRINTK_FLAGS_PRINT))
|
2016-08-03 20:46:39 +00:00
|
|
|
static_branch_disable(&dp->key.dd_key_true);
|
2022-09-04 21:40:38 +00:00
|
|
|
} else if (newflags & _DPRINTK_FLAGS_PRINT) {
|
2016-08-03 20:46:39 +00:00
|
|
|
static_branch_enable(&dp->key.dd_key_true);
|
2022-09-04 21:40:38 +00:00
|
|
|
}
|
2016-08-03 20:46:39 +00:00
|
|
|
#endif
|
2022-09-04 21:40:40 +00:00
|
|
|
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));
|
2009-02-05 16:51:38 +00:00
|
|
|
dp->flags = newflags;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mutex_unlock(&ddebug_lock);
|
|
|
|
|
|
|
|
if (!nfound && verbose)
|
2011-08-11 18:36:33 +00:00
|
|
|
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-19 22:13:21 +00:00
|
|
|
|
|
|
|
return nfound;
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Split the buffer `buf' into space-separated words.
|
2009-02-06 01:54:26 +00:00
|
|
|
* Handles simple " and ' quoting, i.e. without nested,
|
|
|
|
* embedded or escaped \". Return the number of words
|
|
|
|
* or <0 on error.
|
2009-02-05 16:51:38 +00:00
|
|
|
*/
|
|
|
|
static int ddebug_tokenize(char *buf, char *words[], int maxwords)
|
|
|
|
{
|
|
|
|
int nwords = 0;
|
|
|
|
|
2009-02-06 01:54:26 +00:00
|
|
|
while (*buf) {
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
/* Skip leading whitespace */
|
2009-12-15 02:01:06 +00:00
|
|
|
buf = skip_spaces(buf);
|
2009-02-06 01:54:26 +00:00
|
|
|
if (!*buf)
|
|
|
|
break; /* oh, it was trailing whitespace */
|
2011-12-19 22:13:03 +00:00
|
|
|
if (*buf == '#')
|
|
|
|
break; /* token starts comment, skip rest of line */
|
2009-02-06 01:54:26 +00:00
|
|
|
|
2011-12-19 22:11:09 +00:00
|
|
|
/* find `end' of word, whitespace separated or quoted */
|
2009-02-06 01:54:26 +00:00
|
|
|
if (*buf == '"' || *buf == '\'') {
|
|
|
|
int quote = *buf++;
|
2012-12-05 21:48:26 +00:00
|
|
|
for (end = buf; *end && *end != quote; end++)
|
2009-02-06 01:54:26 +00:00
|
|
|
;
|
2012-12-05 21:48:27 +00:00
|
|
|
if (!*end) {
|
|
|
|
pr_err("unclosed quote: %s\n", buf);
|
2009-02-06 01:54:26 +00:00
|
|
|
return -EINVAL; /* unclosed quote */
|
2012-12-05 21:48:27 +00:00
|
|
|
}
|
2009-02-06 01:54:26 +00:00
|
|
|
} else {
|
2020-09-10 16:42:38 +00:00
|
|
|
for (end = buf; *end && !isspace(*end); end++)
|
2009-02-06 01:54:26 +00:00
|
|
|
;
|
|
|
|
BUG_ON(end == buf);
|
|
|
|
}
|
|
|
|
|
2011-12-19 22:11:09 +00:00
|
|
|
/* `buf' is start of word, `end' is one past its end */
|
2012-12-05 21:48:27 +00:00
|
|
|
if (nwords == maxwords) {
|
|
|
|
pr_err("too many words, legal max <=%d\n", maxwords);
|
2009-02-06 01:54:26 +00:00
|
|
|
return -EINVAL; /* ran out of words[] before bytes */
|
2012-12-05 21:48:27 +00:00
|
|
|
}
|
2009-02-06 01:54:26 +00:00
|
|
|
if (*end)
|
|
|
|
*end++ = '\0'; /* terminate the word */
|
|
|
|
words[nwords++] = buf;
|
|
|
|
buf = end;
|
|
|
|
}
|
2009-02-05 16:51:38 +00:00
|
|
|
|
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-19 21:07:46 +00:00
|
|
|
if (verbose >= 3) {
|
2009-02-05 16:51:38 +00:00
|
|
|
int i;
|
2011-08-11 18:36:33 +00:00
|
|
|
pr_info("split into words:");
|
2012-12-05 21:48:26 +00:00
|
|
|
for (i = 0; i < nwords; i++)
|
2011-08-11 18:36:33 +00:00
|
|
|
pr_cont(" \"%s\"", words[i]);
|
|
|
|
pr_cont("\n");
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2014-01-28 01:06:59 +00:00
|
|
|
if (kstrtouint(str, 10, val) < 0) {
|
2012-12-05 21:48:27 +00:00
|
|
|
pr_err("bad line-number: %s\n", str);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
return 0;
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
|
|
|
|
2020-07-19 23:10:52 +00:00
|
|
|
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-19 21:07:46 +00:00
|
|
|
v3pr_info("parsed line %d-%d\n", query->first_lineno,
|
2020-07-19 23:10:52 +00:00
|
|
|
query->last_lineno);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-19 22:12:49 +00:00
|
|
|
static int check_set(const char **dest, char *src, char *name)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (*dest) {
|
|
|
|
rc = -EINVAL;
|
2012-12-05 21:48:26 +00:00
|
|
|
pr_err("match-spec:%s val:%s overridden by %s\n",
|
|
|
|
name, *dest, src);
|
2011-12-19 22:12:49 +00:00
|
|
|
}
|
|
|
|
*dest = src;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
/*
|
|
|
|
* Parse words[] as a ddebug query specification, which is a series
|
2020-09-10 16:45:03 +00:00
|
|
|
* of (keyword, value) pairs chosen from these possibilities:
|
2009-02-05 16:51:38 +00:00
|
|
|
*
|
|
|
|
* 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
|
2011-12-19 22:12:49 +00:00
|
|
|
*
|
|
|
|
* Only 1 of each type is allowed.
|
|
|
|
* Returns 0 on success, <0 on error.
|
2009-02-05 16:51:38 +00:00
|
|
|
*/
|
|
|
|
static int ddebug_parse_query(char *words[], int nwords,
|
2012-04-27 20:30:40 +00:00
|
|
|
struct ddebug_query *query, const char *modname)
|
2009-02-05 16:51:38 +00:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2013-08-27 16:50:03 +00:00
|
|
|
int rc = 0;
|
2020-07-19 23:10:53 +00:00
|
|
|
char *fline;
|
2020-09-10 16:45:03 +00:00
|
|
|
|
|
|
|
/* check we have an even number of words */
|
|
|
|
if (nwords % 2 != 0) {
|
|
|
|
pr_err("expecting pairs of match-spec <value>\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2009-02-05 16:51:38 +00:00
|
|
|
|
2020-09-10 16:45:03 +00:00
|
|
|
for (i = 0; i < nwords; i += 2) {
|
2020-09-21 19:04:33 +00:00
|
|
|
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"))
|
2020-07-19 23:10:53 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* tail :$info is function or line-range */
|
|
|
|
fline = strchr(query->filename, ':');
|
|
|
|
if (!fline)
|
2021-04-14 21:24:00 +00:00
|
|
|
continue;
|
2020-07-19 23:10:53 +00:00
|
|
|
*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;
|
|
|
|
}
|
2020-09-21 19:04:33 +00:00
|
|
|
} else if (!strcmp(keyword, "module")) {
|
|
|
|
rc = check_set(&query->module, arg, "module");
|
|
|
|
} else if (!strcmp(keyword, "format")) {
|
|
|
|
string_unescape_inplace(arg, UNESCAPE_SPACE |
|
2013-04-30 22:27:32 +00:00
|
|
|
UNESCAPE_OCTAL |
|
|
|
|
UNESCAPE_SPECIAL);
|
2020-09-21 19:04:33 +00:00
|
|
|
rc = check_set(&query->format, arg, "format");
|
|
|
|
} else if (!strcmp(keyword, "line")) {
|
|
|
|
if (parse_linerange(query, arg))
|
2009-02-05 16:51:38 +00:00
|
|
|
return -EINVAL;
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
} else if (!strcmp(keyword, "class")) {
|
|
|
|
rc = check_set(&query->class_string, arg, "class");
|
2009-02-05 16:51:38 +00:00
|
|
|
} else {
|
2020-09-21 19:04:33 +00:00
|
|
|
pr_err("unknown keyword \"%s\"\n", keyword);
|
2009-02-05 16:51:38 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
2011-12-19 22:12:49 +00:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
dyndbg: let query-modname override actual module name
dyndbg's control-parser: ddebug_parse_query(), requires that search
terms: module, func, file, lineno, are used only once in a query; a
thing cannot be named both foo and bar.
The cited commit added an overriding module modname, taken from the
module loader, which is authoritative. So it set query.module 1st,
which disallowed its use in the query-string.
But now, its useful to allow a module-load to enable classes across a
whole (or part of) a subsystem at once.
# enable (dynamic-debug in) drm only
modprobe drm dyndbg="class DRM_UT_CORE +p"
# get drm_helper too
modprobe drm dyndbg="class DRM_UT_CORE module drm* +p"
# get everything that knows DRM_UT_CORE
modprobe drm dyndbg="class DRM_UT_CORE module * +p"
# also for boot-args:
drm.dyndbg="class DRM_UT_CORE module * +p"
So convert the override into a default, by filling it only when/after
the query-string omitted the module.
NB: the query class FOO handling is forthcoming.
Fixes: 8e59b5cfb9a6 dynamic_debug: add modname arg to exec_query callchain
Acked-by: Jason Baron <jbaron@akamai.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-8-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:44 +00:00
|
|
|
if (!query->module && modname)
|
|
|
|
/*
|
|
|
|
* support $modname.dyndbg=<multiple queries>, when
|
|
|
|
* not given in the query itself
|
|
|
|
*/
|
|
|
|
query->module = modname;
|
|
|
|
|
2011-12-19 22:13:16 +00:00
|
|
|
vpr_info_dq(query, "parsed");
|
2009-02-05 16:51:38 +00:00
|
|
|
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.
|
|
|
|
*/
|
2020-07-19 23:10:55 +00:00
|
|
|
static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
|
2009-02-05 16:51:38 +00:00
|
|
|
{
|
2020-07-19 23:10:55 +00:00
|
|
|
int op, i;
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
switch (*str) {
|
|
|
|
case '+':
|
|
|
|
case '-':
|
|
|
|
case '=':
|
|
|
|
op = *str++;
|
|
|
|
break;
|
|
|
|
default:
|
2012-12-05 21:48:27 +00:00
|
|
|
pr_err("bad flag-op %c, at start of %s\n", *str, str);
|
2009-02-05 16:51:38 +00:00
|
|
|
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-19 21:07:46 +00:00
|
|
|
v3pr_info("op='%c'\n", op);
|
2009-02-05 16:51:38 +00:00
|
|
|
|
2012-12-05 21:48:26 +00:00
|
|
|
for (; *str ; ++str) {
|
2011-01-23 16:17:24 +00:00
|
|
|
for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
|
|
|
|
if (*str == opt_array[i].opt_char) {
|
2020-07-19 23:10:55 +00:00
|
|
|
modifiers->flags |= opt_array[i].flag;
|
2011-01-23 16:17:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
2012-12-05 21:48:27 +00:00
|
|
|
if (i < 0) {
|
2020-07-19 23:10:48 +00:00
|
|
|
pr_err("unknown flag '%c'\n", *str);
|
2011-01-23 16:17:24 +00:00
|
|
|
return -EINVAL;
|
2012-12-05 21:48:27 +00:00
|
|
|
}
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
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-19 21:07:46 +00:00
|
|
|
v3pr_info("flags=0x%x\n", modifiers->flags);
|
2009-02-05 16:51:38 +00:00
|
|
|
|
2020-07-19 23:10:55 +00:00
|
|
|
/* calculate final flags, mask based upon op */
|
2009-02-05 16:51:38 +00:00
|
|
|
switch (op) {
|
|
|
|
case '=':
|
2020-07-19 23:10:55 +00:00
|
|
|
/* modifiers->flags already set */
|
|
|
|
modifiers->mask = 0;
|
2009-02-05 16:51:38 +00:00
|
|
|
break;
|
|
|
|
case '+':
|
2020-07-19 23:10:55 +00:00
|
|
|
modifiers->mask = ~0U;
|
2009-02-05 16:51:38 +00:00
|
|
|
break;
|
|
|
|
case '-':
|
2020-07-19 23:10:55 +00:00
|
|
|
modifiers->mask = ~modifiers->flags;
|
|
|
|
modifiers->flags = 0;
|
2009-02-05 16:51:38 +00:00
|
|
|
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-19 21:07:46 +00:00
|
|
|
v3pr_info("*flagsp=0x%x *maskp=0x%x\n", modifiers->flags, modifiers->mask);
|
2020-07-19 23:10:55 +00:00
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-27 20:30:40 +00:00
|
|
|
static int ddebug_exec_query(char *query_string, const char *modname)
|
2010-08-06 14:11:01 +00:00
|
|
|
{
|
2020-07-19 23:10:55 +00:00
|
|
|
struct flag_settings modifiers = {};
|
2020-07-19 23:10:49 +00:00
|
|
|
struct ddebug_query query = {};
|
2010-08-06 14:11:01 +00:00
|
|
|
#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-19 22:13:21 +00:00
|
|
|
int nwords, nfound;
|
2010-08-06 14:11:01 +00:00
|
|
|
char *words[MAXWORDS];
|
|
|
|
|
|
|
|
nwords = ddebug_tokenize(query_string, words, MAXWORDS);
|
2012-12-05 21:48:27 +00:00
|
|
|
if (nwords <= 0) {
|
|
|
|
pr_err("tokenize failed\n");
|
2010-08-06 14:11:01 +00:00
|
|
|
return -EINVAL;
|
2012-12-05 21:48:27 +00:00
|
|
|
}
|
|
|
|
/* check flags 1st (last arg) so query is pairs of spec,val */
|
2020-07-19 23:10:55 +00:00
|
|
|
if (ddebug_parse_flags(words[nwords-1], &modifiers)) {
|
2012-12-05 21:48:27 +00:00
|
|
|
pr_err("flags parse failed\n");
|
2010-08-06 14:11:01 +00:00
|
|
|
return -EINVAL;
|
2012-12-05 21:48:27 +00:00
|
|
|
}
|
|
|
|
if (ddebug_parse_query(words, nwords-1, &query, modname)) {
|
|
|
|
pr_err("query parse failed\n");
|
2010-08-06 14:11:01 +00:00
|
|
|
return -EINVAL;
|
2012-12-05 21:48:27 +00:00
|
|
|
}
|
2010-08-06 14:11:01 +00:00
|
|
|
/* actually go and implement the change */
|
2020-07-19 23:10:55 +00:00
|
|
|
nfound = ddebug_change(&query, &modifiers);
|
2012-12-05 21:48:26 +00:00
|
|
|
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-19 22:13:21 +00: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.
|
|
|
|
*/
|
dyndbg: refine export, rename to dynamic_debug_exec_queries()
commit 4c0d77828d4f ("dyndbg: export ddebug_exec_queries") had a few
problems:
- broken non DYNAMIC_DEBUG_CORE configs, sparse warning
- the exported function modifies query string, breaks on RO strings.
- func name follows internal convention, shouldn't be exposed as is.
1st is fixed in header with ifdefd function prototype or stub defn.
Also remove an obsolete HAVE-symbol ifdef-comment, and add others.
Fix others by wrapping existing internal function with a new one,
named in accordance with module-prefix naming convention, before
export hits v5.9.0. In new function, copy query string to a local
buffer, so users can pass hard-coded/RO queries, and internal function
can be used unchanged.
Fixes: 4c0d77828d4f ("dyndbg: export ddebug_exec_queries")
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20200831182210.850852-3-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-08-31 18:22:09 +00:00
|
|
|
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-19 22:13:21 +00: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;
|
|
|
|
|
2021-10-14 22:36:14 +00:00
|
|
|
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-19 22:13:21 +00:00
|
|
|
|
2012-04-27 20:30:40 +00: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-19 22:13:21 +00:00
|
|
|
if (rc < 0) {
|
|
|
|
errs++;
|
|
|
|
exitcode = rc;
|
2012-12-05 21:48:26 +00:00
|
|
|
} 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-19 22:13:21 +00:00
|
|
|
nfound += rc;
|
2012-12-05 21:48:26 +00:00
|
|
|
}
|
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-19 22:13:21 +00:00
|
|
|
i++;
|
|
|
|
}
|
2021-10-13 22:07:26 +00:00
|
|
|
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-19 21:07:46 +00:00
|
|
|
v2pr_info("processed %d queries, with %d matches, %d errs\n",
|
2021-10-13 22:07:26 +00:00
|
|
|
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-19 22:13:21 +00:00
|
|
|
|
|
|
|
if (exitcode)
|
|
|
|
return exitcode;
|
|
|
|
return nfound;
|
2010-08-06 14:11:01 +00:00
|
|
|
}
|
dyndbg: refine export, rename to dynamic_debug_exec_queries()
commit 4c0d77828d4f ("dyndbg: export ddebug_exec_queries") had a few
problems:
- broken non DYNAMIC_DEBUG_CORE configs, sparse warning
- the exported function modifies query string, breaks on RO strings.
- func name follows internal convention, shouldn't be exposed as is.
1st is fixed in header with ifdefd function prototype or stub defn.
Also remove an obsolete HAVE-symbol ifdef-comment, and add others.
Fix others by wrapping existing internal function with a new one,
named in accordance with module-prefix naming convention, before
export hits v5.9.0. In new function, copy query string to a local
buffer, so users can pass hard-coded/RO queries, and internal function
can be used unchanged.
Fixes: 4c0d77828d4f ("dyndbg: export ddebug_exec_queries")
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20200831182210.850852-3-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-08-31 18:22:09 +00:00
|
|
|
|
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-04 21:40:57 +00: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);
|
|
|
|
|
2011-10-04 21:13:19 +00:00
|
|
|
#define PREFIX_SIZE 64
|
|
|
|
|
|
|
|
static int remaining(int wrote)
|
|
|
|
{
|
|
|
|
if (PREFIX_SIZE - wrote > 0)
|
|
|
|
return PREFIX_SIZE - wrote;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-05-04 22:22:34 +00:00
|
|
|
static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
|
2011-01-23 16:17:24 +00:00
|
|
|
{
|
2011-10-04 21:13:19 +00:00
|
|
|
int pos_after_tid;
|
|
|
|
int pos = 0;
|
2011-01-23 16:17:24 +00:00
|
|
|
|
2011-10-04 21:13:19 +00:00
|
|
|
if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {
|
2011-01-23 16:17:24 +00:00
|
|
|
if (in_interrupt())
|
2012-09-13 03:11:29 +00:00
|
|
|
pos += snprintf(buf + pos, remaining(pos), "<intr> ");
|
2011-01-23 16:17:24 +00:00
|
|
|
else
|
2011-10-04 21:13:19 +00:00
|
|
|
pos += snprintf(buf + pos, remaining(pos), "[%d] ",
|
2012-09-13 03:11:29 +00:00
|
|
|
task_pid_vnr(current));
|
2011-01-23 16:17:24 +00:00
|
|
|
}
|
2011-10-04 21:13:19 +00:00
|
|
|
pos_after_tid = pos;
|
|
|
|
if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)
|
|
|
|
pos += snprintf(buf + pos, remaining(pos), "%s:",
|
2012-09-13 03:11:29 +00:00
|
|
|
desc->modname);
|
2011-10-04 21:13:19 +00:00
|
|
|
if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
|
|
|
|
pos += snprintf(buf + pos, remaining(pos), "%s:",
|
2012-09-13 03:11:29 +00:00
|
|
|
desc->function);
|
2011-10-04 21:13:19 +00:00
|
|
|
if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
|
2011-12-19 22:11:09 +00:00
|
|
|
pos += snprintf(buf + pos, remaining(pos), "%d:",
|
2012-09-13 03:11:29 +00:00
|
|
|
desc->lineno);
|
2011-10-04 21:13:19 +00:00
|
|
|
if (pos - pos_after_tid)
|
|
|
|
pos += snprintf(buf + pos, remaining(pos), " ");
|
|
|
|
if (pos >= PREFIX_SIZE)
|
|
|
|
buf[PREFIX_SIZE - 1] = '\0';
|
2011-08-11 18:36:25 +00:00
|
|
|
|
2011-10-04 21:13:19 +00:00
|
|
|
return buf;
|
2011-08-11 18:36:25 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 22:22:34 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-09-24 18:17:56 +00:00
|
|
|
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
|
2011-01-23 16:17:24 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
2011-10-04 21:13:19 +00:00
|
|
|
struct va_format vaf;
|
2021-05-04 22:22:34 +00:00
|
|
|
char buf[PREFIX_SIZE] = "";
|
2011-01-23 16:17:24 +00:00
|
|
|
|
|
|
|
BUG_ON(!descriptor);
|
|
|
|
BUG_ON(!fmt);
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
2012-09-13 03:11:29 +00:00
|
|
|
|
2011-10-04 21:13:19 +00:00
|
|
|
vaf.fmt = fmt;
|
|
|
|
vaf.va = &args;
|
2012-09-13 03:11:29 +00:00
|
|
|
|
2014-09-24 18:17:56 +00:00
|
|
|
printk(KERN_DEBUG "%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf);
|
2012-09-13 03:11:29 +00:00
|
|
|
|
2011-01-23 16:17:24 +00:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__dynamic_pr_debug);
|
|
|
|
|
2014-09-24 18:17:56 +00:00
|
|
|
void __dynamic_dev_dbg(struct _ddebug *descriptor,
|
2011-08-11 18:36:21 +00:00
|
|
|
const struct device *dev, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
struct va_format vaf;
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
BUG_ON(!descriptor);
|
|
|
|
BUG_ON(!fmt);
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
2012-09-13 03:11:29 +00:00
|
|
|
|
2011-08-11 18:36:21 +00:00
|
|
|
vaf.fmt = fmt;
|
|
|
|
vaf.va = &args;
|
2012-09-13 03:11:29 +00:00
|
|
|
|
|
|
|
if (!dev) {
|
2014-09-24 18:17:56 +00:00
|
|
|
printk(KERN_DEBUG "(NULL device *): %pV", &vaf);
|
2012-09-13 03:11:29 +00:00
|
|
|
} else {
|
2021-05-04 22:22:34 +00:00
|
|
|
char buf[PREFIX_SIZE] = "";
|
2012-09-13 03:11:29 +00:00
|
|
|
|
2014-12-10 23:50:15 +00:00
|
|
|
dev_printk_emit(LOGLEVEL_DEBUG, dev, "%s%s %s: %pV",
|
2014-09-24 18:17:56 +00:00
|
|
|
dynamic_emit_prefix(descriptor, buf),
|
|
|
|
dev_driver_string(dev), dev_name(dev),
|
|
|
|
&vaf);
|
2012-09-13 03:11:29 +00:00
|
|
|
}
|
|
|
|
|
2011-08-11 18:36:21 +00:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__dynamic_dev_dbg);
|
|
|
|
|
2011-10-04 21:13:22 +00:00
|
|
|
#ifdef CONFIG_NET
|
|
|
|
|
2014-09-24 18:17:56 +00:00
|
|
|
void __dynamic_netdev_dbg(struct _ddebug *descriptor,
|
|
|
|
const struct net_device *dev, const char *fmt, ...)
|
2011-08-11 18:36:48 +00:00
|
|
|
{
|
|
|
|
struct va_format vaf;
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
BUG_ON(!descriptor);
|
|
|
|
BUG_ON(!fmt);
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
2012-09-13 03:12:19 +00:00
|
|
|
|
2011-08-11 18:36:48 +00:00
|
|
|
vaf.fmt = fmt;
|
|
|
|
vaf.va = &args;
|
2012-09-13 03:12:19 +00:00
|
|
|
|
|
|
|
if (dev && dev->dev.parent) {
|
2021-05-04 22:22:34 +00:00
|
|
|
char buf[PREFIX_SIZE] = "";
|
2012-09-13 03:14:11 +00:00
|
|
|
|
2014-12-10 23:50:15 +00:00
|
|
|
dev_printk_emit(LOGLEVEL_DEBUG, dev->dev.parent,
|
2014-09-24 18:17:56 +00:00
|
|
|
"%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);
|
2012-09-13 03:12:19 +00:00
|
|
|
} else if (dev) {
|
2014-09-24 18:17:56 +00:00
|
|
|
printk(KERN_DEBUG "%s%s: %pV", netdev_name(dev),
|
|
|
|
netdev_reg_state(dev), &vaf);
|
2012-09-13 03:12:19 +00:00
|
|
|
} else {
|
2014-09-24 18:17:56 +00:00
|
|
|
printk(KERN_DEBUG "(NULL net_device): %pV", &vaf);
|
2012-09-13 03:12:19 +00:00
|
|
|
}
|
|
|
|
|
2011-08-11 18:36:48 +00:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__dynamic_netdev_dbg);
|
|
|
|
|
2011-10-04 21:13:22 +00:00
|
|
|
#endif
|
|
|
|
|
2019-05-01 10:48:13 +00:00
|
|
|
#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) {
|
2021-05-04 22:22:34 +00:00
|
|
|
char buf[PREFIX_SIZE] = "";
|
2019-05-01 10:48:13 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2021-10-13 15:40:20 +00:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
/*
|
2014-12-15 03:04:16 +00:00
|
|
|
* File_ops->write method for <debugfs>/dynamic_debug/control. Gathers the
|
2009-02-05 16:51:38 +00:00
|
|
|
* command text from userspace, parses and executes it.
|
|
|
|
*/
|
2011-12-19 22:13:07 +00:00
|
|
|
#define USER_BUF_PAGE 4096
|
2009-02-05 16:51:38 +00:00
|
|
|
static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
|
|
|
|
size_t len, loff_t *offp)
|
|
|
|
{
|
2011-12-19 22:13:07 +00:00
|
|
|
char *tmpbuf;
|
2010-08-06 14:11:01 +00:00
|
|
|
int ret;
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
return 0;
|
2011-12-19 22:13:07 +00:00
|
|
|
if (len > USER_BUF_PAGE - 1) {
|
|
|
|
pr_warn("expected <%d bytes into control\n", USER_BUF_PAGE);
|
2009-02-05 16:51:38 +00:00
|
|
|
return -E2BIG;
|
2011-12-19 22:13:07 +00:00
|
|
|
}
|
2015-12-24 05:06:05 +00:00
|
|
|
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-19 21:07:46 +00:00
|
|
|
v2pr_info("read %zu bytes from userspace\n", len);
|
2009-02-05 16:51:38 +00:00
|
|
|
|
2012-04-27 20:30:40 +00:00
|
|
|
ret = ddebug_exec_queries(tmpbuf, NULL);
|
2011-12-19 22:13:07 +00:00
|
|
|
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-19 22:13:21 +00:00
|
|
|
if (ret < 0)
|
2010-08-06 14:11:01 +00:00
|
|
|
return ret;
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
*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);
|
2022-09-04 21:40:42 +00:00
|
|
|
iter->idx = iter->table->num_ddebugs;
|
|
|
|
return &iter->table->ddebugs[--iter->idx];
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2022-09-04 21:40:42 +00:00
|
|
|
if (--iter->idx < 0) {
|
2009-02-05 16:51:38 +00:00
|
|
|
/* 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);
|
2022-09-04 21:40:42 +00:00
|
|
|
iter->idx = iter->table->num_ddebugs;
|
|
|
|
--iter->idx;
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
2020-07-19 23:10:47 +00:00
|
|
|
struct flagsbuf flags;
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
char const *class;
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
if (p == SEQ_START_TOKEN) {
|
|
|
|
seq_puts(m,
|
2012-12-05 21:48:26 +00:00
|
|
|
"# filename:lineno [module]function flags format\n");
|
2009-02-05 16:51:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-19 22:12:44 +00:00
|
|
|
seq_printf(m, "%s:%u [%s]%s =%s \"",
|
2012-12-05 21:48:26 +00:00
|
|
|
trim_prefix(dp->filename), dp->lineno,
|
|
|
|
iter->table->mod_name, dp->function,
|
2020-07-19 23:10:47 +00:00
|
|
|
ddebug_describe_flags(dp->flags, &flags));
|
2022-09-04 21:40:43 +00:00
|
|
|
seq_escape_str(m, dp->format, ESCAPE_SPACE, "\t\r\n\"");
|
dyndbg: validate class FOO by checking with module
Add module-to-class validation:
#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control
If a query has "class FOO", then ddebug_find_valid_class(), called
from ddebug_change(), requires that FOO is known to module X,
otherwize the query is skipped entirely for X. This protects each
module's class-space, other than the default:31.
The authors' choice of FOO is highly selective, giving isolation
and/or coordinated sharing of FOOs. For example, only DRM modules
should know and respond to DRM_UT_KMS.
So this, combined with module's opt-in declaration of known classes,
effectively privatizes the .class_id space for each module (or
coordinated set of modules).
Notes:
For all "class FOO" queries, ddebug_find_valid_class() is called, it
returns the map matching the query, and sets valid_class via an
*outvar).
If no "class FOO" is supplied, valid_class = _CLASS_DFLT. This
insures that legacy queries do not trample on new class'd callsites,
as they get added.
Also add a new column to control-file output, displaying non-default
class-name (when found) or the "unknown _id:", if it has not been
(correctly) declared with one of the declarator macros.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-18-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:54 +00:00
|
|
|
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");
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2014-10-13 22:51:32 +00:00
|
|
|
return seq_open_private(file, &ddebug_proc_seqops,
|
|
|
|
sizeof(struct ddebug_iter));
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2020-02-10 21:11:42 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
dyndbg: add ddebug_attach_module_classes
Add ddebug_attach_module_classes(), call it from ddebug_add_module().
It scans the classes/section its given, finds records where the
module-name matches the module being added, and adds them to the
module's maps list. No locking here, since the record
isn't yet linked into the ddebug_tables list.
It is called indirectly from 2 sources:
- from load_module(), where it scans the module's __dyndbg_classes
section, which contains DYNAMIC_DEBUG_CLASSES definitions from just
the module.
- from dynamic_debug_init(), where all DYNAMIC_DEBUG_CLASSES
definitions of each builtin module have been packed together.
This is why ddebug_attach_module_classes() checks module-name.
NOTES
Its (highly) likely that builtin classes will be ordered by module
name (just like prdbg descriptors are in the __dyndbg section). So
the list can be replaced by a vector (ptr + length), which will work
for loaded modules too. This would imitate whats currently done for
the _ddebug descriptors.
That said, converting to vector,len is close to pointless; a small
minority of modules will ever define a class-map, and almost all of
them will have only 1 or 2 class-maps, so theres only a couple dozen
pointers to save. TODO: re-evaluate for lines removable.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-17-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:53 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
/*
|
|
|
|
* Allocate a new ddebug_table for the given module
|
|
|
|
* and add it to the global list.
|
|
|
|
*/
|
2023-03-03 16:50:56 +00:00
|
|
|
static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
|
2009-02-05 16:51:38 +00:00
|
|
|
{
|
|
|
|
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-04 21:40:48 +00: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;
|
|
|
|
}
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
|
2019-03-08 00:27:48 +00:00
|
|
|
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-04 21:40:48 +00:00
|
|
|
pr_err("error adding module: %s\n", modname);
|
2009-02-05 16:51:38 +00:00
|
|
|
return -ENOMEM;
|
2019-03-08 00:27:48 +00:00
|
|
|
}
|
2019-03-08 00:27:37 +00:00
|
|
|
/*
|
|
|
|
* 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-04 21:40:48 +00:00
|
|
|
dt->mod_name = modname;
|
|
|
|
dt->ddebugs = di->descs;
|
|
|
|
dt->num_ddebugs = di->num_descs;
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&dt->link);
|
dyndbg: add ddebug_attach_module_classes
Add ddebug_attach_module_classes(), call it from ddebug_add_module().
It scans the classes/section its given, finds records where the
module-name matches the module being added, and adds them to the
module's maps list. No locking here, since the record
isn't yet linked into the ddebug_tables list.
It is called indirectly from 2 sources:
- from load_module(), where it scans the module's __dyndbg_classes
section, which contains DYNAMIC_DEBUG_CLASSES definitions from just
the module.
- from dynamic_debug_init(), where all DYNAMIC_DEBUG_CLASSES
definitions of each builtin module have been packed together.
This is why ddebug_attach_module_classes() checks module-name.
NOTES
Its (highly) likely that builtin classes will be ordered by module
name (just like prdbg descriptors are in the __dyndbg section). So
the list can be replaced by a vector (ptr + length), which will work
for loaded modules too. This would imitate whats currently done for
the _ddebug descriptors.
That said, converting to vector,len is close to pointless; a small
minority of modules will ever define a class-map, and almost all of
them will have only 1 or 2 class-maps, so theres only a couple dozen
pointers to save. TODO: re-evaluate for lines removable.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/r/20220904214134.408619-17-jim.cromie@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-09-04 21:40:53 +00:00
|
|
|
INIT_LIST_HEAD(&dt->maps);
|
|
|
|
|
|
|
|
if (di->classes && di->num_classes)
|
|
|
|
ddebug_attach_module_classes(dt, di->classes, di->num_classes);
|
2009-02-05 16:51:38 +00:00
|
|
|
|
|
|
|
mutex_lock(&ddebug_lock);
|
2022-09-04 21:40:41 +00:00
|
|
|
list_add_tail(&dt->link, &ddebug_tables);
|
2009-02-05 16:51:38 +00:00
|
|
|
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-04 21:40:48 +00:00
|
|
|
vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
|
2009-02-05 16:51:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-27 20:30:37 +00:00
|
|
|
/* 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-27 20:30:35 +00:00
|
|
|
{
|
|
|
|
char *sep;
|
|
|
|
|
|
|
|
sep = strchr(param, '.');
|
|
|
|
if (sep) {
|
2012-04-27 20:30:37 +00:00
|
|
|
/* 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-27 20:30:35 +00:00
|
|
|
*sep = '\0';
|
|
|
|
modname = param;
|
|
|
|
param = sep + 1;
|
|
|
|
}
|
|
|
|
if (strcmp(param, "dyndbg"))
|
2012-04-27 20:30:37 +00:00
|
|
|
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-27 20:30:35 +00:00
|
|
|
|
2012-04-27 20:30:40 +00:00
|
|
|
ddebug_exec_queries((val ? val : "+p"), modname);
|
|
|
|
|
2021-07-08 01:07:31 +00:00
|
|
|
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-27 20:30:35 +00:00
|
|
|
}
|
|
|
|
|
2012-04-27 20:30:37 +00: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-30 23:20:03 +00: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-27 20:30:35 +00:00
|
|
|
{
|
2012-04-27 20:30:37 +00: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-27 20:30:35 +00:00
|
|
|
|
2012-04-27 20:30:37 +00: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-27 20:30:35 +00:00
|
|
|
}
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
static void ddebug_table_free(struct ddebug_table *dt)
|
|
|
|
{
|
|
|
|
list_del_init(&dt->link);
|
|
|
|
kfree(dt);
|
|
|
|
}
|
|
|
|
|
2023-03-03 16:50:56 +00:00
|
|
|
#ifdef CONFIG_MODULES
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
/*
|
|
|
|
* Called in response to a module being unloaded. Removes
|
|
|
|
* any ddebug_table's which point at the module.
|
|
|
|
*/
|
2023-03-03 16:50:56 +00:00
|
|
|
static int ddebug_remove_module(const char *mod_name)
|
2009-02-05 16:51:38 +00:00
|
|
|
{
|
|
|
|
struct ddebug_table *dt, *nextdt;
|
|
|
|
int ret = -ENOENT;
|
|
|
|
|
|
|
|
mutex_lock(&ddebug_lock);
|
|
|
|
list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
|
2019-03-08 00:27:41 +00:00
|
|
|
if (dt->mod_name == mod_name) {
|
2009-02-05 16:51:38 +00:00
|
|
|
ddebug_table_free(dt);
|
|
|
|
ret = 0;
|
2019-03-08 00:27:41 +00:00
|
|
|
break;
|
2009-02-05 16:51:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mutex_unlock(&ddebug_lock);
|
2021-10-13 22:07:25 +00:00
|
|
|
if (!ret)
|
|
|
|
v2pr_info("removed module \"%s\"\n", mod_name);
|
2009-02-05 16:51:38 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-03-03 16:50:56 +00:00
|
|
|
static int ddebug_module_notify(struct notifier_block *self, unsigned long val,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct module *mod = data;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
switch (val) {
|
|
|
|
case MODULE_STATE_COMING:
|
|
|
|
ret = ddebug_add_module(&mod->dyndbg_info, mod->name);
|
|
|
|
if (ret)
|
|
|
|
WARN(1, "Failed to allocate memory: dyndbg may not work properly.\n");
|
|
|
|
break;
|
|
|
|
case MODULE_STATE_GOING:
|
|
|
|
ddebug_remove_module(mod->name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return notifier_from_errno(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct notifier_block ddebug_module_nb = {
|
|
|
|
.notifier_call = ddebug_module_notify,
|
|
|
|
.priority = 0, /* dynamic debug depends on jump label */
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* CONFIG_MODULES */
|
|
|
|
|
2009-02-05 16:51:38 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-08-06 14:11:03 +00:00
|
|
|
static __initdata int ddebug_init_success;
|
|
|
|
|
2020-02-10 21:11:42 +00:00
|
|
|
static int __init dynamic_debug_init_control(void)
|
2009-02-05 16:51:38 +00:00
|
|
|
{
|
2020-02-10 21:11:42 +00:00
|
|
|
struct proc_dir_entry *procfs_dir;
|
|
|
|
struct dentry *debugfs_dir;
|
2010-08-06 14:11:03 +00:00
|
|
|
|
|
|
|
if (!ddebug_init_success)
|
|
|
|
return -ENODEV;
|
2009-02-05 16:51:38 +00:00
|
|
|
|
2020-02-10 21:11:42 +00:00
|
|
|
/* 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);
|
2019-06-12 15:35:34 +00:00
|
|
|
|
2010-08-06 14:11:03 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init dynamic_debug_init(void)
|
|
|
|
{
|
2022-09-04 21:40:47 +00:00
|
|
|
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-27 20:30:35 +00:00
|
|
|
char *cmdline;
|
2010-08-06 14:11:03 +00: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-04 21:40:48 +00:00
|
|
|
struct _ddebug_info di = {
|
|
|
|
.descs = __start___dyndbg,
|
2022-09-04 21:40:52 +00:00
|
|
|
.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-04 21:40:48 +00:00
|
|
|
.num_descs = __stop___dyndbg - __start___dyndbg,
|
2022-09-04 21:40:52 +00:00
|
|
|
.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-04 21:40:48 +00:00
|
|
|
};
|
|
|
|
|
2023-03-03 16:50:56 +00:00
|
|
|
#ifdef CONFIG_MODULES
|
|
|
|
ret = register_module_notifier(&ddebug_module_nb);
|
|
|
|
if (ret) {
|
|
|
|
pr_warn("Failed to register dynamic debug module notifier\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_MODULES */
|
|
|
|
|
2020-07-19 23:10:45 +00:00
|
|
|
if (&__start___dyndbg == &__stop___dyndbg) {
|
2020-06-08 04:40:14 +00:00
|
|
|
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;
|
2011-12-19 22:12:54 +00:00
|
|
|
}
|
2022-09-04 21:40:47 +00:00
|
|
|
|
|
|
|
iter = iter_mod_start = __start___dyndbg;
|
2011-12-19 22:12:54 +00:00
|
|
|
modname = iter->modname;
|
2022-09-04 21:40:47 +00:00
|
|
|
i = mod_sites = mod_ct = 0;
|
|
|
|
|
|
|
|
for (; iter < __stop___dyndbg; iter++, i++, mod_sites++) {
|
|
|
|
|
2011-12-19 22:12:54 +00:00
|
|
|
if (strcmp(modname, iter->modname)) {
|
2022-09-04 21:40:47 +00:00
|
|
|
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-04 21:40:48 +00:00
|
|
|
di.num_descs = mod_sites;
|
|
|
|
di.descs = iter_mod_start;
|
2023-03-03 16:50:56 +00:00
|
|
|
ret = ddebug_add_module(&di, modname);
|
2011-12-19 22:12:54 +00:00
|
|
|
if (ret)
|
2012-04-27 20:30:38 +00:00
|
|
|
goto out_err;
|
2022-09-04 21:40:47 +00:00
|
|
|
|
|
|
|
mod_sites = 0;
|
2011-12-19 22:12:54 +00:00
|
|
|
modname = iter->modname;
|
2022-09-04 21:40:47 +00:00
|
|
|
iter_mod_start = iter;
|
2009-02-05 16:51:38 +00: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-04 21:40:48 +00:00
|
|
|
di.num_descs = mod_sites;
|
|
|
|
di.descs = iter_mod_start;
|
2023-03-03 16:50:56 +00:00
|
|
|
ret = ddebug_add_module(&di, modname);
|
2011-12-19 22:12:54 +00:00
|
|
|
if (ret)
|
2012-04-27 20:30:38 +00:00
|
|
|
goto out_err;
|
2010-08-06 14:11:02 +00:00
|
|
|
|
2012-04-27 20:30:38 +00:00
|
|
|
ddebug_init_success = 1;
|
2021-05-25 03:32:40 +00:00
|
|
|
vpr_info("%d prdebugs in %d modules, %d KiB in ddebug tables, %d kiB in __dyndbg section\n",
|
2022-09-04 21:40:47 +00:00
|
|
|
i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
|
|
|
|
(int)((i * sizeof(struct _ddebug)) >> 10));
|
2012-04-27 20:30:38 +00:00
|
|
|
|
2022-09-04 21:40:52 +00:00
|
|
|
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-27 20:30:35 +00: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-30 23:20:03 +00: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-27 20:30:35 +00:00
|
|
|
kfree(cmdline);
|
2012-04-27 20:30:38 +00:00
|
|
|
return 0;
|
2010-08-06 14:11:02 +00:00
|
|
|
|
2012-04-27 20:30:38 +00:00
|
|
|
out_err:
|
|
|
|
ddebug_remove_all_tables();
|
2009-02-05 16:51:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2010-08-06 14:11:03 +00:00
|
|
|
/* Allow early initialization for boot messages via boot param */
|
2012-04-27 20:30:42 +00:00
|
|
|
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-27 20:30:35 +00:00
|
|
|
|
2010-08-06 14:11:03 +00:00
|
|
|
/* Debugfs setup must be done later */
|
2020-02-10 21:11:42 +00:00
|
|
|
fs_initcall(dynamic_debug_init_control);
|