[RFC PATCH v4 19/19] dyndbg: RFC add linker rules to module.lds.h

2021-03-17 Thread Jim Cromie
Copy the DYNAMIC_DEBUG_DATA macro, that works in vmlinux.lds.h,
into module.lds.h  This does not work here

The point of the KEEPS is to pack section pairs into consecutive
memory, a property we need in order to drop the _ddebug.site pointer.

The problem (ISTM) is that for linking vmlinux, the data is linked
into .data (and the sections are subsumed), and it is is accessed by
iterating beteween __(fstart|stop)___dyndbg(_sites)? symbols.  That
breaks down here cuz kernel/module.c specifically grabs the __dyndb*
sections by name.

I lack the linker-fu to sort this, so I left my commented out
attempts, to show my errors.

no-bisect: expect linker error
Signed-off-by: Jim Cromie 
---
 include/asm-generic/module.lds.h | 21 +
 1 file changed, 21 insertions(+)

diff --git a/include/asm-generic/module.lds.h b/include/asm-generic/module.lds.h
index f210d5c1b78b..0074c5f2421b 100644
--- a/include/asm-generic/module.lds.h
+++ b/include/asm-generic/module.lds.h
@@ -7,4 +7,25 @@
  * Empty for the asm-generic header.
  */
 
+/* implement dynamic printk debug section packing */
+#if defined(CONFIG_DYNAMIC_DEBUG) ||   \
+   (defined(CONFIG_DYNAMIC_DEBUG_CORE) \
+&& defined(DYNAMIC_DEBUG_MODULE))
+#define DYNAMIC_DEBUG_DATA()   \
+   . = ALIGN(8);   \
+   KEEP(*(__dyndbg_sites .gnu.linkonce.dyndbg_site))   \
+   KEEP(*(__dyndbg .gnu.linkonce.dyndbg))
+#else
+#define DYNAMIC_DEBUG_DATA()
+#endif
+
+SECTIONS {
+__dyndbg   : { (*(__dyndbg .gnu.linkonce.dyndbg)) }
+__dyndbg_sites : { (*(__dyndbg_sites .gnu.linkonce.dyndbg_site)) }
+
+   //.data.dyndbg : { DYNAMIC_DEBUG_DATA() } // syntax ok
+   //: { DYNAMIC_DEBUG_DATA() }
+   //DYNAMIC_DEBUG_DATA()
+}
+
 #endif /* __ASM_GENERIC_MODULE_LDS_H */
-- 
2.29.2



[RFC PATCH v4 16/19] dyndbg: prevent build bugs via -DNO_DYNAMIC_DEBUG_TABLE

2021-03-17 Thread Jim Cromie
The next patch adds DEFINE_DYNAMIC_DEBUG_TABLE(), which breaks some
subtrees with special compile constraints (efi etc).

Avoid this by adding a define to suppress the *remote declaration*
done by DEFINE_DYNAMIC_DEBUG_TABLE(), automatically, on behalf of all
possible users of pr_debug.

Signed-off-by: Jim Cromie 
---
 arch/x86/boot/compressed/Makefile | 1 +
 arch/x86/entry/vdso/Makefile  | 3 +++
 arch/x86/purgatory/Makefile   | 1 +
 drivers/firmware/efi/libstub/Makefile | 3 ++-
 4 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/x86/boot/compressed/Makefile 
b/arch/x86/boot/compressed/Makefile
index e0bc3988c3fa..ada4eb960d95 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -31,6 +31,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 
vmlinux.bin.lzma \
 KBUILD_CFLAGS := -m$(BITS) -O2
 KBUILD_CFLAGS += -fno-strict-aliasing -fPIE
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+KBUILD_CFLAGS += -DNO_DYNAMIC_DEBUG_TABLE
 cflags-$(CONFIG_X86_32) := -march=i386
 cflags-$(CONFIG_X86_64) := -mcmodel=small -mno-red-zone
 KBUILD_CFLAGS += $(cflags-y)
diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index 05c4abc2fdfd..619878f2c427 100644
--- a/arch/x86/entry/vdso/Makefile
+++ b/arch/x86/entry/vdso/Makefile
@@ -29,6 +29,9 @@ vobjs32-y := vdso32/note.o vdso32/system_call.o 
vdso32/sigreturn.o
 vobjs32-y += vdso32/vclock_gettime.o
 vobjs-$(CONFIG_X86_SGX)+= vsgx.o
 
+# avoid a x86_64_RELATIVE error
+KBUILD_CFLAGS += -DNO_DYNAMIC_DEBUG_TABLE
+
 # files to link into kernel
 obj-y  += vma.o extable.o
 KASAN_SANITIZE_vma.o   := y
diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile
index 95ea17a9d20c..95ba7b18410f 100644
--- a/arch/x86/purgatory/Makefile
+++ b/arch/x86/purgatory/Makefile
@@ -35,6 +35,7 @@ PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel
 PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss 
-g0
 PURGATORY_CFLAGS += $(DISABLE_STACKLEAK_PLUGIN) -DDISABLE_BRANCH_PROFILING
 PURGATORY_CFLAGS += -fno-stack-protector
+PURGATORY_CFLAGS += -DNO_DYNAMIC_DEBUG_TABLE
 
 # Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
 # in turn leaves some undefined symbols like __fentry__ in purgatory and not
diff --git a/drivers/firmware/efi/libstub/Makefile 
b/drivers/firmware/efi/libstub/Makefile
index c23466e05e60..def8febefbd3 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -13,7 +13,8 @@ cflags-$(CONFIG_X86)  += -m$(BITS) -D__KERNEL__ \
   -Wno-pointer-sign \
   $(call cc-disable-warning, 
address-of-packed-member) \
   $(call cc-disable-warning, gnu) \
-  -fno-asynchronous-unwind-tables
+  -fno-asynchronous-unwind-tables \
+  -DNO_DYNAMIC_DEBUG_TABLE
 
 # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly
 # disable the stackleak plugin
-- 
2.29.2



[RFC PATCH v4 18/19] dyndbg: shuffle ddebug_table fields

2021-03-17 Thread Jim Cromie
In preparation to unionize structs _ddebug & ddebug_table, shuffle
fields in latter so they match the layout of the former.  This MAY
simplify initialization of the header field, in particular by
preserving *sites.

It also sets up a later conversion to a flex-array ddebugs[].

This step is mostly to isolate/prove no breakage before HEAD++

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 29 +
 lib/dynamic_debug.c   |  2 +-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 229cfd81ffb3..22f11218047f 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -66,6 +66,35 @@ struct _ddebug {
 #endif
 } __aligned(8);
 
+/* this pair of header structs correspond quite deeply to struct
+ * _ddebug(|_site)s above; they are also created into __dyndbg*
+ * sections (by DEFINE_DYNAMIC_DEBUG_TABLE), and should be unionized
+ * with them to reinforce this.
+ *
+ * struct _ddebug_header is the important one, it has enough space to
+ * take struct ddebug_table's job, ie: link together into a list, and
+ * keep track of the modname & _ddebug(|_sites) vectors.
+ *
+ * Its other job is handled by its placement in the front of a
+ * module's _ddebug[N] entries.  Each _ddebug knows its N, so the
+ * header's address is computable, and its site pointer is available
+ * to get _ddebug_sites[N].  Then we can drop _ddebug.sites, regaining
+ * parity with original _ddebug footprint.
+ *
+ * Eventually, N will index a fetch from a compressed block, or for
+ * enabled callsites, a hash.  A global hash is probably adequate, if
+ * ~5k elements doesnt degrade access time.
+ */
+struct _ddebug_site_header {
+   /* we have 24 bytes total here, all currently unused */
+} __aligned(8);
+
+struct _ddebug_header {
+   struct _ddebug_site* sites;
+   struct list_head link;
+   const char* mod_name;
+   unsigned num_ddebugs;
+} __aligned(8);
 
 #if defined(CONFIG_DYNAMIC_DEBUG_CORE)
 
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c1a7345277eb..5d1ce7f21c30 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -45,11 +45,11 @@ extern struct _ddebug_site __start___dyndbg_sites[];
 extern struct _ddebug_site __stop___dyndbg_sites[];
 
 struct ddebug_table {
+   struct _ddebug_site *sites;
struct list_head link;
const char *mod_name;
unsigned int num_ddebugs;
struct _ddebug *ddebugs;
-   struct _ddebug_site *sites;
 };
 
 struct ddebug_query {
-- 
2.29.2



[RFC PATCH v4 05/19] dyndbg: hoist ->site out of ddebug_match_site

2021-03-17 Thread Jim Cromie
A coming change adds _get/_put abstraction on the site pointer, to
allow managing site info more flexibly.  The get/put pattern is best
done at a single lexical scope, where its more obviously correct, so
hoist the ->site ref out of ddebug_match_site, and pass it in instead.

no functional changes

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index da732e0c56e3..abe3382aabd5 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -143,10 +143,9 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 }
 
 static int ddebug_match_site(const struct ddebug_query *query,
-const struct _ddebug *dp)
+const struct _ddebug *dp,
+const struct _ddebug_site *dc)
 {
-   struct _ddebug_site *dc;
-
/* match against the format */
if (query->format) {
if (*query->format == '^') {
@@ -167,7 +166,6 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
dp->lineno > query->last_lineno)
return false;
 
-   dc = dp->site;
if (!dc) {
/* site info has been dropped, so query cannot test these 
fields */
if (query->filename || query->function)
@@ -219,9 +217,9 @@ static int ddebug_change(const struct ddebug_query *query,
 
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = >ddebugs[i];
-   struct _ddebug_site *dc;
+   struct _ddebug_site *dc = dp->site;
 
-   if (!ddebug_match_site(query, dp))
+   if (!ddebug_match_site(query, dp, dc))
continue;
 
nfound++;
-- 
2.29.2



[RFC PATCH v4 06/19] dyndbg: accept null site in ddebug_change

2021-03-17 Thread Jim Cromie
fix a debug-print that includes site info, by adding an alternate
debug message that does not.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index abe3382aabd5..151e55ab6bb5 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -235,10 +235,17 @@ static int ddebug_change(const struct ddebug_query *query,
static_branch_enable(>key.dd_key_true);
 #endif
dp->flags = newflags;
-   v2pr_info("changed %s:%d [%s]%s =%s\n",
-trim_prefix(dc->filename), dp->lineno,
-dt->mod_name, dc->function,
-ddebug_describe_flags(dp->flags, ));
+
+   if (dc)
+   v2pr_info("changed %s:%d [%s]%s =%s\n",
+ trim_prefix(dc->filename), dp->lineno,
+ dt->mod_name, dc->function,
+ ddebug_describe_flags(dp->flags, 
));
+   else
+   v2pr_info("changed %s:%d =%s \"%s\"\n",
+ dt->mod_name, dp->lineno,
+ ddebug_describe_flags(dp->flags, 
),
+ dp->format);
}
}
mutex_unlock(_lock);
-- 
2.29.2



[RFC PATCH v4 08/19] dyndbg: accept null site in ddebug_proc_show

2021-03-17 Thread Jim Cromie
Accept a ddebug record with a null site pointer, and write abbreviated
output for that record that doesn't include site info (but does
include line-number, since that can be used in >control queries).
Also add a 2nd header line with a template for the new output.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 25 +
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 0c535f3c2ba9..1f0cac4a66af 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -918,18 +918,27 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 
if (p == SEQ_START_TOKEN) {
seq_puts(m,
-"# filename:lineno [module]function flags format\n");
+"#: filename:lineno [module]function flags format\n"
+"#| [module]:lineno flags format\n"
+   );
return 0;
}
 
dc = dp->site;
-
-   seq_printf(m, "%s:%u [%s]%s =%s \"",
-  trim_prefix(dc->filename), dp->lineno,
-  iter->table->mod_name, dc->function,
-  ddebug_describe_flags(dp->flags, ));
-   seq_escape(m, dp->format, "\t\r\n\"");
-   seq_puts(m, "\"\n");
+   if (dc) {
+   seq_printf(m, "%s:%u [%s]%s =%s \"",
+  trim_prefix(dc->filename), dp->lineno,
+  iter->table->mod_name, dc->function,
+  ddebug_describe_flags(dp->flags, ));
+   seq_escape(m, dp->format, "\t\r\n\"");
+   seq_puts(m, "\"\n");
+   } else {
+   seq_printf(m, "[%s]:%u =%s \"",
+  iter->table->mod_name, dp->lineno,
+  ddebug_describe_flags(dp->flags, ));
+   seq_escape(m, dp->format, "\t\r\n\"");
+   seq_puts(m, "\"\n");
+   }
 
return 0;
 }
-- 
2.29.2



[RFC PATCH v4 15/19] dyndbg: add _index to struct _ddebug

2021-03-17 Thread Jim Cromie
We currently use dp->site to map: &__dyndbg[N] -> &__dyndbg_sites[N].
We want to drop site, new _ddebug._index provides the N.

The mapping is done in ddebug_site_get():

For builtin modules, a _ddebug *ptr is between __start___dyndbg and
__stop___dyndbg, and we can use &__start___dyndbg_sites[N] directly.
For loadable modules, we still need work, so we print rubbish, and
just return site pointer (which is correct).

ddebug_add_module() handles _index initialization:
Its new task is to number each module consecutively, so it gets new
base arg to pass the next starting index.

To actually drop site, We need both the module's __dyndbg* section
addys, and we need their relative placement to have a base-to-base
offset.

PLAN - a table header connecting 2 tables.

- ddebug_table points to both __dyndbgs & __dyndbg_sites.
  but *ddebugs & *sites are independent.
  no path from ddebugs[n] -> ddebug_sites[n]

If we have a header record in-situ, which keeps the site pointer we
seek to eliminate from _ddebug, and its in element[0] of both vectors,
we can go:

  ddebugs[n] -> ddebugs[0] -> containerof -> site[n]

  union ddebug_table_header {
struct ddebug_table *owner;
struct _ddebug item;
  }
  and
  struct ddebug_table_vector {
 struct ddebug_table *owner;
 struct _ddebug vector[];
  }

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h |  2 ++
 lib/dynamic_debug.c   | 40 +--
 2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 7d33475d226a..18689db0e2c0 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -29,6 +29,7 @@ struct _ddebug {
/* format is always needed, lineno shares word with flags */
const char *format;
const unsigned lineno:18;
+   unsigned _index:14;
/*
 * The flags field controls the behaviour at the callsite.
 * The bits here are changed dynamically when the user
@@ -56,6 +57,7 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_DEFAULT 0
 #endif
unsigned int flags:8;
+
 #ifdef CONFIG_JUMP_LABEL
union {
struct static_key_true dd_key_true;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 1f59407b6a83..54737647556c 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -123,6 +123,8 @@ do {
\
 #define vpr_info(fmt, ...) vnpr_info(1, fmt, ##__VA_ARGS__)
 #define v2pr_info(fmt, ...)vnpr_info(2, fmt, ##__VA_ARGS__)
 #define v3pr_info(fmt, ...)vnpr_info(3, fmt, ##__VA_ARGS__)
+#define v4pr_info(fmt, ...)vnpr_info(4, fmt, ##__VA_ARGS__)
+#define v5pr_info(fmt, ...)vnpr_info(5, fmt, ##__VA_ARGS__)
 
 static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 {
@@ -146,7 +148,17 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 
 static struct _ddebug_site *ddebug_site_get(struct _ddebug *dp)
 {
-   return dp->site; /* passthru abstraction */
+   v4pr_info("get %d: %s.%s.%d\n", dp->_index, dp->site->modname,
+ dp->site->function, dp->lineno);
+
+   if (dp >= __start___dyndbg && dp < __stop___dyndbg) {
+   v4pr_info(" is builtin: %d %ld\n", dp->_index, dp - 
__start___dyndbg);
+   return &__start___dyndbg_sites[ dp - __start___dyndbg ];
+   } else {
+   v3pr_info(" is loaded: %d %ld\n", dp->_index, dp - 
__start___dyndbg);
+   return dp->site;
+   }
+   return dp->site;
 }
 static inline void ddebug_site_put(struct _ddebug *dp)
 {
@@ -1034,10 +1046,12 @@ static const struct proc_ops proc_fops = {
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
  */
-int ddebug_add_module(struct _ddebug *tab, struct _ddebug_site *sites,
- unsigned int numdbgs, const char *modname)
+static int __ddebug_add_module(struct _ddebug *tab, struct _ddebug_site *sites,
+  unsigned numdbgs, unsigned base,
+  const char *modname)
 {
struct ddebug_table *dt;
+   int i;
 
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
if (dt == NULL) {
@@ -1055,6 +1069,13 @@ int ddebug_add_module(struct _ddebug *tab, struct 
_ddebug_site *sites,
dt->ddebugs = tab;
dt->sites = sites;
 
+   v3pr_info("add-module: %s\n", modname);
+   for (i = 0; i < numdbgs; i++) {
+   tab[i]._index = base++;
+   v3pr_info(" %d %d %s.%s.%d\n", i, tab[i]._index, modname,
+ tab[i].site->function, tab[i].lineno);
+   }
+
mutex_lock(_lock);
list_add(>link, _tables);
mutex_unlock(_lock);
@@ -10

[RFC PATCH v4 17/19] dyndbg: RFC - DECLARE/DEFINE_DYNAMIC_DEBUG_TABLE

2021-03-17 Thread Jim Cromie
V4-proto - now currently diet-3i

Simplify:
.gnu.linkonce._mod_.dyndbg -> .gnu.linkonce.dyndbg
ie drop _mod_

This puts a single header record at front of the vectors, solving 2
problems (discussed below) simultaneously:

- header in front, allowing flex-array rep of layout.
- single header, not per-module. adequate for needs, no wasted space.

this now appears to work
- get: dp range-check good on builtin, !builtin.

todo:
- _sym_##_site symbols in init/main.i still busted
- _index init in __ddebug_add_module
- cleanup commentary below.

DEFINE_DYNAMIC_DEBUG_TABLE is based on DECLARE_DYNAMIC_DEBUG_METADATA.
Like its model, it creates/allocates a pair of structs: _ddebug &
_ddebug_site, and inits them distinctively.

Its purpose is to create an in-situ module-header-pair for each
module's sub-vectors of _ddebug[], _ddebug_sites[].  Once the
header-pair is reliably linked into the vectors, code can get from
_ddebug[N] to the header-pair, then to _ddebug_sites[N] at runtime by
saving N into _ddebug._index during init.  With this, we can drop the
site pointer in struct _ddebug.

Eventually, this module-header-pair can be adapted to be an in-situ
replacement for the separately allocated struct ddebug_tables, and be
linked into the ddebug_tables list.

RFC, NOTES:

DYNAMIC_DEBUG is a 'transparent' facility, in that uses of pr_debug
get extra features without additional api.  Because of this,
DEFINE_DYNAMIC_DEBUG_TABLE is 'transparently' invoked by
dynamic_debug.h on behalf of all its (indirect) users, including
printk.h.

IOW this has wide effects; it results in multiple redundant
declarations of header records, even single object files may get
multiple copies.  Using .gnu.linkonce._mod_.dyndbg(|_site) section
names and "__used __weak " seems to resolve the redundancies.  I
havent tried with clang.

In vmlinux-lds.h, the 2 KEEPs are modified to append those 2 new
header sections to their respective existing __dyndbg* sections, in an
interleaved manner.  This places the header records immediately after
the modules' block of _ddebug*s, in a knowable offset from &__dyndbg[0].

scripts/Makefile.lib gets a new -DKBUILD_MODSYM defn, with a value
like KBUILD_MODNAME, except that its not __stringified.  It is used to
create a pair of module-ish named variables: _sym_##_dyndbg_base.

For some non-obvious reason, the substitution doesnt work, resulting
in per-module symbol names like KBUILD_MODSYM_dyndbg_base.  This
subtly alters the header initialization and is_dyndbg_header_pair(),
which is used in __init to find the headers adjacent to each modules'
block of _ddebug records.  This isnt fatal to the plan; we just need
the storage reserved where its accessible by known offset from the
_ddebug[N] record of an enabled pr-debug.  But it would be nice to
have the symbol names consistent with the intent.  I looked for a
MODULE_SINGLETON(name_suffix) to use, similarly to how UNIQUE_ID is
used to construct names, but found nothing.

The .gnu.linkonce._mod_. works to eliminate all the extra headers in
each module, but a problem remains; it adds unneeded headers for
modules with zero pr-debugs.  So Im seeing ~1500 extra headers.

I tried several flavors of conditional linking, now think I want/need
a linker-script language extension:

  KEEP ( *(__dyndbg) AND *(.gnu.linkonce.dyndbg) )  # my need
  KEEP ( *(foo_tbl)   OR *(.gnu.linkonce.foo_alt) ) # for completeness

I've managed to alter ld's grammar, but its only compile tested, and
is missing the conditional linking pieces.  Since this patchset's
value proposition is a memory shrink, ~1500 extra headers is fatal,
and this patchset must be a slow-cook.

V4 todo:

Time to simplify, drop _mod_, and change _ddebug.module_index to
._index, indicating that its no longer keyed to module, but to the
whole compilation unit, which for the kernel includes all the builtin
modules.  loadable modules should get their own. tbt.

this could obsolete all the above problems.

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/i915/i915_drv.c   |   2 +
 include/asm-generic/vmlinux.lds.h |  27 +---
 include/linux/dynamic_debug.h | 100 +-
 lib/dynamic_debug.c   |  27 +---
 scripts/Makefile.lib  |   2 +
 5 files changed, 139 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 8e9cb44e66e5..51163e0d40cf 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -91,6 +91,8 @@
 
 static const struct drm_driver driver;
 
+//DEFINE_DYNAMIC_DEBUG_TABLE();
+
 static int i915_get_bridge_dev(struct drm_i915_private *dev_priv)
 {
int domain = pci_domain_nr(dev_priv->drm.pdev->bus);
diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 4f2af9de2f03..482d94078785 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -335,6 +335,22 @@

[RFC PATCH v4 14/19] dyndbg: add ddebug_site(_get|_put) abstraction

2021-03-17 Thread Jim Cromie
Replace direct ->site refs with _get(),_put() internal API.  Right
now, _get() just returns ->site and _put() does nothing.  Later we can
replace that implementation with one using ->module_index to fetch
then forget site data dynamically.

Several approaches are possible:

A: !site -> fill from backing store

1st try at this is/was using zram.  At init, it copied each callsite
into a zs-allocation, and all site-> refs afterward went thru
_get/_put to zs-map on demand, and zs-unmap the site info.  This
worked until I tried to keep callsites mapped while they're enabled,
when it gave lockdep warns/panics.  IIRC theres a zram patchset doing
something with locking; I need to retry this approach, even if other
options are better, this might be a validating use case.

B: block store

Another approach is to compress the new linker section, using some
algorithm thats good at indexed decompression.  I probed this
approach, using objcopy, unsuccessfully:

   objcopy --dump-section __dyndbg=dd \
   --dump-section __dyndbg_sites=ddsites $IMG

>From vmlinux.o dumps were mostly empty (pre-link/reloc data?)
and vmlinux didnt have the section.

C: callsite composed from __dyndbg[N] & __dyndbg_site[N]

We know _ddebug records are in a vector, either in the builtin
__dyndbg linker section, or the same from a modprobed one.  The
builtin section has all builtin module sub-sections catenated
dogether.

At init, we iterate over the section, and "parse it" by creating a
ddebug_table for each module with prdebugs.  ddebug_table.num_debugs
remembers the size of each modules' vector of prdebugs.

We need a few things:

- _ddebug.index field, which knows offset to start of this sub-vector.
  this new field will be "free" because the struct has padding.
  it can be initialized during init, then RO.

- a back-pointer at the beginning of the sub-vector, to the
  ddebug_table "owning" (but not containing) this sub-vector of
  prdebugs.

If we had both, we could get from the ddebug element to its vector
root, back up to the owning ddebug_table, then down to the _callsite
vector, and index to the right element.  While slower than a pointer
deref, this is a cold path, and it allows elimination of the
per-callsite pointer member, thus greater density of the sections, and
still can support sparse site info.

That back-pointer feels tricky.  It needs to be 1st in the sub-vector

D: (C1?) add a header record to each sub-vector

If we can insert a header record into each modules' __dyndbg* section
sub-vectors, we can simplify the cold path above; a single sites*
pointer in the header can give us access to __dyndbg_sites[N]

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 31 +--
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index be2e97ae2da9..1f59407b6a83 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -144,6 +144,14 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 query->first_lineno, query->last_lineno);
 }
 
+static struct _ddebug_site *ddebug_site_get(struct _ddebug *dp)
+{
+   return dp->site; /* passthru abstraction */
+}
+static inline void ddebug_site_put(struct _ddebug *dp)
+{
+}
+
 static int ddebug_match_site(const struct ddebug_query *query,
 const struct _ddebug *dp,
 const struct _ddebug_site *dc)
@@ -239,16 +247,18 @@ static int ddebug_change(const struct ddebug_query *query,
 
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = >ddebugs[i];
-   struct _ddebug_site *dc = dp->site;
+   struct _ddebug_site *dc;
+
+   dc = ddebug_site_get(dp);
 
if (!ddebug_match_site(query, dp, dc))
-   continue;
+   goto skipsite;
 
nfound++;
 
newflags = (dp->flags & modifiers->mask) | 
modifiers->flags;
if (newflags == dp->flags)
-   continue;
+   goto skipsite;
 
ddebug_alter_site(dp, modifiers);
 
@@ -264,6 +274,9 @@ static int ddebug_change(const struct ddebug_query *query,
  dt->mod_name, dp->lineno,
  ddebug_describe_flags(dp->flags, 
),
  dp->format);
+
+   skipsite:
+   ddebug_site_put(dp);
}
}
mutex_unlock(_lock);
@@ -633,11 +646,11 @@ static int remaining(int wrote)
return 0;
 }
 
-static char *__dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
+static char *__dynamic_emit_prefix(s

[RFC PATCH v4 13/19] dyndbg+module: expose ddebug_sites to modules

2021-03-17 Thread Jim Cromie
In order to drop the pointer connecting _ddebug's to _ddebug_sites,
we need to elevate the latter; we need to track it in (internal)
ddebug_tables, and set it in ddebug_add_module.  That last part
exposes it by interface to module.c, so we add a field to load_info,
and adjust load_module to initialize it from the elf section.

Its possible that this closes a "hole" created when __dyndbg_sites
section was added, in that the section wasn't "managed" directly, and
could conceivably get lost later.  I never saw any misbehavior loading
i915.ko into a vm, but still..

TBD/RFC:

these 2 vectors should be in a single struct.  if this struct can have
ddebugs[], ie a flex-array, then container_of can get us to the
sites*, yielding _sites[N], and allowing to drop _ddebug.site

The trouble with this is that ddebugs* now points to someone elses
memory, and we cant just steal it and stomp on the memory just in
front of it (for the sites ptr).

rename n to numdbgs

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h |  4 ++--
 kernel/module-internal.h  |  1 +
 kernel/module.c   |  9 ++---
 lib/dynamic_debug.c   | 20 
 4 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index d811273c8484..7d33475d226a 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -70,8 +70,8 @@ struct _ddebug {
 /* exported for module authors to exercise >control */
 int dynamic_debug_exec_queries(const char *query, const char *modname);
 
-int ddebug_add_module(struct _ddebug *tab, unsigned int n,
-   const char *modname);
+int ddebug_add_module(struct _ddebug *tab, struct _ddebug_site *sites,
+ unsigned int numdbgs, const char *modname);
 extern int ddebug_remove_module(const char *mod_name);
 extern __printf(2, 3)
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
diff --git a/kernel/module-internal.h b/kernel/module-internal.h
index 33783abc377b..fb61eb2f8032 100644
--- a/kernel/module-internal.h
+++ b/kernel/module-internal.h
@@ -18,6 +18,7 @@ struct load_info {
char *secstrings, *strtab;
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
struct _ddebug *debug;
+   struct _ddebug_site *sites;
unsigned int num_debug;
bool sig_ok;
 #ifdef CONFIG_KALLSYMS
diff --git a/kernel/module.c b/kernel/module.c
index 30479355ab85..792903230acd 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2780,11 +2780,12 @@ static void add_kallsyms(struct module *mod, const 
struct load_info *info)
 }
 #endif /* CONFIG_KALLSYMS */
 
-static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, 
unsigned int num)
+static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug,
+   struct _ddebug_site *sites, unsigned int num)
 {
if (!debug)
return;
-   ddebug_add_module(debug, num, mod->name);
+   ddebug_add_module(debug, sites, num, mod->name);
 }
 
 static void dynamic_debug_remove(struct module *mod, struct _ddebug *debug)
@@ -,6 +3334,8 @@ static int find_module_sections(struct module *mod, 
struct load_info *info)
 
info->debug = section_objs(info, "__dyndbg",
   sizeof(*info->debug), >num_debug);
+   info->sites = section_objs(info, "__dyndbg_sites",
+  sizeof(*info->sites), >num_debug);
 
return 0;
 }
@@ -4004,7 +4007,7 @@ static int load_module(struct load_info *info, const char 
__user *uargs,
goto free_arch_cleanup;
}
 
-   dynamic_debug_setup(mod, info->debug, info->num_debug);
+   dynamic_debug_setup(mod, info->debug, info->sites, info->num_debug);
 
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
ftrace_module_init(mod);
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index fdc2d0e15731..be2e97ae2da9 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -49,6 +49,7 @@ struct ddebug_table {
const char *mod_name;
unsigned int num_ddebugs;
struct _ddebug *ddebugs;
+   struct _ddebug_site *sites;
 };
 
 struct ddebug_query {
@@ -1014,14 +1015,14 @@ static const struct proc_ops proc_fops = {
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
  */
-int ddebug_add_module(struct _ddebug *tab, unsigned int n,
-const char *name)
+int ddebug_add_module(struct _ddebug *tab, struct _ddebug_site *sites,
+ unsigned int numdbgs, const char *modname)
 {
struct ddebug_table *dt;
 
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
if (dt == NULL) {
-   pr_err("error adding module: %s\n", name);

[RFC PATCH v4 12/19] dyndbg: allow deleting site info via control interface

2021-03-17 Thread Jim Cromie
Allow users & subsystems to selectively delete callsite info for
pr-debug callsites.  Hopefully, this can lead to actual recovery of
memory.

DRM is a potential user which would drop the sites:

- has distinct categories for logging, and can map them over to a
  format prefix, like: "drm:core:", "drm:kms:", etc.

- are happy with group control of all the callsites in a class/cateory.
  individual control is still possible using queries including line numbers

- don't need dynamic "module:function:line:" prefixes in log messages

- don't care about loss of context in /proc/dynamic_debug/control

before:

init/initramfs.c:485 [initramfs]unpack_to_rootfs =_ "Detected %s compressed 
data\012"
init/main.c:1337 [main]run_init_process =pm "%s\012"
init/main.c:1335 [main]run_init_process =pm "  with environment:\012"
init/main.c:1334 [main]run_init_process =pm "%s\012"
init/main.c:1332 [main]run_init_process =pm "  with arguments:\012"
init/main.c:1121 [main]initcall_blacklisted =pm "initcall %s blacklisted\012"
init/main.c:1082 [main]initcall_blacklist =pm "blacklisting initcall %s\012"

then:
  bash-5.0# echo file init/main.c +D > /proc/dynamic_debug/control

after:

init/initramfs.c:485 [initramfs]unpack_to_rootfs =_ "Detected %s compressed 
data\012"
[main]:1337 =pmD "%s\012"
[main]:1335 =pmD "  with environment:\012"
[main]:1334 =pmD "%s\012"
[main]:1332 =pmD "  with arguments:\012"
[main]:1121 =pmD "initcall %s blacklisted\012"
[main]:1082 =pmD "blacklisting initcall %s\012"

Notes:

If Drm adopted dyndbg, i915 + drm* would add ~1600 prdebugs, amdgpu +
drm* would add ~3200 callsites, so the additional memory costs are
substantial.  In trade, drm and drivers would avoid lots of calls to
drm_debug_enabled().  This patch should reduce the costs.

Using this interface, drm could drop site info for all categories /
prefixes controlled by bits in drm.debug, while preserving site info
and individual selectivity for any uncategorized prdebugs, and for all
other modules.

Lastly, because lineno field was not moved into _ddebug_callsite, it
can be used to modify a single[*] callsite even if drm has dropped all
the callsite data:

  echo module $mod format ^$prefix line $line +p >control

Dropping site info is a one-way, information losing operation, so
minor misuse is possible.  Worst case is maybe (depending upon
previous settings) some loss of logging context/decorations.

  echo +D > /proc/dynamic_debug/control

[*] amdgpu has some macros invoking clusters of pr_debugs; each use of
them creates a cluster of pr-debugs with the same line number.

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 1 +
 lib/dynamic_debug.c   | 9 +
 2 files changed, 10 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index aa4a3f5d8d35..d811273c8484 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -40,6 +40,7 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_INCL_FUNCNAME   (1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
 #define _DPRINTK_FLAGS_INCL_TID(1<<4)
+#define _DPRINTK_FLAGS_DELETE_SITE (1<<7) /* drop site info to save ram */
 
 #define _DPRINTK_FLAGS_INCL_ANYSITE\
(_DPRINTK_FLAGS_INCL_MODNAME\
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 6fbd9099c2fa..fdc2d0e15731 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -92,6 +92,7 @@ static struct { unsigned flag:8; char opt_char; } opt_array[] 
= {
{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
{ _DPRINTK_FLAGS_INCL_TID, 't' },
{ _DPRINTK_FLAGS_NONE, '_' },
+   { _DPRINTK_FLAGS_DELETE_SITE, 'D' },
 };
 
 struct flagsbuf { char buf[ARRAY_SIZE(opt_array)+1]; };
@@ -201,6 +202,14 @@ static void ddebug_alter_site(struct _ddebug *dp,
} else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
static_branch_enable(>key.dd_key_true);
 #endif
+   /* delete site info for this callsite */
+   if (modifiers->flags & _DPRINTK_FLAGS_DELETE_SITE) {
+   if (dp->site) {
+   vpr_info("dropping site info %s.%s.%d\n", 
dp->site->filename,
+   dp->site->function, dp->lineno);
+   dp->site = NULL;
+   }
+   }
 }
 
 /*
-- 
2.29.2



[RFC PATCH v4 11/19] dyndbg: refactor ddebug_alter_site out of ddebug_change

2021-03-17 Thread Jim Cromie
Move the JUMP_LABEL/static-key code to a separate function.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 22 +++---
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 2d011ac3308d..6fbd9099c2fa 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -191,6 +191,18 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
return true;
 }
 
+static void ddebug_alter_site(struct _ddebug *dp,
+ struct flag_settings *modifiers)
+{
+#ifdef CONFIG_JUMP_LABEL
+   if (dp->flags & _DPRINTK_FLAGS_PRINT) {
+   if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
+   static_branch_disable(>key.dd_key_true);
+   } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
+   static_branch_enable(>key.dd_key_true);
+#endif
+}
+
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -227,13 +239,9 @@ static int ddebug_change(const struct ddebug_query *query,
newflags = (dp->flags & modifiers->mask) | 
modifiers->flags;
if (newflags == dp->flags)
continue;
-#ifdef CONFIG_JUMP_LABEL
-   if (dp->flags & _DPRINTK_FLAGS_PRINT) {
-   if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
-   
static_branch_disable(>key.dd_key_true);
-   } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
-   static_branch_enable(>key.dd_key_true);
-#endif
+
+   ddebug_alter_site(dp, modifiers);
+
dp->flags = newflags;
 
if (dc)
-- 
2.29.2



[RFC PATCH v4 09/19] dyndbg: optimize ddebug_emit_prefix

2021-03-17 Thread Jim Cromie
Add early return if no callsite info is specified in site-flags.
This avoids fetching site info that isn't going to be printed.

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 9 +
 lib/dynamic_debug.c   | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index bc8027292c02..aa4a3f5d8d35 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -40,6 +40,15 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_INCL_FUNCNAME   (1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
 #define _DPRINTK_FLAGS_INCL_TID(1<<4)
+
+#define _DPRINTK_FLAGS_INCL_ANYSITE\
+   (_DPRINTK_FLAGS_INCL_MODNAME\
+| _DPRINTK_FLAGS_INCL_FUNCNAME \
+| _DPRINTK_FLAGS_INCL_LINENO)
+#define _DPRINTK_FLAGS_INCL_ANY\
+   (_DPRINTK_FLAGS_INCL_ANYSITE\
+| _DPRINTK_FLAGS_INCL_TID)
+
 #if defined DEBUG
 #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
 #else
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 1f0cac4a66af..af9cf97f869b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -632,6 +632,9 @@ static char *dynamic_emit_prefix(const struct _ddebug *dp, 
char *buf)
}
pos_after_tid = pos;
 
+   if (!(dp->flags & _DPRINTK_FLAGS_INCL_ANYSITE))
+   return buf;
+
if (desc) {
if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
pos += snprintf(buf + pos, remaining(pos), "%s:",
-- 
2.29.2



[RFC PATCH v4 10/19] dyndbg: avoid calling dyndbg_emit_prefix when it has no work

2021-03-17 Thread Jim Cromie
Wrap function in a static-inline one, which checks flags to avoid
calling the function unnecessarily.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index af9cf97f869b..2d011ac3308d 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -615,7 +615,7 @@ static int remaining(int wrote)
return 0;
 }
 
-static char *dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
+static char *__dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
 {
int pos_after_tid;
int pos = 0;
@@ -655,6 +655,13 @@ static char *dynamic_emit_prefix(const struct _ddebug *dp, 
char *buf)
return buf;
 }
 
+static inline char *dynamic_emit_prefix(struct _ddebug *dp, char *buf)
+{
+   if (unlikely(dp->flags & _DPRINTK_FLAGS_INCL_ANY))
+   return __dynamic_emit_prefix(dp, buf);
+   return buf;
+}
+
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
 {
va_list args;
-- 
2.29.2



[RFC PATCH v4 07/19] dyndbg: accept null site in dynamic_emit_prefix

2021-03-17 Thread Jim Cromie
2 prints use site->member, protect them with if site.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 16 ++--
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 151e55ab6bb5..0c535f3c2ba9 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -631,15 +631,19 @@ static char *dynamic_emit_prefix(const struct _ddebug 
*dp, char *buf)
task_pid_vnr(current));
}
pos_after_tid = pos;
-   if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
-   pos += snprintf(buf + pos, remaining(pos), "%s:",
-   desc->modname);
-   if (dp->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
-   pos += snprintf(buf + pos, remaining(pos), "%s:",
-   desc->function);
+
+   if (desc) {
+   if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
+   pos += snprintf(buf + pos, remaining(pos), "%s:",
+   desc->modname);
+   if (dp->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
+   pos += snprintf(buf + pos, remaining(pos), "%s:",
+   desc->function);
+   }
if (dp->flags & _DPRINTK_FLAGS_INCL_LINENO)
pos += snprintf(buf + pos, remaining(pos), "%d:",
dp->lineno);
+
if (pos - pos_after_tid)
pos += snprintf(buf + pos, remaining(pos), " ");
if (pos >= PREFIX_SIZE)
-- 
2.29.2



[RFC PATCH v4 04/19] dyndbg: accept null site in ddebug_match_site

2021-03-17 Thread Jim Cromie
basically, reorder the elements to minimize data fetches.

1- move format and line-number check code to the top of the function,
   since they don't use/check site info.

2- test site pointer:
   If its null, we return early, skipping 3:
  If the query tests against missing site info, fail the match.
  otherwize site matches.

3- rest of function (checking site vs query) is unchanged.

ddebug_match_site ignores module, because it's tested already
by the caller, where it is known from debug_tables.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 41 +
 1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 9cff9db15937..da732e0c56e3 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -145,21 +145,7 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 static int ddebug_match_site(const struct ddebug_query *query,
 const struct _ddebug *dp)
 {
-   struct _ddebug_site *dc = dp->site;
-
-   /* match against the source filename */
-   if (query->filename &&
-   !match_wildcard(query->filename, dc->filename) &&
-   !match_wildcard(query->filename,
-   kbasename(dc->filename)) &&
-   !match_wildcard(query->filename,
-   trim_prefix(dc->filename)))
-   return false;
-
-   /* match against the function */
-   if (query->function &&
-   !match_wildcard(query->function, dc->function))
-   return false;
+   struct _ddebug_site *dc;
 
/* match against the format */
if (query->format) {
@@ -181,6 +167,29 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
dp->lineno > query->last_lineno)
return false;
 
+   dc = dp->site;
+   if (!dc) {
+   /* site info has been dropped, so query cannot test these 
fields */
+   if (query->filename || query->function)
+   return false;
+   else
+   return true;
+   }
+
+   /* match against the source filename */
+   if (query->filename &&
+   !match_wildcard(query->filename, dc->filename) &&
+   !match_wildcard(query->filename,
+   kbasename(dc->filename)) &&
+   !match_wildcard(query->filename,
+   trim_prefix(dc->filename)))
+   return false;
+
+   /* match against the function */
+   if (query->function &&
+   !match_wildcard(query->function, dc->function))
+   return false;
+
return true;
 }
 
@@ -210,7 +219,7 @@ static int ddebug_change(const struct ddebug_query *query,
 
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = >ddebugs[i];
-   struct _ddebug_site *dc = dp->site;
+   struct _ddebug_site *dc;
 
if (!ddebug_match_site(query, dp))
continue;
-- 
2.29.2



[RFC PATCH v4 02/19] dyndbg: __init iterate over __dyndbg & __dyndbg_site in parallel

2021-03-17 Thread Jim Cromie
In dynamic_debug_init(), rework for-loop; add 2nd 'site' var, and
iterate over both __dyndbg* sections in parallel.  Replace uses of
iter->site with the new 'site' iter, add a BUG_ON to enforce the
invariant given by HEAD~1's DECLARE_DYNAMIC_DEBUG_METADATA base->site
initialization.

0- declare the new elf section start/stop, named in vmlinux.lds.h
   I disregarded a checkpatch warning about externs in c-files, stuck
   with current practice.

1- clean up use of 4 iterators for clarity:
   (iter, site), and ((iter, site)_mod_start) block markers.

2- iterate over __dyndbg_sites in parallel with __dyndbg
   s/iter->site/site/g;

3- add BUG_ON(iter->site != site)
   DECLARE_DYNAMIC_DEBUG_METADATA + linker insure this now.
   Maybe we can drop pointer, still get order.

4- var rename n to site_ct

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 36 +++-
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 738c4ce28046..c3c35dcc6a59 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -41,6 +41,8 @@
 
 extern struct _ddebug __start___dyndbg[];
 extern struct _ddebug __stop___dyndbg[];
+extern struct _ddebug_site __start___dyndbg_sites[];
+extern struct _ddebug_site __stop___dyndbg_sites[];
 
 struct ddebug_table {
struct list_head link;
@@ -118,6 +120,7 @@ do {
\
 
 #define vpr_info(fmt, ...) vnpr_info(1, fmt, ##__VA_ARGS__)
 #define v2pr_info(fmt, ...)vnpr_info(2, fmt, ##__VA_ARGS__)
+#define v3pr_info(fmt, ...)vnpr_info(3, fmt, ##__VA_ARGS__)
 
 static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 {
@@ -1082,11 +1085,12 @@ static int __init dynamic_debug_init_control(void)
 
 static int __init dynamic_debug_init(void)
 {
-   struct _ddebug *iter, *iter_start;
+   struct _ddebug *iter, *iter_mod_start;
+   struct _ddebug_site *site, *site_mod_start;
const char *modname = NULL;
char *cmdline;
int ret = 0;
-   int n = 0, entries = 0, modct = 0;
+   int site_ct = 0, entries = 0, modct = 0;
 
if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
@@ -1097,23 +1101,29 @@ static int __init dynamic_debug_init(void)
ddebug_init_success = 1;
return 0;
}
-   iter = __start___dyndbg;
-   modname = iter->site->modname;
-   iter_start = iter;
-   for (; iter < __stop___dyndbg; iter++) {
+
+   iter = iter_mod_start = __start___dyndbg;
+   site = site_mod_start = __start___dyndbg_sites;
+   modname = site->modname;
+
+   for (; iter < __stop___dyndbg; iter++, site++) {
+
+   BUG_ON(site != iter->site);
entries++;
-   if (strcmp(modname, iter->site->modname)) {
+
+   if (strcmp(modname, site->modname)) {
modct++;
-   ret = ddebug_add_module(iter_start, n, modname);
+   ret = ddebug_add_module(iter_mod_start, site_ct, 
modname);
if (ret)
goto out_err;
-   n = 0;
-   modname = iter->site->modname;
-   iter_start = iter;
+   site_ct = 0;
+   modname = site->modname;
+   iter_mod_start = iter;
+   site_mod_start = site;
}
-   n++;
+   site_ct++;
}
-   ret = ddebug_add_module(iter_start, n, modname);
+   ret = ddebug_add_module(iter_mod_start, site_ct, modname);
if (ret)
goto out_err;
 
-- 
2.29.2



[RFC PATCH v4 03/19] dyndbg: refactor part of ddebug_change to ddebug_match_site

2021-03-17 Thread Jim Cromie
Move all the site-match logic into a separate function, reindent the
code, and replace the continues with return falses.

No functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 75 ++---
 1 file changed, 43 insertions(+), 32 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c3c35dcc6a59..9cff9db15937 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -142,6 +142,48 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 query->first_lineno, query->last_lineno);
 }
 
+static int ddebug_match_site(const struct ddebug_query *query,
+const struct _ddebug *dp)
+{
+   struct _ddebug_site *dc = dp->site;
+
+   /* match against the source filename */
+   if (query->filename &&
+   !match_wildcard(query->filename, dc->filename) &&
+   !match_wildcard(query->filename,
+   kbasename(dc->filename)) &&
+   !match_wildcard(query->filename,
+   trim_prefix(dc->filename)))
+   return false;
+
+   /* match against the function */
+   if (query->function &&
+   !match_wildcard(query->function, dc->function))
+   return false;
+
+   /* match against the format */
+   if (query->format) {
+   if (*query->format == '^') {
+   char *p;
+   /* anchored search. match must be at beginning */
+   p = strstr(dp->format, query->format+1);
+   if (p != dp->format)
+   return false;
+   } else if (!strstr(dp->format, query->format))
+   return false;
+   }
+
+   /* match against the line number range */
+   if (query->first_lineno &&
+   dp->lineno < query->first_lineno)
+   return false;
+   if (query->last_lineno &&
+   dp->lineno > query->last_lineno)
+   return false;
+
+   return true;
+}
+
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -170,38 +212,7 @@ static int ddebug_change(const struct ddebug_query *query,
struct _ddebug *dp = >ddebugs[i];
struct _ddebug_site *dc = dp->site;
 
-   /* match against the source filename */
-   if (query->filename &&
-   !match_wildcard(query->filename, dc->filename) &&
-   !match_wildcard(query->filename,
-  kbasename(dc->filename)) &&
-   !match_wildcard(query->filename,
-  trim_prefix(dc->filename)))
-   continue;
-
-   /* match against the function */
-   if (query->function &&
-   !match_wildcard(query->function, dc->function))
-   continue;
-
-   /* match against the format */
-   if (query->format) {
-   if (*query->format == '^') {
-   char *p;
-   /* anchored search. match must be at 
beginning */
-   p = strstr(dp->format, query->format+1);
-   if (p != dp->format)
-   continue;
-   } else if (!strstr(dp->format, query->format))
-   continue;
-   }
-
-   /* match against the line number range */
-   if (query->first_lineno &&
-   dp->lineno < query->first_lineno)
-   continue;
-   if (query->last_lineno &&
-   dp->lineno > query->last_lineno)
+   if (!ddebug_match_site(query, dp))
continue;
 
nfound++;
-- 
2.29.2



[RFC PATCH v4 00/19] dynamic debug diet plan

2021-03-17 Thread Jim Cromie
v4 fixes 'series grooming errors',
Reported-by: kernel test robot 

CONFIG_DYNAMIC_DEBUG creates a struct _ddebug (56 bytes) for each
callsite, which includes 3 pointers to: module, filename, function.
These are repetetive, and compressible, this patch series goes about
doing that, it:

- splits struct _ddebug and __dyndbg[] section/array into 2
  creating struct _ddebug_site and __dyndbg_sites[]
  temporary _ddebug.site connects them.
  
- makes _ddebug_site data optional
- minor optimizations
- makes _ddebug_site data deleteable
  not necessary, proof of optionality

The RFC stuff comes at the end:

- attach __dyndbg_sites[] to module-info, like __dyndbg[]
- add index to struct _ddebug, use it for builtins
- add ddebug_site(_get|_put) abstraction to hide _ddebug.site

At this point, its practical to: compress __dyndbg_sites[] & replace
the section, then expand it on-demand to serve ddebug_site_get()
calls.  For enabled callsites (with decorations flags), the retrieved
records can be cached in a hash after theyre 1st needed/used (when
callsite is actually executed).

Whats my (ideal?) decompressing interface ?
And whats the name of the api call ? I couldnt suss it out yet.

For any control read, a simple block decompress and cache is close to
ideal; all site data is then available to iterate over, and each
ddebug_site_get() just indexes into it.  A stream of decompressed site
records would also work well, with less lumpy memory allocs and frees.

Actually dropping _ddebug.site is not yet possible.  While we could
drop it for builtin modules, thats cuz we know __start___dyndbg_sites.
For loaded modules, I need the elf section: __dyndbg_sites.  This is
in load-info, but I dont have a path to it.  In:

- add _ddebug_header/table

That adds a single header entry pair (structs _ddebug*s with special
initialization) into the arrays, and it links to the front of the
array, where its useful.  But creating this header entry only works
for vmlinux itself (because of vmlinux.ld.h patch), not for loadable
modules.

- add linker rules to module.lds.h

I tried to re-use the DYMAMIC_DEBUG_DATA macro added above for
modules, this failed, commit msg guesses the cause.  This breaks with
a linker script syntax error

TODO

Presuming the fixed header can be linked reliably in front doing
something like I tried, it can be recast as a ddebug_header and
unionized with struct _ddebug, and the _ddebugs[] will fit nicely as a
flex-array:

struct ddebug_table2 {
   struct ddebug_header foo;
   struct _ddebug ddebugs[];
}

A header would have 40 bytes, room to contain most/all of struct
ddebug_table's fields, a pointer to the __dyndbg_sites[] table, and a
list-head too, meaning it supports essential and nice-to-have
properties:

- the mapping: __dyndbg[N] --> __dyndbg_sites[N] # NEEDed to drop .site
  using container_of_flex() for flex-arrays

- we can add them directly to ddebug_tables list # freebie
  ie avoid the kzalloc in ddebug_add_module()  

If not all fields fit in the space available in __dyndbg[0], there is
space available in __dyndbg_sites[0].

Additionally, at the end of __init, ddebug_tables list is composed of
memory entirely in __dyndbg[], which could then be make readonly (by
means I dont know).  If this breaks insertions of loadable modules, we
can easily a 2nd list for that.


Jim Cromie (19):
  dyndbg: split struct _ddebug, move display fields to new _ddebug_site
  dyndbg: __init iterate over __dyndbg & __dyndbg_site in parallel
  dyndbg: refactor part of ddebug_change to ddebug_match_site
  dyndbg: accept null site in ddebug_match_site
  dyndbg: hoist ->site out of ddebug_match_site
  dyndbg: accept null site in ddebug_change
  dyndbg: accept null site in dynamic_emit_prefix
  dyndbg: accept null site in ddebug_proc_show
  dyndbg: optimize ddebug_emit_prefix
  dyndbg: avoid calling dyndbg_emit_prefix when it has no work
  dyndbg: refactor ddebug_alter_site out of ddebug_change
  dyndbg: allow deleting site info via control interface
  dyndbg+module: expose ddebug_sites to modules
  dyndbg: add ddebug_site(_get|_put) abstraction
  dyndbg: add _index to struct _ddebug
  dyndbg: prevent build bugs via -DNO_DYNAMIC_DEBUG_TABLE
  dyndbg: RFC - DECLARE/DEFINE_DYNAMIC_DEBUG_TABLE
  dyndbg: shuffle ddebug_table fields
  dyndbg: RFC add linker rules to module.lds.h

 arch/x86/boot/compressed/Makefile |   1 +
 arch/x86/entry/vdso/Makefile  |   3 +
 arch/x86/purgatory/Makefile   |   1 +
 drivers/firmware/efi/libstub/Makefile |   3 +-
 drivers/gpu/drm/i915/i915_drv.c   |   2 +
 include/asm-generic/module.lds.h  |  21 ++
 include/asm-generic/vmlinux.lds.h |  24 +-
 include/linux/dynamic_debug.h | 180 +--
 kernel/module-internal.h  |   1 +
 kernel/module.c   |   9 +-
 lib/dynamic_debug.c   | 313 +++---
 scripts/Makefile.lib  |   2 +
 12 files changed, 

[RFC PATCH v4 01/19] dyndbg: split struct _ddebug, move display fields to new _ddebug_site

2021-03-17 Thread Jim Cromie
struct _ddebug has 2 flavors of fields: essential and optional.  Split
the 3 optional fields: module, function, file into a new struct
_ddebug_site, and add pointer to it from _ddebug.

These fields are optional in that they are primarily used to generate
the optional "module:func:line" log prefix.  They're also used to
select callsites to >control.  lineno is arguably optional too, but
leaving it uses spare bytes in struct _ddebug.

The new ptr increases memory footprint by 1 ptr per pr_debug, but I
think its temporary, and the indirection gives several advantages:

- we can drop sites and their storage opportunistically.
  this reduces per-site mem by 24/64.

  Subsystems may not need/want "module:func:line:" in their logs.
  If they already use format-prefixes such as "drm:kms:",
  they can select on those, and don't need the site info for that.
  forex:
  #> echo module drm format "^drm:kms: " +p >control
  ie: dynamic_debug_exec_queries("format '^drm:kms: '", "drm");

- the moved display fields are inherently hierarchical, and the linker
  section is ordered; so (module, file, function) have repeating
  values (90%, 85%, 45%).  This is readily compressible, even with a
  simple field-wise run length encoding.  Since I'm splitting the struct,
  I also reordered the fields to match the hierarchy.

- the separate linker section sets up naturally for block compression.

IFF we can on-demand map:  ddebugs[N] -> ddebug_sites[N]

- we can compress __dyndbg_sites during __init, and mark section __initdata

- can decompress on-demand, say for `cat control`
- can save chunks of decompressed buffer for enabled callsites
- free chunks on site disable, or on memory pressure.

Whats actually done here is rather mechanical, and preparatory.

dynamic_debug.h:

I cut struct _ddebug in half, renamed optional top-half to
_ddebug_site, kept __align(8) for both halves.  I added a forward decl
for a unified comment for both head & body, and added head.site to
point at body.

DECLARE_DYNAMIC_DEBUG_METADATA does the core of the work; it declares
and initializes both static struct variables together, and refs one to
the other.

dynamic_debug.c:

dynamic_debug_init() mem-usage now also counts sites.

dynamic_emit_prefix() & ddebug_change() use those moved fields; they
get a new initialized auto-var, and the field refs get adjusted as
needed to follow the move from one struct to the other.

   struct _ddebug_site *dc = dp->site;

ddebug_proc_show() differs slightly; it assigns to (not initializes)
the autovar, to avoid a panic when p == SEQ_START_TOKEN.

vmlinux.lds.h:

add __dyndbg_sites section, with the same align(8) and KEEP as
used in the __dyndbg section.

Signed-off-by: Jim Cromie 
---
 include/asm-generic/vmlinux.lds.h |  3 ++
 include/linux/dynamic_debug.h | 37 -
 lib/dynamic_debug.c   | 46 +--
 3 files changed, 53 insertions(+), 33 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 0331d5d49551..4f2af9de2f03 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -353,6 +353,9 @@
*(__tracepoints)\
/* implement dynamic printk debug */\
. = ALIGN(8);   \
+   __start___dyndbg_sites = .; \
+   KEEP(*(__dyndbg_sites)) \
+   __stop___dyndbg_sites = .;  \
__start___dyndbg = .;   \
KEEP(*(__dyndbg))   \
__stop___dyndbg = .;\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index a57ee75342cf..bc8027292c02 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -7,20 +7,28 @@
 #endif
 
 /*
- * An instance of this structure is created in a special
- * ELF section at every dynamic debug callsite.  At runtime,
- * the special section is treated as an array of these.
+ * A pair of these structs are created in 2 special ELF sections
+ * (__dyndbg, __dyndbg_sites) for every dynamic debug callsite.
+ * At runtime, the sections are treated as arrays.
  */
-struct _ddebug {
+struct _ddebug;
+struct _ddebug_site {
/*
-* These fields are used to drive the user interface
-* for selecting and displaying debug callsites.
+* These fields (and lineno) are used to:
+* - decorate log messages per site flags
+* - select callsites for modification via >control
+* - display callsites & settings in `cat control`
 */
const char *modname;
-   const char *function;

[RFC PATCH v3 18/18] dyndbg: shuffle ddebug_table fields

2021-03-15 Thread Jim Cromie
In preparation to unionize structs _ddebug & ddebug_table, shuffle
fields in latter so they match the layout of the former.  This MAY
simplify initialization of the header field, in particular by
preserving *sites.

It also sets up a later conversion to a flex-array ddebugs[].

This step is mostly to isolate/prove no breakage before HEAD++

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 29 +
 lib/dynamic_debug.c   |  2 +-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 229cfd81ffb3..22f11218047f 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -66,6 +66,35 @@ struct _ddebug {
 #endif
 } __aligned(8);
 
+/* this pair of header structs correspond quite deeply to struct
+ * _ddebug(|_site)s above; they are also created into __dyndbg*
+ * sections (by DEFINE_DYNAMIC_DEBUG_TABLE), and should be unionized
+ * with them to reinforce this.
+ *
+ * struct _ddebug_header is the important one, it has enough space to
+ * take struct ddebug_table's job, ie: link together into a list, and
+ * keep track of the modname & _ddebug(|_sites) vectors.
+ *
+ * Its other job is handled by its placement in the front of a
+ * module's _ddebug[N] entries.  Each _ddebug knows its N, so the
+ * header's address is computable, and its site pointer is available
+ * to get _ddebug_sites[N].  Then we can drop _ddebug.sites, regaining
+ * parity with original _ddebug footprint.
+ *
+ * Eventually, N will index a fetch from a compressed block, or for
+ * enabled callsites, a hash.  A global hash is probably adequate, if
+ * ~5k elements doesnt degrade access time.
+ */
+struct _ddebug_site_header {
+   /* we have 24 bytes total here, all currently unused */
+} __aligned(8);
+
+struct _ddebug_header {
+   struct _ddebug_site* sites;
+   struct list_head link;
+   const char* mod_name;
+   unsigned num_ddebugs;
+} __aligned(8);
 
 #if defined(CONFIG_DYNAMIC_DEBUG_CORE)
 
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c1a7345277eb..5d1ce7f21c30 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -45,11 +45,11 @@ extern struct _ddebug_site __start___dyndbg_sites[];
 extern struct _ddebug_site __stop___dyndbg_sites[];
 
 struct ddebug_table {
+   struct _ddebug_site *sites;
struct list_head link;
const char *mod_name;
unsigned int num_ddebugs;
struct _ddebug *ddebugs;
-   struct _ddebug_site *sites;
 };
 
 struct ddebug_query {
-- 
2.29.2



[RFC PATCH v3 17/18] dyndbg: RFC - DECLARE/DEFINE_DYNAMIC_DEBUG_TABLE

2021-03-15 Thread Jim Cromie
V4-proto - now currently diet-3i

Simplify:
.gnu.linkonce._mod_.dyndbg -> .gnu.linkonce.dyndbg
ie drop _mod_

This puts a single header record at front of the vectors, solving 2
problems (discussed below) simultaneously:

- header in front, allowing flex-array rep of layout.
- single header, not per-module. adequate for needs, no wasted space.

this now appears to work
- get: dp range-check good on builtin, !builtin.

todo:
- _sym_##_site symbols in init/main.i still busted
- _index init in __ddebug_add_module
- cleanup commentary below.

DEFINE_DYNAMIC_DEBUG_TABLE is based on DECLARE_DYNAMIC_DEBUG_METADATA.
Like its model, it creates/allocates a pair of structs: _ddebug &
_ddebug_site, and inits them distinctively.

Its purpose is to create an in-situ module-header-pair for each
module's sub-vectors of _ddebug[], _ddebug_sites[].  Once the
header-pair is reliably linked into the vectors, code can get from
_ddebug[N] to the header-pair, then to _ddebug_sites[N] at runtime by
saving N into _ddebug._index during init.  With this, we can drop the
site pointer in struct _ddebug.

Eventually, this module-header-pair can be adapted to be an in-situ
replacement for the separately allocated struct ddebug_tables, and be
linked into the ddebug_tables list.

RFC, NOTES:

DYNAMIC_DEBUG is a 'transparent' facility, in that uses of pr_debug
get extra features without additional api.  Because of this,
DEFINE_DYNAMIC_DEBUG_TABLE is 'transparently' invoked by
dynamic_debug.h on behalf of all its (indirect) users, including
printk.h.

IOW this has wide effects; it results in multiple redundant
declarations of header records, even single object files may get
multiple copies.  Using .gnu.linkonce._mod_.dyndbg(|_site) section
names and "__used __weak " seems to resolve the redundancies.  I
havent tried with clang.

In vmlinux-lds.h, the 2 KEEPs are modified to append those 2 new
header sections to their respective existing __dyndbg* sections, in an
interleaved manner.  This places the header records immediately after
the modules' block of _ddebug*s, in a knowable offset from &__dyndbg[0].

scripts/Makefile.lib gets a new -DKBUILD_MODSYM defn, with a value
like KBUILD_MODNAME, except that its not __stringified.  It is used to
create a pair of module-ish named variables: _sym_##_dyndbg_base.

For some non-obvious reason, the substitution doesnt work, resulting
in per-module symbol names like KBUILD_MODSYM_dyndbg_base.  This
subtly alters the header initialization and is_dyndbg_header_pair(),
which is used in __init to find the headers adjacent to each modules'
block of _ddebug records.  This isnt fatal to the plan; we just need
the storage reserved where its accessible by known offset from the
_ddebug[N] record of an enabled pr-debug.  But it would be nice to
have the symbol names consistent with the intent.  I looked for a
MODULE_SINGLETON(name_suffix) to use, similarly to how UNIQUE_ID is
used to construct names, but found nothing.

The .gnu.linkonce._mod_. works to eliminate all the extra headers in
each module, but a problem remains; it adds unneeded headers for
modules with zero pr-debugs.  So Im seeing ~1500 extra headers.

I tried several flavors of conditional linking, now think I want/need
a linker-script language extension:

  KEEP ( *(__dyndbg) AND *(.gnu.linkonce.dyndbg) )  # my need
  KEEP ( *(foo_tbl)   OR *(.gnu.linkonce.foo_alt) ) # for completeness

I've managed to alter ld's grammar, but its only compile tested, and
is missing the conditional linking pieces.  Since this patchset's
value proposition is a memory shrink, ~1500 extra headers is fatal,
and this patchset must be a slow-cook.

V4 todo:

Time to simplify, drop _mod_, and change _ddebug.module_index to
._index, indicating that its no longer keyed to module, but to the
whole compilation unit, which for the kernel includes all the builtin
modules.  loadable modules should get their own. tbt.

this could obsolete all the above problems.

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/i915/i915_drv.c   |   2 +
 include/asm-generic/vmlinux.lds.h |  27 +---
 include/linux/dynamic_debug.h | 100 +-
 lib/dynamic_debug.c   |  28 ++---
 scripts/Makefile.lib  |   2 +
 5 files changed, 139 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 8e9cb44e66e5..51163e0d40cf 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -91,6 +91,8 @@
 
 static const struct drm_driver driver;
 
+//DEFINE_DYNAMIC_DEBUG_TABLE();
+
 static int i915_get_bridge_dev(struct drm_i915_private *dev_priv)
 {
int domain = pci_domain_nr(dev_priv->drm.pdev->bus);
diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 4f2af9de2f03..482d94078785 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -335,6 +335,22 @@

[RFC PATCH v3 16/18] dyndbg: prevent build bugs via -DNO_DYNAMIC_DEBUG_TABLE

2021-03-15 Thread Jim Cromie
The next patch adds DEFINE_DYNAMIC_DEBUG_TABLE(), which breaks some
subtrees with special compile constraints (efi etc).

Avoid this by adding a define to suppress the *remote declaration*
done by DEFINE_DYNAMIC_DEBUG_TABLE(), automatically, on behalf of all
possible users of pr_debug.

Signed-off-by: Jim Cromie 
---
 arch/x86/boot/compressed/Makefile | 1 +
 arch/x86/entry/vdso/Makefile  | 3 +++
 arch/x86/purgatory/Makefile   | 1 +
 drivers/firmware/efi/libstub/Makefile | 3 ++-
 4 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/x86/boot/compressed/Makefile 
b/arch/x86/boot/compressed/Makefile
index e0bc3988c3fa..ada4eb960d95 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -31,6 +31,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 
vmlinux.bin.lzma \
 KBUILD_CFLAGS := -m$(BITS) -O2
 KBUILD_CFLAGS += -fno-strict-aliasing -fPIE
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+KBUILD_CFLAGS += -DNO_DYNAMIC_DEBUG_TABLE
 cflags-$(CONFIG_X86_32) := -march=i386
 cflags-$(CONFIG_X86_64) := -mcmodel=small -mno-red-zone
 KBUILD_CFLAGS += $(cflags-y)
diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index 05c4abc2fdfd..619878f2c427 100644
--- a/arch/x86/entry/vdso/Makefile
+++ b/arch/x86/entry/vdso/Makefile
@@ -29,6 +29,9 @@ vobjs32-y := vdso32/note.o vdso32/system_call.o 
vdso32/sigreturn.o
 vobjs32-y += vdso32/vclock_gettime.o
 vobjs-$(CONFIG_X86_SGX)+= vsgx.o
 
+# avoid a x86_64_RELATIVE error
+KBUILD_CFLAGS += -DNO_DYNAMIC_DEBUG_TABLE
+
 # files to link into kernel
 obj-y  += vma.o extable.o
 KASAN_SANITIZE_vma.o   := y
diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile
index 95ea17a9d20c..95ba7b18410f 100644
--- a/arch/x86/purgatory/Makefile
+++ b/arch/x86/purgatory/Makefile
@@ -35,6 +35,7 @@ PURGATORY_CFLAGS_REMOVE := -mcmodel=kernel
 PURGATORY_CFLAGS := -mcmodel=large -ffreestanding -fno-zero-initialized-in-bss 
-g0
 PURGATORY_CFLAGS += $(DISABLE_STACKLEAK_PLUGIN) -DDISABLE_BRANCH_PROFILING
 PURGATORY_CFLAGS += -fno-stack-protector
+PURGATORY_CFLAGS += -DNO_DYNAMIC_DEBUG_TABLE
 
 # Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. That
 # in turn leaves some undefined symbols like __fentry__ in purgatory and not
diff --git a/drivers/firmware/efi/libstub/Makefile 
b/drivers/firmware/efi/libstub/Makefile
index c23466e05e60..def8febefbd3 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -13,7 +13,8 @@ cflags-$(CONFIG_X86)  += -m$(BITS) -D__KERNEL__ \
   -Wno-pointer-sign \
   $(call cc-disable-warning, 
address-of-packed-member) \
   $(call cc-disable-warning, gnu) \
-  -fno-asynchronous-unwind-tables
+  -fno-asynchronous-unwind-tables \
+  -DNO_DYNAMIC_DEBUG_TABLE
 
 # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly
 # disable the stackleak plugin
-- 
2.29.2



[RFC PATCH v3 13/18] dyndbg+module: expose ddebug_sites to modules

2021-03-15 Thread Jim Cromie
In order to drop the pointer connecting _ddebug's to _ddebug_sites,
we need to elevate the latter; we need to track it in (internal)
ddebug_tables, and set it in ddebug_add_module.  That last part
exposes it by interface to module.c, so we add a field to load_info,
and adjust load_module to initialize it from the elf section.

Its possible that this closes a "hole" created when __dyndbg_sites
section was added, in that the section wasn't "managed" directly, and
could conceivably get lost later.  I never saw any misbehavior loading
i915.ko into a vm, but still..

TBD/RFC:

these 2 vectors should be in a single struct.  if this struct can have
ddebugs[], ie a flex-array, then container_of can get us to the
sites*, yielding _sites[N], and allowing to drop _ddebug.site

The trouble with this is that ddebugs* now points to someone elses
memory, and we cant just steal it and stomp on the memory just in
front of it (for the sites ptr).

rename n to numdbgs

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h |  4 ++--
 kernel/module-internal.h  |  1 +
 kernel/module.c   |  9 ++---
 lib/dynamic_debug.c   | 18 +++---
 4 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index d811273c8484..7d33475d226a 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -70,8 +70,8 @@ struct _ddebug {
 /* exported for module authors to exercise >control */
 int dynamic_debug_exec_queries(const char *query, const char *modname);
 
-int ddebug_add_module(struct _ddebug *tab, unsigned int n,
-   const char *modname);
+int ddebug_add_module(struct _ddebug *tab, struct _ddebug_site *sites,
+ unsigned int numdbgs, const char *modname);
 extern int ddebug_remove_module(const char *mod_name);
 extern __printf(2, 3)
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
diff --git a/kernel/module-internal.h b/kernel/module-internal.h
index 33783abc377b..fb61eb2f8032 100644
--- a/kernel/module-internal.h
+++ b/kernel/module-internal.h
@@ -18,6 +18,7 @@ struct load_info {
char *secstrings, *strtab;
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
struct _ddebug *debug;
+   struct _ddebug_site *sites;
unsigned int num_debug;
bool sig_ok;
 #ifdef CONFIG_KALLSYMS
diff --git a/kernel/module.c b/kernel/module.c
index 30479355ab85..792903230acd 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2780,11 +2780,12 @@ static void add_kallsyms(struct module *mod, const 
struct load_info *info)
 }
 #endif /* CONFIG_KALLSYMS */
 
-static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, 
unsigned int num)
+static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug,
+   struct _ddebug_site *sites, unsigned int num)
 {
if (!debug)
return;
-   ddebug_add_module(debug, num, mod->name);
+   ddebug_add_module(debug, sites, num, mod->name);
 }
 
 static void dynamic_debug_remove(struct module *mod, struct _ddebug *debug)
@@ -,6 +3334,8 @@ static int find_module_sections(struct module *mod, 
struct load_info *info)
 
info->debug = section_objs(info, "__dyndbg",
   sizeof(*info->debug), >num_debug);
+   info->sites = section_objs(info, "__dyndbg_sites",
+  sizeof(*info->sites), >num_debug);
 
return 0;
 }
@@ -4004,7 +4007,7 @@ static int load_module(struct load_info *info, const char 
__user *uargs,
goto free_arch_cleanup;
}
 
-   dynamic_debug_setup(mod, info->debug, info->num_debug);
+   dynamic_debug_setup(mod, info->debug, info->sites, info->num_debug);
 
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
ftrace_module_init(mod);
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index fdc2d0e15731..5529b17461ae 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -49,6 +49,7 @@ struct ddebug_table {
const char *mod_name;
unsigned int num_ddebugs;
struct _ddebug *ddebugs;
+   struct _ddebug_site *sites;
 };
 
 struct ddebug_query {
@@ -1014,8 +1015,8 @@ static const struct proc_ops proc_fops = {
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
  */
-int ddebug_add_module(struct _ddebug *tab, unsigned int n,
-const char *name)
+int ddebug_add_module(struct _ddebug *tab, struct _ddebug_site *sites,
+ unsigned int numdbgs, const char *modname)
 {
struct ddebug_table *dt;
 
@@ -1030,15 +1031,16 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int 
n,
 * member of struct module, which lives at least as long as
  

[RFC PATCH v3 09/18] dyndbg: optimize ddebug_emit_prefix

2021-03-15 Thread Jim Cromie
Add early return if no callsite info is specified in site-flags.
This avoids fetching site info that isn't going to be printed.

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 9 +
 lib/dynamic_debug.c   | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index bc8027292c02..aa4a3f5d8d35 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -40,6 +40,15 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_INCL_FUNCNAME   (1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
 #define _DPRINTK_FLAGS_INCL_TID(1<<4)
+
+#define _DPRINTK_FLAGS_INCL_ANYSITE\
+   (_DPRINTK_FLAGS_INCL_MODNAME\
+| _DPRINTK_FLAGS_INCL_FUNCNAME \
+| _DPRINTK_FLAGS_INCL_LINENO)
+#define _DPRINTK_FLAGS_INCL_ANY\
+   (_DPRINTK_FLAGS_INCL_ANYSITE\
+| _DPRINTK_FLAGS_INCL_TID)
+
 #if defined DEBUG
 #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
 #else
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 1f0cac4a66af..af9cf97f869b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -632,6 +632,9 @@ static char *dynamic_emit_prefix(const struct _ddebug *dp, 
char *buf)
}
pos_after_tid = pos;
 
+   if (!(dp->flags & _DPRINTK_FLAGS_INCL_ANYSITE))
+   return buf;
+
if (desc) {
if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
pos += snprintf(buf + pos, remaining(pos), "%s:",
-- 
2.29.2



[RFC PATCH v3 14/18] dyndbg: add ddebug_site(_get|_put) abstraction

2021-03-15 Thread Jim Cromie
Replace direct ->site refs with _get(),_put() internal API.  Right
now, _get() just returns ->site and _put() does nothing.  Later we can
replace that implementation with one using ->module_index to fetch
then forget site data dynamically.

Several approaches are possible:

A: !site -> fill from backing store

1st try at this is/was using zram.  At init, it copied each callsite
into a zs-allocation, and all site-> refs afterward went thru
_get/_put to zs-map on demand, and zs-unmap the site info.  This
worked until I tried to keep callsites mapped while they're enabled,
when it gave lockdep warns/panics.  IIRC theres a zram patchset doing
something with locking; I need to retry this approach, even if other
options are better, this might be a validating use case.

B: block store

Another approach is to compress the new linker section, using some
algorithm thats good at indexed decompression.  I probed this
approach, using objcopy, unsuccessfully:

   objcopy --dump-section __dyndbg=dd \
   --dump-section __dyndbg_sites=ddsites $IMG

>From vmlinux.o dumps were mostly empty (pre-link/reloc data?)
and vmlinux didnt have the section.

C: callsite composed from __dyndbg[N] & __dyndbg_site[N]

We know _ddebug records are in a vector, either in the builtin
__dyndbg linker section, or the same from a modprobed one.  The
builtin section has all builtin module sub-sections catenated
dogether.

At init, we iterate over the section, and "parse it" by creating a
ddebug_table for each module with prdebugs.  ddebug_table.num_debugs
remembers the size of each modules' vector of prdebugs.

We need a few things:

- _ddebug.index field, which knows offset to start of this sub-vector.
  this new field will be "free" because the struct has padding.
  it can be initialized during init, then RO.

- a back-pointer at the beginning of the sub-vector, to the
  ddebug_table "owning" (but not containing) this sub-vector of
  prdebugs.

If we had both, we could get from the ddebug element to its vector
root, back up to the owning ddebug_table, then down to the _callsite
vector, and index to the right element.  While slower than a pointer
deref, this is a cold path, and it allows elimination of the
per-callsite pointer member, thus greater density of the sections, and
still can support sparse site info.

That back-pointer feels tricky.  It needs to be 1st in the sub-vector

D: (C1?) add a header record to each sub-vector

If we can insert a header record into each modules' __dyndbg* section
sub-vectors, we can simplify the cold path above; a single sites*
pointer in the header can give us access to __dyndbg_sites[N]

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 31 +--
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 5529b17461ae..34329e323ed5 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -144,6 +144,14 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 query->first_lineno, query->last_lineno);
 }
 
+static struct _ddebug_site *ddebug_site_get(struct _ddebug *dp)
+{
+   return dp->site; /* passthru abstraction */
+}
+static inline void ddebug_site_put(struct _ddebug *dp)
+{
+}
+
 static int ddebug_match_site(const struct ddebug_query *query,
 const struct _ddebug *dp,
 const struct _ddebug_site *dc)
@@ -239,16 +247,18 @@ static int ddebug_change(const struct ddebug_query *query,
 
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = >ddebugs[i];
-   struct _ddebug_site *dc = dp->site;
+   struct _ddebug_site *dc;
+
+   dc = ddebug_site_get(dp);
 
if (!ddebug_match_site(query, dp, dc))
-   continue;
+   goto skipsite;
 
nfound++;
 
newflags = (dp->flags & modifiers->mask) | 
modifiers->flags;
if (newflags == dp->flags)
-   continue;
+   goto skipsite;
 
ddebug_alter_site(dp, modifiers);
 
@@ -264,6 +274,9 @@ static int ddebug_change(const struct ddebug_query *query,
  dt->mod_name, dp->lineno,
  ddebug_describe_flags(dp->flags, 
),
  dp->format);
+
+   skipsite:
+   ddebug_site_put(dp);
}
}
mutex_unlock(_lock);
@@ -633,11 +646,11 @@ static int remaining(int wrote)
return 0;
 }
 
-static char *__dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
+static char *__dynamic_emit_prefix(s

[RFC PATCH v3 15/18] dyndbg: add _index to struct _ddebug

2021-03-15 Thread Jim Cromie
We currently use dp->site to map: &__dyndbg[N] -> &__dyndbg_sites[N].
We want to drop site, new _ddebug._index provides the N.

The mapping is done in ddebug_site_get():

For builtin modules, a _ddebug *ptr is between __start___dyndbg and
__stop___dyndbg, and we can use &__start___dyndbg_sites[N] directly.
For loadable modules, we still need work, so we print rubbish, and
just return site pointer (which is correct).

ddebug_add_module() handles _index initialization:
Its new task is to number each module consecutively, so it gets new
base arg to pass the next starting index.

To actually drop site, We need both the module's __dyndbg* section
addys, and we need their relative placement to have a base-to-base
offset.

PLAN - a table header connecting 2 tables.

- ddebug_table points to both __dyndbgs & __dyndbg_sites.
  but *ddebugs & *sites are independent.
  no path from ddebugs[n] -> ddebug_sites[n]

If we have a header record in-situ, which keeps the site pointer we
seek to eliminate from _ddebug, and its in element[0] of both vectors,
we can go:

  ddebugs[n] -> ddebugs[0] -> containerof -> site[n]

  union ddebug_table_header {
struct ddebug_table *owner;
struct _ddebug item;
  }
  and
  struct ddebug_table_vector {
 struct ddebug_table *owner;
 struct _ddebug vector[];
  }

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h |  2 ++
 lib/dynamic_debug.c   | 43 +--
 2 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 7d33475d226a..18689db0e2c0 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -29,6 +29,7 @@ struct _ddebug {
/* format is always needed, lineno shares word with flags */
const char *format;
const unsigned lineno:18;
+   unsigned _index:14;
/*
 * The flags field controls the behaviour at the callsite.
 * The bits here are changed dynamically when the user
@@ -56,6 +57,7 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_DEFAULT 0
 #endif
unsigned int flags:8;
+
 #ifdef CONFIG_JUMP_LABEL
union {
struct static_key_true dd_key_true;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 34329e323ed5..3b53035d63d6 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -123,6 +123,8 @@ do {
\
 #define vpr_info(fmt, ...) vnpr_info(1, fmt, ##__VA_ARGS__)
 #define v2pr_info(fmt, ...)vnpr_info(2, fmt, ##__VA_ARGS__)
 #define v3pr_info(fmt, ...)vnpr_info(3, fmt, ##__VA_ARGS__)
+#define v4pr_info(fmt, ...)vnpr_info(4, fmt, ##__VA_ARGS__)
+#define v5pr_info(fmt, ...)vnpr_info(5, fmt, ##__VA_ARGS__)
 
 static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 {
@@ -146,7 +148,17 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 
 static struct _ddebug_site *ddebug_site_get(struct _ddebug *dp)
 {
-   return dp->site; /* passthru abstraction */
+   v4pr_info("get %d: %s.%s.%d\n", dp->_index, dp->site->modname,
+ dp->site->function, dp->lineno);
+
+   if (dp >= __start___dyndbg && dp < __stop___dyndbg) {
+   v4pr_info(" is builtin: %d %ld\n", dp->_index, dp - 
__start___dyndbg);
+   return &__start___dyndbg_sites[ dp - __start___dyndbg ];
+   } else {
+   v3pr_info(" is loaded: %d %ld\n", dp->_index, dp - 
__start___dyndbg);
+   return dp->site;
+   }
+   return dp->site;
 }
 static inline void ddebug_site_put(struct _ddebug *dp)
 {
@@ -1034,14 +1046,16 @@ static const struct proc_ops proc_fops = {
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
  */
-int ddebug_add_module(struct _ddebug *tab, struct _ddebug_site *sites,
- unsigned int numdbgs, const char *modname)
+static int __ddebug_add_module(struct _ddebug *tab, struct _ddebug_site *sites,
+  unsigned numdbgs, unsigned base,
+  const char *modname)
 {
struct ddebug_table *dt;
+   int i;
 
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
if (dt == NULL) {
-   pr_err("error adding module: %s\n", name);
+   pr_err("error adding module: %s\n", modname);
return -ENOMEM;
}
/*
@@ -1055,6 +1069,13 @@ int ddebug_add_module(struct _ddebug *tab, struct 
_ddebug_site *sites,
dt->ddebugs = tab;
dt->sites = sites;
 
+   v3pr_info("add-module: %s\n", modname);
+   for (i = 0; i < numdbgs; i++) {
+   tab[i]._index = base++;
+   v3pr_info(" %d %d %s.%s.%d\n&q

[RFC PATCH v3 08/18] dyndbg: accept null site in ddebug_proc_show

2021-03-15 Thread Jim Cromie
Accept a ddebug record with a null site pointer, and write abbreviated
output for that record that doesn't include site info (but does
include line-number, since that can be used in >control queries).
Also add a 2nd header line with a template for the new output.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 25 +
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 0c535f3c2ba9..1f0cac4a66af 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -918,18 +918,27 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 
if (p == SEQ_START_TOKEN) {
seq_puts(m,
-"# filename:lineno [module]function flags format\n");
+"#: filename:lineno [module]function flags format\n"
+"#| [module]:lineno flags format\n"
+   );
return 0;
}
 
dc = dp->site;
-
-   seq_printf(m, "%s:%u [%s]%s =%s \"",
-  trim_prefix(dc->filename), dp->lineno,
-  iter->table->mod_name, dc->function,
-  ddebug_describe_flags(dp->flags, ));
-   seq_escape(m, dp->format, "\t\r\n\"");
-   seq_puts(m, "\"\n");
+   if (dc) {
+   seq_printf(m, "%s:%u [%s]%s =%s \"",
+  trim_prefix(dc->filename), dp->lineno,
+  iter->table->mod_name, dc->function,
+  ddebug_describe_flags(dp->flags, ));
+   seq_escape(m, dp->format, "\t\r\n\"");
+   seq_puts(m, "\"\n");
+   } else {
+   seq_printf(m, "[%s]:%u =%s \"",
+  iter->table->mod_name, dp->lineno,
+  ddebug_describe_flags(dp->flags, ));
+   seq_escape(m, dp->format, "\t\r\n\"");
+   seq_puts(m, "\"\n");
+   }
 
return 0;
 }
-- 
2.29.2



[RFC PATCH v3 12/18] dyndbg: allow deleting site info via control interface

2021-03-15 Thread Jim Cromie
Allow users & subsystems to selectively delete callsite info for
pr-debug callsites.  Hopefully, this can lead to actual recovery of
memory.

DRM is a potential user which would drop the sites:

- has distinct categories for logging, and can map them over to a
  format prefix, like: "drm:core:", "drm:kms:", etc.

- are happy with group control of all the callsites in a class/cateory.
  individual control is still possible using queries including line numbers

- don't need dynamic "module:function:line:" prefixes in log messages

- don't care about loss of context in /proc/dynamic_debug/control

before:

init/initramfs.c:485 [initramfs]unpack_to_rootfs =_ "Detected %s compressed 
data\012"
init/main.c:1337 [main]run_init_process =pm "%s\012"
init/main.c:1335 [main]run_init_process =pm "  with environment:\012"
init/main.c:1334 [main]run_init_process =pm "%s\012"
init/main.c:1332 [main]run_init_process =pm "  with arguments:\012"
init/main.c:1121 [main]initcall_blacklisted =pm "initcall %s blacklisted\012"
init/main.c:1082 [main]initcall_blacklist =pm "blacklisting initcall %s\012"

then:
  bash-5.0# echo file init/main.c +D > /proc/dynamic_debug/control

after:

init/initramfs.c:485 [initramfs]unpack_to_rootfs =_ "Detected %s compressed 
data\012"
[main]:1337 =pmD "%s\012"
[main]:1335 =pmD "  with environment:\012"
[main]:1334 =pmD "%s\012"
[main]:1332 =pmD "  with arguments:\012"
[main]:1121 =pmD "initcall %s blacklisted\012"
[main]:1082 =pmD "blacklisting initcall %s\012"

Notes:

If Drm adopted dyndbg, i915 + drm* would add ~1600 prdebugs, amdgpu +
drm* would add ~3200 callsites, so the additional memory costs are
substantial.  In trade, drm and drivers would avoid lots of calls to
drm_debug_enabled().  This patch should reduce the costs.

Using this interface, drm could drop site info for all categories /
prefixes controlled by bits in drm.debug, while preserving site info
and individual selectivity for any uncategorized prdebugs, and for all
other modules.

Lastly, because lineno field was not moved into _ddebug_callsite, it
can be used to modify a single[*] callsite even if drm has dropped all
the callsite data:

  echo module $mod format ^$prefix line $line +p >control

Dropping site info is a one-way, information losing operation, so
minor misuse is possible.  Worst case is maybe (depending upon
previous settings) some loss of logging context/decorations.

  echo +D > /proc/dynamic_debug/control

[*] amdgpu has some macros invoking clusters of pr_debugs; each use of
them creates a cluster of pr-debugs with the same line number.

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 1 +
 lib/dynamic_debug.c   | 9 +
 2 files changed, 10 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index aa4a3f5d8d35..d811273c8484 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -40,6 +40,7 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_INCL_FUNCNAME   (1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
 #define _DPRINTK_FLAGS_INCL_TID(1<<4)
+#define _DPRINTK_FLAGS_DELETE_SITE (1<<7) /* drop site info to save ram */
 
 #define _DPRINTK_FLAGS_INCL_ANYSITE\
(_DPRINTK_FLAGS_INCL_MODNAME\
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 6fbd9099c2fa..fdc2d0e15731 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -92,6 +92,7 @@ static struct { unsigned flag:8; char opt_char; } opt_array[] 
= {
{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
{ _DPRINTK_FLAGS_INCL_TID, 't' },
{ _DPRINTK_FLAGS_NONE, '_' },
+   { _DPRINTK_FLAGS_DELETE_SITE, 'D' },
 };
 
 struct flagsbuf { char buf[ARRAY_SIZE(opt_array)+1]; };
@@ -201,6 +202,14 @@ static void ddebug_alter_site(struct _ddebug *dp,
} else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
static_branch_enable(>key.dd_key_true);
 #endif
+   /* delete site info for this callsite */
+   if (modifiers->flags & _DPRINTK_FLAGS_DELETE_SITE) {
+   if (dp->site) {
+   vpr_info("dropping site info %s.%s.%d\n", 
dp->site->filename,
+   dp->site->function, dp->lineno);
+   dp->site = NULL;
+   }
+   }
 }
 
 /*
-- 
2.29.2



[RFC PATCH v3 11/18] dyndbg: refactor ddebug_alter_site out of ddebug_change

2021-03-15 Thread Jim Cromie
Move the JUMP_LABEL/static-key code to a separate function.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 22 +++---
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 2d011ac3308d..6fbd9099c2fa 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -191,6 +191,18 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
return true;
 }
 
+static void ddebug_alter_site(struct _ddebug *dp,
+ struct flag_settings *modifiers)
+{
+#ifdef CONFIG_JUMP_LABEL
+   if (dp->flags & _DPRINTK_FLAGS_PRINT) {
+   if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
+   static_branch_disable(>key.dd_key_true);
+   } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
+   static_branch_enable(>key.dd_key_true);
+#endif
+}
+
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -227,13 +239,9 @@ static int ddebug_change(const struct ddebug_query *query,
newflags = (dp->flags & modifiers->mask) | 
modifiers->flags;
if (newflags == dp->flags)
continue;
-#ifdef CONFIG_JUMP_LABEL
-   if (dp->flags & _DPRINTK_FLAGS_PRINT) {
-   if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
-   
static_branch_disable(>key.dd_key_true);
-   } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
-   static_branch_enable(>key.dd_key_true);
-#endif
+
+   ddebug_alter_site(dp, modifiers);
+
dp->flags = newflags;
 
if (dc)
-- 
2.29.2



[RFC PATCH v3 10/18] dyndbg: avoid calling dyndbg_emit_prefix when it has no work

2021-03-15 Thread Jim Cromie
Wrap function in a static-inline one, which checks flags to avoid
calling the function unnecessarily.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index af9cf97f869b..2d011ac3308d 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -615,7 +615,7 @@ static int remaining(int wrote)
return 0;
 }
 
-static char *dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
+static char *__dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
 {
int pos_after_tid;
int pos = 0;
@@ -655,6 +655,13 @@ static char *dynamic_emit_prefix(const struct _ddebug *dp, 
char *buf)
return buf;
 }
 
+static inline char *dynamic_emit_prefix(struct _ddebug *dp, char *buf)
+{
+   if (unlikely(dp->flags & _DPRINTK_FLAGS_INCL_ANY))
+   return __dynamic_emit_prefix(dp, buf);
+   return buf;
+}
+
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
 {
va_list args;
-- 
2.29.2



[RFC PATCH v3 03/18] dyndbg: refactor part of ddebug_change to ddebug_match_site

2021-03-15 Thread Jim Cromie
Move all the site-match logic into a separate function, reindent the
code, and replace the continues with return falses.

No functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 75 ++---
 1 file changed, 43 insertions(+), 32 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c3c35dcc6a59..9cff9db15937 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -142,6 +142,48 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 query->first_lineno, query->last_lineno);
 }
 
+static int ddebug_match_site(const struct ddebug_query *query,
+const struct _ddebug *dp)
+{
+   struct _ddebug_site *dc = dp->site;
+
+   /* match against the source filename */
+   if (query->filename &&
+   !match_wildcard(query->filename, dc->filename) &&
+   !match_wildcard(query->filename,
+   kbasename(dc->filename)) &&
+   !match_wildcard(query->filename,
+   trim_prefix(dc->filename)))
+   return false;
+
+   /* match against the function */
+   if (query->function &&
+   !match_wildcard(query->function, dc->function))
+   return false;
+
+   /* match against the format */
+   if (query->format) {
+   if (*query->format == '^') {
+   char *p;
+   /* anchored search. match must be at beginning */
+   p = strstr(dp->format, query->format+1);
+   if (p != dp->format)
+   return false;
+   } else if (!strstr(dp->format, query->format))
+   return false;
+   }
+
+   /* match against the line number range */
+   if (query->first_lineno &&
+   dp->lineno < query->first_lineno)
+   return false;
+   if (query->last_lineno &&
+   dp->lineno > query->last_lineno)
+   return false;
+
+   return true;
+}
+
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -170,38 +212,7 @@ static int ddebug_change(const struct ddebug_query *query,
struct _ddebug *dp = >ddebugs[i];
struct _ddebug_site *dc = dp->site;
 
-   /* match against the source filename */
-   if (query->filename &&
-   !match_wildcard(query->filename, dc->filename) &&
-   !match_wildcard(query->filename,
-  kbasename(dc->filename)) &&
-   !match_wildcard(query->filename,
-  trim_prefix(dc->filename)))
-   continue;
-
-   /* match against the function */
-   if (query->function &&
-   !match_wildcard(query->function, dc->function))
-   continue;
-
-   /* match against the format */
-   if (query->format) {
-   if (*query->format == '^') {
-   char *p;
-   /* anchored search. match must be at 
beginning */
-   p = strstr(dp->format, query->format+1);
-   if (p != dp->format)
-   continue;
-   } else if (!strstr(dp->format, query->format))
-   continue;
-   }
-
-   /* match against the line number range */
-   if (query->first_lineno &&
-   dp->lineno < query->first_lineno)
-   continue;
-   if (query->last_lineno &&
-   dp->lineno > query->last_lineno)
+   if (!ddebug_match_site(query, dp))
continue;
 
nfound++;
-- 
2.29.2



[RFC PATCH v3 07/18] dyndbg: accept null site in dynamic_emit_prefix

2021-03-15 Thread Jim Cromie
2 prints use site->member, protect them with if site.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 16 ++--
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 151e55ab6bb5..0c535f3c2ba9 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -631,15 +631,19 @@ static char *dynamic_emit_prefix(const struct _ddebug 
*dp, char *buf)
task_pid_vnr(current));
}
pos_after_tid = pos;
-   if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
-   pos += snprintf(buf + pos, remaining(pos), "%s:",
-   desc->modname);
-   if (dp->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
-   pos += snprintf(buf + pos, remaining(pos), "%s:",
-   desc->function);
+
+   if (desc) {
+   if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
+   pos += snprintf(buf + pos, remaining(pos), "%s:",
+   desc->modname);
+   if (dp->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
+   pos += snprintf(buf + pos, remaining(pos), "%s:",
+   desc->function);
+   }
if (dp->flags & _DPRINTK_FLAGS_INCL_LINENO)
pos += snprintf(buf + pos, remaining(pos), "%d:",
dp->lineno);
+
if (pos - pos_after_tid)
pos += snprintf(buf + pos, remaining(pos), " ");
if (pos >= PREFIX_SIZE)
-- 
2.29.2



[RFC PATCH v3 05/18] dyndbg: hoist ->site out of ddebug_match_site

2021-03-15 Thread Jim Cromie
A coming change adds _get/_put abstraction on the site pointer, to
allow managing site info more flexibly.  The get/put pattern is best
done at a single lexical scope, where its more obviously correct, so
hoist the ->site ref out of ddebug_match_site, and pass it in instead.

no functional changes

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index da732e0c56e3..abe3382aabd5 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -143,10 +143,9 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 }
 
 static int ddebug_match_site(const struct ddebug_query *query,
-const struct _ddebug *dp)
+const struct _ddebug *dp,
+const struct _ddebug_site *dc)
 {
-   struct _ddebug_site *dc;
-
/* match against the format */
if (query->format) {
if (*query->format == '^') {
@@ -167,7 +166,6 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
dp->lineno > query->last_lineno)
return false;
 
-   dc = dp->site;
if (!dc) {
/* site info has been dropped, so query cannot test these 
fields */
if (query->filename || query->function)
@@ -219,9 +217,9 @@ static int ddebug_change(const struct ddebug_query *query,
 
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = >ddebugs[i];
-   struct _ddebug_site *dc;
+   struct _ddebug_site *dc = dp->site;
 
-   if (!ddebug_match_site(query, dp))
+   if (!ddebug_match_site(query, dp, dc))
continue;
 
nfound++;
-- 
2.29.2



[RFC PATCH v3 04/18] dyndbg: accept null site in ddebug_match_site

2021-03-15 Thread Jim Cromie
basically, reorder the elements to minimize data fetches.

1- move format and line-number check code to the top of the function,
   since they don't use/check site info.

2- test site pointer:
   If its null, we return early, skipping 3:
  If the query tests against missing site info, fail the match.
  otherwize site matches.

3- rest of function (checking site vs query) is unchanged.

ddebug_match_site ignores module, because it's tested already
by the caller, where it is known from debug_tables.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 41 +
 1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 9cff9db15937..da732e0c56e3 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -145,21 +145,7 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 static int ddebug_match_site(const struct ddebug_query *query,
 const struct _ddebug *dp)
 {
-   struct _ddebug_site *dc = dp->site;
-
-   /* match against the source filename */
-   if (query->filename &&
-   !match_wildcard(query->filename, dc->filename) &&
-   !match_wildcard(query->filename,
-   kbasename(dc->filename)) &&
-   !match_wildcard(query->filename,
-   trim_prefix(dc->filename)))
-   return false;
-
-   /* match against the function */
-   if (query->function &&
-   !match_wildcard(query->function, dc->function))
-   return false;
+   struct _ddebug_site *dc;
 
/* match against the format */
if (query->format) {
@@ -181,6 +167,29 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
dp->lineno > query->last_lineno)
return false;
 
+   dc = dp->site;
+   if (!dc) {
+   /* site info has been dropped, so query cannot test these 
fields */
+   if (query->filename || query->function)
+   return false;
+   else
+   return true;
+   }
+
+   /* match against the source filename */
+   if (query->filename &&
+   !match_wildcard(query->filename, dc->filename) &&
+   !match_wildcard(query->filename,
+   kbasename(dc->filename)) &&
+   !match_wildcard(query->filename,
+   trim_prefix(dc->filename)))
+   return false;
+
+   /* match against the function */
+   if (query->function &&
+   !match_wildcard(query->function, dc->function))
+   return false;
+
return true;
 }
 
@@ -210,7 +219,7 @@ static int ddebug_change(const struct ddebug_query *query,
 
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = >ddebugs[i];
-   struct _ddebug_site *dc = dp->site;
+   struct _ddebug_site *dc;
 
if (!ddebug_match_site(query, dp))
continue;
-- 
2.29.2



[RFC PATCH v3 06/18] dyndbg: accept null site in ddebug_change

2021-03-15 Thread Jim Cromie
fix a debug-print that includes site info, by adding an alternate
debug message that does not.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index abe3382aabd5..151e55ab6bb5 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -235,10 +235,17 @@ static int ddebug_change(const struct ddebug_query *query,
static_branch_enable(>key.dd_key_true);
 #endif
dp->flags = newflags;
-   v2pr_info("changed %s:%d [%s]%s =%s\n",
-trim_prefix(dc->filename), dp->lineno,
-dt->mod_name, dc->function,
-ddebug_describe_flags(dp->flags, ));
+
+   if (dc)
+   v2pr_info("changed %s:%d [%s]%s =%s\n",
+ trim_prefix(dc->filename), dp->lineno,
+ dt->mod_name, dc->function,
+ ddebug_describe_flags(dp->flags, 
));
+   else
+   v2pr_info("changed %s:%d =%s \"%s\"\n",
+ dt->mod_name, dp->lineno,
+ ddebug_describe_flags(dp->flags, 
),
+ dp->format);
}
}
mutex_unlock(_lock);
-- 
2.29.2



[RFC PATCH v3 02/18] dyndbg: __init iterate over __dyndbg & __dyndbg_site in parallel

2021-03-15 Thread Jim Cromie
In dynamic_debug_init(), rework for-loop; add 2nd 'site' var, and
iterate over both __dyndbg* sections in parallel.  Replace uses of
iter->site with the new 'site' iter, add a BUG_ON to enforce the
invariant given by HEAD~1's DECLARE_DYNAMIC_DEBUG_METADATA base->site
initialization.

0- declare the new elf section start/stop, named in vmlinux.lds.h
   I disregarded a checkpatch warning about externs in c-files, stuck
   with current practice.

1- clean up use of 4 iterators for clarity:
   (iter, site), and ((iter, site)_mod_start) block markers.

2- iterate over __dyndbg_sites in parallel with __dyndbg
   s/iter->site/site/g;

3- add BUG_ON(iter->site != site)
   DECLARE_DYNAMIC_DEBUG_METADATA + linker insure this now.
   Maybe we can drop pointer, still get order.

4- var rename n to site_ct

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 36 +++-
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 738c4ce28046..c3c35dcc6a59 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -41,6 +41,8 @@
 
 extern struct _ddebug __start___dyndbg[];
 extern struct _ddebug __stop___dyndbg[];
+extern struct _ddebug_site __start___dyndbg_sites[];
+extern struct _ddebug_site __stop___dyndbg_sites[];
 
 struct ddebug_table {
struct list_head link;
@@ -118,6 +120,7 @@ do {
\
 
 #define vpr_info(fmt, ...) vnpr_info(1, fmt, ##__VA_ARGS__)
 #define v2pr_info(fmt, ...)vnpr_info(2, fmt, ##__VA_ARGS__)
+#define v3pr_info(fmt, ...)vnpr_info(3, fmt, ##__VA_ARGS__)
 
 static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 {
@@ -1082,11 +1085,12 @@ static int __init dynamic_debug_init_control(void)
 
 static int __init dynamic_debug_init(void)
 {
-   struct _ddebug *iter, *iter_start;
+   struct _ddebug *iter, *iter_mod_start;
+   struct _ddebug_site *site, *site_mod_start;
const char *modname = NULL;
char *cmdline;
int ret = 0;
-   int n = 0, entries = 0, modct = 0;
+   int site_ct = 0, entries = 0, modct = 0;
 
if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
@@ -1097,23 +1101,29 @@ static int __init dynamic_debug_init(void)
ddebug_init_success = 1;
return 0;
}
-   iter = __start___dyndbg;
-   modname = iter->site->modname;
-   iter_start = iter;
-   for (; iter < __stop___dyndbg; iter++) {
+
+   iter = iter_mod_start = __start___dyndbg;
+   site = site_mod_start = __start___dyndbg_sites;
+   modname = site->modname;
+
+   for (; iter < __stop___dyndbg; iter++, site++) {
+
+   BUG_ON(site != iter->site);
entries++;
-   if (strcmp(modname, iter->site->modname)) {
+
+   if (strcmp(modname, site->modname)) {
modct++;
-   ret = ddebug_add_module(iter_start, n, modname);
+   ret = ddebug_add_module(iter_mod_start, site_ct, 
modname);
if (ret)
goto out_err;
-   n = 0;
-   modname = iter->site->modname;
-   iter_start = iter;
+   site_ct = 0;
+   modname = site->modname;
+   iter_mod_start = iter;
+   site_mod_start = site;
}
-   n++;
+   site_ct++;
}
-   ret = ddebug_add_module(iter_start, n, modname);
+   ret = ddebug_add_module(iter_mod_start, site_ct, modname);
if (ret)
goto out_err;
 
-- 
2.29.2



[RFC PATCH v3 01/18] dyndbg: split struct _ddebug, move display fields to new _ddebug_site

2021-03-15 Thread Jim Cromie
struct _ddebug has 2 flavors of fields: essential and optional.  Split
the 3 optional fields: module, function, file into a new struct
_ddebug_site, and add pointer to it from _ddebug.

These fields are optional in that they are primarily used to generate
the optional "module:func:line" log prefix.  They're also used to
select callsites to >control.  lineno is arguably optional too, but
leaving it uses spare bytes in struct _ddebug.

The new ptr increases memory footprint by 1 ptr per pr_debug, but I
think its temporary, and the indirection gives several advantages:

- we can drop sites and their storage opportunistically.
  this reduces per-site mem by 24/64.

  Subsystems may not need/want "module:func:line:" in their logs.
  If they already use format-prefixes such as "drm:kms:",
  they can select on those, and don't need the site info for that.
  forex:
  #> echo module drm format "^drm:kms: " +p >control
  ie: dynamic_debug_exec_queries("format '^drm:kms: '", "drm");

- the moved display fields are inherently hierarchical, and the linker
  section is ordered; so (module, file, function) have repeating
  values (90%, 85%, 45%).  This is readily compressible, even with a
  simple field-wise run length encoding.  Since I'm splitting the struct,
  I also reordered the fields to match the hierarchy.

- the separate linker section sets up naturally for block compression.

IFF we can on-demand map:  ddebugs[N] -> ddebug_sites[N]

- we can compress __dyndbg_sites during __init, and mark section __initdata

- can decompress on-demand, say for `cat control`
- can save chunks of decompressed buffer for enabled callsites
- free chunks on site disable, or on memory pressure.

Whats actually done here is rather mechanical, and preparatory.

dynamic_debug.h:

I cut struct _ddebug in half, renamed optional top-half to
_ddebug_site, kept __align(8) for both halves.  I added a forward decl
for a unified comment for both head & body, and added head.site to
point at body.

DECLARE_DYNAMIC_DEBUG_METADATA does the core of the work; it declares
and initializes both static struct variables together, and refs one to
the other.

dynamic_debug.c:

dynamic_debug_init() mem-usage now also counts sites.

dynamic_emit_prefix() & ddebug_change() use those moved fields; they
get a new initialized auto-var, and the field refs get adjusted as
needed to follow the move from one struct to the other.

   struct _ddebug_site *dc = dp->site;

ddebug_proc_show() differs slightly; it assigns to (not initializes)
the autovar, to avoid a panic when p == SEQ_START_TOKEN.

vmlinux.lds.h:

add __dyndbg_sites section, with the same align(8) and KEEP as
used in the __dyndbg section.

Signed-off-by: Jim Cromie 
---
 include/asm-generic/vmlinux.lds.h |  3 ++
 include/linux/dynamic_debug.h | 37 -
 lib/dynamic_debug.c   | 46 +--
 3 files changed, 53 insertions(+), 33 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 0331d5d49551..4f2af9de2f03 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -353,6 +353,9 @@
*(__tracepoints)\
/* implement dynamic printk debug */\
. = ALIGN(8);   \
+   __start___dyndbg_sites = .; \
+   KEEP(*(__dyndbg_sites)) \
+   __stop___dyndbg_sites = .;  \
__start___dyndbg = .;   \
KEEP(*(__dyndbg))   \
__stop___dyndbg = .;\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index a57ee75342cf..bc8027292c02 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -7,20 +7,28 @@
 #endif
 
 /*
- * An instance of this structure is created in a special
- * ELF section at every dynamic debug callsite.  At runtime,
- * the special section is treated as an array of these.
+ * A pair of these structs are created in 2 special ELF sections
+ * (__dyndbg, __dyndbg_sites) for every dynamic debug callsite.
+ * At runtime, the sections are treated as arrays.
  */
-struct _ddebug {
+struct _ddebug;
+struct _ddebug_site {
/*
-* These fields are used to drive the user interface
-* for selecting and displaying debug callsites.
+* These fields (and lineno) are used to:
+* - decorate log messages per site flags
+* - select callsites for modification via >control
+* - display callsites & settings in `cat control`
 */
const char *modname;
-   const char *function;

[RFC PATCH v3 00/18] dynamic debug diet plan

2021-03-15 Thread Jim Cromie
CONFIG_DYNAMIC_DEBUG creates a struct _ddebug (56 bytes) for each
callsite, which includes 3 pointers to: module, filename, function.
These are repetetive, and compressible, this patch series goes about
doing that, it:

- splits struct _ddebug and __dyndbg[] section/array into 2
  creating struct _ddebug_site and __dyndbg_sites[]
  temporary _ddebug.site connects them.
  
- makes _ddebug_site data optional
- minor optimizations
- makes _ddebug_site data deleteable
  not necessary, proof of optionality

The RFC stuff comes at the end:

- attach __dyndbg_sites[] to module-info, like __dyndbg[]
- add index to struct _ddebug, use it for builtins
- add ddebug_site(_get|_put) abstraction to hide _ddebug.site

At this point, actually compressing __dyndbg_sites[] and using that is
doable: ddebug_site_get() has the info (compressed-table-ref, N) to do
the decompress / lookup, and could stick it (the retrieved records)
into a hash if the site is enabled for printing with the prefix.

Whats my (ideal?) decompressing interface ?
And whats the name of the api call ? I couldnt suss it out yet.

For any control read, a simple block decompress and cache is close to
ideal; all site data is then available to iterate over, and each
ddebug_site_get() just indexes into it.  A stream of decompressed site
records would also work well, with less lumpy memory allocs and frees,
or maybe none at all.

Actually dropping _ddebug.site is not yet possible.  While we could
drop it for builtin modules, thats cuz we know __start___dyndbg_sites.
For loaded modules, I need the elf section: __dyndbg_sites.  This is
in load-info, but I dont have a path to it.  In:

- add _ddebug_header/table

I managed to add a single header entry (a struct _ddebug with special
initialization) to the array, and it links to the front of the array,
where its useful.  But creating this header entry only works for
vmlinux itself (because of vmlinux.ld.h patch), not for loadable
modules.  Some breakout & reuse of the macro I added to vmxlinux.ld.h
might be the ticket.  Please signal agreement, and suggest how.

Presuming the fixed header can be linked reliably in front doing
something like I tried, it can be recast as a ddebug_header and
unionized with struct _ddebug, and the _ddebugs[] will fit nicely as a
flex-array:

struct ddebug_table2 {
   struct ddebug_header foo;
   struct _ddebug ddebugs[];
}

A header would have 40 bytes, room to contain most/all of struct
ddebug_table's fields, a pointer to the __dyndbg_sites[] table, and a
list-head too, meaning it supports essential and nice-to-have
properties:

- the mapping: __dyndbg[N] --> __dyndbg_sites[N] # we NEED this
- we can enlist them directly in ddebug_tables.  # freebie
  ie avoid the kzalloc in ddebug_add_module()  

And if not all fields fit in the space available in __dyndbg[0], there
is space available in __dyndbg_sites[0].

Additionally, at the end of __init, ddebug_tables list is composed of
memory entirely in __dyndbg[], which can then be make readonly (by
means I dont know).  If this breaks insertions of loadable modules, we
can easily a 2nd list for that.



Jim Cromie (18):
  dyndbg: split struct _ddebug, move display fields to new _ddebug_site
  dyndbg: __init iterate over __dyndbg & __dyndbg_site in parallelg
  dyndbg: refactor part of ddebug_change to ddebug_match_site
  dyndbg: accept null site in ddebug_match_site
  dyndbg: hoist ->site out of ddebug_match_site
  dyndbg: accept null site in ddebug_change
  dyndbg: accept null site in dynamic_emit_prefix
  dyndbg: accept null site in ddebug_proc_show
  dyndbg: optimize ddebug_emit_prefix
  dyndbg: avoid calling dyndbg_emit_prefix when it has no work
  dyndbg: refactor ddebug_alter_site out of ddebug_change
  dyndbg: allow deleting site info via control interface
  dyndbg+module: expose ddebug_sites to modules
  dyndbg: add ddebug_site(_get|_put) abstraction
  dyndbg: add _index to struct _ddebug
  dyndbg: prevent build bugs via -DNO_DYNAMIC_DEBUG_TABLE
  dyndbg: RFC - DECLARE/DEFINE_DYNAMIC_DEBUG_TABLE
  dyndbg: shuffle ddebug_table fields




 arch/x86/boot/compressed/Makefile |   1 +
 arch/x86/entry/vdso/Makefile  |   3 +
 arch/x86/purgatory/Makefile   |   1 +
 drivers/firmware/efi/libstub/Makefile |   3 +-
 drivers/gpu/drm/i915/i915_drv.c   |   2 +
 include/asm-generic/vmlinux.lds.h |  24 +-
 include/linux/dynamic_debug.h | 180 +--
 kernel/module-internal.h  |   1 +
 kernel/module.c   |   9 +-
 lib/dynamic_debug.c   | 313 +++---
 scripts/Makefile.lib  |   2 +
 11 files changed, 428 insertions(+), 111 deletions(-)

-- 
2.29.2



[PATCH 19/20] dyndbg: try conditional linker expression in KEEP - RFC

2021-01-26 Thread Jim Cromie
This is the last patch in v3 of patchest Ive sent previously:
v2: https://lore.kernel.org/lkml/?q=Cromie+v2+00%2F19+2020-12-25+-Re

It isolates my only issue now, Id appreciate advice, and dont want to
distract you with the 18 previous commits.

Im trying to use ? : inside a KEEP(*(expression)) to only include
A_header when A has content.

IE:
  KEEP(*( A ? A_header : ))

It fails with inscrutable linker error.
  GEN modules.builtin
  LD  .tmp_vmlinux.kallsyms1
ld:./arch/x86/kernel/vmlinux.lds:46: syntax error

Is this possible by other modes of expression ?

I tried inserting {} 1st, that failed, appearing to foreclose any
foreach-like construct.  I also tried () around each term, and a
preceding, embedded "_loc=.;" statement to test the parser.

I didnt try doing this with 2 separate KEEPs; while it would be
simple, it defeats the adjacency guaranteed by *(.text .rdata), which
is the point of this.

If this were to be possible, it opens up interesting options to
statically construct table headers, and possibly even tree structures
in the linker script.  Id use it to add 1 header for each module, and
strip a column out of the table.

Ive pulled binutils to take a look at the source; having never done
anything bison-ish, I anticipate a long study without some focused
primer knowledge.

Signed-off-by: Jim Cromie 
---
 include/asm-generic/vmlinux.lds.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 87868c5a980a..6198cc850f9b 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -329,10 +329,10 @@
 #define DYNAMIC_DEBUG_DATA()   \
. = ALIGN(8);   \
__start___dyndbg_sites = .; \
-   KEEP(*(__dyndbg_sites .gnu.linkonce.*.dyndbg_site)) 
\
+   KEEP(*(__dyndbg_sites ? .gnu.linkonce.*.dyndbg_site : ))\
__stop___dyndbg_sites = .;  \
__start___dyndbg = .;   \
-   KEEP(*(__dyndbg .gnu.linkonce.*.dyndbg))
\
+   KEEP(*(__dyndbg ? .gnu.linkonce.*.dyndbg : ))   \
__stop___dyndbg = .;
 #else
 #define DYNAMIC_DEBUG_DATA()
-- 
2.29.2



Re: [RFC PATCH v2 00/19] dynamic debug diet plan

2021-01-06 Thread jim . cromie
On Tue, Dec 29, 2020 at 11:56 AM Joe Perches  wrote:
>
> On Fri, 2020-12-25 at 13:19 -0700, Jim Cromie wrote:
> > Well, we're mostly overeating, but we can all look forward to a diet
> > in January.  And more exersize.
> >
> > dyndbg's compiled-in data-table currently uses 56 bytes per prdebug;
> > this includes 3 pointers to hierarchical "decorator" data, which is
> > primarily for adding "module:function:line:" prefixes to prdebug
> > messages, and for enabling and modifying those prdebugs selectively.
> >
> > This patchset decouples "decorator" data, and makes it optional, and
> > disposable.  By separating that data, it opens up possiblities to
> > compress it, swap it out, map it selectively, etc.
>
> While this may be somewhat useful, what debugging does it really help?
> Are there really memory limited platforms that enable dynamic debug?
>
>

hi Joe, happy new year!

Who wants to drop 5 lbs of weight for free ?
You dont even have to put down the turkey leg.

Seriously, I cant point to any particular use case that suddenly becomes
possible. and there are no powerful new debugging features here either.
but
dynamic_debug: add an option to enable dynamic debug for modules only

Recently reduced dyndbg's system footprint, surely to open up new use
cases, users.  This is an orthogonal (and more involved) approach to
dropping more weight, and improving the coefficients in a
user's cost-benefit equation.


I tried out DRM as a user
https://lore.kernel.org/lkml/20201204035318.332419-1-jim.cro...@gmail.com/

it works, but I got the impression Ville is inclined to use static-keys
directly to replace drm_debug_enabled(), avoiding dyndbg overheads.

The possible in-memory savings here are asymptotically 24/64 (56 maybe)
of the footprint, which is easy if subsystems dont need the
decorators/selectors,
DRM has that option.

Possible savings in dyndbg aside, a static-key takes 16 bytes.
I think I can get struct _ddebug down to 32 bytes (RFC on 18,19 particularly)
so Im still playing catch-up wrt what a minimal static-keys drm update could do.
Theres also a vector of jump-labels form of static-keys
that Ville may be able to exploit too.

IOW, drm is not my ace card.  but memory savings is still nice.

Where Id like to RFC:

(patch-19) DEFINE_DYNAMIC_DEBUG_TABLE(i915)  worked.
it adds a pair of header records into the 2 elf sections, It will let me drop
the site pointer currently needed to get each site's decorations, when needed.

But I had to code it in manually, as a test. Its not a general solution.

I'd like to figure out how to have it defined in module scope automatically,
and weakly, and maybe-unused, so that if the module does not have any
pr_debugs, the header record is silently excluded, and that module's
sections are left empty.

When the header is linked in, as with my hacked i915.ko,
It becomes possible to finally lose the  _ddebug.site pointer.
.module_index and container-of can replace it:
it gets us from struct _ddebug *p back up to the header,
then we could follow a header.sites_vector[.module_index]
to the right decorators/selectors.
Its a modest cost increase for a rarely used path,
to shave 8/40 off our minimum footprint

Then the total footprint reduces back to 56 bytes/callsite,
but now with 24 optional, and manageable..
module_index would be a fine lookup to a compressed RO table of callsites,
and a good-enough key to a hashtable of active/enabled pr-debug callsites.

I played with zs-pool to store callsite data. Though it had problems,
I did see 3/1 pages/zs-page, which is a decent (slightly pessimistic)
proxy for what could be had with another (block) compression choice.

Once compressed callsites works, we can drop and recycle the
__dyndbg_callsites section.


other pertinences:

the 2 section relative ordering may be a consequence of :
- natural ordering of compilation & lexical placement of the paired declarations
- OR the site pointer, and its initialization between the 2 records.
I suspect former.

if 2nd, dropping site may lose the constraint between 2 sections.
I havent tried yet to test the drop to see what happens,
I cannot use the current BUG_ON (site_iter != iter->site) construct.

I tried invoking TABLE from METADATA,
hoping that __weak and __maybe_unused would allow redundant definitions
it errored, something about "local" and "section" mumble.
I now believe that initialization in TABLE is part of the problem,



I tried :
$ objcopy --dump-section __dyndbg_callsites=dd_callsites
--dump-section __dyndbg=dd vmlinux.o

I got mostly null data, as if some final linking wasnt yet done.

[jimc@frodo local-i915m]$ od -c dd_callsites
000  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
*
0205620

trying it on vmlinux doesnt work;
objcopy: vmlinux: can't dump section '__dyndbg' - it does not exist:
file format not recog

[RFC PATCH v2 01/19] dyndbg: fix use before null check

2020-12-25 Thread Jim Cromie
In commit a2d375eda771 ("dyndbg: refine export, rename to
dynamic_debug_exec_queries()"), a string is copied before checking it
isn't NULL.  Fix this, report a usage/interface error, and return the
proper error code.

Fixes: a2d375eda771 ("dyndbg: refine export, rename to 
dynamic_debug_exec_queries()")
Cc: sta...@vger.kernel.org
--
-v2 drop comment tweak, improve commit message

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index bd7b3aaa93c3..c70d6347afa2 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -561,9 +561,14 @@ static int ddebug_exec_queries(char *query, const char 
*modname)
 int dynamic_debug_exec_queries(const char *query, const char *modname)
 {
int rc;
-   char *qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+   char *qry; /* writable copy of query */
 
-   if (!query)
+   if (!query) {
+   pr_err("non-null query/command string expected\n");
+   return -EINVAL;
+   }
+   qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+   if (!qry)
return -ENOMEM;
 
rc = ddebug_exec_queries(qry, modname);
-- 
2.29.2



[RFC PATCH v2 17/19] dyndbg: rearrange struct ddebug_callsites

2020-12-25 Thread Jim Cromie
move static-key field to top of struct.  It is the biggest field, and
most alignment constrained (I believe), so this improves ambient
pahole conditions.

It doesn't actually improve the packing, it only simplifies and
shrinks the pahole reporting.

probably drop during rebase, cleanup.

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 0fcbe96736f3..e7b5e7664e51 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -25,7 +25,14 @@ struct _ddebug_callsite {
 };
 
 struct _ddebug {
+#ifdef CONFIG_JUMP_LABEL
+   union {
+   struct static_key_true dd_key_true;
+   struct static_key_false dd_key_false;
+   } key;
+#endif
struct _ddebug_callsite *site;
+
/* format is always needed, lineno shares word with flags */
const char *format;
const unsigned lineno:18;
@@ -56,12 +63,6 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_DEFAULT 0
 #endif
unsigned int flags:8;
-#ifdef CONFIG_JUMP_LABEL
-   union {
-   struct static_key_true dd_key_true;
-   struct static_key_false dd_key_false;
-   } key;
-#endif
 } __aligned(8);
 
 
-- 
2.29.2



[RFC PATCH v2 18/19] dyndbg: add module_index to struct _ddebug

2020-12-25 Thread Jim Cromie
We seek to drop the pointer added when we split struct _ddebug.  This
would restore our footprint to parity worst case, with all the upsides
of callsite overhead management.

we will rely upon existing structure (and modify it):

__dyndbg[], __dyndbg_callsites[] are parallel arrays, packed in order
by the linker [*].  Together the pairs compose each prdebug's state.
Each _ddebug[].site points at the corresponding _ddebug_callsite[],
visually like a ladder.

At init we (already) iterate over __dyndbg[] & __dyndbg_callsites[],
and parse them into sub-vectors reffered/owned by ddebug_table's that
we create and collect in a list.  We also prove via BUG_ON(site_iter
!= iter->site) that the ladder is straight.

IFF we can recreate site_iter, we can drop the .site pointer.  But
site_iter is really just &__dyndbg_callsites[module_index], so we add
module_index here and now.

This doesn't finish the job.

With module_index, we can find the vector root.  Now we need a
backlink up to the sponsor/owner ddebug_table record.
This has a few steps:

1 claim space in the linkage, for a module header.
  DECLARE_DYNAMIC_DEBUG_TABLE
  a special variety of DECLARE_DYNAMIC_DEBUG_METADATA,
  sounds like it fits.
  ideally its transparent, registers with module somehow.
  linker needs to put this 1st in module's sub-vector

2 define that header - maybe something like:

  union ddebug_table_header {
struct ddebug_table *owner;
struct _ddebug item;
  }
  OR
  struct ddebug_table_vector {
 struct ddebug_table *owner;
 struct _ddebug vector[];
  }

So with module_index, we can go from our _ddebug element in our
sub-vector to the root, and container_of() to get the backlink up to
the ddebug_table, then down to the sites[N]

The backlink is sort-of a poor-mans list, so why not just use one ?
- we only have 2 vectors in the list
- they never change size
- we only go up one leg, and down other
- list rotation would just confuse.

Given the amount of space in a struct _ddebug (40 bytes), we might be
able to pack part or all of ddebug_table into it, share it in a union,
and avoid kmalloc'g them at all.

if DECLARE_DYNAMIC_DEBUG_TABLE can be forced into the linkage at
the front of each modules sub-section, we can probably initialize
module_index statically, and not have to do it during _init().

add DEFINE_DYNAMIC_DEBUG_TABLE(module) as a special case of:
DEFINE_DYNAMIC_DEBUG_METADATA(module, "00-1st-in-subsection")

It's just a "callsite" we expect not to use, except as a 0th element
we can compute an offset from, to initialize each ddebug.module_index.

The next step is to get one into a module by brute force, see if it
compiles, and places this header record where we need it.
If that doesnt work, we need to fix it.

Later, this macro will be adapted to initialize a pair of alternate
structures; analogous to structs _ddebug & _ddebug_callsite, equal or
smaller in size, and implemented as structs unionized with them.  This
pair of alt-structs is big enough to contain all of ddebug_table's
fields.  For reference, the respective sizes:

A: struct _ddebug_callsite {
/* size: 24, cachelines: 1, members: 3 */
/* last cacheline: 24 bytes */

B: struct _ddebug {
/* XXX 6 bits hole, try to pack */
/* size: 40, cachelines: 1, members: 6 */
/* sum members: 36 */
/* sum bitfield members: 26 bits, bit holes: 1, sum bit holes: 6 bits */
/* last cacheline: 40 bytes */

C: struct ddebug_table {
struct list_head   link; /* 016 */
const char  *  mod_name; /*16 8 */
unsigned int   num_ddebugs;  /*24 4 */

/* XXX 4 bytes hole, try to pack */

struct _ddebug *   ddebugs;  /*32 8 */
struct _ddebug_callsite *  sites;/*40 8 */

/* size: 48, cachelines: 1, members: 5 */
/* sum members: 44, holes: 1, sum holes: 4 */
/* last cacheline: 48 bytes */

Clearly theres enough room in A + B to hold the contents of C.  We
will keep the pointer in A" -> B", it will get us to all the contents
there, most importantly the sites vector.

It will be interesting to see just how much can be done by linker and
static initialization.  Id be tickled if the linked list init could be
done statically, but it hardly matters; __ro_after_init (however its
spelled) would probably suffice for a solid security guarantee.

I presume its ok to have a list which is partly of items in RO memory,
but is extended at runtime, in our case when modules are (un)loaded.
If not, we can keep 2 lists, for builtin and dynamic-loaded modules
respectively.

[1] DECLARE_DYNAMIC_DEBUG_METADATA may be why 2 linker sections are
in-order; it links head->body as it "allocates" them.  If we drop the
pointer, we lose the constraint on the relative or

[RFC PATCH v2 16/19] dyndbg: ddebug_site_get/put api commentary

2020-12-25 Thread Jim Cromie
Paths forward: (not mutually exclusive)

A: !site -> fill from backing store

1st try at this is/was using zram.  At init, it copied each callsite
into a zs-allocation, and all site-> refs afterward went thru
_get/_put to zs-map on demand, and zs-unmap the site info.  This
worked until I tried to keep callsites mapped while they're enabled.

Another approach is to compress the new linker section, using some
algo thats good at indexed decompression.  I tried to test this a bit,
using objcopy, unsuccessfully:

   objcopy --dump-section __dyndbg_callsites=dd_callsites vmlinux.o

>From vmlinux.o it was mostly empty, vmlinux didnt have the section.

B: callsite as a set of property vectors, indexed by 'N'

We know dp is in a vector, either in the builtin __dyndbg_callsite
linker section, or the same from a modprobed one.  The builtin section
has all builtin module sub-sections catenated dogether.

At init, we iterate over the section, and "parse it" by creating a
ddebug_table for each module with prdebugs.  ddebug_table.num_debugs
remembers the size of each modules' vector of prdebugs.

We need a few things:

- _ddebug.index field, which knows offset to start of this sub-vector.
  this new field will be "free" because the struct has padding.
  it can be initialized during init, then RO.

- a back-pointer at the beginning of the sub-vector, to the
  ddebug_table "owning" (but not containing) this sub-vector of
  prdebugs.

If we had both, we could get from the ddebug element to its vector
root, back up to the owning ddebug_table, then down to the _callsite
vector, and index to the right element.  While slower than a pointer
deref, this is a cold path, and it allows elimination of the
per-callsite pointer member, thus greater density of the sections, and
still can support sparse site info.

That back-pointer feels tricky.  It needs to be 1st in the sub-vector

is to reserve the 0th slot

ing its spot at the
front of

each module's ddebug sub-vector.

getting space in the
section for it.  Initializing it is easy.

prdebugs are added to section when DECLARE_DYAMIC_DEBUG_METADATA is
compiled; its unclear whether they are intrinsically sorted during
compile, or whether thats a linker thing.

Ideally, a MODULE-mumble declaration can be coaxed into declaring a
module singleton in the section(s), either naturally at the top (or
bottom) or sorted into place.

If that doesn't work, a "preload if module is different" strategy
could maybe work, but I dont know how to do that in macros.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 25f49515c235..ec28c113a361 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -146,7 +146,7 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 
 static struct _ddebug_callsite *ddebug_site_get(struct _ddebug *dp)
 {
-   return dp->site;
+   return dp->site; /* passthru abstraction */
 }
 static inline void ddebug_site_put(struct _ddebug *dp)
 {
-- 
2.29.2



[RFC PATCH v2 12/19] dyndbg: allow deleting site info via control interface

2020-12-25 Thread Jim Cromie
Allow users & subsystems to selectively delete callsite info for
individual pr-debug callsites, or groups of them.

Its purpose is for subsystems such as DRM which:

- use distinct categories for logging, and can map them over to a
  format prefix, like: "drm:core:", "drm:kms:", etc.

- are happy with group control of all the callsites in a class/cateory.
  individual control is still possible using queries including line numbers

- don't need dynamic "module:function:line:" prefixes in log messages

- don't care about loss of context in /proc/dynamic_debug/control

before:

init/initramfs.c:485 [initramfs]unpack_to_rootfs =_ "Detected %s compressed 
data\012"
init/main.c:1337 [main]run_init_process =pm "%s\012"
init/main.c:1335 [main]run_init_process =pm "  with environment:\012"
init/main.c:1334 [main]run_init_process =pm "%s\012"
init/main.c:1332 [main]run_init_process =pm "  with arguments:\012"
init/main.c:1121 [main]initcall_blacklisted =pm "initcall %s blacklisted\012"
init/main.c:1082 [main]initcall_blacklist =pm "blacklisting initcall %s\012"

then:
  bash-5.0# echo file init/main.c +D > /proc/dynamic_debug/control

after:

init/initramfs.c:485 [initramfs]unpack_to_rootfs =_ "Detected %s compressed 
data\012"
[main]:1337 =pmD "%s\012"
[main]:1335 =pmD "  with environment:\012"
[main]:1334 =pmD "%s\012"
[main]:1332 =pmD "  with arguments:\012"
[main]:1121 =pmD "initcall %s blacklisted\012"
[main]:1082 =pmD "blacklisting initcall %s\012"

Notes:

If Drm adopted dyndbg, i915 + drm* would add ~1600 prdebugs, amdgpu +
drm* would add ~3200 callsites, so the additional memory costs are
substantial.  In trade, drm and drivers would avoid lots of calls to
drm_debug_enabled().  This patch should reduce the costs.

Using this interface, drm could drop site info for all categories /
prefixes controlled by bits in drm.debug, while preserving site info
and individual selectivity for any uncategorized prdebugs.

Lastly, because lineno field was not moved into _ddebug_callsite, it
can be used to modify a single[*] callsite even if drm has dropped all
the callsite data:

  echo module $mod format ^$prefix line $line +p >control

Dropping a _callsite a one-way, information losing operation, so minor
misuse is possible.  Worst case is maybe (depending upon previous
settings) some loss of logging context/decorations.

  echo +D > /proc/dynamic_debug/control

[*] amdgpu has some macros invoking clusters of pr_debugs; each use of
them creates a cluster of pr-debugs with the same line number.

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 1 +
 lib/dynamic_debug.c   | 9 +
 2 files changed, 10 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index ea07a91a43bc..49fa1390d1f8 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -40,6 +40,7 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_INCL_FUNCNAME   (1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
 #define _DPRINTK_FLAGS_INCL_TID(1<<4)
+#define _DPRINTK_FLAGS_DELETE_SITE (1<<7) /* drop site info to save ram */
 
 #define _DPRINTK_FLAGS_INCL_ANYSITE\
(_DPRINTK_FLAGS_INCL_MODNAME\
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 6203a6ad1706..2d10fc1e16cd 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -90,6 +90,7 @@ static struct { unsigned flag:8; char opt_char; } opt_array[] 
= {
{ _DPRINTK_FLAGS_INCL_LINENO, 'l' },
{ _DPRINTK_FLAGS_INCL_TID, 't' },
{ _DPRINTK_FLAGS_NONE, '_' },
+   { _DPRINTK_FLAGS_DELETE_SITE, 'D' },
 };
 
 struct flagsbuf { char buf[ARRAY_SIZE(opt_array)+1]; };
@@ -198,6 +199,14 @@ static inline void ddebug_alter_site(struct _ddebug *dp,
} else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
static_branch_enable(>key.dd_key_true);
 #endif
+   /* delete site info for this callsite */
+   if (modifiers->flags & _DPRINTK_FLAGS_DELETE_SITE) {
+   if (dp->site) {
+   vpr_info("dropping site info %s.%s.%d\n", 
dp->site->filename,
+   dp->site->function, dp->lineno);
+   dp->site = NULL;
+   }
+   }
 }
 
 /*
-- 
2.29.2



[RFC PATCH v2 15/19] dyndbg: add ddebug_site_get/put api with pass-thru impl

2020-12-25 Thread Jim Cromie
Now that site info is optional, abstract it so we can manage it more
flexibly later.  Change all site users to use ddebug_site_get(p)
instead, which just returns ->site.  ddebug_site_put is called to
balance gets, it currently does nothing.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 27 ++-
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 8ad9be28f38e..25f49515c235 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -144,6 +144,14 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 query->first_lineno, query->last_lineno);
 }
 
+static struct _ddebug_callsite *ddebug_site_get(struct _ddebug *dp)
+{
+   return dp->site;
+}
+static inline void ddebug_site_put(struct _ddebug *dp)
+{
+}
+
 static int ddebug_match_site(const struct ddebug_query *query,
 const struct _ddebug *dp,
 const struct _ddebug_callsite *dc)
@@ -242,13 +250,13 @@ static int ddebug_change(const struct ddebug_query *query,
struct _ddebug_callsite *dc = dp->site;
 
if (!ddebug_match_site(query, dp, dc))
-   continue;
+   goto skipsite;
 
nfound++;
 
newflags = (dp->flags & modifiers->mask) | 
modifiers->flags;
if (newflags == dp->flags)
-   continue;
+   goto skipsite;
 
ddebug_alter_site(dp, modifiers);
 
@@ -264,6 +272,9 @@ static int ddebug_change(const struct ddebug_query *query,
  dt->mod_name, dp->lineno,
  ddebug_describe_flags(dp->flags, 
),
  dp->format);
+
+   skipsite:
+   ddebug_site_put(dp);
}
}
mutex_unlock(_lock);
@@ -633,11 +644,11 @@ static int remaining(int wrote)
return 0;
 }
 
-static char *__dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
+static char *__dynamic_emit_prefix(struct _ddebug *dp, char *buf)
 {
int pos_after_tid;
int pos = 0;
-   const struct _ddebug_callsite *desc = dp->site;
+   const struct _ddebug_callsite *desc;
 
*buf = '\0';
 
@@ -653,6 +664,7 @@ static char *__dynamic_emit_prefix(const struct _ddebug 
*dp, char *buf)
if (!(dp->flags & _DPRINTK_FLAGS_INCL_ANYSITE))
return buf;
 
+   desc = ddebug_site_get(dp);
if (desc) {
if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
pos += snprintf(buf + pos, remaining(pos), "%s:",
@@ -670,6 +682,8 @@ static char *__dynamic_emit_prefix(const struct _ddebug 
*dp, char *buf)
if (pos >= PREFIX_SIZE)
buf[PREFIX_SIZE - 1] = '\0';
 
+   ddebug_site_put(dp);
+
return buf;
 }
 
@@ -952,7 +966,8 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
return 0;
}
 
-   dc = dp->site;
+   dc = ddebug_site_get(dp);
+
if (dc) {
seq_printf(m, "%s:%u [%s]%s =%s \"",
   trim_prefix(dc->filename), dp->lineno,
@@ -968,6 +983,8 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
seq_puts(m, "\"\n");
}
 
+   ddebug_site_put(dp);
+
return 0;
 }
 
-- 
2.29.2



[RFC PATCH v2 11/19] dyndbg: refactor ddebug_alter_site out of ddebug_change

2020-12-25 Thread Jim Cromie
Move the JUMP_LABEL/static-key code to a separate inline function.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 22 +++---
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index daded73c8575..6203a6ad1706 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -188,6 +188,18 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
return true;
 }
 
+static inline void ddebug_alter_site(struct _ddebug *dp,
+struct flag_settings *modifiers)
+{
+#ifdef CONFIG_JUMP_LABEL
+   if (dp->flags & _DPRINTK_FLAGS_PRINT) {
+   if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
+   static_branch_disable(>key.dd_key_true);
+   } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
+   static_branch_enable(>key.dd_key_true);
+#endif
+}
+
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -224,13 +236,9 @@ static int ddebug_change(const struct ddebug_query *query,
newflags = (dp->flags & modifiers->mask) | 
modifiers->flags;
if (newflags == dp->flags)
continue;
-#ifdef CONFIG_JUMP_LABEL
-   if (dp->flags & _DPRINTK_FLAGS_PRINT) {
-   if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
-   
static_branch_disable(>key.dd_key_true);
-   } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
-   static_branch_enable(>key.dd_key_true);
-#endif
+
+   ddebug_alter_site(dp, modifiers);
+
dp->flags = newflags;
 
if (dc)
-- 
2.29.2



[RFC PATCH v2 09/19] dyndbg: optimize ddebug_emit_prefix

2020-12-25 Thread Jim Cromie
Add early return if no callsite info is specified in site-flags.
This avoids fetching site info that isn't going to be printed.
RFC: is this a proper place to use likely()?

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 9 +
 lib/dynamic_debug.c   | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index e155dfafc4d9..ea07a91a43bc 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -40,6 +40,15 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_INCL_FUNCNAME   (1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO (1<<3)
 #define _DPRINTK_FLAGS_INCL_TID(1<<4)
+
+#define _DPRINTK_FLAGS_INCL_ANYSITE\
+   (_DPRINTK_FLAGS_INCL_MODNAME\
+| _DPRINTK_FLAGS_INCL_FUNCNAME \
+| _DPRINTK_FLAGS_INCL_LINENO)
+#define _DPRINTK_FLAGS_INCL_ANY\
+   (_DPRINTK_FLAGS_INCL_ANYSITE\
+| _DPRINTK_FLAGS_INCL_TID)
+
 #if defined DEBUG
 #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
 #else
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index f6d8137e4a46..8e81ce58c1bd 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -629,6 +629,9 @@ static char *dynamic_emit_prefix(const struct _ddebug *dp, 
char *buf)
}
pos_after_tid = pos;
 
+   if (!(dp->flags & _DPRINTK_FLAGS_INCL_ANYSITE))
+   return buf;
+
if (desc) {
if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
pos += snprintf(buf + pos, remaining(pos), "%s:",
-- 
2.29.2



[RFC PATCH v2 19/19] dyndbg: try DEFINE_DYNAMIC_DEBUG_TABLE

2020-12-25 Thread Jim Cromie
Test DEFINE_DYNAMIC_DEBUG_TABLE, in i915.ko, by adding an invocation
into i915_drv.c, the 1st object built in the Makefile.  This does
manually what can perhaps be done transparently in headers (hopefully).

DEFINE_DYNAMIC_DEBUG_TABLE is based on DEFINE_DYNAMIC_DEBUG_METADATA;
just like its model, it creates a pair of structs: _ddebug &
_ddebug_callsite, and inits them with format="", lineno=0.

This:
- identifies it clearly in control output
- appears to place it 1st in the section(s)
  it works here, at least for modprobed module
  1st-to-build might be the real reason for the sort.

drivers/gpu/drm/i915/i915_drv.c:0 [i915](null) =_ ""
drivers/gpu/drm/i915/gvt/gvt.c:437 [i915]intel_gvt_register_hypervisor =_ "gvt: 
core: Running with hypervisor %s
drivers/gpu/drm/i915/gvt/gvt.c:378 [i915]intel_gvt_init_device =_ "gvt: core: 
gvt device initialization is done\0

other big diff between DEFINE_DYNAMIC_DEBUG_TABLE/_METADATA:
- not static decls.
  removing static made the line appear in control output (below).
  (cuz it might be reffd elsewhere, so its linked).
  we want this.

  it also needs to be visible where DEFINE_DYNAMIC_DEBUG_METADATA is
  used, so it can be used to initialize .module_index, ie in many other
  objects where pr_debugs are coded.

A peek inside i915_drv.o looks about right; i915_site is expected at least.

Relocation section '.rela__dyndbg' at offset 0x6f48 contains 2 entries:
  Offset  Info   Type   Sym. ValueSym. Name + Addend
0010  014c0001 R_X86_64_64    i915_site + 0
0018  001a0001 R_X86_64_64    .rodata.str1.1 + 
548

Relocation section '.rela__dyndbg_callsites' at offset 0x6f90 contains 2 
entries:
  Offset  Info   Type   Sym. ValueSym. Name + Addend
  001a0001 R_X86_64_64    .rodata.str1.1 + 
d8
0008  000a0001 R_X86_64_64    .rodata.str1.8 + 
110

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/i915/i915_drv.c |  3 +++
 include/linux/dynamic_debug.h   | 47 ++---
 2 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index acc32066cec3..f2fae2a476db 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -88,6 +88,9 @@
 
 static struct drm_driver driver;
 
+DEFINE_DYNAMIC_DEBUG_TABLE(i915);
+// DEFINE_DYNAMIC_DEBUG_TABLE(THIS_MODULE);  // one alternative form
+
 static int i915_get_bridge_dev(struct drm_i915_private *dev_priv)
 {
int domain = pci_domain_nr(dev_priv->drm.pdev->bus);
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 0f4e703c97ee..2f3c0f35cea0 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -102,6 +102,36 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
 const struct ib_device *ibdev,
 const char *fmt, ...);
 
+/** DEFINE_DYNAMIC_DEBUG_TABLE(module)
+ *
+ * This is an analogue to DEFINE_DYNAMIC_DEBUG_METADATA()
+
+ * It's just a "callsite" whose primary purpose is to create or
+ * reserve the 0th element pair in our sub-vectors of __dyndbg[] &
+ * __dyndbg_callsites[].  The format & lineno are set to sort 1st,
+ * though I suspect our good order is more about linkage.  Either way,
+ * the TABLE is appearing 1st in control's i915 output.
+
+ * We want to use it to initialize .module_index, but I was unable to
+ * ref ##_base by any construct I thought to try;
+ * KBUILD_MODNAME in particular didnt work.
+
+ */
+
+#define DEFINE_DYNAMIC_DEBUG_TABLE(module) \
+   struct _ddebug_callsite  __aligned(8)   \
+   __section("__dyndbg_callsites") module##_site = {   \
+   .modname = KBUILD_MODNAME,  \
+   .filename = __FILE__,   \
+   .function = NULL,   \
+   };  \
+   struct _ddebug  __aligned(8)\
+   __section("__dyndbg") module##_base = { \
+   .site = ##_site, \
+   .format = "",   \
+   .lineno = 0, /* sort on mod, line */\
+   }
+
 #define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)   \
static struct _ddebug_callsite  __aligned(8)\
__section("__dyndbg_callsites") name##_site = { \
@@ -115,23 +145,10 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
.format = (fmt),\
.lineno = __LINE__, \
 

[RFC PATCH v2 13/19] dyndbg: verify __dyndbg & __dyndbg_callsite invariant

2020-12-25 Thread Jim Cromie
Prove that linker + DECLARE_DYNAMIC_DEBUG_METADATA reliably place the
2 related struct _ddebug* initializations into parallel/ordered slots
in the __dyndbg_* sections.

This is a step towards dropping the pointer between the 2 structs;
maybe the 2 vectors stay ordered, and we can deduce and use N.  Of
course this test won't survive, since it needs the pointer we seek to
drop, but its a start.

0- iterate over __dyndbg_callsite in parallel with __dyndbg
   rename var: s/iter_start/iter_mod_start/ for clarity, consistency.

I disregarded a checkpatch warning about externs in c-files, staying
consistent with long-standing code seemed better.

1- prove that iter->site == site_iter.
   DECLARE_DYNAMIC_DEBUG_METADATA + linker insure this now
   Maybe we can drop pointer, still get order.

WRT the debug-printing, its noisy, but only with verbose=3.
It warrants trimming later.

The offset grows smoothly, because it is N * sizeof(structs), which
differ.  It looks reliable.  Amend later to do math, converge on
truth.  If numbers are stable after stripping pointer, we have N.

   recptr  mod-ptr N (void*)p
[1.929072] dyndbg: 2828: 82b32f28 82b32f10 1 24 40
[1.929326] dyndbg: 2829: 82b32f40 82b32f10 2 48 80
[1.930209] dyndbg:   2 debug prints in module i386

We have N (col 4), and N * structsize (col 5).  I feel like it still
needs more staring at.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 28 +---
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 2d10fc1e16cd..c1a113460637 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -41,6 +41,8 @@
 
 extern struct _ddebug __start___dyndbg[];
 extern struct _ddebug __stop___dyndbg[];
+extern struct _ddebug_callsite __start___dyndbg_callsites[];
+extern struct _ddebug_callsite __stop___dyndbg_callsites[];
 
 struct ddebug_table {
struct list_head link;
@@ -119,6 +121,7 @@ do {
\
 
 #define vpr_info(fmt, ...) vnpr_info(1, fmt, ##__VA_ARGS__)
 #define v2pr_info(fmt, ...)vnpr_info(2, fmt, ##__VA_ARGS__)
+#define v3pr_info(fmt, ...)vnpr_info(2, fmt, ##__VA_ARGS__)
 
 static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
 {
@@ -1147,7 +1150,8 @@ static int __init dynamic_debug_init_control(void)
 
 static int __init dynamic_debug_init(void)
 {
-   struct _ddebug *iter, *iter_start;
+   struct _ddebug *iter, *iter_mod_start;
+   struct _ddebug_callsite *site, *site_mod_start;
const char *modname = NULL;
char *cmdline;
int ret = 0;
@@ -1162,23 +1166,33 @@ static int __init dynamic_debug_init(void)
ddebug_init_success = 1;
return 0;
}
-   iter = __start___dyndbg;
+
+   iter = iter_mod_start = __start___dyndbg;
+   site = site_mod_start = __start___dyndbg_callsites;
modname = iter->site->modname;
-   iter_start = iter;
-   for (; iter < __stop___dyndbg; iter++) {
+
+   for (; iter < __stop___dyndbg; iter++, site++) {
+
+   BUG_ON(site != iter->site);
+   v3pr_info("%u: %px %ld %ld %ld\n", entries, site,
+ site - site_mod_start,
+ ((void *)site - (void *)site_mod_start),
+ ((void *)iter - (void *)iter_mod_start));
entries++;
+
if (strcmp(modname, iter->site->modname)) {
modct++;
-   ret = ddebug_add_module(iter_start, n, modname);
+   ret = ddebug_add_module(iter_mod_start, n, modname);
if (ret)
goto out_err;
n = 0;
modname = iter->site->modname;
-   iter_start = iter;
+   iter_mod_start = iter;
+   site_mod_start = site;
}
n++;
}
-   ret = ddebug_add_module(iter_start, n, modname);
+   ret = ddebug_add_module(iter_mod_start, n, modname);
if (ret)
goto out_err;
 
-- 
2.29.2



[RFC PATCH v2 10/19] dyndbg: avoid calling dyndbg_emit_prefix when it has no work

2020-12-25 Thread Jim Cromie
Wrap function in a static-inline one, which checks flags to avoid
calling the function unnecessarily.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 8e81ce58c1bd..daded73c8575 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -612,7 +612,7 @@ static int remaining(int wrote)
return 0;
 }
 
-static char *dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
+static char *__dynamic_emit_prefix(const struct _ddebug *dp, char *buf)
 {
int pos_after_tid;
int pos = 0;
@@ -652,6 +652,13 @@ static char *dynamic_emit_prefix(const struct _ddebug *dp, 
char *buf)
return buf;
 }
 
+static inline char *dynamic_emit_prefix(struct _ddebug *dp, char *buf)
+{
+   if (unlikely(dp->flags & _DPRINTK_FLAGS_INCL_ANY))
+   return __dynamic_emit_prefix(dp, buf);
+   return buf;
+}
+
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
 {
va_list args;
-- 
2.29.2



[RFC PATCH v2 07/19] dyndbg: accept null site in dynamic_emit_prefix

2020-12-25 Thread Jim Cromie
2 prints use site->member, protect them with if site.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 16 ++--
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 5422cef58130..190a796da03a 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -628,15 +628,19 @@ static char *dynamic_emit_prefix(const struct _ddebug 
*dp, char *buf)
task_pid_vnr(current));
}
pos_after_tid = pos;
-   if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
-   pos += snprintf(buf + pos, remaining(pos), "%s:",
-   desc->modname);
-   if (dp->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
-   pos += snprintf(buf + pos, remaining(pos), "%s:",
-   desc->function);
+
+   if (desc) {
+   if (dp->flags & _DPRINTK_FLAGS_INCL_MODNAME)
+   pos += snprintf(buf + pos, remaining(pos), "%s:",
+   desc->modname);
+   if (dp->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
+   pos += snprintf(buf + pos, remaining(pos), "%s:",
+   desc->function);
+   }
if (dp->flags & _DPRINTK_FLAGS_INCL_LINENO)
pos += snprintf(buf + pos, remaining(pos), "%d:",
dp->lineno);
+
if (pos - pos_after_tid)
pos += snprintf(buf + pos, remaining(pos), " ");
if (pos >= PREFIX_SIZE)
-- 
2.29.2



[RFC PATCH v2 14/19] dyndbg+module: expose ddebug_callsites to modules

2020-12-25 Thread Jim Cromie
In order to drop the pointer connecting _ddebug records to _callsites,
we need to elevate the latter; we need to track it in (internal)
ddebug_tables, and set it in ddebug_add_module.  That last part
exposes it by interface to module.c, so we add a field to load_info,
and adjust load_module to initialize it from the elf section.

Its possible that this closes a hole created when __dyndbg_callsites
section was added, and wasnt handled by module load-info.  I never saw
any misbehavior loading i915.ko into a vm, but still..

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h |  4 ++--
 kernel/module-internal.h  |  1 +
 kernel/module.c   |  9 ++---
 lib/dynamic_debug.c   | 12 
 4 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 49fa1390d1f8..0fcbe96736f3 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -70,8 +70,8 @@ struct _ddebug {
 /* exported for module authors to exercise >control */
 int dynamic_debug_exec_queries(const char *query, const char *modname);
 
-int ddebug_add_module(struct _ddebug *tab, unsigned int n,
-   const char *modname);
+int ddebug_add_module(struct _ddebug *tab, struct _ddebug_callsite *sites,
+ unsigned int n, const char *modname);
 extern int ddebug_remove_module(const char *mod_name);
 extern __printf(2, 3)
 void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
diff --git a/kernel/module-internal.h b/kernel/module-internal.h
index 33783abc377b..920b085d2a1b 100644
--- a/kernel/module-internal.h
+++ b/kernel/module-internal.h
@@ -18,6 +18,7 @@ struct load_info {
char *secstrings, *strtab;
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
struct _ddebug *debug;
+   struct _ddebug_callsite *sites;
unsigned int num_debug;
bool sig_ok;
 #ifdef CONFIG_KALLSYMS
diff --git a/kernel/module.c b/kernel/module.c
index a4fa44a652a7..876765bc666a 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2820,11 +2820,12 @@ static void add_kallsyms(struct module *mod, const 
struct load_info *info)
 }
 #endif /* CONFIG_KALLSYMS */
 
-static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, 
unsigned int num)
+static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug,
+   struct _ddebug_callsite *sites, unsigned int 
num)
 {
if (!debug)
return;
-   ddebug_add_module(debug, num, mod->name);
+   ddebug_add_module(debug, sites, num, mod->name);
 }
 
 static void dynamic_debug_remove(struct module *mod, struct _ddebug *debug)
@@ -3299,6 +3300,8 @@ static int find_module_sections(struct module *mod, 
struct load_info *info)
 
info->debug = section_objs(info, "__dyndbg",
   sizeof(*info->debug), >num_debug);
+   info->sites = section_objs(info, "__dyndbg_callsites",
+  sizeof(*info->sites), >num_debug);
 
return 0;
 }
@@ -3937,7 +3940,7 @@ static int load_module(struct load_info *info, const char 
__user *uargs,
goto free_arch_cleanup;
}
 
-   dynamic_debug_setup(mod, info->debug, info->num_debug);
+   dynamic_debug_setup(mod, info->debug, info->sites, info->num_debug);
 
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
ftrace_module_init(mod);
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c1a113460637..8ad9be28f38e 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -49,6 +49,7 @@ struct ddebug_table {
const char *mod_name;
unsigned int num_ddebugs;
struct _ddebug *ddebugs;
+   struct _ddebug_callsite *sites;
 };
 
 struct ddebug_query {
@@ -1014,8 +1015,8 @@ static const struct proc_ops proc_fops = {
  * Allocate a new ddebug_table for the given module
  * and add it to the global list.
  */
-int ddebug_add_module(struct _ddebug *tab, unsigned int n,
-const char *name)
+int ddebug_add_module(struct _ddebug *tab, struct _ddebug_callsite *sites,
+ unsigned int n, const char *name)
 {
struct ddebug_table *dt;
 
@@ -1033,6 +1034,7 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
dt->mod_name = name;
dt->num_ddebugs = n;
dt->ddebugs = tab;
+   dt->sites = sites;
 
mutex_lock(_lock);
list_add(>link, _tables);
@@ -1182,7 +1184,9 @@ static int __init dynamic_debug_init(void)
 
if (strcmp(modname, iter->site->modname)) {
modct++;
-   ret = ddebug_add_module(iter_mod_start, n, modname);
+
+   ret = ddebug_add_module(iter_mod_start, site_mod_start,
+

[RFC PATCH v2 08/19] dyndbg: accept null site in ddebug_proc_show

2020-12-25 Thread Jim Cromie
Accept a ddebug record with a null site pointer, and write abbreviated
output for that record that doesn't include site info (but does
include line-number, since that can be used in >control queries).
Also add a 2nd header line with a template for the new output.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 25 +
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 190a796da03a..f6d8137e4a46 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -915,18 +915,27 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 
if (p == SEQ_START_TOKEN) {
seq_puts(m,
-"# filename:lineno [module]function flags format\n");
+"#: filename:lineno [module]function flags format\n"
+"#| [module]:lineno flags format\n"
+   );
return 0;
}
 
dc = dp->site;
-
-   seq_printf(m, "%s:%u [%s]%s =%s \"",
-  trim_prefix(dc->filename), dp->lineno,
-  iter->table->mod_name, dc->function,
-  ddebug_describe_flags(dp->flags, ));
-   seq_escape(m, dp->format, "\t\r\n\"");
-   seq_puts(m, "\"\n");
+   if (dc) {
+   seq_printf(m, "%s:%u [%s]%s =%s \"",
+  trim_prefix(dc->filename), dp->lineno,
+  iter->table->mod_name, dc->function,
+  ddebug_describe_flags(dp->flags, ));
+   seq_escape(m, dp->format, "\t\r\n\"");
+   seq_puts(m, "\"\n");
+   } else {
+   seq_printf(m, "[%s]:%u =%s \"",
+  iter->table->mod_name, dp->lineno,
+  ddebug_describe_flags(dp->flags, ));
+   seq_escape(m, dp->format, "\t\r\n\"");
+   seq_puts(m, "\"\n");
+   }
 
return 0;
 }
-- 
2.29.2



[RFC PATCH v2 04/19] dyndbg: accept null site in ddebug_match_site

2020-12-25 Thread Jim Cromie
make ddebug_match_site() tolerate null site.

1- move format and line-number check code to the top of the function,
   since they don't use/check site info.

2- test site pointer:
   If its null, we return early, skipping 3:
  If the query tests against missing site info, fail the match.
  otherwize site matches.

3- rest of function (checking site vs query) is unchanged.

ddebug_match_site is agnostic re' module, because it's tested already
by the caller, where it is known from debug_tables.  If a query
constrains module, forex: "module drm*", non-matching modules are
skipped entirely in caller, so we can ignore it here.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 41 +
 1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index d9a0527ec842..bb9279c8cbfd 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -142,21 +142,7 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 static int ddebug_match_site(const struct ddebug_query *query,
 const struct _ddebug *dp)
 {
-   struct _ddebug_callsite *dc = dp->site;
-
-   /* match against the source filename */
-   if (query->filename &&
-   !match_wildcard(query->filename, dc->filename) &&
-   !match_wildcard(query->filename,
-   kbasename(dc->filename)) &&
-   !match_wildcard(query->filename,
-   trim_prefix(dc->filename)))
-   return false;
-
-   /* match against the function */
-   if (query->function &&
-   !match_wildcard(query->function, dc->function))
-   return false;
+   struct _ddebug_callsite *dc;
 
/* match against the format */
if (query->format) {
@@ -178,6 +164,29 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
dp->lineno > query->last_lineno)
return false;
 
+   dc = dp->site;
+   if (!dc) {
+   /* site info has been dropped, so query cannot test these 
fields */
+   if (query->filename || query->function)
+   return false;
+   else
+   return true;
+   }
+
+   /* match against the source filename */
+   if (query->filename &&
+   !match_wildcard(query->filename, dc->filename) &&
+   !match_wildcard(query->filename,
+   kbasename(dc->filename)) &&
+   !match_wildcard(query->filename,
+   trim_prefix(dc->filename)))
+   return false;
+
+   /* match against the function */
+   if (query->function &&
+   !match_wildcard(query->function, dc->function))
+   return false;
+
return true;
 }
 
@@ -207,7 +216,7 @@ static int ddebug_change(const struct ddebug_query *query,
 
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = >ddebugs[i];
-   struct _ddebug_callsite *dc = dp->site;
+   struct _ddebug_callsite *dc;
 
if (!ddebug_match_site(query, dp))
continue;
-- 
2.29.2



[RFC PATCH v2 06/19] dyndbg: accept null site in ddebug_change

2020-12-25 Thread Jim Cromie
fix a debug-print that includes site info, by adding an alternate
debug message that does not.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 050c65142d9b..5422cef58130 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -232,10 +232,17 @@ static int ddebug_change(const struct ddebug_query *query,
static_branch_enable(>key.dd_key_true);
 #endif
dp->flags = newflags;
-   v2pr_info("changed %s:%d [%s]%s =%s\n",
-trim_prefix(dc->filename), dp->lineno,
-dt->mod_name, dc->function,
-ddebug_describe_flags(dp->flags, ));
+
+   if (dc)
+   v2pr_info("changed %s:%d [%s]%s =%s\n",
+ trim_prefix(dc->filename), dp->lineno,
+ dt->mod_name, dc->function,
+ ddebug_describe_flags(dp->flags, 
));
+   else
+   v2pr_info("changed %s:%d =%s \"%s\"\n",
+ dt->mod_name, dp->lineno,
+ ddebug_describe_flags(dp->flags, 
),
+ dp->format);
}
}
mutex_unlock(_lock);
-- 
2.29.2



[RFC PATCH v2 05/19] dyndbg: hoist ->site out of ddebug_match_site

2020-12-25 Thread Jim Cromie
A coming change adds _get/_put abstraction on the site pointer, to
allow managing site info more flexibly.  The get/put pattern is best
done at a single lexical scope, where its more obviously correct, so
hoist the ->site ref out of ddebug_match_site, and pass it in instead.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index bb9279c8cbfd..050c65142d9b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -140,10 +140,9 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 }
 
 static int ddebug_match_site(const struct ddebug_query *query,
-const struct _ddebug *dp)
+const struct _ddebug *dp,
+const struct _ddebug_callsite *dc)
 {
-   struct _ddebug_callsite *dc;
-
/* match against the format */
if (query->format) {
if (*query->format == '^') {
@@ -164,7 +163,6 @@ static int ddebug_match_site(const struct ddebug_query 
*query,
dp->lineno > query->last_lineno)
return false;
 
-   dc = dp->site;
if (!dc) {
/* site info has been dropped, so query cannot test these 
fields */
if (query->filename || query->function)
@@ -216,9 +214,9 @@ static int ddebug_change(const struct ddebug_query *query,
 
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = >ddebugs[i];
-   struct _ddebug_callsite *dc;
+   struct _ddebug_callsite *dc = dp->site;
 
-   if (!ddebug_match_site(query, dp))
+   if (!ddebug_match_site(query, dp, dc))
continue;
 
nfound++;
-- 
2.29.2



[RFC PATCH v2 02/19] dyndbg: split struct _ddebug, move display fields to new _ddebug_callsite

2020-12-25 Thread Jim Cromie
struct _ddebug has 5 fields used to select/display pr_debug callsites;
move 3 of them: module, function, file to new struct _ddebug_callsite,
and add pointer from 1st to 2nd (head to body).

The format field is excluded from the move because it is always needed
for an enabled site, the others are just optional decorations, at
least from the logging perspective.  While lineno is also optional, it
can share space with flags, so it stays for density reasons.

While this increases memory footprint by 1 ptr per pr_debug, the
indirection gives several advantages:

- we can drop callsites and their storage opportunistically.

  Subsystems may not want "module:func:line:" in their logs.
  If they use format-prefixes, they can select on them,
  and don't need the site info.
  forex:
  #> echo module drm format "^drm:kms: " +p >control
  ie: dynamic_debug_exec_queries("format '^drm:kms: '", "drm");

- the moved display fields are inherently hierarchical, and the linker
  section is ordered; so (module, file, function) have repeating
  values (90%, 85%, 45%).  This is readily compressible, even with a
  simple field-wise run length encoding.  Since I'm touching this so
  deeply, I reordered the fields to match the hierarchy.

- the separate linker section sets up nice for block compression.
  we could even provide as a kernel associated 'blob', like initrd, DT

- we can allocate uncompressed storage only for enabled callsites.
  could deallocate sites on memory pressure.

- if we can rely on the linker to fill the 2 __dyndbg* sections in the
  same order, we could treat them as parallel vectors, drop the
  pointer, and store each element's index into _ddebug's padding to
  get the _callsite[N].  Do same for flags.

Whats actually done here is rather mechanical.

dynamic_debug.h:

I cut struct _ddebug in half, renamed top-half (body), dropped
__align(8) on the body (its a no-op with 8 byte pointers), and kept
the __align(8) on the head (I suspect its there for the static_key
member).  I added a forward decl for a unified comment for both head &
body, and added head.site to point at body.

DECLARE_DYNAMIC_DEBUG_METADATA does the core of the work; it declares
and initializes both static struct vars together, and refs one to the
other.

dynamic_debug.c:

dynamic_debug_init() mem-usage now also counts callsites.

dynamic_emit_prefix() & ddebug_change() use those moved fields; they
get a new initialized auto-var, and the field refs get adjusted as
needed to follow the move from one struct to the other.

   struct _ddebug_callsite *dc = dp->site;

ddebug_proc_show() differs slightly; it assigns to (not initializes)
the autovar, to avoid a panic when p == SEQ_START_TOKEN.

vmlinux.lds.h:

add __ddebug_callsites section, with the same align(8) and KEEP as
used in the __ddebug section.  RFC this is slightly out of sync with
METADATA code, and dropping align(8) on the struct itself.

Signed-off-by: Jim Cromie 
---
 include/asm-generic/vmlinux.lds.h |  4 +++
 include/linux/dynamic_debug.h | 37 +-
 lib/dynamic_debug.c   | 44 ++-
 3 files changed, 53 insertions(+), 32 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index b2b3d81b1535..1ef1efc73d20 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -340,6 +340,10 @@
*(__tracepoints)\
/* implement dynamic printk debug */\
. = ALIGN(8);   \
+   __start___dyndbg_callsites = .; \
+   KEEP(*(__dyndbg_callsites)) \
+   __stop___dyndbg_callsites = .;  \
+   . = ALIGN(8);   \
__start___dyndbg = .;   \
KEEP(*(__dyndbg))   \
__stop___dyndbg = .;\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index a57ee75342cf..e155dfafc4d9 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -7,20 +7,28 @@
 #endif
 
 /*
- * An instance of this structure is created in a special
- * ELF section at every dynamic debug callsite.  At runtime,
- * the special section is treated as an array of these.
+ * A pair of these structs are created in 2 special ELF sections
+ * (__dyndbg, __dyndbg_callsites) for every dynamic debug callsite.
+ * At runtime, the sections are treated as arrays.
  */
-struct _ddebug {
+struct _ddebug;
+struct _ddebug_callsite {
/*
-* These fields are used to drive the user interface
-* for selecting and displaying debug callsites.
+* The

[RFC PATCH v2 00/19] dynamic debug diet plan

2020-12-25 Thread Jim Cromie
Well, we're mostly overeating, but we can all look forward to a diet
in January.  And more exersize.

dyndbg's compiled-in data-table currently uses 56 bytes per prdebug;
this includes 3 pointers to hierarchical "decorator" data, which is
primarily for adding "module:function:line:" prefixes to prdebug
messages, and for enabling and modifying those prdebugs selectively.

This patchset decouples "decorator" data, and makes it optional, and
disposable.  By separating that data, it opens up possiblities to
compress it, swap it out, map it selectively, etc.


In more detail, patchset does:

1- split struct _ddebug in 2, move "decorator" fields to _ddebug_callsites.

while this adds a pointer per site to memory footprint, it allows:

a- dropping decorations and storage, for some use cases.
   this could include DRM:
   - want to save calls to drm_debug_enabled()
   - use distinct categories, can map to format-prefixes, ex: "drm:kms:"
   - don't need "module:function:line" dynamic prefixes.
   - dont mind loss of info/context in /proc/dynamic_debug/control

b- ddebug_callsites[] contents are hierarchical, compressible.
c- ddebug_callsites[] in separate section is compressible as a block.
d- for just enabled prdebugs, could allocate callsites and fill from zblock.

2- make ddebug_callsites optional internally.
   This lets us drop them outright, for any reason, perhaps memory pressure.

3- allow dropping callsites by those users.
   echo module drm +D > /proc/dynamic_debug/control
   this doesnt currently recover __dyndbg_callsites storage

4- drop _ddebug.site, convert to _ddebug[N].property lookup.
   RFC is mostly here.

rev1: 
https://lore.kernel.org/lkml/20201125194855.2267337-1-jim.cro...@gmail.com/

rev2 differs by dropping zram attempt, making callsite data optional, etc.


Jim Cromie (19): against v5.10

  dyndbg: fix use before null check
1 dyndbg: split struct _ddebug, move display fields to new
_ddebug_callsite

2 dyndbg: refactor part of ddebug_change to ddebug_match_site
  dyndbg: accept null site in ddebug_match_site
  dyndbg: hoist ->site out of ddebug_match_site
  dyndbg: accept null site in ddebug_change
  dyndbg: accept null site in dynamic_emit_prefix
  dyndbg: accept null site in ddebug_proc_show
  
  dyndbg: optimize ddebug_emit_prefix
  dyndbg: avoid calling dyndbg_emit_prefix when it has no work
  
3 dyndbg: refactor ddebug_alter_site out of ddebug_change
  dyndbg: allow deleting site info via control interface
  
4 dyndbg: verify __dyndbg & __dyndbg_callsite invariant
  dyndbg+module: expose dyndbg_callsites to modules
  dyndbg: add ddebug_site_get/put api with pass-thru impl
  dyndbg: ddebug_site_get/put api commentary
  dyndbg: rearrange struct ddebug_callsites
  dyndbg: add module_index to struct _ddebug
  dyndbg: try DEFINE_DYNAMIC_DEBUG_TABLE

 drivers/gpu/drm/i915/i915_drv.c   |   3 +
 include/asm-generic/vmlinux.lds.h |   4 +
 include/linux/dynamic_debug.h |  97 ---
 kernel/module-internal.h  |   1 +
 kernel/module.c   |   9 +-
 lib/dynamic_debug.c   | 271 +-
 6 files changed, 283 insertions(+), 102 deletions(-)

-- 
2.29.2



[RFC PATCH v2 03/19] dyndbg: refactor part of ddebug_change to ddebug_match_site

2020-12-25 Thread Jim Cromie
Move all the site-match logic into a separate function, reindent the
code, and replace the continues with return falses.

No functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 75 ++---
 1 file changed, 43 insertions(+), 32 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index fb8e0b288f89..d9a0527ec842 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -139,6 +139,48 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 query->first_lineno, query->last_lineno);
 }
 
+static int ddebug_match_site(const struct ddebug_query *query,
+const struct _ddebug *dp)
+{
+   struct _ddebug_callsite *dc = dp->site;
+
+   /* match against the source filename */
+   if (query->filename &&
+   !match_wildcard(query->filename, dc->filename) &&
+   !match_wildcard(query->filename,
+   kbasename(dc->filename)) &&
+   !match_wildcard(query->filename,
+   trim_prefix(dc->filename)))
+   return false;
+
+   /* match against the function */
+   if (query->function &&
+   !match_wildcard(query->function, dc->function))
+   return false;
+
+   /* match against the format */
+   if (query->format) {
+   if (*query->format == '^') {
+   char *p;
+   /* anchored search. match must be at beginning */
+   p = strstr(dp->format, query->format+1);
+   if (p != dp->format)
+   return false;
+   } else if (!strstr(dp->format, query->format))
+   return false;
+   }
+
+   /* match against the line number range */
+   if (query->first_lineno &&
+   dp->lineno < query->first_lineno)
+   return false;
+   if (query->last_lineno &&
+   dp->lineno > query->last_lineno)
+   return false;
+
+   return true;
+}
+
 /*
  * Search the tables for _ddebug's which match the given `query' and
  * apply the `flags' and `mask' to them.  Returns number of matching
@@ -167,38 +209,7 @@ static int ddebug_change(const struct ddebug_query *query,
struct _ddebug *dp = >ddebugs[i];
struct _ddebug_callsite *dc = dp->site;
 
-   /* match against the source filename */
-   if (query->filename &&
-   !match_wildcard(query->filename, dc->filename) &&
-   !match_wildcard(query->filename,
-  kbasename(dc->filename)) &&
-   !match_wildcard(query->filename,
-  trim_prefix(dc->filename)))
-   continue;
-
-   /* match against the function */
-   if (query->function &&
-   !match_wildcard(query->function, dc->function))
-   continue;
-
-   /* match against the format */
-   if (query->format) {
-   if (*query->format == '^') {
-   char *p;
-   /* anchored search. match must be at 
beginning */
-   p = strstr(dp->format, query->format+1);
-   if (p != dp->format)
-   continue;
-   } else if (!strstr(dp->format, query->format))
-   continue;
-   }
-
-   /* match against the line number range */
-   if (query->first_lineno &&
-   dp->lineno < query->first_lineno)
-   continue;
-   if (query->last_lineno &&
-   dp->lineno > query->last_lineno)
+   if (!ddebug_match_site(query, dp))
continue;
 
nfound++;
-- 
2.29.2



Re: [RFC PATCH 1/2] drm: RFC add choice to use dynamic debug in drm-debug

2020-12-17 Thread jim . cromie
On Fri, Dec 11, 2020 at 8:34 AM Ville Syrjälä
 wrote:
>
> On Thu, Dec 03, 2020 at 08:53:17PM -0700, Jim Cromie wrote:
> > drm's debug system uses distinct categories of debug messages, mapped
> > to bits in drm.debug.  Currently, code does a lot of unlikely bit-mask
> > checks on drm.debug (in drm_debug_enabled), we can use dynamic debug
> > instead, and get all that jump_label goodness.

> Is there an actual need to go through dyndbg and do all this stringy
> stuff, or would just eg. a static keys array for the debug categories
> get us the benefits of jump_label?
>

You certainly can strip the car, take the engine.
but you might need some of the drivetrain too.
maybe you want to skip the heated seats ?
dyndbg has some stuff you dont need, for sure.

for one, its heavy on data per callsite, with a static-key and
overhead for each.

But Id be wary that the jump-label code-patching is a slow path,
so trying to change hundreds of jump-sites with one static-key field
may run into problems with long lock hold times, etc.

There is a batching mechanism built-in to the jump-label stuff somewhere,
my impression is that it amortized system-wide syncs while being RT aware.


I've been working on trimming dyndbg down, at least the memory.
I'll be sending it out shortly, but heres a preview:


Subject: [RFC PATCH v2 0/7] dynamic debug diet plan

V2 is a rethought diet plan for dyndbg (I meant -v1 as rfc).

at highest level, patchset does:
1- move struct _ddebug "selector" fields to new struct _ddebug_callsite
2- make ddebug_callsites optional, good for some users
3- allow dropping callsites by those users.

1-v2. Rasmus noted that I shouldn't move format with the other fields,
and I realized that the "module:function:line" dynamic prefixes are
ultimately just log decorations, and are not needed for certain use
cases, including drm (with category -> prefix adaptation).

The drm use case:

- can benefit from jump-labels to avoid drm_debug_enabled()
- can map categories to format-prefixes: "drm:core:" "drm:kms:" etc
- can use dynamic_debug_exec_queries("format ^drm:core: +p", NULL)
- drm + amdgpu have ~3200 drm-debugs, drm + i915 have ~1600

If drm dropped optional site info, net 16 bytes saved / callsite, maybe more...

dropping optional info : module file func means loss of log "decorations"
and slimmer contents of control file.  uncategorized pr-debugs can be
avoided when dropping callsites.   Even with dropped info,
format, line, module queries can select individual sites precisely.

As of now, we still need the __dyndbg_callsites linker section; the
3-drop is just a forget-the-addy, not a kfree.

But compression is possible. v1 tried using zram, with mixed success.
v2 is a better foundation to re-try the zram.


[PATCH v2] dyndbg: fix use before null check

2020-12-09 Thread Jim Cromie
In commit a2d375eda771 ("dyndbg: refine export, rename to
dynamic_debug_exec_queries()"), a string is copied before checking it
isn't NULL.  Fix this, report a usage/interface error, and return the
proper error code.

Fixes: a2d375eda771 ("dyndbg: refine export, rename to 
dynamic_debug_exec_queries()")
Cc: sta...@vger.kernel.org
--
-v2 drop comment tweak, improve commit message

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index bd7b3aaa93c3..c70d6347afa2 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -561,9 +561,14 @@ static int ddebug_exec_queries(char *query, const char 
*modname)
 int dynamic_debug_exec_queries(const char *query, const char *modname)
 {
int rc;
-   char *qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+   char *qry; /* writable copy of query */
 
-   if (!query)
+   if (!query) {
+   pr_err("non-null query/command string expected\n");
+   return -EINVAL;
+   }
+   qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+   if (!qry)
return -ENOMEM;
 
rc = ddebug_exec_queries(qry, modname);
-- 
2.29.2



Re: [RFC PATCH 1/2] drm: RFC add choice to use dynamic debug in drm-debug

2020-12-04 Thread jim . cromie
On Fri, Dec 4, 2020 at 8:42 AM Ville Syrjälä
 wrote:
>
> On Thu, Dec 03, 2020 at 08:53:17PM -0700, Jim Cromie wrote:
> > drm's debug system uses distinct categories of debug messages, mapped
> > to bits in drm.debug.  Currently, code does a lot of unlikely bit-mask
> > checks on drm.debug (in drm_debug_enabled), we can use dynamic debug
> > instead, and get all that jump_label goodness.
>
> whatis jump_label?

Sorry, I should have at least capitalized that, and spelled it differently

kernel/Makefile
118:obj-$(CONFIG_JUMP_LABEL) += jump_label.o

it is the hot-patching substrate underneath it all.
static-key, static-call, etc?
dynamic-debug uses static-key directly.



>
> One thing that bugs me about the current drm_dbg() stuff is that
> it's a function, and thus we pay the cost of setting up the
> arguments even when debugs are not enabled. I played around a bit
> with making it a macro again with the unlikely bit check moved
> into the macro. That did seem to make some of the asm a bit nicer
> where the debug stuff got shoved out the main codepath, but
> it did result in a slight net increase in code size. What I didn't
> have time to do is check if this has any measurable speed effect
> on eg. TEST_ONLY commits.
>
> And while doing that I started to ponder if we could use something
> like the alternate() instruction stuff to patch the code at runtime
> in order to turn all those debug checks into nops when debugging
> is not enabled. But I couldn't immediately find any generic
> infrastructure for it. So now I wonder if this jump_label is something
> like that?
>

this is the droid youre looking for ;-)

> >

> --
> Ville Syrjälä
> Intel


[RFC PATCH 2/2] i915: POC use dynamic_debug_exec_queries to control pr_debugs in gvt

2020-12-03 Thread Jim Cromie
The gvt component of this driver has ~120 pr_debugs, in 9 "classes".
Following model of drm.debug, add a parameter to map bits to these
classes.

In Makefile, add DYNAMIC_DEBUG_MODULE.  This converts gvt's pr_debugs,
even if the rest of drm is not using CONFIG_DRM_USE_DYNAMIC_DEBUG.

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/i915/gvt/Makefile  |  1 +
 drivers/gpu/drm/i915/i915_params.c | 74 ++
 2 files changed, 75 insertions(+)

diff --git a/drivers/gpu/drm/i915/gvt/Makefile 
b/drivers/gpu/drm/i915/gvt/Makefile
index ea8324abc784..e38a1eb618bd 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -6,4 +6,5 @@ GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o 
trace_points.o firmware.o \
fb_decoder.o dmabuf.o page_track.o
 
 ccflags-y  += -I $(srctree)/$(src) -I 
$(srctree)/$(src)/$(GVT_DIR)/
+ccflags-y  += -DDYNAMIC_DEBUG_MODULE
 i915-y += $(addprefix $(GVT_DIR)/, 
$(GVT_SOURCE))
diff --git a/drivers/gpu/drm/i915/i915_params.c 
b/drivers/gpu/drm/i915/i915_params.c
index 7f139ea4a90b..ecc825558e00 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -260,3 +260,77 @@ void i915_params_free(struct i915_params *params)
I915_PARAMS_FOR_EACH(FREE);
 #undef FREE
 }
+
+/* POC for callback -> dynamic_debug_exec_queries */
+unsigned long __gvt_debug;
+EXPORT_SYMBOL(__gvt_debug);
+
+static char *format_prefix_classes[] = {
+   "gvt: cmd: ",
+   "gvt: core: ",
+   "gvt: dpy: ",
+   "gvt: el: ",
+   "gvt: irq: ",
+   "gvt: mm: ",
+   "gvt: mmio: ",
+   "gvt: render: ",
+   "gvt: sched: "
+};
+#define NUM_CLASSESARRAY_SIZE(format_prefix_classes)
+#define OUR_QUERY_SIZE 128 /* we need about 20 */
+
+#include 
+
+static int param_set_dyndbg(const char *instr, const struct kernel_param *kp)
+{
+   unsigned int val;
+   unsigned long changes, result;
+   int rc, chgct = 0, totct = 0, bitpos;
+   char query[OUR_QUERY_SIZE];
+
+   rc = kstrtouint(instr, 0, );
+   if (rc) {
+   pr_err("set_dyndbg: failed\n");
+   return -EINVAL;
+   }
+   result = val;
+   pr_info("set_dyndbg: result:0x%lx from %s\n", result, instr);
+
+   changes = result ^ __gvt_debug;
+
+   for_each_set_bit(bitpos, , NUM_CLASSES) {
+
+   sprintf(query, "format '^%s' %cp", 
format_prefix_classes[bitpos],
+   test_bit(bitpos, ) ? '+' : '-');
+
+   chgct = dynamic_debug_exec_queries(query, "i915");
+
+   pr_info("%d changes on: %s\n", chgct, query);
+   totct += chgct;
+   }
+   pr_info("total changes: %d\n", totct);
+   __gvt_debug = result;
+   return 0;
+}
+static int param_get_dyndbg(char *buffer, const struct kernel_param *kp)
+{
+   return scnprintf(buffer, PAGE_SIZE, "%u\n",
+*((unsigned int *)kp->arg));
+}
+static const struct kernel_param_ops param_ops_dyndbg = {
+   .set = param_set_dyndbg,
+   .get = param_get_dyndbg,
+};
+
+MODULE_PARM_DESC(debug_gvt, " gvt debug categories:"
+"\n\t0x1\t gvt: cmd:"
+"\n\t0x2\t gvt: core:"
+"\n\t0x4\t gvt: dpy:"
+"\n\t0x8\t gvt: el:"
+"\n\t0x10\t gvt: irq:"
+"\n\t0x20\t gvt: mm:"
+"\n\t0x40\t gvt: mmio:"
+"\n\t0x80\t gvt: render:"
+"\n\t0x100\t gvt: sched:" "\n");
+
+module_param_cb(debug_gvt, _ops_dyndbg, &__gvt_debug, 0644);
-- 
2.28.0



[RFC PATCH 1/2] drm: RFC add choice to use dynamic debug in drm-debug

2020-12-03 Thread Jim Cromie
drm's debug system uses distinct categories of debug messages, mapped
to bits in drm.debug.  Currently, code does a lot of unlikely bit-mask
checks on drm.debug (in drm_debug_enabled), we can use dynamic debug
instead, and get all that jump_label goodness.

RFC: dynamic debug has no concept of category, but we can do without
one if we can prepend a class-prefix to each printk format.  Then we
can use "format ^prefix" to select the whole category with one query.
This is a log-facing and user visible change, but it seems unlikely to
cause trouble for log watchers; they're not relying on the absence of
class prefix strings.

This conversion yields ~2100 new callsites on my i7 laptop:

  dyndbg: 195 debug prints in module drm_kms_helper
  dyndbg: 298 debug prints in module drm
  dyndbg: 1630 debug prints in module i915

Since this change has wide-ranging effects (many drm drivers, with
many callsites, and kernel image growth), and most vendors don't
enable DYNAMIC_DEBUG, we supplement the existing mechanism, adding
CONFIG_DRM_USE_DYNAMIC_DEBUG to enable the new one.

The indirection/switchover has a few parts:

1 a new callback on drm.debug which calls dynamic_debug_exec_queries
  to map those bits to specific query/commands
  dynamic_debug_exec_queries("format ^drm:kms: +p", "drm*");

2 a "converted" or "classy" DRM_UT_* map
  similar to DRM_UT_* ( symbol => bit-mask )
  named it  cDRM_UT_* ( symbol => format-class-prefix-string )

  cDRM_UT_* is either ( CONFIG_DRM_USE_DYNAMIC_DEBUG )
  legacy: cDRM_UT_* <-- DRM_UT_*
  enabled:
  +#define cDRM_UT_KMS"drm:kms: "
  +#define cDRM_UT_PRIME  "drm:prime: "
  +#define cDRM_UT_ATOMIC "drm:atomic: "

  these are similar to "gvt: cmd:" in i915/gvt
  and effectively a replacement for DRM_NAME
  please bikeshed on keys, values. latter are log-facing.

3 drm_dev_dbg & drm_debug are renamed (prefixed with '_')
  old names are now macros, which are ifdefd
  legacy:  -> to renamed fn
  enabled: -> dev_dbg & pr_debug, after prepending prefix to format.

4 names in (2) are called from DRM_DEBUG_ and drm_dbg_.
  all these get "converted" to use cDRM_UT_*, to get right token type.

RFC: for dynamic debug, category is a source-facing addition;
something like pr_debug_cat(cat, ...) would do it, iff cat is a
compile-time const.  Note that cat isn't needed in the printing, it
would be saved into a new field in struct _ddebug, and used only for
callsite selection, activation and control.

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/Kconfig | 13 ++
 drivers/gpu/drm/drm_print.c | 75 --
 include/drm/drm_print.h | 92 +++--
 3 files changed, 153 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 147d61b9674e..854bc1ad21fb 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -54,6 +54,19 @@ config DRM_DEBUG_MM
 
  If in doubt, say "N".
 
+config DRM_USE_DYNAMIC_DEBUG
+   bool "use dynamic debug to implement drm.debug"
+   default n
+   depends on DRM
+   depends on DYNAMIC_DEBUG
+   depends on JUMP_LABEL
+   help
+ The drm debug category facility does a lot of unlikely bit-field
+ tests at runtime; while cheap individually, the cost accumulates.
+ This option uses dynamic debug facility (if configured and
+ using jump_label) to avoid those runtime checks, patching
+ the kernel when those debugs are desired.
+
 config DRM_DEBUG_SELFTEST
tristate "kselftests for DRM"
depends on DRM
diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c
index 111b932cf2a9..e2acdfc7088b 100644
--- a/drivers/gpu/drm/drm_print.c
+++ b/drivers/gpu/drm/drm_print.c
@@ -52,8 +52,75 @@ MODULE_PARM_DESC(debug, "Enable debug output, where each bit 
enables a debug cat
 "\t\tBit 5 (0x20)  will enable VBL messages (vblank code)\n"
 "\t\tBit 7 (0x80)  will enable LEASE messages (leasing code)\n"
 "\t\tBit 8 (0x100) will enable DP messages (displayport code)");
+
+#ifndef CONFIG_DRM_USE_DYNAMIC_DEBUG
 module_param_named(debug, __drm_debug, int, 0600);
 
+#else
+static char *format_class_prefixes[] = {
+   cDRM_UT_CORE,
+   cDRM_UT_DRIVER,
+   cDRM_UT_KMS,
+   cDRM_UT_PRIME,
+   cDRM_UT_ATOMIC,
+   cDRM_UT_VBL,
+   cDRM_UT_STATE,
+   cDRM_UT_LEASE,
+   cDRM_UT_DP,
+   cDRM_UT_DRMRES
+};
+
+#define OUR_QUERY_SIZE 64 /* > strlen "format '^%s' %cp" + longest prefix */
+
+static int param_set_dyndbg(const char *instr, const struct kernel_param *kp)
+{
+   unsigned int val;
+   unsigned long changes, result;
+   int rc, chgct = 0, totct = 0, bitpos;
+   char query[OUR_QUERY_SIZE];
+
+   rc = kstrtouint(instr, 0, );
+   i

[RFC PATCH 0/2] drm: use dynamic_debug

2020-12-03 Thread Jim Cromie
hello gentle readers,

These 2 rfc patches convert part of drm-world to use dynamic debug.

1st one addresses drm.debug category based logging.  If DYNAMIC_DEBUG
is configured, then CONFIG_DRM_USE_DYNAMIC_DEBUG controls whether
dynamic-debug is used to avoid runtime costs of drm_debug_enabled().
We require CONFIG_JUMP_LABEL too, since we are selling its
optimization.

This change adds many new callsites to /proc/dynamic_debug/control;
~300 in drm, ~200 in drm_kms_helper, as well as ~1500 in i915 driver,
and ~3200 in amdgpu.  So there are substantial implications here.

2nd one is for i915, which I have in my laptop.  `grep pr_debug` found
~90 callsites with a meaningful format-prefix-string, to demonstrate
use of "format ^prefix" to control user categorized debugs.

Jim Cromie (2):
  drm: RFC add choice to use dynamic debug in drm-debug
  i915: POC use dynamic_debug_exec_queries to control pr_debugs in gvt

 drivers/gpu/drm/Kconfig| 13 +
 drivers/gpu/drm/drm_print.c| 75 ++--
 drivers/gpu/drm/i915/gvt/Makefile  |  1 +
 drivers/gpu/drm/i915/i915_params.c | 74 
 include/drm/drm_print.h| 92 ++
 5 files changed, 228 insertions(+), 27 deletions(-)

-- 
2.28.0



Re: [PATCH 7/7] dyndbg: enable 'cache' of active pr_debug callsites

2020-11-25 Thread jim . cromie
On Wed, Nov 25, 2020 at 1:54 PM Jason Baron  wrote:
>
>
>
> On 11/25/20 2:36 PM, Jim Cromie wrote:
> > In ddebug_putsite(), dont zs_unmap the callsite if it is enabled for
> > printing.  This means that the next time this pr_debug callsite is
> > executed, the _getsite() will succeed quickly without remapping the
> > zrec.
> >
> > Once the callsite is disabled via >control, a following _putsite()
> > will see the flag cleared, and zs_unmap it.
> >
> > This changes the lifetime of our zs_mappings from brief (only for the
> > single printk) to as long as uptime (if a prdebug is enabled til
> > poweroff).  This appears to be triggering the ensuing mayhem.
> >
> > I am able to get through init, to root console, by disabling all
> > dynamic-debugs, including the ones that are enabled at compile.
> >
> > $ kruna --kopt \*.dyndbg=-p --kopt debug_locks_proceed=1
> >
> > but enabling any pr-debug crashes.
> > Plain old boot also panics, as pasted below.
> >
>
>
> Hi Jim,
>
> Looks like you've made a lot of progress with this series...but if I
> understand correctly there are still some unresolved issues (panic).
> So I think this series is more 'RFC' at this point?
>

yes, RFC.  WIP suggests I know whats needed next.

certainly Ive seen a variety of sleeping while atomic ... BUGs,



> I was also expecting to see updates to the actual printing functions
> to now use dp->site. But perhaps I missed those bits?

those bits were changed in patch 5
basically changes are ~ s/dp/dc/g, and in ddebug_getsite / _putsite

>
> Thanks,
>
> -Jason
>
> > $ kruna --kopt debug_locks_proceed=1
> >




 [1.915768]  ? rest_init+0x24d/0x24d
> > [1.916417]  kernel_init+0xaf/0x103
> > [1.917038]  ret_from_fork+0x22/0x30
> > [1.917726] Kernel Offset: disabled
> > [1.918324] ---[ end Kernel panic - not syncing: Requested init /bin/sh 
> > failed (error -14). ]---
> > QEMU 5.1.0 monitor - type 'help' for more information
> >
> > Signed-off-by: Jim Cromie 
> > ---
> >  lib/dynamic_debug.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 534d73e45844..0c69aa52395d 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -165,7 +165,9 @@ static void ddebug_putsite(struct _ddebug *dp)
> >   /* need to keep site until zmap backing exists */
> >   return;
> >
> > - /* always unmap for now. if !pr-debug has locking issues */
> > + if (dp->flags & _DPRINTK_FLAGS_PRINT)
> > + return; /* keep maps of enabled pr_debugs */
> > +
> >   zs_unmap_object(dd_callsite_zpool, dp->zhandle);
> >   dp->site = NULL;
> >  }
> >


[PATCH 0/7] WIP dyndbg diet plan, paging Dr Zram.

2020-11-25 Thread Jim Cromie
hi all,

To celebrate a season of ritual overeating, Id like to propose a diet
plan for dynamic_debug.

dynamic-debug is carrying extra weight/memory in the __dyndbg linker
section, which is basically a struct _ddebug array[].  The 5 display
oriented fields carry hierarchical data, and since the linker section
is ordered, there is lots of repetition in .module .file .function
fields.

This patch-set:

1) splits struct _ddebug in 2, creating creating _ddebug_callsites
with 5 display-fields, which are placed in a new linker section.

while this adds indirection, it lets us manage storage of the .site
data, letting us keep the bulk of it in compressed form.

2,3) explores run-length-encoding as one alternative to zram,
basically throwaway, but for any ensuing discussion.

4) do kconfig bits - needs work

5) at late-init, copy site recs into zram (and save to .zhandle),
thereafter .site is "refilled" (when null) from the .zhandle.

Updating the _ddebug.site pointers also means we forget the link-time
refs to _callsites section, allowing its reclaim later (once I know
how).

The .site "refill" is by _getsite(); the corresponding _putsite()
works: it zs_unmaps ASAP and zeros .site.  This means that every
pr_debug will map/unmap once, and `cat control` will do so per line.
Probably too expensive.

But it works. Im seeing 3 pages_per_zspage, on entire section.

6) a hot locking mess. well, maybe not. plenty of uncertainty though.

7) does not work.  It changes _putsite() to keep each zs_mapping when
the pr_debug is enabled.  But it panics in late-init, with BUG
sleeping in atomic context.  ? dynamic_emit_prefix is in backtrace.

disabling all pr_debugs (--kopt \*.dyndbg=-p) gets to root prompt.
once there:
  echo module main +m > /proc/dynamic_debug/control # is ok
  echo module main +p > /proc/dynamic_debug/control # BUG sleeping invalid 
context

This strongly implicates the dynamic_emit_prefix call chain.  It
puzzles me that keeping the zs_mapping would cause so much trouble;
its not causing more pr_debugs, and they should all be mapped already.
But I really dont know what Im doing here..

WAG at possible memory savings:
- add 2 pointers (zhandle, site) 56+16
- drop 48 (sizeof _callsite) * num-pr-debugs linker section
- replace with 3:1 storage on same
- 48 bytes per enabled pr_debug, typically <1% of set

IE:
 dyndbg: 216 modules, 2058 entries and 8640 bytes in ddebug tables, 115248 
bytes in __dyndbg section
VS:
 dyndbg: 224 modules, 2015 entries and 8960 bytes in ddebug tables, 80600 bytes 
in __dyndbg section, 80600 bytes in __dyndbg_callsites section
 dyndbg: 2015 entries. repeated entries: 1790 module 1668 file 810 func

Once __dyndbg_callsites section is reclaimed, %30 savings looks likely.

Jim Cromie (7):
  dyndbg: move struct _ddebug's display fields to new _ddebug_callsite
  dyndbg: count repetition in __dyndbg_callsite fields.
  dyndbg: add some code to see alignments of linkage data
  dyndbg: select ZPOOL,ZS_MALLOC in Kconfig.debug DYNAMIC_DEBUG_CORE
  dyndbg: replace __dyndbg_callsite section with a zs-pool copy.
  dyndbg: add locking around zpool-add loop in zpool-init
  dyndbg: enable 'cache' of active pr_debug callsites


 include/asm-generic/vmlinux.lds.h |   4 +
 include/linux/dynamic_debug.h |  42 --
 lib/Kconfig.debug |   2 +
 lib/dynamic_debug.c   | 242 +-
 4 files changed, 239 insertions(+), 51 deletions(-)

To: linux...@kvack.org
Cc: Rasmus Villemoes 
-- 
2.28.0



[PATCH 4/7] dyndbg: select ZPOOL,ZS_MALLOC in Kconfig.debug DYNAMIC_DEBUG_CORE

2020-11-25 Thread Jim Cromie
dyndbg will next need zs_malloc and friends, so add config reqs now,
to maybe avoid churny remakes later.

ZPOOL,ZSMALLOC are now required for DYNAMIC_DEBUG_CORE, as theyre
needed to get value (mem use reduction) from the upcoming
dyndbg/callsite split.

---

ZS_MALLOC is done with "depends on" instead of "select" to break a
recursive dependency.  I think this doesnt quite sort things out for
other config permutations, TBD.

-v2 fixup -> _CORE
Reported-by: kernel test robot 

Signed-off-by: Jim Cromie 
---
 lib/Kconfig.debug | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index c789b39ed527..7eb7b43037d9 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -170,6 +170,8 @@ config DYNAMIC_DEBUG_CORE
bool "Enable core function of dynamic debug support"
depends on PRINTK
depends on (DEBUG_FS || PROC_FS)
+   select ZPOOL
+   depends on ZSMALLOC
help
  Enable core functional support of dynamic debug. It is useful
  when you want to tie dynamic debug to your kernel modules with
-- 
2.28.0



[PATCH 2/7] dyndbg: count repetition in __dyndbg_callsite fields.

2020-11-25 Thread Jim Cromie
The __dyndbg_callsite section is basically a flat db-table, an array
of struct _ddebug_callsite[]s.  Its data is inherently hierarchical
and sorted, so a field-wise run-length encoding would compress well.

Add counters and code to test 3 fields of consecutive callsites for
repeated values.  The results inform a compression estimate.

 dyndbg: 2605 entries. repeated entries: 2369 module 2231 file 1147 func

Thats (91%, 86%, 44%) repeated values in those pointers/columns, on my
i7 laptop build.  With a zero-overhead markup, like LSB-stealing, we
could mark the differing tails of consecutive records, and get 11/24
compression on init/main pr_debugs.

For a slightly apples-to-oranges comparison (text vs pointers),
`gzip /proc/dynamic_debug/control` achieves 6/1 compression.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 2e4a39c349a5..5980d44ff2f8 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1081,11 +1081,12 @@ static int __init dynamic_debug_init_control(void)
 
 static int __init dynamic_debug_init(void)
 {
-   struct _ddebug *iter, *iter_start;
+   struct _ddebug *iter, *iter_start, *prev = NULL;
const char *modname = NULL;
char *cmdline;
int ret = 0;
int n = 0, entries = 0, modct = 0;
+   int modreps = 0, funcreps = 0, filereps = 0;
 
if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
@@ -1099,7 +1100,16 @@ static int __init dynamic_debug_init(void)
iter = __start___dyndbg;
modname = iter->site->modname;
iter_start = iter;
-   for (; iter < __stop___dyndbg; iter++) {
+   for (prev = iter; iter < __stop___dyndbg; iter++) {
+   if (entries) {
+   if (prev->site->modname == iter->site->modname)
+   modreps++;
+   if (prev->site->function == iter->site->function)
+   funcreps++;
+   if (prev->site->filename == iter->site->filename)
+   filereps++;
+   prev++; /* one behind iter */
+   }
entries++;
if (strcmp(modname, iter->site->modname)) {
modct++;
@@ -1122,6 +1132,9 @@ static int __init dynamic_debug_init(void)
 (int)(entries * sizeof(struct _ddebug)),
 (int)(entries * sizeof(struct _ddebug_callsite)));
 
+   vpr_info("%d entries. repeated entries: %d module %d file %d func\n",
+entries, modreps, filereps, funcreps);
+
/* apply ddebug_query boot param, dont unload tables on err */
if (ddebug_setup_string[0] != '\0') {
pr_warn("ddebug_query param name is deprecated, change it to 
dyndbg\n");
-- 
2.28.0



[PATCH 7/7] dyndbg: enable 'cache' of active pr_debug callsites

2020-11-25 Thread Jim Cromie
 1996), BIOS 
1.13.0-3.fc33 04/01/2014
[1.912845] Call Trace:
[1.913289]  dump_stack+0x7d/0x9f
[1.913957]  ? rest_init+0x210/0x24d
[1.914535]  panic+0x10a/0x2de
[1.915094]  ? kernel_execve+0x145/0x1b0
[1.915768]  ? rest_init+0x24d/0x24d
[1.916417]  kernel_init+0xaf/0x103
[1.917038]  ret_from_fork+0x22/0x30
[1.917726] Kernel Offset: disabled
[1.918324] ---[ end Kernel panic - not syncing: Requested init /bin/sh 
failed (error -14). ]---
QEMU 5.1.0 monitor - type 'help' for more information

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 534d73e45844..0c69aa52395d 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -165,7 +165,9 @@ static void ddebug_putsite(struct _ddebug *dp)
/* need to keep site until zmap backing exists */
return;
 
-   /* always unmap for now. if !pr-debug has locking issues */
+   if (dp->flags & _DPRINTK_FLAGS_PRINT)
+   return; /* keep maps of enabled pr_debugs */
+
zs_unmap_object(dd_callsite_zpool, dp->zhandle);
dp->site = NULL;
 }
-- 
2.28.0



[PATCH 6/7] dyndbg: add locking around zpool-add loop in zpool-init

2020-11-25 Thread Jim Cromie
This commit doesnt improve things, last commit was working, next one
still breaks, despite this "fix".  I keep it separate to isolate it
and the reasoning for review, which now stated, will be refuted as
needed. ;-)

Locking review:

ddebug_zpool_init(), like other ddebug_*_init() routines, does no
locking itself.  Unlike them, it runs later, at late_init.  This patch
doesnt fix the kernel panic that HEAD+1 does.

ddebug_callsite_get/put() are called as a pair under mutex-lock for
all 3 callsite users.

2 of them; ddebug_change() and dynamic_emit_prefix(), do their own
ABBA-ish LGPU (Lock-Get-Put-Unlock).

ddebug_proc_show() does the GP part, and is wrapped by
ddebug_proc_start|stop() with LU.

ddebug_add_module() does LU to protect list_add(), HEAD~1 added
ddebug_zpool_add() loop inside that protection.

This commit adds locking to ddebug_zpool_init(), around the loop of
ddebug_zpool_add(), to match the locking in ddebug_add_module().

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 473406b069a7..534d73e45844 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1195,8 +1195,10 @@ static void __init ddebug_zpool_init(void)
}
 
/* add-module normally does this, but not in time for builtins */
+   mutex_lock(_lock);
for (iter = __start___dyndbg; iter < __stop___dyndbg; iter++)
ddebug_zpool_add(iter);
+   mutex_unlock(_lock);
 
v2pr_info("total pages: %lu compaction: %lu\n",
  zs_get_total_pages(dd_callsite_zpool),
-- 
2.28.0



[PATCH 1/7] dyndbg: move struct _ddebug's display fields to new _ddebug_callsite

2020-11-25 Thread Jim Cromie
struct _ddebug has 5 fields used to display and select pr_debug
callsites, move these to a new struct _ddebug_callsite, and add ptr to
link 1st to 2nd.  While this increases memory footprint by 1 ptr per
pr_debug, the indirection gives several advantages:

- we can allocate storage only for enabled callsites.  Since pr_debugs
  are 99% disabled, we should see savings.

- the display fields are inherently hierarchical, and the linker
  section is ordered; so (module, file, function) have redundant
  values (90%, 85%, 45%).  This is readily compressible, even with a
  simple field-wise run length encoding.  Because theyre placed in a
  separate linker section, theyre in a contiguous block of memory,
  which should simplify that compression.

Looking forward, there are several approaches to get the advantages.

A - copy each callsite to zram, save to new .zhandle member, and
update site pointers.  Must later retire __dyndbg_callsite section
afterwards to actually recover memory.

I did this (next patches), and get 3:1 zs_page:page compression.  It
works when sites are zs_mapped in just for the print.  But if I leave
them mapped in cuz the pr_debug is enabled, locking conflicts & panic
ensue.  Patches follow.

B - compress __dyndbg_callsite linker section, using some format which
is good at random-index decompression.

I did objcopy --dump-sections .. vmlinux.o, got mostly empty data,
like Im getting values before the final link.  Im missing some
understanding.

C - field-wise RLE.  This is feeling increasingly suitable.

Whats actually done here:

dynamic_debug.h:

I cut struct _ddebug in half, renamed top-half (body), kept __align(8)
on both head & body, added a forward decl for a unified comment for
both head & body.  And added head.site to point at body.

DECLARE_DYNAMIC_DEBUG_METADATA does the core of the work; it declares
and initializes both static struct vars together, and refs one to the
other.

And since Im rejiggering the structs:

- I moved static_key key to front of struct _ddebug; its the biggest
  member, and most alignment sensitive, so moving it to front may
  improve ambient pahole conditions.

- reorder display fields to match the hierarchy.  This should help
  improve compressability, particularly for field-wise RLE.  With
  this, consecutive records are tail-different.

Also
- reserved a flag bit for zram mapping (no use yet)
- I shrunk lineno member from 18 to 16 bits, and made it const.
  No source file is near 64k-lines, I doubt any could get added.

dynamic_debug.c:

dynamic_debug_init() mem-usage now counts callsites.

The 3 funcs which use _ddebug* pointers (ddebug_change,
dynamic_emit_prefix, ddebug_proc_show) each get an auto-var, inited
with ->site, and s/dp/dc/ as needed.  These once-per-func dp->site
derefs are also a setup for the next commit.

vmlinux.lds.h:

add __ddebug_callsites section, with the same align(8) and KEEP as
used in the __ddebug section.

TBD:

_align(8) may be unnecessary on struct _ddebug_callsite, I think its
there for the static_key member.  I do wonder if its arch dependent, 8
seems big for i686 at least.

Signed-off-by: Jim Cromie 
---
 include/asm-generic/vmlinux.lds.h |  4 +++
 include/linux/dynamic_debug.h | 41 +++-
 lib/dynamic_debug.c   | 52 +--
 3 files changed, 58 insertions(+), 39 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index b2b3d81b1535..1ef1efc73d20 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -340,6 +340,10 @@
*(__tracepoints)\
/* implement dynamic printk debug */\
. = ALIGN(8);   \
+   __start___dyndbg_callsites = .; \
+   KEEP(*(__dyndbg_callsites)) \
+   __stop___dyndbg_callsites = .;  \
+   . = ALIGN(8);   \
__start___dyndbg = .;   \
KEEP(*(__dyndbg))   \
__stop___dyndbg = .;\
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index a57ee75342cf..0bf7036bcdb2 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -7,11 +7,14 @@
 #endif
 
 /*
- * An instance of this structure is created in a special
- * ELF section at every dynamic debug callsite.  At runtime,
- * the special section is treated as an array of these.
+ * a pair of these structs are created in 2 special ELF sections
+ * (__dyndbg, __dyndbg_callsites) for every dynamic debug callsite.
+ * During init, __dyndbg_callsites is copied to zram, and links to
+ * them in _ddebug are up

[PATCH 5/7] dyndbg: replace __dyndbg_callsite section with a zs-pool copy.

2020-11-25 Thread Jim Cromie
A previous commit split struct _ddebugs into heads & bodies, linked
across 2 ELF sections.  Lets now copy the bodies into a zs_pool, and
relink the head to the new body.  This should allow recycling the
__dyndbg_callsite section soon.

The goal is to let a compression algo handle the repetition, and map
individual records in when needed.  I have seen 3:1 page/zspage
compression (in /sys/kernel/debug/zsmalloc/callsites)

Since dynamic_debug is nice to have but rarely used, paying more for
active logging to save in-kernel memory might be a worthwhile tradeoff.

This is how:

New ddebug_zpool_init(), at late_initcall time, creates the zpool.
Per dmesg, this is shortly after zswap is ready.

ddebug_add_module() now also calls new ddebug_zpool_add(1) foreach
callsite in the module. (1) copies the _ddebug_callsite record into
the zpool, once the zpool is ready.  For builtin modules, added in
early-boot, that zpool was not ready yet.  So ddebug_zpool_init() also
calls ddebug_zpool_add() for all those builtin modules already added
by ddebug_add_module().

New ddebug_zpool_add() does, foreach _ddebug:
 - zs_mallocs a zrec, saves handle to .zhandle,
 - zs_maps and copies callsite to it
 - zs_unmaps it, triggering write to zram
 - .site=0, detaching __dyndbg_callsites[item]
   which later triggers zs_map (.zhandle)

So we leave late-init with a full zram copy of __dyndbg_callsites
section, which is thus ready to reclaim.

ddebug_zpool_remove() undoes ddebug_zpool_add().
We call it from ddebug_remove_module().

The 3 existing users of struct _ddebug get the site ref entirely via 2
helpers, which manage the zs-mapping;

- ddebug_getsite() returns .site 1st, or maps zrec to it
  and returns it.

- ddebug_putsite() always unmaps, minimizing online ram.
  (see 1 below)

Those 3 users each take ddebug_lock around the get/puts, either
directly, or via ddebug_proc_(start|end).

ddebug_change() also gets s/continue/goto skipsite/g to cleanly unmap
the record at the bottom of the loop.

Im seeing 3:1 pages_per_zspage:

 # cut -c1-12,40-77,85-90 $SKD/zsmalloc/dyndbg_callsites/classes | head -n3
 class  sizebj_allocated   obj_used pages_used pagzspage
 032   0  0  0 1
 1482816   2605 33 3

This much works.

Next steps:

1. dont always unmap in _put(), leave enabled pr_debugs mapped.

this is sticking point atm.

This would make the set of zs_mapped recs work like a cache, reducing
zs_mappings to a trickle, and only for <>control.

2. move key from struct _ddebug into _ddebug_callsite

key doesnt exactly fit semantically (and its not RO), but its use is
super rare, and is never needed without also needing all the other
callsite data.  Getting it out of head would save on-line ram.

But it broke in HEAD~1 when I tried it, with asm goto errors.
`grep arch_static_branch` suggests my argument to it was uniquely
complicated and dereferencing.

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h |   1 +
 lib/dynamic_debug.c   | 148 +++---
 2 files changed, 137 insertions(+), 12 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 0bf7036bcdb2..a8336b9cc011 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -34,6 +34,7 @@ struct _ddebug {
} key;
 #endif
struct _ddebug_callsite *site;
+   long unsigned int zhandle;
/*
 * The flags field controls the behaviour at the callsite.
 * The bits here are changed dynamically when the user
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index c84efb4e036b..473406b069a7 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -72,6 +73,8 @@ static LIST_HEAD(ddebug_tables);
 static int verbose;
 module_param(verbose, int, 0644);
 
+static struct zs_pool *dd_callsite_zpool;
+
 /* Return the path relative to source root */
 static inline const char *trim_prefix(const char *path)
 {
@@ -139,6 +142,34 @@ static void vpr_info_dq(const struct ddebug_query *query, 
const char *msg)
 query->first_lineno, query->last_lineno);
 }
 
+/*
+ * ddebug_getsite - returns site, or maps it then returns it.
+ */
+static struct _ddebug_callsite* ddebug_getsite(struct _ddebug *dp)
+{
+   if (dp->site)
+   return dp->site;
+
+   dp->site = (struct _ddebug_callsite*)
+   zs_map_object(dd_callsite_zpool, dp->zhandle, ZS_MM_RO);
+
+   return dp->site;
+}
+
+/*
+ * ddebug_putsite - unmaps site, implements policy choice
+ */
+static void ddebug_putsite(struct _ddebug *dp)
+{
+   if (!dp->zhandle)
+   /* need to keep site until zmap backing exists */
+   return;
+
+   /* always unmap for now. if !pr-debug has locking issues */
+   zs_unmap_object(dd_callsite_zpool, dp-

[PATCH 3/7] dyndbg: add some code to see alignments of linkage data

2020-11-25 Thread Jim Cromie
To be able to use LSB-stealing (lsb as flag, mask b4 addressing), we
need to know that the alignments of existing data is never odd.  So
add code to check the alignment of pointers in _dyndbg_callsites
section.

It turns out that all these fields point to a variety of odd
alignments in the deeper linkage data.  We will need ALIGN(2) to allow
use of LSB to signal the EOT of differing-tail records.

[0.587654] dyndbg: 2014 entries. \
   repeated entries: 1789 module 1667 file 809 func
[0.588653] dyndbg: mod aligns:
[0.589130] dyndbg:   align 0 0: 107
[0.589653] dyndbg:   align 0 1: 210
[0.590271] dyndbg:   align 0 2: 234
[0.590652] dyndbg:   align 0 3: 179
[0.591224] dyndbg:   align 0 4: 358
[0.591652] dyndbg:   align 0 5: 374
[0.592283] dyndbg:   align 0 6: 231
[0.592653] dyndbg:   align 0 7: 321
[0.593203] dyndbg:  mod align totals: 2014
[0.593652] dyndbg: file aligns:
[0.594168] dyndbg:   align 1 0: 569
[0.594652] dyndbg:   align 1 1: 172
[0.595179] dyndbg:   align 1 2: 263
[0.595652] dyndbg:   align 1 3: 252
[0.596368] dyndbg:   align 1 4: 200
[0.596652] dyndbg:   align 1 5: 126
[0.597327] dyndbg:   align 1 6: 177
[0.597669] dyndbg:   align 1 7: 255
[0.598316] dyndbg:  file align totals: 2014
[0.598652] dyndbg: func aligns:
[0.599214] dyndbg:   align 2 0: 2006
[0.599652] dyndbg:   align 2 1: 7
[0.600168] dyndbg:   align 2 2: 0
[0.600648] dyndbg:   align 2 3: 0
[0.600652] dyndbg:   align 2 4: 0
[0.601105] dyndbg:   align 2 5: 0
[0.601652] dyndbg:   align 2 6: 0
[0.602203] dyndbg:   align 2 7: 1
[0.602654] dyndbg:  func align totals: 2014
[0.603431] dyndbg: format aligns:
[0.603658] dyndbg:   align 3 0: 1053
[0.604429] dyndbg:   align 3 1: 134
[0.604653] dyndbg:   align 3 2: 161
[0.605181] dyndbg:   align 3 3: 142
[0.605652] dyndbg:   align 3 4: 137
[0.606250] dyndbg:   align 3 5: 117
[0.606652] dyndbg:   align 3 6: 124
[0.607183] dyndbg:   align 3 7: 146
[0.608669] dyndbg: earlyprintk="serial,ttyS0,115200"

This means low order bits are unavailable for encoding extra info, as
is done in struct static_key.

Consider the last lines of /proc/dynamic_debug/control, here with
matching fields replaced by '^'.  The pattern here is common head(s)
& differing tail(s).

init/main.c main run_init_process "%s\012" 1339
^ ^ ^ "  with environment:\012" 1337
^ ^ ^ "%s\012" 1336
^ ^ ^ "  with arguments:\012" 1334
^ ^ initcall_blacklisted "initcall %s blacklisted\012" 1123
^ ^ initcall_blacklist "blacklisting initcall %s\012" 1084

struct ddebug_callsite fields [mod, file, func, format] are 4-tuples;
each element points at different kinds/sources of linkage data
(>name, __FILE__, __FUNC__, format-strings).

callsite-tails are 4,3,2,1-tuples, with matching heads removed.

If we can force ALIGN(2) on all those linkage data sources, then we
can use +1 to mark the Beginning-Of-Tuple (or EOT), and so distinguish
amongst the N-tuples, and reconstruct each record by copying and
changing the previous record.  Each new module block starts with a
4-tuple; the init/main example block above is a 4,1,1,1,2,2-tuple
sequence, using 11/24 of the space.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 27 ++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 5980d44ff2f8..c84efb4e036b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1079,6 +1079,13 @@ static int __init dynamic_debug_init_control(void)
return 0;
 }
 
+
+static __initdata int alignments[4][8];
+static void bump_ct(int i, const char *p)
+{
+   alignments[i][ (long)p & 7 ]++;
+}
+
 static int __init dynamic_debug_init(void)
 {
struct _ddebug *iter, *iter_start, *prev = NULL;
@@ -1087,7 +1094,9 @@ static int __init dynamic_debug_init(void)
int ret = 0;
int n = 0, entries = 0, modct = 0;
int modreps = 0, funcreps = 0, filereps = 0;
-
+   int i,k;
+   char *kind[] = { "mod","file","func","format" };
+   
if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
pr_warn("_ddebug table is empty in a 
CONFIG_DYNAMIC_DEBUG build\n");
@@ -,6 +1120,12 @@ static int __init dynamic_debug_init(void)
prev++; /* one behind iter */
}
entries++;
+
+   bump_ct(0, iter->site->modname);
+   bump_ct(1, iter->site->filename);
+   bump_ct(2, iter->site->function);
+   bump_ct(3, iter->site->format);
+
if (strcmp(modname, iter->site->modname)) {
modct++;

Re: [PATCH] locking-selftest: add option to proceed through unexpected failures

2020-11-24 Thread jim . cromie
On Tue, Nov 17, 2020 at 3:02 AM Peter Zijlstra  wrote:
>
> On Fri, Nov 13, 2020 at 04:00:48PM -0700, Jim Cromie wrote:
> > Locking selftest is currently (v.5.10-rc3) seeing 14 unexpected failures.
> > Add option to not disable debug_locks, so as to let it reveal any
> > locking flaws in new unrelated work.
>
> I'm assuming this is the arm64 fallout? Mark anything I can do to help
> you there?
>
> The reasoning doesn't make sense though; if it can't pass the selftest,
> then why would you trust any further reports?

because it knows more than I do.
having chosen to proceed anyway,
Im free to discount the advice.


[PATCH] dyndbg: fix use before null check

2020-11-23 Thread Jim Cromie
commit a2d375eda771 ("dyndbg: refine export, rename to 
dynamic_debug_exec_queries()")

Above commit copies a string before checking for null pointer, fix
this, and add a pr_err.  Also trim comment, and add return val info.

Fixes: a2d375eda771
Cc: sta...@vger.kernel.org
Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 18 --
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index bd7b3aaa93c3..711a9def8c83 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -553,17 +553,23 @@ static int ddebug_exec_queries(char *query, const char 
*modname)
  * @query: query-string described in admin-guide/dynamic-debug-howto
  * @modname: string containing module name, usually _name
  *
- * This uses the >/proc/dynamic_debug/control reader, allowing module
- * authors to modify their dynamic-debug callsites. The modname is
- * canonically struct module.mod_name, but can also be null or a
- * module-wildcard, for example: "drm*".
+ * This uses the >control reader, allowing module authors to modify
+ * their dynamic-debug callsites. The modname is canonically struct
+ * module.mod_name, but can also be null or a module-wildcard, for
+ * example: "drm*".
+ * Returns <0 on error, >=0 for callsites changed
  */
 int dynamic_debug_exec_queries(const char *query, const char *modname)
 {
int rc;
-   char *qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+   char *qry; /* writable copy of query */
 
-   if (!query)
+   if (!query) {
+   pr_err("non-null query/command string expected\n");
+   return -EINVAL;
+   }
+   qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+   if (!qry)
return -ENOMEM;
 
rc = ddebug_exec_queries(qry, modname);
-- 
2.28.0



[PATCH] locking-selftest: add option to proceed through unexpected failures

2020-11-13 Thread Jim Cromie
Locking selftest is currently (v.5.10-rc3) seeing 14 unexpected failures.
Add option to not disable debug_locks, so as to let it reveal any
locking flaws in new unrelated work.

Signed-off-by: Jim Cromie 
---
 lib/locking-selftest.c | 21 ++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/lib/locking-selftest.c b/lib/locking-selftest.c
index a899b3f0e2e5..87889bcf3232 100644
--- a/lib/locking-selftest.c
+++ b/lib/locking-selftest.c
@@ -41,6 +41,20 @@ static int __init setup_debug_locks_verbose(char *str)
 
 __setup("debug_locks_verbose=", setup_debug_locks_verbose);
 
+/*
+ * proceed thru debug fails, leave debugging enabled
+ */
+static unsigned int debug_locks_proceed;
+
+static int __init setup_debug_locks_proceed(char *str)
+{
+   get_option(, _locks_proceed);
+
+   return 1;
+}
+
+__setup("debug_locks_proceed=", setup_debug_locks_proceed);
+
 #define FAILURE0
 #define SUCCESS1
 
@@ -2480,9 +2494,10 @@ void locking_selftest(void)
 
if (unexpected_testcase_failures) {

printk("-\n");
-   debug_locks = 0;
-   printk("BUG: %3d unexpected failures (out of %3d) - debugging 
disabled! |\n",
-   unexpected_testcase_failures, testcase_total);
+   debug_locks = debug_locks_proceed;
+   printk("BUG: %3d unexpected failures (out of %3d) - debugging 
%s! |\n",
+  unexpected_testcase_failures, testcase_total,
+  (!debug_locks_proceed) ? "disabled" : "proceeding 
anyway");

printk("-\n");
} else if (expected_testcase_failures && testcase_successes) {

printk("\n");
-- 
2.28.0



Re: [PATCH 1/2] dyndbg: dont panic over bad input

2020-09-22 Thread jim . cromie
On Tue, Sep 22, 2020 at 2:08 AM Petr Mladek  wrote:
>
> On Mon 2020-09-21 13:04:32, Jim Cromie wrote:
> > This BUG_ON, from 2009, caught the impossible case of a word-char both
> > starting and ending a string (loosely speaking).  A bad (reverted)
> > patch finally hit this case, but even "impossibly bad input" is no
> > reason to panic the kernel.  Instead pr_err and return -EINVAL.
> >
> > Reported-by: Petr Mladek 
> > Signed-off-by: Jim Cromie 
> > ---
> >  lib/dynamic_debug.c | 5 -
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> > index 2d4dfd44b0fa5..90ddf07ce34fe 100644
> > --- a/lib/dynamic_debug.c
> > +++ b/lib/dynamic_debug.c
> > @@ -259,7 +259,10 @@ static int ddebug_tokenize(char *buf, char *words[], 
> > int maxwords)
> >   } else {
> >   for (end = buf; *end && !isspace(*end); end++)
> >   ;
> > - BUG_ON(end == buf);
> > + if (end == buf) {
> > + pr_err("expected non-empty bareword");
> > + return -EINVAL;
>
> My understanding is that the BUG_ON() was there to catch eventual bugs
> in the algorithm.
>
> IMHO, it was never reachable in the original code:
>
>1. The following lines will skip all spaces and bail out
>   when we reached the trailing '\0':
>
> buf = skip_spaces(buf);
> if (!*buf)
> break;  /* oh, it was trailing whitespace */
>
>
>2. The following code will find the end of a quoted text:
>
> if (*buf == '"' || *buf == '\'') {
> int quote = *buf++;
> for (end = buf; *end && *end != quote; end++)
>
>
> 3. The else part will find end of non-quoted word:
>
> } else {
> for (end = buf; *end && !isspace(*end); end++)
>
> 4. The BUG_ON() will trigger when the above cycle reached the
>trailing '\0' or space.
>
>This will never happen because this situation was caught
>in the 1st step.
>
>
> Your patch triggered the BUG_ON() because it wanted to handle
> '=' as a special character and was incomplete.
>
> If you want to handle '=' special way. You need to do it the same way
> as with the space. You need to skip it in 1st step. And it must mark
> the end of the word in 4th step.
>
> But it will be more complicated. You must be able to handle
> mix of spaces and '='. I mean the following situations:
>
> word=word
> word =word
> word= word
> word = word
> word = = word   /* failure ? */
>
>
> Back to the BUG_ON(). It might be changed to something like:
>
> pr_err("Internal error when parsing dynamic debug query\n");
> return -EINVAL;
>
>
> Best Regards,
> Petr


yes, the original patch was ill conceived

Im blaming Transient Acute Myopia,
where I couldnt see to the end of the line, where "=flags"
is a proper flag setting.

That "interferes" with using '=' to separate keyword=value.

As you outlined, its possible to implement something that handles both,
but I decided that handling keyword=value is just a convenience feature,
and isnt worth the added corner-cases and explanatory burden.


Re: [PATCH 1/2] dyndbg: dont panic over bad input

2020-09-21 Thread jim . cromie
On Mon, Sep 21, 2020 at 1:29 PM Joe Perches  wrote:
>
> On Mon, 2020-09-21 at 13:04 -0600, Jim Cromie wrote:
> > This BUG_ON, from 2009, caught the impossible case of a word-char both
> > starting and ending a string (loosely speaking).  A bad (reverted)
> > patch finally hit this case, but even "impossibly bad input" is no
> > reason to panic the kernel.  Instead pr_err and return -EINVAL.
> []
> > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
> []
> > @@ -259,7 +259,10 @@ static int ddebug_tokenize(char *buf, char *words[], 
> > int maxwords)
> >   } else {
> >   for (end = buf; *end && !isspace(*end); end++)
> >   ;
> > - BUG_ON(end == buf);
> > + if (end == buf) {
> > + pr_err("expected non-empty bareword");
>
> missing newline
>
> This message is also unintelligible.
> What is a non-empty bareword?
>
>

hmm, I borrowed the term from perl

en.wiktionary.org › wiki › bareword
(programming, chiefly Perl) A sequence of text characters in source
code that do not form a keyword nor part of a quoted string, and may
potentially be interpreted ...

basically, a not-quoted word, a keyword or not-quoted-value

Im open that there might be better terminology.
have any suggestions ?


[PATCH 0/2] dyndbg: 2 fixes/cleanups for 5.9

2020-09-21 Thread Jim Cromie
2 things which might qualify as fixes
  a bad (reverted) patch hit a BUG_ON, change that to return -EINVAL instead
  keep useful part of the reverted patch, use keyword, arg varnames

Jim Cromie (2):
  dyndbg: dont panic over bad input
  dyndbg: use keyword, arg varnames for query term pairs

 lib/dynamic_debug.c | 32 +++-
 1 file changed, 19 insertions(+), 13 deletions(-)

-- 
2.26.2



[PATCH 2/2] dyndbg: use keyword, arg varnames for query term pairs

2020-09-21 Thread Jim Cromie
optimize for clarity by replacing word[i,i+1] refs with temps.
no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 27 +++
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 90ddf07ce34fe..23e7dd967b0e6 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -387,10 +387,13 @@ static int ddebug_parse_query(char *words[], int nwords,
query->module = modname;
 
for (i = 0; i < nwords; i += 2) {
-   if (!strcmp(words[i], "func")) {
-   rc = check_set(>function, words[i+1], "func");
-   } else if (!strcmp(words[i], "file")) {
-   if (check_set(>filename, words[i+1], "file"))
+   char *keyword = words[i];
+   char *arg = words[i+1];
+
+   if (!strcmp(keyword, "func")) {
+   rc = check_set(>function, arg, "func");
+   } else if (!strcmp(keyword, "file")) {
+   if (check_set(>filename, arg, "file"))
return -EINVAL;
 
/* tail :$info is function or line-range */
@@ -406,18 +409,18 @@ static int ddebug_parse_query(char *words[], int nwords,
if (parse_linerange(query, fline))
return -EINVAL;
}
-   } else if (!strcmp(words[i], "module")) {
-   rc = check_set(>module, words[i+1], "module");
-   } else if (!strcmp(words[i], "format")) {
-   string_unescape_inplace(words[i+1], UNESCAPE_SPACE |
+   } else if (!strcmp(keyword, "module")) {
+   rc = check_set(>module, arg, "module");
+   } else if (!strcmp(keyword, "format")) {
+   string_unescape_inplace(arg, UNESCAPE_SPACE |
UNESCAPE_OCTAL |
UNESCAPE_SPECIAL);
-   rc = check_set(>format, words[i+1], "format");
-   } else if (!strcmp(words[i], "line")) {
-   if (parse_linerange(query, words[i+1]))
+   rc = check_set(>format, arg, "format");
+   } else if (!strcmp(keyword, "line")) {
+   if (parse_linerange(query, arg))
return -EINVAL;
} else {
-   pr_err("unknown keyword \"%s\"\n", words[i]);
+   pr_err("unknown keyword \"%s\"\n", keyword);
return -EINVAL;
}
if (rc)
-- 
2.26.2



[PATCH 1/2] dyndbg: dont panic over bad input

2020-09-21 Thread Jim Cromie
This BUG_ON, from 2009, caught the impossible case of a word-char both
starting and ending a string (loosely speaking).  A bad (reverted)
patch finally hit this case, but even "impossibly bad input" is no
reason to panic the kernel.  Instead pr_err and return -EINVAL.

Reported-by: Petr Mladek 
Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 2d4dfd44b0fa5..90ddf07ce34fe 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -259,7 +259,10 @@ static int ddebug_tokenize(char *buf, char *words[], int 
maxwords)
} else {
for (end = buf; *end && !isspace(*end); end++)
;
-   BUG_ON(end == buf);
+   if (end == buf) {
+   pr_err("expected non-empty bareword");
+   return -EINVAL;
+   }
}
 
/* `buf' is start of word, `end' is one past its end */
-- 
2.26.2



Re: [PATCH 1/3] net: ax88796c: ASIX AX88796C SPI Ethernet Adapter Driver

2020-09-14 Thread jim . cromie
> >
> > Please you should not be using netdev_info(). netdev_dbg() please.
> >
>
> I changed most netif_msg_*()+netdev_*() to netif_*(), including
> netif_dbg() in several places. However, after reading other drivers I
> decided to leave this at INFO level. I think this is the way to go,
> because this is what user asks for and with dynamic debug enabled users
> would have to ask for these in two different places.

dynamic_debug_exec_queries is now exported,
allowing module authors full  >control of their debug


Re: kernel BUG at /usr/src/kernel/lib/dynamic_debug.c:267!

2020-09-09 Thread jim . cromie
On Wed, Sep 9, 2020 at 6:24 AM Greg Kroah-Hartman
 wrote:
>
> On Wed, Sep 09, 2020 at 10:00:25AM +0200, Petr Mladek wrote:
> > On Wed 2020-09-09 14:47:45, Masami Hiramatsu wrote:
> > > Hi Naresh,
> > >
> > > Thanks for reporting, it seems that you have run the 
> > > kselftests/livepatch/test-livepatch.sh.
> > > Then, I think it is better to report to Livepatch maintainers too. (I 
> > > Cc'd them)
> > >
> > > Thank you,
> > >
> > > On Wed, 9 Sep 2020 10:24:09 +0530
> > > Naresh Kamboju  wrote:
> > >
> > > > While testing livepatch test cases on x86_64 with Linux next 20200908 
> > > > tag kernel
> > > > this kernel BUG noticed several times.
> > > >
> > > > metadata:
> > > >   git branch: master
> > > >   git repo: 
> > > > https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
> > > >   git commit: dff9f829e5b0181d4ed9d35aa62d695292399b54
> > > >   git describe: next-20200908
> > > > kernel-config:
> > > > http://snapshots.linaro.org/openembedded/lkft/lkft/sumo/intel-corei7-64/lkft/linux-next/853/config
> > > >
> > > > kernel BUG log,
> > > > --
> > > > [  634.063970] % rmmod test_klp_livepatch
> > > > [  634.114787] test_klp_atomic_replace: this has been live patched
> > > > [  634.121953] % echo 0 > 
> > > > /sys/kernel/livepatch/test_klp_atomic_replace/enabled
> > > > [  634.129391] livepatch: 'test_klp_atomic_replace': starting
> > > > unpatching transition
> > > > [  634.143990] livepatch: 'test_klp_atomic_replace': unpatching complete
> > > > [  634.156223] % rmmod test_klp_atomic_replace
> > > > [  634.235451] [ cut here ]
> > > > [  634.240314] kernel BUG at /usr/src/kernel/lib/dynamic_debug.c:267!
> > > > [  634.246584] invalid opcode:  [#1] SMP PTI
> > > > [  634.250955] CPU: 0 PID: 12791 Comm: test-livepatch. Tainted: G
> > > >   W K   5.9.0-rc4-next-20200908 #1
> > > > [  634.260615] Hardware name: Supermicro SYS-5019S-ML/X11SSH-F, BIOS
> > > > 2.2 05/23/2018
> > > > [  634.268007] RIP: 0010:ddebug_exec_query+0x77b/0xb90
> > > > [  634.272886] Code: 4c 89 ad 70 ff ff ff e9 db fb ff ff b8 03 00 00
> > > > 00 e9 20 fb ff ff b8 02 00 00 00 e9 16 fb ff ff b8 01 00 00 00 e9 0c
> > > > fb ff ff <0f> 0b 31 c0 e9 03 fb ff ff 49 89 f4 48 89 f7 e9 78 f9 ff ff
> > > > 8b 15
> > > > [  634.291630] RSP: 0018:9f0c80a5bd18 EFLAGS: 00010246
> > > > [  634.296856] RAX: 003d RBX:  RCX: 
> > > > 
> > > > [  634.303987] RDX: 003d RSI:  RDI: 
> > > > 90db906583ec
> > > > [  634.31] RBP: 9f0c80a5bde8 R08: 000a R09: 
> > > > 003b
> > > > [  634.318236] R10: 90db9261 R11: 0246 R12: 
> > > > 90db906583ec
> > > > [  634.325368] R13: be87cbc0 R14:  R15: 
> > > > 0004
> > > > [  634.332500] FS:  7fd37249a740() GS:90dbefa0()
> > > > knlGS:
> > > > [  634.340578] CS:  0010 DS:  ES:  CR0: 80050033
> > > > [  634.346315] CR2: 00e6d00c CR3: 00026a4b8004 CR4: 
> > > > 003706f0
> > > > [  634.353446] DR0:  DR1:  DR2: 
> > > > 
> > > > [  634.360570] DR3:  DR6: fffe0ff0 DR7: 
> > > > 0400
> > > > [  634.367693] Call Trace:
> > > > [  634.370139]  ? lock_acquire+0xa6/0x390
> > > > [  634.373892]  ? __might_fault+0x34/0x80
> > > > [  634.377648]  ddebug_exec_queries+0x6e/0x140
> > > > [  634.381831]  ddebug_proc_write+0x4b/0xa0
> > > > [  634.385756]  full_proxy_write+0x5f/0x90
> > > > [  634.389595]  vfs_write+0xed/0x240
> > > > [  634.392915]  ksys_write+0xad/0xf0
> > > > [  634.396233]  ? syscall_trace_enter+0x17a/0x240
> > > > [  634.400670]  __x64_sys_write+0x1a/0x20
> > > > [  634.404416]  do_syscall_64+0x37/0x50
> > > > [  634.407993]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> > > > [  634.413038] RIP: 0033:0x7fd371b84144
> > > > [  634.416617] Code: 89 02 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00
> > > > 00 00 00 00 66 90 48 8d 05 c1 e7 2c 00 8b 00 85 c0 75 13 b8 01 00 00
> > > > 00 0f 05 <48> 3d 00 f0 ff ff 77 54 c3 0f 1f 00 41 54 49 89 d4 55 48 89
> > > > f5 53
> > > > [  634.435362] RSP: 002b:7ffd19447658 EFLAGS: 0246 ORIG_RAX:
> > > > 0001
> > > > [  634.442928] RAX: ffda RBX: 00bc RCX: 
> > > > 7fd371b84144
> > > > [  634.450059] RDX: 00bc RSI: 00e6cf70 RDI: 
> > > > 0001
> > > > [  634.457181] RBP: 00e6cf70 R08: 00e9 R09: 
> > > > 
> > > > [  634.464305] R10: 7ffd19447c48 R11: 0246 R12: 
> > > > 7fd371e4e760
> > > > [  634.471429] R13: 00bc R14: 7fd371e49760 R15: 
> > > > 00bc
> > > > [  634.478559] Modules linked in: trace_printk sch_fq 8021q
> > > > iptable_filter xt_mark ip_tables cls_bpf sch_ingress veth algif_hash
> > > > x86_pkg_temp_thermal fuse [last 

Re: [dyndbg] 70f06a871f: kernel_BUG_at_lib/dynamic_debug.c

2020-09-07 Thread jim . cromie
Got it.
will investigate asap

On Wed, Sep 2, 2020 at 3:42 AM kernel test robot  wrote:
>
> Greeting,
>
> FYI, we noticed the following commit (built with gcc-9):
>
> commit: 70f06a871f5d40ca8f977eb412358ab03b6804da ("[PATCH v3 3/3] dyndbg: fix 
> problem parsing format="foo bar"")
> url: 
> https://github.com/0day-ci/linux/commits/Jim-Cromie/dyndbg-cleanups-for-5-9/20200901-022403
> base: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git 
> f75aef392f869018f78cfedf3c320a6b3fcfda6b
>
> in testcase: kernel-selftests
> with following parameters:
>
> group: kselftests-livepatch
>
> test-description: The kernel contains a set of "self tests" under the 
> tools/testing/selftests/ directory. These are intended to be small unit tests 
> to exercise individual code paths in the kernel.
> test-url: https://www.kernel.org/doc/Documentation/kselftest.txt
>
>
> on test machine: qemu-system-x86_64 -enable-kvm -cpu SandyBridge -smp 2 -m 8G
>
> caused below changes (please refer to attached dmesg/kmsg for entire 
> log/backtrace):
>
>
> +--+++
> |  | 12aeaa9439 | 70f06a871f |
> +--+++
> | boot_successes   | 6  | 2  |
> | boot_failures| 0  | 4  |
> | kernel_BUG_at_lib/dynamic_debug.c| 0  | 4  |
> | invalid_opcode:#[##] | 0  | 4  |
> | RIP:ddebug_exec_query| 0  | 4  |
> | Kernel_panic-not_syncing:Fatal_exception | 0  | 4  |
> +--+++
>
>
> If you fix the issue, kindly add following tag
> Reported-by: kernel test robot 
>
>
> [   78.796907] kernel BUG at lib/dynamic_debug.c:267!
> [   78.799930] invalid opcode:  [#1] PREEMPT SMP PTI
> [   78.801632] CPU: 1 PID: 1068 Comm: test-livepatch. Tainted: G  
> K   5.9.0-rc3-3-g70f06a871f5d4 #1
> [   78.803877] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 
> 1.12.0-1 04/01/2014
> [   78.805929] RIP: 0010:ddebug_exec_query+0x684/0x760
> [   78.807642] Code: 0f 85 c0 08 00 00 4c 89 7c 24 28 e9 2d fc ff ff 4c 89 fe 
> 48 8d 7c 24 10 e8 a9 f8 ff ff 85 c0 0f 84 18 fc ff ff e9 c1 07 00 00 <0f> 0b 
> 8b 15 ac 37 e2 02 85 d2 0f 85 c1 00 00 00 45 31 e4 48 c7 c6
> [   78.812169] RSP: 0018:b325411c7d78 EFLAGS: 00010246
> [   78.815411] RAX: 003d RBX: 9f4dab69286c RCX: 
> 
> [   78.821166] RDX: 003d RSI: 9f4dab692868 RDI: 
> 9f4dab69286c
> [   78.823160] RBP: 0004 R08: 9f4dab69286e R09: 
> 0001
> [   78.825172] R10:  R11: 0246 R12: 
> 0004
> [   78.827212] R13: 0004 R14:  R15: 
> 
> [   78.829228] FS:  7f024c29c740() GS:9f4e77d0() 
> knlGS:
> [   78.831343] CS:  0010 DS:  ES:  CR0: 80050033
> [   78.833243] CR2: 7f024c45c8a0 CR3: 00016836 CR4: 
> 000406e0
> [   78.835312] DR0:  DR1:  DR2: 
> 
> [   78.837371] DR3:  DR6: fffe0ff0 DR7: 
> 0400
> [   78.839398] Call Trace:
> [   78.840935]  ? __might_fault+0x36/0x80
> [   78.842574]  ddebug_exec_queries+0x6a/0x100
> [   78.844322]  ddebug_proc_write+0x4e/0x80
> [   78.845985]  full_proxy_write+0x56/0x80
> [   78.847621]  vfs_write+0xec/0x240
> [   78.849189]  ksys_write+0x68/0xe0
> [   78.850738]  do_syscall_64+0x33/0x40
> [   78.852347]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [   78.854106] RIP: 0033:0x7f024c389504
> [   78.855634] Code: 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 
> 00 00 00 48 8d 05 f9 61 0d 00 8b 00 85 c0 75 13 b8 01 00 00 00 0f 05 <48> 3d 
> 00 f0 ff ff 77 54 c3 0f 1f 00 41 54 49 89 d4 55 48 89 f5 53
> [   78.860364] RSP: 002b:7fff5962d2b8 EFLAGS: 0246 ORIG_RAX: 
> 0001
> [   78.864609] RAX: ffda RBX: 00bc RCX: 
> 7f024c389504
> [   78.866696] RDX: 00bc RSI: 5582ce63dcd0 RDI: 
> 0001
> [   78.868751] RBP: 5582ce63dcd0 R08: fff0 R09: 
> 7f024c419e80
> [   78.870832] R10: 5582ce63dd8c R11: 0246 R12: 
> 7f024c45b760
> [   78.872933] R13: 00bc R14: 7f024c456760 R15: 
> 00bc
> [   78.875077] Modules linked in: intel_rapl_msr intel_rap

[PATCH v3 1/3] dyndbg: give %3u width in pr-format, cosmetic only

2020-08-31 Thread Jim Cromie
Specify the print-width so log entries line up nicely.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 1d012e597cc3..01b7d0210412 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -947,7 +947,7 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
list_add(>link, _tables);
mutex_unlock(_lock);
 
-   v2pr_info("%u debug prints in module %s\n", n, dt->mod_name);
+   v2pr_info("%3u debug prints in module %s\n", n, dt->mod_name);
return 0;
 }
 
-- 
2.26.2



[PATCH v3 0/3] dyndbg: cleanups for 5.9

2020-08-31 Thread Jim Cromie
3 items for v5.9-rc
  fixed width format %3u in debug output - cosmetic
  fix export: ddebug_exec_queries -> dynamic_debug_exec_queries
  fix format="foo bar" parsing

Jim Cromie (3):
  dyndbg: give %3u width in pr-format, cosmetic only
  dyndbg: refine export, rename to dynamic_debug_exec_queries()
  dyndbg: fix problem parsing format="foo bar"

 include/linux/dynamic_debug.h | 20 ---
 lib/dynamic_debug.c   | 67 ++-
 2 files changed, 59 insertions(+), 28 deletions(-)

-- 
2.26.2



[PATCH v3 2/3] dyndbg: refine export, rename to dynamic_debug_exec_queries()

2020-08-31 Thread Jim Cromie
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")
---
v2- code improvements, per Joe Perches
v3- commit message fixups

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 20 
 lib/dynamic_debug.c   | 27 +--
 2 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index aa9ff9e1c0b3..8aa0c7c2608c 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -49,6 +49,10 @@ struct _ddebug {
 
 
 #if defined(CONFIG_DYNAMIC_DEBUG_CORE)
+
+/* exported for module authors to exercise >control */
+int dynamic_debug_exec_queries(const char *query, const char *modname);
+
 int ddebug_add_module(struct _ddebug *tab, unsigned int n,
const char *modname);
 extern int ddebug_remove_module(const char *mod_name);
@@ -105,7 +109,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
static_branch_unlikely(_key_false)
 #endif
 
-#else /* !HAVE_JUMP_LABEL */
+#else /* !CONFIG_JUMP_LABEL */
 
 #define _DPRINTK_KEY_INIT
 
@@ -117,7 +121,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
 #endif
 
-#endif
+#endif /* CONFIG_JUMP_LABEL */
 
 #define __dynamic_func_call(id, fmt, func, ...) do {   \
DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt); \
@@ -172,10 +176,11 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
   KERN_DEBUG, prefix_str, prefix_type, \
   rowsize, groupsize, buf, len, ascii)
 
-#else
+#else /* !CONFIG_DYNAMIC_DEBUG_CORE */
 
 #include 
 #include 
+#include 
 
 static inline int ddebug_add_module(struct _ddebug *tab, unsigned int n,
const char *modname)
@@ -210,6 +215,13 @@ static inline int ddebug_dyndbg_module_param_cb(char 
*param, char *val,
print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, \
rowsize, groupsize, buf, len, ascii);   \
} while (0)
-#endif
+
+static inline int dynamic_debug_exec_queries(const char *query, const char 
*modname)
+{
+   pr_warn("kernel not built with CONFIG_DYNAMIC_DEBUG_CORE\n");
+   return 0;
+}
+
+#endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
 
 #endif
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 01b7d0210412..08e4b057514c 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -525,7 +525,7 @@ static int ddebug_exec_query(char *query_string, const char 
*modname)
last error or number of matching callsites.  Module name is either
in param (for boot arg) or perhaps in query string.
 */
-int ddebug_exec_queries(char *query, const char *modname)
+static int ddebug_exec_queries(char *query, const char *modname)
 {
char *split;
int i, errs = 0, exitcode = 0, rc, nfound = 0;
@@ -557,7 +557,30 @@ int ddebug_exec_queries(char *query, const char *modname)
return exitcode;
return nfound;
 }
-EXPORT_SYMBOL_GPL(ddebug_exec_queries);
+
+/**
+ * dynamic_debug_exec_queries - select and change dynamic-debug prints
+ * @query: query-string described in admin-guide/dynamic-debug-howto
+ * @modname: string containing module name, usually _name
+ *
+ * This uses the >/proc/dynamic_debug/control reader, allowing module
+ * authors to modify their dynamic-debug callsites. The modname is
+ * canonically struct module.mod_name, but can also be null or a
+ * module-wildcard, for example: "drm*".
+ */
+int dynamic_debug_exec_queries(const char *query, const char *modname)
+{
+   int rc;
+   char *qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+
+   if (!query)
+   return -ENOMEM;
+
+   rc = ddebug_exec_queries(qry, modname);
+   kfree(qry);
+   return rc;
+}
+EXPORT_SYMBOL_GPL(dynamic_debug_exec_queries);
 
 #define PREFIX_SIZE 64
 
-- 
2.26.2



[PATCH v3 3/3] dyndbg: fix problem parsing format="foo bar"

2020-08-31 Thread Jim Cromie
commit 14775b049642 ("dyndbg: accept query terms like file=bar and module=foo")

added the combined keyword=value parsing poorly; revert most of it,
keeping the keyword & arg change.

Instead, fix the tokenizer for the new input, by terminating the
keyword (an unquoted word) on '=' as well as space, thus letting the
tokenizer work on the quoted argument, like it would have previously.

Also add a few debug-prints to show more parsing context, into
tokenizer and parse-query, and use "keyword, value" in others.

Fixes: 14775b049642 ("dyndbg: accept query terms like file=bar and module=foo")
---
-v3 commit message, checkpatch fixes

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 38 +-
 1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 08e4b057514c..04f4c80b0d16 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -237,6 +237,7 @@ static int ddebug_tokenize(char *buf, char *words[], int 
maxwords)
 {
int nwords = 0;
 
+   vpr_info("entry, buf:'%s'\n", buf);
while (*buf) {
char *end;
 
@@ -247,6 +248,8 @@ static int ddebug_tokenize(char *buf, char *words[], int 
maxwords)
if (*buf == '#')
break;  /* token starts comment, skip rest of line */
 
+   vpr_info("start-of-word:%d '%s'\n", nwords, buf);
+
/* find `end' of word, whitespace separated or quoted */
if (*buf == '"' || *buf == '\'') {
int quote = *buf++;
@@ -257,7 +260,9 @@ static int ddebug_tokenize(char *buf, char *words[], int 
maxwords)
return -EINVAL; /* unclosed quote */
}
} else {
-   for (end = buf; *end && !isspace(*end); end++)
+   for (end = buf;
+*end && *end != '=' && !isspace(*end);
+end++)
;
BUG_ON(end == buf);
}
@@ -373,30 +378,21 @@ static int ddebug_parse_query(char *words[], int nwords,
unsigned int i;
int rc = 0;
char *fline;
-   char *keyword, *arg;
 
-   if (modname)
+   if (nwords % 2 != 0) {
+   pr_err("expecting pairs of match-spec \n");
+   return -EINVAL;
+   }
+   if (modname) {
/* support $modname.dyndbg= */
+   vpr_info("module:%s queries:'%s'\n", modname);
query->module = modname;
+   }
+   for (i = 0; i < nwords; i += 2) {
+   char *keyword = words[i];
+   char *arg = words[i+1];
 
-   for (i = 0; i < nwords; i++) {
-   /* accept keyword=arg */
-   vpr_info("%d w:%s\n", i, words[i]);
-
-   keyword = words[i];
-   arg = strchr(keyword, '=');
-   if (arg) {
-   *arg++ = '\0';
-   } else {
-   i++; /* next word is arg */
-   if (!(i < nwords)) {
-   pr_err("missing arg to keyword: %s\n", keyword);
-   return -EINVAL;
-   }
-   arg = words[i];
-   }
-   vpr_info("%d key:%s arg:%s\n", i, keyword, arg);
-
+   vpr_info("keyword:'%s' value:'%s'\n", keyword, arg);
if (!strcmp(keyword, "func")) {
rc = check_set(>function, arg, "func");
} else if (!strcmp(keyword, "file")) {
-- 
2.26.2



[PATCH 0/4] dyndbg: POC use dynamic_debug_exec_queries in DRM

2020-08-26 Thread Jim Cromie
This patchset tests/demonstrates using dynamic_debug_exec_queries() to
alter 2 drivers' pr_debugs without a user directly using >control.

For drm.core, I copied drm.debug module parameter model, adding
drm.debug2 as a POC user interface to control 2 pr_debug additions to
drm_printk:drm_dbg,dev_dbg, allowing both category and >control to
work in parallel.  This patch makes no attempt to integrate drm's
category mechanism with the "format=^class" callsite selection; thats
the "theory", but it needs testing.

For i915/gvt, I repeated the pattern.  I focussed on gvt only, because
it had the most compelling use of format strings as pr_debug classes;
~120 pr_debugs in 9 classes.  These are mapped onto bits of the param.

bash-5.0# echo 0x0 > /sys/module/i915/parameters/debug_dyn 
[ 3137.044185] set_dyndbg: result:0x0 from 0x0
[ 3137.044185] 
[ 3137.047370] dyndbg: query 0: "format='^gvt: cmd: ' -p"
[ 3137.050302] dyndbg: entry, buf:'format='^gvt: cmd: ' -p'
[ 3137.053331] dyndbg: start-of-word:0 'format='^gvt: cmd: ' -p'

These patches were the test/use case for-59 fixes:
https://lore.kernel.org/lkml/20200825173339.2082585-1-jim.cro...@gmail.com/


Jim Cromie (4):
  drm-printk: POC caller of dynamic-debug-exec-queries
  drm-printk: call pr_debug() from drm_dev_dbg, __drm_dbg
  i915: add -DDYNAMIC_DEBUG_MODULE to i915/gvt/Makefile
  i915: POC use dynamic_debug_exec_queries to control pr_debugs in gvt

 drivers/gpu/drm/drm_print.c| 54 ++---
 drivers/gpu/drm/i915/gvt/Makefile  |  5 +-
 drivers/gpu/drm/i915/i915_params.c | 76 ++
 3 files changed, 127 insertions(+), 8 deletions(-)

-- 
2.26.2



[PATCH 4/4] i915: POC use dynamic_debug_exec_queries to control pr_debugs in gvt

2020-08-26 Thread Jim Cromie
The gvt component of this driver has ~120 pr_debugs, in 9 "classes".
Add a "knob", like drm.debug, to map bits to these classes.

bash-5.0# echo 0x01 > /sys/module/i915/parameters/debug_dyn
 set_dyndbg: result:0x1 from 0x01
 dyndbg: query 0: "format='^gvt: cmd: ' +p"
 dyndbg: entry, buf:'format='^gvt: cmd: ' +p'
 dyndbg: start-of-word:0 'format='^gvt: cmd: ' +p'
 dyndbg: start-of-word:1 ''^gvt: cmd: ' +p'
 dyndbg: start-of-word:2 '+p'
 dyndbg: split into words: "format" "^gvt: cmd: " "+p"
 dyndbg: op='+'
 dyndbg: flags=0x1
 dyndbg: *flagsp=0x1 *maskp=0x
 dyndbg: key:'format' arg:'^gvt: cmd: '
 dyndbg: parsed: func="" file="" module="i915" format="^gvt: cmd: " lineno=0-0
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:3081 
[i915]init_cmd_table =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:1376 
[i915]gen8_check_mi_display_flip =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:1373 
[i915]gen8_check_mi_display_flip =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:745 
[i915]parser_exec_state_dump =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:744 
[i915]parser_exec_state_dump =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:742 
[i915]parser_exec_state_dump =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:733 
[i915]parser_exec_state_dump =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:729 
[i915]parser_exec_state_dump =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:722 
[i915]parser_exec_state_dump =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:716 
[i915]parser_exec_state_dump =p
 dyndbg: changed drivers/gpu/drm/i915/gvt/cmd_parser.c:691 [i915]print_opcode =p
 dyndbg: applied: func="" file="" module="i915" format="^gvt: cmd: " lineno=0-0
 dyndbg: processed 1 queries, with 11 matches, 0 errs
 change ct:11 on format='gvt: cmd: '
 change ct:11

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/i915/i915_params.c | 76 ++
 1 file changed, 76 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_params.c 
b/drivers/gpu/drm/i915/i915_params.c
index 8d8db9ff0a48..4e1f01ab4865 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -255,3 +255,79 @@ void i915_params_free(struct i915_params *params)
I915_PARAMS_FOR_EACH(FREE);
 #undef FREE
 }
+
+/* POC for callback -> dynamic_debug_exec_queries */
+unsigned long __new_knob;
+EXPORT_SYMBOL(__new_knob);
+
+static char *pr_debug_classes[] = {
+   "gvt: cmd: ",
+   "gvt: core: ",
+   "gvt: dpy: ",
+   "gvt: el: ",
+   "gvt: irq: ",
+   "gvt: mm: ",
+   "gvt: mmio: ",
+   "gvt: render: ",
+   "gvt: sched: "
+};
+#define NUM_CLASSESARRAY_SIZE(pr_debug_classes)
+#define OUR_QUERY_SIZE 128 /* we need about 20 */
+
+#include 
+
+static int param_set_dyndbg(const char *instr, const struct kernel_param *kp)
+{
+   static unsigned long int old_val;
+unsigned int val;
+   unsigned long int changes, result;
+   int rc, chgct = 0, totct = 0, bitpos;
+   char query[OUR_QUERY_SIZE];
+
+   rc = kstrtouint(instr, 0, );
+   if (rc) {
+   pr_err("set_dyndbg: failed\n");
+   return -EINVAL;
+   }
+   result = val;
+   pr_info("set_dyndbg: result:0x%lx from %s\n", result, instr);
+
+   changes = result ^ old_val;
+
+   for_each_set_bit(bitpos, , NUM_CLASSES) {
+
+   sprintf(query, "format='^%s' %cp", pr_debug_classes[bitpos],
+   test_bit(bitpos, ) ? '+' : '-');
+
+   chgct = dynamic_debug_exec_queries(query, "i915");
+   totct += chgct;
+   pr_info("change ct:%d on format='%s'\n", chgct,
+   pr_debug_classes[bitpos]);
+   }
+   old_val = result;
+   pr_info("change ct:%d\n", totct);
+   return 0;
+}
+static int param_get_dyndbg(char *buffer, const struct kernel_param *kp)
+{
+   return scnprintf(buffer, PAGE_SIZE, "%u\n",
+*((unsigned int *)kp->arg));
+}
+static const struct kernel_param_ops param_ops_dyndbg = {
+   .set = param_set_dyndbg,
+   .get = param_get_dyndbg,
+};
+
+MODULE_PARM_DESC(debug_dyn, " enable dynamic-debug by format-string 
classifications.\n"
+"\t\twhich are:"
+"\n\t\t gvt: cmd:"
+"\n\t\t gvt: core:"
+"\n\t\t gvt: dpy:"
+"\n\t\t gvt: el:"
+"\n\t\t gvt: irq:"
+"\n\t\t gvt: mm:"
+"\n\t\t gvt: mmio:"
+"\n\t\t gvt: render:"
+"\n\t\t gvt: sched:" "\n");
+
+module_param_cb(debug_dyn, _ops_dyndbg, &__new_knob, 0644);
-- 
2.26.2



[PATCH 1/4] drm-printk: POC caller of dynamic-debug-exec-queries

2020-08-26 Thread Jim Cromie
Export of dynamic-debug-exec-queries exists for users like drm.

This commit is a 1st user-test; it adds a 2nd knob, __drm_debug2,
similar in function to __drm_debug.  module_param_cb wires it to a
callback which maps the input value to one of: "module=drm* +/-p".

The include is needed to see the exported function prototype.

Notes:

The define DEBUG at top of drm-printk enables all pr_debug()s,
independent of CONFIG_DYNAMIC_DEBUG_CORE.

drm-printk is an independent print control system using __drm_debug
bits.  The plan is to find the low-level macros in which to insert a
pr_debug call, their eventual callsites will have distinct METADATA,
so will be itemized in control, and individually selectable.

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/drm_print.c | 35 +++
 1 file changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c
index 111b932cf2a9..52abaf2ae053 100644
--- a/drivers/gpu/drm/drm_print.c
+++ b/drivers/gpu/drm/drm_print.c
@@ -27,6 +27,7 @@
 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -54,6 +55,40 @@ MODULE_PARM_DESC(debug, "Enable debug output, where each bit 
enables a debug cat
 "\t\tBit 8 (0x100) will enable DP messages (displayport code)");
 module_param_named(debug, __drm_debug, int, 0600);
 
+/* POC for callback -> ddebug_exec_queries */
+unsigned int __drm_debug2;
+EXPORT_SYMBOL(__drm_debug2);
+
+static int param_set_dyndbg(const char *val, const struct kernel_param *kp)
+{
+   int chgct, result;
+
+   result = kstrtouint(val, 0, (unsigned int *)kp->arg);
+   pr_warn("set_dyndbg: result:%d from %s\n", result, val);
+
+   if (result)
+   chgct = dynamic_debug_exec_queries("module=drm* +p", NULL);
+   else
+   chgct = dynamic_debug_exec_queries("module=drm* -p", NULL);
+
+   pr_warn("change ct:%d\n", chgct);
+   return 0;
+}
+static int param_get_dyndbg(char *buffer, const struct kernel_param *kp)
+{
+   return scnprintf(buffer, PAGE_SIZE, "%u\n",
+*((unsigned int *)kp->arg));
+}
+static const struct kernel_param_ops param_ops_dyndbg = {
+   .set = param_set_dyndbg,
+   .get = param_get_dyndbg,
+};
+
+MODULE_PARM_DESC(debug_dyn, "Enable debug output, where each bit enables a 
debug category.\n"
+"\t\tthese wont work yet\n");
+module_param_cb(debug_dyn, _ops_dyndbg, &__drm_debug2, 0644);
+
+
 void __drm_puts_coredump(struct drm_printer *p, const char *str)
 {
struct drm_print_iterator *iterator = p->arg;
-- 
2.26.2



[PATCH 2/4] drm-printk: call pr_debug() from drm_dev_dbg, __drm_dbg

2020-08-26 Thread Jim Cromie
Put the pr_debug() after the vaf setup work, so as to use it.  And
move the if-category-disabled-return after both, so the pr_debug()
runs unconditionally.

This lets both debug-printers execute independently, according to
their respective controls, allowing later comparison to each other.

 #> echo module=drm +pmftl > /proc/dynamic_debug/control
yields logging like:

 [1772] drm:drm_dev_dbg:305: i915 :00:02.0: 
[drm:intel_atomic_get_global_obj_state [i915]]
   Cat:16 Added new global object 6fa51dd6 state bbddcf9d to 
5f6e1bc3
 [1772] drm:drm_dev_dbg:305: i915 :00:02.0: 
[drm:intel_atomic_get_global_obj_state [i915]]
   Cat:16 Added new global object 2a5e020a state 2b3685ed to 
5f6e1bc3
 [198] drm:drm_dev_dbg:305: i915 :00:02.0: [drm:drm_update_vblank_count 
[drm]]
   Cat:32 updating vblank count on crtc 0: current=260920, diff=0, hw=192024 
hw_last=192024
 [1772] drm:__drm_dbg:331: [drm:drm_atomic_nonblocking_commit [drm]] Cat:16 
committing 5f6e1bc3 nonblocking
 [1772] drm:__drm_dbg:331: [drm:drm_mode_object_put.part.0 [drm]] Cat:1 OBJ ID: 
113 (4)
 [1772] drm:__drm_dbg:331: [drm:drm_ioctl [drm]] Cat:1 comm="gnome-shell" 
pid=1772, dev=0xe200, auth=1, I915_GEM_CREATE
 [1772] drm:__drm_dbg:331: [drm:drm_ioctl [drm]] Cat:1 comm="gnome-shell" 
pid=1772, dev=0xe200, auth=1, I915_GEM_SET_DOMAIN
 [1772] drm:__drm_dbg:331: [drm:drm_ioctl [drm]] Cat:1 comm="gnome-shell" 
pid=1772, dev=0xe200, auth=1, I915_GEM_SET_TILING
 [1772] drm:__drm_dbg:331: [drm:drm_ioctl [drm]] Cat:1 comm="gnome-shell" 
pid=1772, dev=0xe200, auth=1, I915_GEM_MMAP_OFFSET

Clearly, the mflt flags arent very helpful here, and callsite control
is all or nothing (since theres only 2 callsites handling all the
categories).  We are 1 below the function layer of interest, but
theres room for optimism.

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/drm_print.c | 27 +--
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c
index 52abaf2ae053..fa2bcf4ec475 100644
--- a/drivers/gpu/drm/drm_print.c
+++ b/drivers/gpu/drm/drm_print.c
@@ -27,6 +27,7 @@
 
 #include 
 
+#define DYNAMIC_DEBUG_MODULE
 #include 
 #include 
 #include 
@@ -61,17 +62,17 @@ EXPORT_SYMBOL(__drm_debug2);
 
 static int param_set_dyndbg(const char *val, const struct kernel_param *kp)
 {
-   int chgct, result;
+   int chgct, rc, result;
 
-   result = kstrtouint(val, 0, (unsigned int *)kp->arg);
-   pr_warn("set_dyndbg: result:%d from %s\n", result, val);
+   rc = kstrtouint(val, 0, );
+   pr_debug("set_dyndbg: rc:%d got:%d from %s\n", rc, result, val);
 
if (result)
chgct = dynamic_debug_exec_queries("module=drm* +p", NULL);
else
chgct = dynamic_debug_exec_queries("module=drm* -p", NULL);
 
-   pr_warn("change ct:%d\n", chgct);
+   pr_debug("change ct:%d\n", chgct);
return 0;
 }
 static int param_get_dyndbg(char *buffer, const struct kernel_param *kp)
@@ -297,13 +298,16 @@ void drm_dev_dbg(const struct device *dev, enum 
drm_debug_category category,
struct va_format vaf;
va_list args;
 
-   if (!drm_debug_enabled(category))
-   return;
-
va_start(args, format);
vaf.fmt = format;
vaf.va = 
 
+   dev_dbg(dev, "[" DRM_NAME ":%ps] Cat:%d %pV",
+   __builtin_return_address(0), category, );
+
+   if (!drm_debug_enabled(category))
+   return;
+
if (dev)
dev_printk(KERN_DEBUG, dev, "[" DRM_NAME ":%ps] %pV",
   __builtin_return_address(0), );
@@ -320,13 +324,16 @@ void __drm_dbg(enum drm_debug_category category, const 
char *format, ...)
struct va_format vaf;
va_list args;
 
-   if (!drm_debug_enabled(category))
-   return;
-
va_start(args, format);
vaf.fmt = format;
vaf.va = 
 
+   pr_debug("[" DRM_NAME ":%ps] Cat:%d %pV",
+__builtin_return_address(0), category, );
+
+   if (!drm_debug_enabled(category))
+   return;
+
printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
   __builtin_return_address(0), );
 
-- 
2.26.2



[PATCH 3/4] i915: add -DDYNAMIC_DEBUG_MODULE to i915/gvt/Makefile

2020-08-26 Thread Jim Cromie
This addition to cflags enables dyndbg in the gvt component of the
i915 module, on a CONFIG_DYNAMIC_DEBUG_CORE build.

So here are the message classifications that the gvt driver uses.

   cut -d= -f2 | cut -d\  -f2,3 | \
   perl -ne 'chomp $_ && $h{$_}++; END{print "$_\" \tseen $h{$_}\n" for sort 
keys %h}'

"gvt: cmd:" seen 11
"gvt: core:"seen 48
"gvt: dpy:" seen 4
"gvt: el:"  seen 21
"gvt: irq:" seen 1
"gvt: mm:"  seen 6
"gvt: mmio:"seen 9
"gvt: render:"  seen 1
"gvt: sched:"   seen 15

Signed-off-by: Jim Cromie 
---
 drivers/gpu/drm/i915/gvt/Makefile | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/gvt/Makefile 
b/drivers/gpu/drm/i915/gvt/Makefile
index ea8324abc784..2c581e910688 100644
--- a/drivers/gpu/drm/i915/gvt/Makefile
+++ b/drivers/gpu/drm/i915/gvt/Makefile
@@ -5,5 +5,6 @@ GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o 
trace_points.o firmware.o \
execlist.o scheduler.o sched_policy.o mmio_context.o cmd_parser.o 
debugfs.o \
fb_decoder.o dmabuf.o page_track.o
 
-ccflags-y  += -I $(srctree)/$(src) -I 
$(srctree)/$(src)/$(GVT_DIR)/
-i915-y += $(addprefix $(GVT_DIR)/, 
$(GVT_SOURCE))
+ccflags-y  += -I $(srctree)/$(src) -I $(srctree)/$(src)/$(GVT_DIR)/
+ccflags-y  += -DDYNAMIC_DEBUG_MODULE
+i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
-- 
2.26.2



[PATCH v2 3/3] dyndbg: fix problem parsing format="foo bar"

2020-08-25 Thread Jim Cromie
 14775b049642 dyndbg: accept query terms like file=bar and module=foo

That commit broke on a tokenization modality where a word could start
with a quote, but couldnt continue with one.  So the above would
tokenize as 'format="foo' and 'bar"', and fail hard.

This commit fixes the tokenizer by terminating an unquoted token on
the '=', avoiding that problem.  And since ddebug-parse-query will
never see a combined 'keyword=value', revert those parts of the
previous commit.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 33 ++---
 1 file changed, 14 insertions(+), 19 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index a23b5d153153..04b851117eeb 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -237,6 +237,7 @@ static int ddebug_tokenize(char *buf, char *words[], int 
maxwords)
 {
int nwords = 0;
 
+   vpr_info("entry, buf:'%s'\n", buf);
while (*buf) {
char *end;
 
@@ -247,6 +248,8 @@ static int ddebug_tokenize(char *buf, char *words[], int 
maxwords)
if (*buf == '#')
break;  /* token starts comment, skip rest of line */
 
+   vpr_info("start-of-word:%d '%s'\n", nwords, buf);
+
/* find `end' of word, whitespace separated or quoted */
if (*buf == '"' || *buf == '\'') {
int quote = *buf++;
@@ -257,7 +260,9 @@ static int ddebug_tokenize(char *buf, char *words[], int 
maxwords)
return -EINVAL; /* unclosed quote */
}
} else {
-   for (end = buf; *end && !isspace(*end); end++)
+   for (end = buf;
+*end && *end != '=' && !isspace(*end);
+end++)
;
BUG_ON(end == buf);
}
@@ -373,30 +378,20 @@ static int ddebug_parse_query(char *words[], int nwords,
unsigned int i;
int rc = 0;
char *fline;
-   char *keyword, *arg;
 
+   if (nwords % 2 != 0) {
+   pr_err("expecting pairs of match-spec \n");
+   return -EINVAL;
+   }
if (modname)
/* support $modname.dyndbg= */
query->module = modname;
 
-   for (i = 0; i < nwords; i++) {
-   /* accept keyword=arg */
-   vpr_info("%d w:%s\n", i, words[i]);
-
-   keyword = words[i];
-   arg = strchr(keyword, '=');
-   if (arg) {
-   *arg++ = '\0';
-   } else {
-   i++; /* next word is arg */
-   if (!(i < nwords)) {
-   pr_err("missing arg to keyword: %s\n", keyword);
-   return -EINVAL;
-   }
-   arg = words[i];
-   }
-   vpr_info("%d key:%s arg:%s\n", i, keyword, arg);
+   for (i = 0; i < nwords; i+=2) {
+   char *keyword = words[i];
+   char *arg = words[i+1];
 
+   vpr_info("key:'%s' arg:'%s'\n", keyword, arg);
if (!strcmp(keyword, "func")) {
rc = check_set(>function, arg, "func");
} else if (!strcmp(keyword, "file")) {
-- 
2.26.2



[PATCH-v2 0/3] dynamic-debug fixups for 5.9

2020-08-25 Thread Jim Cromie
 - fix new export name, with a wrapper for more utility.
   now with fixes per Joe Perches
 - parse format="foo bar" like "format" "foo bar"
 - pretty-print

Jim Cromie (3):
  dyndbg: give %3u width in pr-format, cosmetic only
  dyndbg: refine export, rename to dynamic_debug_exec_queries()
  dyndbg: fix problem parsing format="foo bar"

 include/linux/dynamic_debug.h | 20 +---
 lib/dynamic_debug.c   | 59 ++-
 2 files changed, 53 insertions(+), 26 deletions(-)

-- 
2.26.2



[PATCH v2 1/3] dyndbg: give %3u width in pr-format, cosmetic only

2020-08-25 Thread Jim Cromie
Specify the print-width so log entries line up nicely.

no functional changes.

Signed-off-by: Jim Cromie 
---
 lib/dynamic_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 1d012e597cc3..01b7d0210412 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -947,7 +947,7 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
list_add(>link, _tables);
mutex_unlock(_lock);
 
-   v2pr_info("%u debug prints in module %s\n", n, dt->mod_name);
+   v2pr_info("%3u debug prints in module %s\n", n, dt->mod_name);
return 0;
 }
 
-- 
2.26.2



[PATCH v2 2/3] dyndbg: refine export, rename to dynamic_debug_exec_queries()

2020-08-25 Thread Jim Cromie
commit 59cf47e7df31 dyndbg: export ddebug_exec_queries
left a few configs broken, fix them with ifdef stub-fns.

Rename the export to dynamic_debug_exec_queries().  This is a more
canonical function name, instead of exposing the 'ddebug' internal
name prefix.  Do this now, before export hits v5.9.0

Implement as new function wrapping ddebug_exec_queries(now static
again), which copies the query-string, preserving ddebug_exec_queries'
in-place parsing, while allowing users to pass const strings.

--
v2- fixes per Joe Perches

Signed-off-by: Jim Cromie 
---
 include/linux/dynamic_debug.h | 20 
 lib/dynamic_debug.c   | 26 --
 2 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index aa9ff9e1c0b3..8aa0c7c2608c 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -49,6 +49,10 @@ struct _ddebug {
 
 
 #if defined(CONFIG_DYNAMIC_DEBUG_CORE)
+
+/* exported for module authors to exercise >control */
+int dynamic_debug_exec_queries(const char *query, const char *modname);
+
 int ddebug_add_module(struct _ddebug *tab, unsigned int n,
const char *modname);
 extern int ddebug_remove_module(const char *mod_name);
@@ -105,7 +109,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
static_branch_unlikely(_key_false)
 #endif
 
-#else /* !HAVE_JUMP_LABEL */
+#else /* !CONFIG_JUMP_LABEL */
 
 #define _DPRINTK_KEY_INIT
 
@@ -117,7 +121,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)
 #endif
 
-#endif
+#endif /* CONFIG_JUMP_LABEL */
 
 #define __dynamic_func_call(id, fmt, func, ...) do {   \
DEFINE_DYNAMIC_DEBUG_METADATA(id, fmt); \
@@ -172,10 +176,11 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
   KERN_DEBUG, prefix_str, prefix_type, \
   rowsize, groupsize, buf, len, ascii)
 
-#else
+#else /* !CONFIG_DYNAMIC_DEBUG_CORE */
 
 #include 
 #include 
+#include 
 
 static inline int ddebug_add_module(struct _ddebug *tab, unsigned int n,
const char *modname)
@@ -210,6 +215,13 @@ static inline int ddebug_dyndbg_module_param_cb(char 
*param, char *val,
print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, \
rowsize, groupsize, buf, len, ascii);   \
} while (0)
-#endif
+
+static inline int dynamic_debug_exec_queries(const char *query, const char 
*modname)
+{
+   pr_warn("kernel not built with CONFIG_DYNAMIC_DEBUG_CORE\n");
+   return 0;
+}
+
+#endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
 
 #endif
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 01b7d0210412..a23b5d153153 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -525,7 +525,7 @@ static int ddebug_exec_query(char *query_string, const char 
*modname)
last error or number of matching callsites.  Module name is either
in param (for boot arg) or perhaps in query string.
 */
-int ddebug_exec_queries(char *query, const char *modname)
+static int ddebug_exec_queries(char *query, const char *modname)
 {
char *split;
int i, errs = 0, exitcode = 0, rc, nfound = 0;
@@ -557,7 +557,29 @@ int ddebug_exec_queries(char *query, const char *modname)
return exitcode;
return nfound;
 }
-EXPORT_SYMBOL_GPL(ddebug_exec_queries);
+
+/**
+ * dynamic_debug_exec_queries - select and change dynamic-debug prints
+ * @query: query-string described in admin-guide/dynamic-debug-howto
+ * @modname: string containing module name, usually _name
+ *
+ * This uses the >/proc/dynamic_debug/control reader, allowing module
+ * authors to modify their dynamic-debug callsites. The modname is
+ * canonically struct module.mod_name, but can also be null or a
+ * module-wildcard, for example: "drm*".
+ */
+int dynamic_debug_exec_queries(const char *query, const char *modname)
+{
+   int rc;
+   char *qry = kstrndup(query, PAGE_SIZE, GFP_KERNEL);
+   if (!query)
+   return -ENOMEM;
+
+   rc = ddebug_exec_queries(qry, modname);
+   kfree(qry);
+   return rc;
+}
+EXPORT_SYMBOL_GPL(dynamic_debug_exec_queries);
 
 #define PREFIX_SIZE 64
 
-- 
2.26.2



  1   2   3   4   >