2022-08-11 17:41:42

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 00/11] DYNAMIC_DEBUG for this cycle

Hi Greg, Jason,

Please consider these for this rc-cycle.
- 1-9 have Jason's Ack,
- 9th removes unused EXPORTed fn.
- 10 is simple var cleanup
- 11 is a partial decoupling of dyndbg from kernel/module

Jim Cromie (11):
dyndbg: fix static_branch manipulation
dyndbg: fix module.dyndbg handling
dyndbg: show both old and new in change-info
dyndbg: reverse module walk in cat control
dyndbg: reverse module.callsite walk in cat control
dyndbg: use ESCAPE_SPACE for cat control
dyndbg: let query-modname override actual module name
dyndbg: add test_dynamic_debug module
dyndbg: drop EXPORTed dynamic_debug_exec_queries
dyndbg: cleanup auto vars in dynamic_debug_init
dyndbg: create and use struct _ddebug_info

MAINTAINERS | 2 +
include/linux/dynamic_debug.h | 22 ++----
kernel/module/internal.h | 4 +-
kernel/module/main.c | 18 ++---
lib/Kconfig.debug | 10 +++
lib/Makefile | 1 +
lib/dynamic_debug.c | 141 +++++++++++++++++-----------------
lib/test_dynamic_debug.c | 70 +++++++++++++++++
8 files changed, 172 insertions(+), 96 deletions(-)
create mode 100644 lib/test_dynamic_debug.c

--
2.37.1


2022-08-11 17:41:42

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 01/11] dyndbg: fix static_branch manipulation

In https://lore.kernel.org/lkml/[email protected]/

Vincent's patch commented on, and worked around, a bug toggling
static_branch's, when a 2nd PRINTK-ish flag was added. The bug
results in a premature static_branch_disable when the 1st of 2 flags
was disabled.

The cited commit computed newflags, but then in the JUMP_LABEL block,
failed to use that result, instead using just one of the terms in it.
Using newflags instead made the code work properly.

This is Vincents test-case, reduced. It needs the 2nd flag to
demonstrate the bug, but it's explanatory here.

pt_test() {
echo 5 > /sys/module/dynamic_debug/verbose

site="module tcp" # just one callsite
echo " $site =_ " > /proc/dynamic_debug/control # clear it

# A B ~A ~B
for flg in +T +p "-T #broke here" -p; do
echo " $site $flg " > /proc/dynamic_debug/control
done;

# A B ~B ~A
for flg in +T +p "-p #broke here" -T; do
echo " $site $flg " > /proc/dynamic_debug/control
done
}
pt_test

Fixes: 84da83a6ffc0 dyndbg: combine flags & mask into a struct, simplify with it
CC: [email protected]
Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
.drop @stable, no exposed bug.
.add jbaron ack
---
lib/dynamic_debug.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index dd7f56af9aed..a56c1286ffa4 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -211,10 +211,11 @@ static int ddebug_change(const struct ddebug_query *query,
continue;
#ifdef CONFIG_JUMP_LABEL
if (dp->flags & _DPRINTK_FLAGS_PRINT) {
- if (!(modifiers->flags & _DPRINTK_FLAGS_PRINT))
+ if (!(newflags & _DPRINTK_FLAGS_PRINT))
static_branch_disable(&dp->key.dd_key_true);
- } else if (modifiers->flags & _DPRINTK_FLAGS_PRINT)
+ } else if (newflags & _DPRINTK_FLAGS_PRINT) {
static_branch_enable(&dp->key.dd_key_true);
+ }
#endif
dp->flags = newflags;
v4pr_info("changed %s:%d [%s]%s =%s\n",
--
2.37.1

2022-08-11 17:41:54

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 04/11] dyndbg: reverse module walk in cat control

/proc/dynamic_debug/control walks the prdbg catalog in "reverse",
fix this by adding new ddebug_tables to tail of list.

This puts init/main.c entries 1st, which looks more than coincidental.

no functional changes.

Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
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 8faf584f2f4b..7fb99492c16f 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -970,7 +970,7 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
dt->ddebugs = tab;

mutex_lock(&ddebug_lock);
- list_add(&dt->link, &ddebug_tables);
+ list_add_tail(&dt->link, &ddebug_tables);
mutex_unlock(&ddebug_lock);

vpr_info("%3u debug prints in module %s\n", n, dt->mod_name);
--
2.37.1

2022-08-11 17:41:57

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 05/11] dyndbg: reverse module.callsite walk in cat control

Walk the module's vector of callsites backwards; ie N..0. This
"corrects" the backwards appearance of a module's prdbg vector when
walked 0..N. I think this is due to linker mechanics, which I'm
inclined to treat as immutable, and the order is fixable in display.

No functional changes.

Combined with previous commit, which reversed tables-list, we get:

:#> head -n7 /proc/dynamic_debug/control
# filename:lineno [module]function flags format
init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\012"
init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\012"
init/main.c:1424 [main]run_init_process =_ " with arguments:\012"
init/main.c:1426 [main]run_init_process =_ " %s\012"
init/main.c:1427 [main]run_init_process =_ " with environment:\012"
init/main.c:1429 [main]run_init_process =_ " %s\012"

Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
lib/dynamic_debug.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 7fb99492c16f..8ff11977b8bd 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -59,7 +59,7 @@ struct ddebug_query {

struct ddebug_iter {
struct ddebug_table *table;
- unsigned int idx;
+ int idx;
};

struct flag_settings {
@@ -805,13 +805,12 @@ static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter)
{
if (list_empty(&ddebug_tables)) {
iter->table = NULL;
- iter->idx = 0;
return NULL;
}
iter->table = list_entry(ddebug_tables.next,
struct ddebug_table, link);
- iter->idx = 0;
- return &iter->table->ddebugs[iter->idx];
+ iter->idx = iter->table->num_ddebugs;
+ return &iter->table->ddebugs[--iter->idx];
}

/*
@@ -824,15 +823,16 @@ static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter)
{
if (iter->table == NULL)
return NULL;
- if (++iter->idx == iter->table->num_ddebugs) {
+ if (--iter->idx < 0) {
/* iterate to next table */
- iter->idx = 0;
if (list_is_last(&iter->table->link, &ddebug_tables)) {
iter->table = NULL;
return NULL;
}
iter->table = list_entry(iter->table->link.next,
struct ddebug_table, link);
+ iter->idx = iter->table->num_ddebugs;
+ --iter->idx;
}
return &iter->table->ddebugs[iter->idx];
}
--
2.37.1

2022-08-11 17:41:59

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 08/11] dyndbg: add test_dynamic_debug module

Provide a simple module to allow testing DYNAMIC_DEBUG behavior. It
calls do_prints() from module-init, and with a sysfs-node.

dmesg -C
dmesg -w &
modprobe test_dynamic_debug dyndbg=+p
echo 1 > /sys/module/dynamic_debug/parameters/verbose

cat /sys/module/test_dynamic_debug/parameters/do_prints
echo module test_dynamic_debug +mftl > /proc/dynamic_debug/control
echo junk > /sys/module/test_dynamic_debug/parameters/do_prints

Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
MAINTAINERS | 2 ++
lib/Kconfig.debug | 10 ++++++
lib/Makefile | 1 +
lib/test_dynamic_debug.c | 70 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 83 insertions(+)
create mode 100644 lib/test_dynamic_debug.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 64379c699903..a14fc4b6a10b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7093,6 +7093,8 @@ M: Jason Baron <[email protected]>
S: Maintained
F: include/linux/dynamic_debug.h
F: lib/dynamic_debug.c
+M: Jim Cromie <[email protected]>
+F: lib/test_dynamic_debug.c

DYNAMIC INTERRUPT MODERATION
M: Tal Gilboa <[email protected]>
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2e24db4bff19..ca5978e1d18a 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2529,6 +2529,16 @@ config TEST_STATIC_KEYS

If unsure, say N.

+config TEST_DYNAMIC_DEBUG
+ tristate "Test DYNAMIC_DEBUG"
+ depends on DYNAMIC_DEBUG
+ help
+ This module registers a tracer callback to count enabled
+ pr_debugs in a 'do_debugging' function, then alters their
+ enablements, calls the function, and compares counts.
+
+ If unsure, say N.
+
config TEST_KMOD
tristate "kmod stress tester"
depends on m
diff --git a/lib/Makefile b/lib/Makefile
index f99bf61f8bbc..9c316df868de 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_TEST_SORT) += test_sort.o
obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
+obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
obj-$(CONFIG_TEST_PRINTF) += test_printf.o
obj-$(CONFIG_TEST_SCANF) += test_scanf.o
obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
new file mode 100644
index 000000000000..ba3882ca3e48
--- /dev/null
+++ b/lib/test_dynamic_debug.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Kernel module for testing dynamic_debug
+ *
+ * Authors:
+ * Jim Cromie <[email protected]>
+ */
+
+#define pr_fmt(fmt) "test_dd: " fmt
+
+#include <linux/module.h>
+
+static void do_prints(void); /* device under test */
+
+/* run tests by reading or writing sysfs node */
+
+static int param_set_do_prints(const char *instr, const struct kernel_param *kp)
+{
+ do_prints();
+ return 0;
+}
+
+static int param_get_do_prints(char *buffer, const struct kernel_param *kp)
+{
+ do_prints();
+ return scnprintf(buffer, PAGE_SIZE, "did do_prints\n");
+}
+
+static const struct kernel_param_ops param_ops_do_prints = {
+ .set = param_set_do_prints,
+ .get = param_get_do_prints,
+};
+
+module_param_cb(do_prints, &param_ops_do_prints, NULL, 0600);
+
+static void do_alpha(void)
+{
+ pr_debug("do alpha\n");
+}
+static void do_beta(void)
+{
+ pr_debug("do beta\n");
+}
+
+static void do_prints(void)
+{
+ do_alpha();
+ do_beta();
+}
+
+static int __init test_dynamic_debug_init(void)
+{
+ pr_debug("init start\n");
+
+ do_prints();
+
+ pr_debug("init done\n");
+ return 0;
+}
+
+static void __exit test_dynamic_debug_exit(void)
+{
+ pr_debug("exiting\n");
+}
+
+module_init(test_dynamic_debug_init);
+module_exit(test_dynamic_debug_exit);
+
+MODULE_AUTHOR("Jim Cromie <[email protected]>");
+MODULE_LICENSE("GPL");
--
2.37.1

2022-08-11 17:41:59

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 07/11] dyndbg: let query-modname override actual module name

dyndbg's control-parser: ddebug_parse_query(), requires that search
terms: module, func, file, lineno, are used only once in a query; a
thing cannot be named both foo and bar.

The cited commit added an overriding module modname, taken from the
module loader, which is authoritative. So it set query.module 1st,
which disallowed its use in the query-string.

But now, its useful to allow a module-load to enable classes across a
whole (or part of) a subsystem at once.

# enable (dynamic-debug in) drm only
modprobe drm dyndbg="class DRM_UT_CORE +p"

# get drm_helper too
modprobe drm dyndbg="class DRM_UT_CORE module drm* +p"

# get everything that knows DRM_UT_CORE
modprobe drm dyndbg="class DRM_UT_CORE module * +p"

# also for boot-args:
drm.dyndbg="class DRM_UT_CORE module * +p"

So convert the override into a default, by filling it only when/after
the query-string omitted the module.

NB: the query class FOO handling is forthcoming.

Fixes: 8e59b5cfb9a6 dynamic_debug: add modname arg to exec_query callchain
Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
lib/dynamic_debug.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index e5cbe603000c..5a849716220a 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -385,10 +385,6 @@ static int ddebug_parse_query(char *words[], int nwords,
return -EINVAL;
}

- if (modname)
- /* support $modname.dyndbg=<multiple queries> */
- query->module = modname;
-
for (i = 0; i < nwords; i += 2) {
char *keyword = words[i];
char *arg = words[i+1];
@@ -429,6 +425,13 @@ static int ddebug_parse_query(char *words[], int nwords,
if (rc)
return rc;
}
+ if (!query->module && modname)
+ /*
+ * support $modname.dyndbg=<multiple queries>, when
+ * not given in the query itself
+ */
+ query->module = modname;
+
vpr_info_dq(query, "parsed");
return 0;
}
--
2.37.1

2022-08-11 17:41:59

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 06/11] dyndbg: use ESCAPE_SPACE for cat control

`cat control` currently does octal escape, so '\n' becomes "\012".
Change this to display as "\n" instead, which reads much cleaner.

:#> head -n7 /proc/dynamic_debug/control
# filename:lineno [module]function flags format
init/main.c:1179 [main]initcall_blacklist =_ "blacklisting initcall %s\n"
init/main.c:1218 [main]initcall_blacklisted =_ "initcall %s blacklisted\n"
init/main.c:1424 [main]run_init_process =_ " with arguments:\n"
init/main.c:1426 [main]run_init_process =_ " %s\n"
init/main.c:1427 [main]run_init_process =_ " with environment:\n"
init/main.c:1429 [main]run_init_process =_ " %s\n"

Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
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 8ff11977b8bd..e5cbe603000c 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -900,7 +900,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
trim_prefix(dp->filename), dp->lineno,
iter->table->mod_name, dp->function,
ddebug_describe_flags(dp->flags, &flags));
- seq_escape(m, dp->format, "\t\r\n\"");
+ seq_escape_str(m, dp->format, ESCAPE_SPACE, "\t\r\n\"");
seq_puts(m, "\"\n");

return 0;
--
2.37.1

2022-08-11 17:42:09

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 09/11] dyndbg: drop EXPORTed dynamic_debug_exec_queries

This exported fn is unused, and will not be needed. Lets dump it.

The export was added to let drm control pr_debugs, as part of using
them to avoid drm_debug_enabled overheads. But its better to just
implement the drm.debug bitmap interface, then its available for
everyone.

Fixes: a2d375eda771 ("dyndbg: refine export, rename to dynamic_debug_exec_queries()")
Fixes: 4c0d77828d4f ("dyndbg: export ddebug_exec_queries")
Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
include/linux/dynamic_debug.h | 9 ---------
lib/dynamic_debug.c | 29 -----------------------------
2 files changed, 38 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index f30b01aa9fa4..8d9eec5f6d8b 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -55,9 +55,6 @@ 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);
@@ -221,12 +218,6 @@ static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
rowsize, groupsize, buf, len, ascii); \
} while (0)

-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 5a849716220a..e96dc216463b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -558,35 +558,6 @@ static int ddebug_exec_queries(char *query, const char *modname)
return nfound;
}

-/**
- * 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 &module.mod_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; /* writable copy of 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);
- kfree(qry);
- return rc;
-}
-EXPORT_SYMBOL_GPL(dynamic_debug_exec_queries);
-
#define PREFIX_SIZE 64

static int remaining(int wrote)
--
2.37.1

2022-08-11 17:42:10

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 11/11] dyndbg: create and use struct _ddebug_info

this new struct gathers the linker provided vectors/sections:

descs - the vector of descriptors in __dyndbg section.
num_descs - length of the data/section

Use it as follows:

In lib/dynamic_debug.c:

Alter ddebug_add_module() params-list, replacing descriptor-table and
its length with a single _ddebug_info object containing them. This
future-proofs the function against the looming addition of class-map
info, for either the builtin module set, or the loaded module.

In dynamic_debug_init(): add & initialize an auto struct _ddebug_info
var, and use it like a cursor / multi-part iterator. Re-initialize
the var's component values before each call to ddebug_add_module().
This gives us an explicit by-module walk thru the built-in __dyndbgs
data section.

In kernel/module/{main.c,internal.h}:

Embed a struct _ddebug_info into struct load_info, replacing the 2 fields it
contains. Populate its members in find_module_sections.

Also adjust dynamic_debug_setup/remove() to match the change to
ddebug_add_module().

Note: this adds an include dynamic_debug, and might be prone to
include loops, since its also smuggled in by printk.h. Nothing has
puked in robot-land.

cc: Luis Chamberlain <[email protected]>
Signed-off-by: Jim Cromie <[email protected]>
---
include/linux/dynamic_debug.h | 13 +++++++-----
kernel/module/internal.h | 4 ++--
kernel/module/main.c | 18 ++++++++--------
lib/dynamic_debug.c | 40 +++++++++++++++++++++++++++--------
4 files changed, 50 insertions(+), 25 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 8d9eec5f6d8b..6a2001250da1 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -51,12 +51,16 @@ struct _ddebug {
#endif
} __attribute__((aligned(8)));

-
+/* encapsulate linker provided built-in (or module) dyndbg data */
+struct _ddebug_info {
+ struct _ddebug *descs;
+ unsigned int num_descs;
+};

#if defined(CONFIG_DYNAMIC_DEBUG_CORE)

-int ddebug_add_module(struct _ddebug *tab, unsigned int n,
- const char *modname);
+int ddebug_add_module(struct _ddebug_info *dyndbg, 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, ...);
@@ -184,8 +188,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
#include <linux/errno.h>
#include <linux/printk.h>

-static inline int ddebug_add_module(struct _ddebug *tab, unsigned int n,
- const char *modname)
+static inline int ddebug_add_module(struct _ddebug_info *dinfo, const char *modname)
{
return 0;
}
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index ec104c2950c3..ce42b5b8b4da 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -53,6 +53,7 @@ extern const struct kernel_symbol __stop___ksymtab_gpl[];
extern const s32 __start___kcrctab[];
extern const s32 __start___kcrctab_gpl[];

+#include <linux/dynamic_debug.h>
struct load_info {
const char *name;
/* pointer to module in temporary copy, freed at end of load_module() */
@@ -62,8 +63,7 @@ struct load_info {
Elf_Shdr *sechdrs;
char *secstrings, *strtab;
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
- struct _ddebug *debug;
- unsigned int num_debug;
+ struct _ddebug_info dyndbg;
bool sig_ok;
#ifdef CONFIG_KALLSYMS
unsigned long mod_kallsyms_init_off;
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 0548151dd933..cfe10356793d 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -1593,16 +1593,16 @@ static void free_modinfo(struct module *mod)
}
}

-static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num)
+static void dynamic_debug_setup(struct module *mod, struct _ddebug_info *dyndbg)
{
- if (!debug)
+ if (!dyndbg->num_descs)
return;
- ddebug_add_module(debug, num, mod->name);
+ ddebug_add_module(dyndbg, mod->name);
}

-static void dynamic_debug_remove(struct module *mod, struct _ddebug *debug)
+static void dynamic_debug_remove(struct module *mod, struct _ddebug_info *dyndbg)
{
- if (debug)
+ if (dyndbg->num_descs)
ddebug_remove_module(mod->name);
}

@@ -2093,8 +2093,8 @@ static int find_module_sections(struct module *mod, struct load_info *info)
if (section_addr(info, "__obsparm"))
pr_warn("%s: Ignoring obsolete parameters\n", mod->name);

- info->debug = section_objs(info, "__dyndbg",
- sizeof(*info->debug), &info->num_debug);
+ info->dyndbg.descs = section_objs(info, "__dyndbg",
+ sizeof(*info->dyndbg.descs), &info->dyndbg.num_descs);

return 0;
}
@@ -2783,7 +2783,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
}

init_build_id(mod, info);
- dynamic_debug_setup(mod, info->debug, info->num_debug);
+ dynamic_debug_setup(mod, &info->dyndbg);

/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
ftrace_module_init(mod);
@@ -2845,7 +2845,7 @@ static int load_module(struct load_info *info, const char __user *uargs,

ddebug_cleanup:
ftrace_release_mod(mod);
- dynamic_debug_remove(mod, info->debug);
+ dynamic_debug_remove(mod, &info->dyndbg);
synchronize_rcu();
kfree(mod->args);
free_arch_cleanup:
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 2e8ebef3bd0d..457ce936191a 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -923,14 +923,20 @@ 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)
+static int __ddebug_add_module(struct _ddebug_info *di, unsigned int base,
+ const char *modname)
{
struct ddebug_table *dt;

+ v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
+ if (!di->num_descs) {
+ v3pr_info(" skip %s\n", modname);
+ return 0;
+ }
+
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
if (dt == NULL) {
- pr_err("error adding module: %s\n", name);
+ pr_err("error adding module: %s\n", modname);
return -ENOMEM;
}
/*
@@ -939,18 +945,25 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
* member of struct module, which lives at least as long as
* this struct ddebug_table.
*/
- dt->mod_name = name;
- dt->num_ddebugs = n;
- dt->ddebugs = tab;
+ dt->mod_name = modname;
+ dt->ddebugs = di->descs;
+ dt->num_ddebugs = di->num_descs;
+
+ INIT_LIST_HEAD(&dt->link);

mutex_lock(&ddebug_lock);
list_add_tail(&dt->link, &ddebug_tables);
mutex_unlock(&ddebug_lock);

- vpr_info("%3u debug prints in module %s\n", n, dt->mod_name);
+ vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
return 0;
}

+int ddebug_add_module(struct _ddebug_info *di, const char *modname)
+{
+ return __ddebug_add_module(di, 0, modname);
+}
+
/* helper for ddebug_dyndbg_(boot|module)_param_cb */
static int ddebug_dyndbg_param_cb(char *param, char *val,
const char *modname, int on_err)
@@ -1064,6 +1077,11 @@ static int __init dynamic_debug_init(void)
const char *modname;
char *cmdline;

+ struct _ddebug_info di = {
+ .descs = __start___dyndbg,
+ .num_descs = __stop___dyndbg - __start___dyndbg,
+ };
+
if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n");
@@ -1082,7 +1100,9 @@ static int __init dynamic_debug_init(void)

if (strcmp(modname, iter->modname)) {
mod_ct++;
- ret = ddebug_add_module(iter_mod_start, mod_sites, modname);
+ di.num_descs = mod_sites;
+ di.descs = iter_mod_start;
+ ret = __ddebug_add_module(&di, i, modname);
if (ret)
goto out_err;

@@ -1091,7 +1111,9 @@ static int __init dynamic_debug_init(void)
iter_mod_start = iter;
}
}
- ret = ddebug_add_module(iter_mod_start, mod_sites, modname);
+ di.num_descs = mod_sites;
+ di.descs = iter_mod_start;
+ ret = __ddebug_add_module(&di, i, modname);
if (ret)
goto out_err;

--
2.37.1

2022-08-11 17:42:11

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 10/11] dyndbg: cleanup auto vars in dynamic_debug_init

rework var-names for clarity, regularity
rename variables
- n to mod_sites - it counts sites-per-module
- entries to i - display only
- iter_start to iter_mod_start - marks start of each module's subrange
- modct to mod_ct - stylistic

new iterator var:
- site - cursor parallel to iter
1st step towards 'demotion' of iter->site, for removal later

treat vars as iters:
- drop init at top
init just above for-loop, in a textual block

Signed-off-by: Jim Cromie <[email protected]>
---
lib/dynamic_debug.c | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index e96dc216463b..2e8ebef3bd0d 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1059,11 +1059,10 @@ static int __init dynamic_debug_init_control(void)

static int __init dynamic_debug_init(void)
{
- struct _ddebug *iter, *iter_start;
- const char *modname = NULL;
+ struct _ddebug *iter, *iter_mod_start;
+ int ret, i, mod_sites, mod_ct;
+ const char *modname;
char *cmdline;
- int ret = 0;
- int n = 0, entries = 0, modct = 0;

if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
@@ -1074,30 +1073,32 @@ static int __init dynamic_debug_init(void)
ddebug_init_success = 1;
return 0;
}
- iter = __start___dyndbg;
+
+ iter = iter_mod_start = __start___dyndbg;
modname = iter->modname;
- iter_start = iter;
- for (; iter < __stop___dyndbg; iter++) {
- entries++;
+ i = mod_sites = mod_ct = 0;
+
+ for (; iter < __stop___dyndbg; iter++, i++, mod_sites++) {
+
if (strcmp(modname, iter->modname)) {
- modct++;
- ret = ddebug_add_module(iter_start, n, modname);
+ mod_ct++;
+ ret = ddebug_add_module(iter_mod_start, mod_sites, modname);
if (ret)
goto out_err;
- n = 0;
+
+ mod_sites = 0;
modname = iter->modname;
- iter_start = iter;
+ iter_mod_start = iter;
}
- n++;
}
- ret = ddebug_add_module(iter_start, n, modname);
+ ret = ddebug_add_module(iter_mod_start, mod_sites, modname);
if (ret)
goto out_err;

ddebug_init_success = 1;
vpr_info("%d prdebugs in %d modules, %d KiB in ddebug tables, %d kiB in __dyndbg section\n",
- entries, modct, (int)((modct * sizeof(struct ddebug_table)) >> 10),
- (int)((entries * sizeof(struct _ddebug)) >> 10));
+ i, mod_ct, (int)((mod_ct * sizeof(struct ddebug_table)) >> 10),
+ (int)((i * sizeof(struct _ddebug)) >> 10));

/* now that ddebug tables are loaded, process all boot args
* again to find and activate queries given in dyndbg params.
--
2.37.1

2022-08-11 18:04:55

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 03/11] dyndbg: show both old and new in change-info

print "old => new" flag values to the info("change") message.

no functional change.

Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
lib/dynamic_debug.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index a56c1286ffa4..8faf584f2f4b 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -156,7 +156,7 @@ static int ddebug_change(const struct ddebug_query *query,
struct ddebug_table *dt;
unsigned int newflags;
unsigned int nfound = 0;
- struct flagsbuf fbuf;
+ struct flagsbuf fbuf, nbuf;

/* search for matching ddebugs */
mutex_lock(&ddebug_lock);
@@ -217,11 +217,12 @@ static int ddebug_change(const struct ddebug_query *query,
static_branch_enable(&dp->key.dd_key_true);
}
#endif
+ v4pr_info("changed %s:%d [%s]%s %s => %s\n",
+ trim_prefix(dp->filename), dp->lineno,
+ dt->mod_name, dp->function,
+ ddebug_describe_flags(dp->flags, &fbuf),
+ ddebug_describe_flags(newflags, &nbuf));
dp->flags = newflags;
- v4pr_info("changed %s:%d [%s]%s =%s\n",
- trim_prefix(dp->filename), dp->lineno,
- dt->mod_name, dp->function,
- ddebug_describe_flags(dp->flags, &fbuf));
}
}
mutex_unlock(&ddebug_lock);
--
2.37.1

2022-08-11 18:21:25

by Jim Cromie

[permalink] [raw]
Subject: [PATCH 02/11] dyndbg: fix module.dyndbg handling

For CONFIG_DYNAMIC_DEBUG=N, the ddebug_dyndbg_module_param_cb()
stub-fn is too permissive:

bash-5.1# modprobe drm JUNKdyndbg
bash-5.1# modprobe drm dyndbgJUNK
[ 42.933220] dyndbg param is supported only in CONFIG_DYNAMIC_DEBUG builds
[ 42.937484] ACPI: bus type drm_connector registered

This caused no ill effects, because unknown parameters are either
ignored by default with an "unknown parameter" warning, or ignored
because dyndbg allows its no-effect use on non-dyndbg builds.

But since the code has an explicit feedback message, it should be
issued accurately. Fix with strcmp for exact param-name match.

Reported-by: Rasmus Villemoes <[email protected]>
Fixes: b48420c1d301 dynamic_debug: make dynamic-debug work for module initialization
Signed-off-by: Jim Cromie <[email protected]>
Acked-by: Jason Baron <[email protected]>
---
include/linux/dynamic_debug.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index dce631e678dd..f30b01aa9fa4 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -201,7 +201,7 @@ static inline int ddebug_remove_module(const char *mod)
static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
const char *modname)
{
- if (strstr(param, "dyndbg")) {
+ if (!strcmp(param, "dyndbg")) {
/* avoid pr_warn(), which wants pr_fmt() fully defined */
printk(KERN_WARNING "dyndbg param is supported only in "
"CONFIG_DYNAMIC_DEBUG builds\n");
--
2.37.1

2022-08-12 06:00:01

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 00/11] DYNAMIC_DEBUG for this cycle

On Thu, Aug 11, 2022 at 11:35:30AM -0600, Jim Cromie wrote:
> Hi Greg, Jason,
>
> Please consider these for this rc-cycle.
> - 1-9 have Jason's Ack,
> - 9th removes unused EXPORTed fn.
> - 10 is simple var cleanup
> - 11 is a partial decoupling of dyndbg from kernel/module

This is _WAY_ to late for -rc1, this stuff should have been in
linux-next already in order to have that happen, you know this :(

Unless linux-next is pulling in your tree already? Otherwise I can pick
this up into my tree after -rc1 is out for the next release after this
one (i.e. if this is going to be 5.20-rc1, it would go into 5.21-rc1.)

thanks,

greg k-h

2022-09-01 16:51:21

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 00/11] DYNAMIC_DEBUG for this cycle

On Thu, Aug 11, 2022 at 11:35:30AM -0600, Jim Cromie wrote:
> Hi Greg, Jason,
>
> Please consider these for this rc-cycle.
> - 1-9 have Jason's Ack,
> - 9th removes unused EXPORTed fn.
> - 10 is simple var cleanup
> - 11 is a partial decoupling of dyndbg from kernel/module
>
> Jim Cromie (11):
> dyndbg: fix static_branch manipulation
> dyndbg: fix module.dyndbg handling
> dyndbg: show both old and new in change-info
> dyndbg: reverse module walk in cat control
> dyndbg: reverse module.callsite walk in cat control
> dyndbg: use ESCAPE_SPACE for cat control
> dyndbg: let query-modname override actual module name
> dyndbg: add test_dynamic_debug module
> dyndbg: drop EXPORTed dynamic_debug_exec_queries
> dyndbg: cleanup auto vars in dynamic_debug_init
> dyndbg: create and use struct _ddebug_info
>
> MAINTAINERS | 2 +
> include/linux/dynamic_debug.h | 22 ++----
> kernel/module/internal.h | 4 +-
> kernel/module/main.c | 18 ++---
> lib/Kconfig.debug | 10 +++
> lib/Makefile | 1 +
> lib/dynamic_debug.c | 141 +++++++++++++++++-----------------
> lib/test_dynamic_debug.c | 70 +++++++++++++++++
> 8 files changed, 172 insertions(+), 96 deletions(-)
> create mode 100644 lib/test_dynamic_debug.c
>
> --
> 2.37.1
>

Is this still ok for linux-next now to go into 6.1-rc1?

Or does it need to be rebased?

thanks,

greg k-h