* [PATCH v4 17/25] dyndbg: macrofy a 2-index for-loop pattern
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
dynamic-debug currently has 2 __sections (__dyndbg, __dyndb_classes),
struct _ddebug_info keeps track of them both, with 2 members each:
_vec and _vec#_len.
We need to loop over these sections, with index and record pointer,
making ref to both _vec and _vec_len. This is already fiddly and
error-prone, and will get worse as we add a 3rd section.
Lets instead embed/abstract the fiddly-ness in the `for_subvec()`
macro, and avoid repeating it going forward.
This is a for-loop macro expander, so it syntactically expects to
precede either a single statement or a { block } of them, and the
usual typeof or do-while-0 tricks are unavailable to fix the
multiple-expansion warning.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
v2: move RvB after SoB
---
lib/dynamic_debug.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index b8a494835ef5..a593e040d1ae 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -149,6 +149,20 @@ static void v3pr_info_dq(const struct ddebug_query *query, const char *msg)
query->first_lineno, query->last_lineno, query->class_string);
}
+/*
+ * simplify a repeated for-loop pattern walking N steps in a T _vec
+ * member inside a struct _box. It expects int i and T *_sp to be
+ * declared in the caller.
+ * @_i: caller provided counter.
+ * @_sp: cursor into _vec, to examine each item.
+ * @_box: ptr to a struct containing @_vec member
+ * @_vec: name of a member in @_box
+ */
+#define for_subvec(_i, _sp, _box, _vec) \
+ for ((_i) = 0, (_sp) = (_box)->_vec; \
+ (_i) < (_box)->num_##_vec; \
+ (_i)++, (_sp)++) /* { block } */
+
static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
const char *class_string,
int *class_id)
@@ -156,7 +170,7 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
struct ddebug_class_map *map;
int i, idx;
- for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
+ for_subvec(i, map, dt, classes) {
idx = match_string(map->class_names, map->length, class_string);
if (idx >= 0) {
*class_id = idx + map->base;
@@ -1162,8 +1176,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug
* the builtin/modular classmap vector/section. Save the start
* and length of the subrange at its edges.
*/
- for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
-
+ for_subvec(i, cm, di, classes) {
if (!strcmp(cm->mod_name, dt->mod_name)) {
if (!nc) {
v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
--
2.54.0
^ permalink raw reply related
* [PATCH v4 16/25] dyndbg: replace classmap list with an array-slice
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
Classmaps are stored in an elf section/array, but currently are
individually list-linked onto dyndbg's per-module ddebug_table for
operation. This is unnecessary.
Just like dyndbg's descriptors, classes are packed in compile order;
so even with many builtin modules employing multiple classmaps, each
modules' maps are packed contiguously, and can be treated as a
array-start-address & array-length.
So this drops the whole list building operation done in
ddebug_attach_module_classes(), and removes the list-head members of
the classmap structs. The "select-by-modname" condition is reused to
find the start,end of the subrange of classmaps belonging to the module.
NOTES:
There are multiple modules named "main" but thats an artifact of how
KBUILD_MODNAME gets its value, and none of those repeats are
contiguous. The legacy code segmenting the builtin descriptors
depends upon this, we are "reusing" that dependency.
The "filter-by-modname" on classmaps should really be done in
ddebug_add_module(1); ie closer to dynamic_debug_init(2), which
already splits up pr-debug descriptors into subranges by modname, then
calls (1) on each. (2) knows nothing of classmaps currently, and
doesn't need to.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
v2: RvB after SoB
---
include/linux/dynamic_debug.h | 1 -
lib/dynamic_debug.c | 65 +++++++++++++++++++++++--------------------
2 files changed, 35 insertions(+), 31 deletions(-)
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 867e3978675f..0443781ed95b 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -73,7 +73,6 @@ enum ddebug_class_map_type {
};
struct ddebug_class_map {
- struct list_head link;
struct module *mod;
const char *mod_name; /* needed for builtins */
const char **class_names;
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 9bd521651c48..b8a494835ef5 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -45,10 +45,11 @@ extern struct ddebug_class_map __start___dyndbg_classes[];
extern struct ddebug_class_map __stop___dyndbg_classes[];
struct ddebug_table {
- struct list_head link, maps;
+ struct list_head link;
const char *mod_name;
- unsigned int num_ddebugs;
struct _ddebug *ddebugs;
+ struct ddebug_class_map *classes;
+ unsigned int num_ddebugs, num_classes;
};
struct ddebug_query {
@@ -149,12 +150,13 @@ static void v3pr_info_dq(const struct ddebug_query *query, const char *msg)
}
static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table const *dt,
- const char *class_string, int *class_id)
+ const char *class_string,
+ int *class_id)
{
struct ddebug_class_map *map;
- int idx;
+ int i, idx;
- list_for_each_entry(map, &dt->maps, link) {
+ for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
idx = match_string(map->class_names, map->length, class_string);
if (idx >= 0) {
*class_id = idx + map->base;
@@ -165,7 +167,6 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
return NULL;
}
-#define __outvar /* filled by callee */
/*
* Search the tables for _ddebug's which match the given `query' and
* apply the `flags' and `mask' to them. Returns number of matching
@@ -227,7 +228,7 @@ static int ddebug_change(const struct ddebug_query *query,
unsigned int nfound = 0;
struct flagsbuf fbuf, nbuf;
struct ddebug_class_map *map = NULL;
- int __outvar valid_class;
+ int valid_class;
/* search for matching ddebugs */
mutex_lock(&ddebug_lock);
@@ -1064,9 +1065,10 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp)
{
- struct ddebug_class_map *map;
+ struct ddebug_class_map *map = iter->table->classes;
+ int i, nc = iter->table->num_classes;
- list_for_each_entry(map, &iter->table->maps, link)
+ for (i = 0; i < nc; i++, map++)
if (class_in_range(dp->class_id, map))
return map->class_names[dp->class_id - map->base];
@@ -1150,30 +1152,34 @@ static const struct proc_ops proc_fops = {
.proc_write = ddebug_proc_write
};
-static void ddebug_attach_module_classes(struct ddebug_table *dt,
- struct ddebug_class_map *classes,
- int num_classes)
+static void ddebug_attach_module_classes(struct ddebug_table *dt, struct _ddebug_info *di)
{
struct ddebug_class_map *cm;
- int i, j, ct = 0;
+ int i, nc = 0;
- for (cm = classes, i = 0; i < num_classes; i++, cm++) {
+ /*
+ * Find this module's classmaps in a subrange/wholerange of
+ * the builtin/modular classmap vector/section. Save the start
+ * and length of the subrange at its edges.
+ */
+ for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
if (!strcmp(cm->mod_name, dt->mod_name)) {
-
- v2pr_info("class[%d]: module:%s base:%d len:%d ty:%d\n", i,
- cm->mod_name, cm->base, cm->length, cm->map_type);
-
- for (j = 0; j < cm->length; j++)
- v3pr_info(" %d: %d %s\n", j + cm->base, j,
- cm->class_names[j]);
-
- list_add(&cm->link, &dt->maps);
- ct++;
+ if (!nc) {
+ v2pr_info("start subrange, class[%d]: module:%s base:%d len:%d ty:%d\n",
+ i, cm->mod_name, cm->base, cm->length, cm->map_type);
+ dt->classes = cm;
+ }
+ nc++;
+ } else if (nc) {
+ /* end of matching classmaps */
+ break;
}
}
- if (ct)
- vpr_info("module:%s attached %d classes\n", dt->mod_name, ct);
+ if (nc) {
+ dt->num_classes = nc;
+ vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
+ }
}
/*
@@ -1205,10 +1211,9 @@ static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
dt->num_ddebugs = di->num_descs;
INIT_LIST_HEAD(&dt->link);
- INIT_LIST_HEAD(&dt->maps);
if (di->classes && di->num_classes)
- ddebug_attach_module_classes(dt, di->classes, di->num_classes);
+ ddebug_attach_module_classes(dt, di);
mutex_lock(&ddebug_lock);
list_add_tail(&dt->link, &ddebug_tables);
@@ -1321,8 +1326,8 @@ static void ddebug_remove_all_tables(void)
mutex_lock(&ddebug_lock);
while (!list_empty(&ddebug_tables)) {
struct ddebug_table *dt = list_entry(ddebug_tables.next,
- struct ddebug_table,
- link);
+ struct ddebug_table,
+ link);
ddebug_table_free(dt);
}
mutex_unlock(&ddebug_lock);
--
2.54.0
^ permalink raw reply related
* [PATCH v4 15/25] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
old_bits arg is currently a pointer to the input bits, but this could
allow inadvertent changes to the input by the fn. Disallow this.
And constify new_bits while here.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
v2: move RvB after SoB
---
lib/dynamic_debug.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index f59fe7b25ea9..9bd521651c48 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -612,7 +612,8 @@ static int ddebug_exec_queries(char *query, const char *modname)
/* apply a new class-param setting */
static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
- unsigned long *new_bits, unsigned long *old_bits,
+ const unsigned long *new_bits,
+ const unsigned long old_bits,
const char *query_modname)
{
#define QUERY_SIZE 128
@@ -621,12 +622,12 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
int matches = 0;
int bi, ct;
- if (*new_bits != *old_bits)
+ if (*new_bits != old_bits)
v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
- *old_bits, query_modname ?: "'*'");
+ old_bits, query_modname ?: "'*'");
for (bi = 0; bi < map->length; bi++) {
- if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
+ if (test_bit(bi, new_bits) == test_bit(bi, &old_bits))
continue;
snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
@@ -638,9 +639,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
ct, map->class_names[bi], *new_bits);
}
- if (*new_bits != *old_bits)
+ if (*new_bits != old_bits)
v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
- *old_bits, query_modname ?: "'*'");
+ old_bits, query_modname ?: "'*'");
return matches;
}
@@ -688,7 +689,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
inrep &= CLASSMAP_BITMASK(map->length);
}
v2pr_info("bits:0x%lx > %s.%s\n", inrep, mod_name ?: "*", KP_NAME(kp));
- totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, mod_name);
+ totct += ddebug_apply_class_bitmap(dcp, &inrep, *dcp->bits, mod_name);
*dcp->bits = inrep;
break;
case DD_CLASS_TYPE_LEVEL_NUM:
@@ -701,7 +702,7 @@ static int param_set_dyndbg_module_classes(const char *instr,
old_bits = CLASSMAP_BITMASK(*dcp->lvl);
new_bits = CLASSMAP_BITMASK(inrep);
v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
- totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, mod_name);
+ totct += ddebug_apply_class_bitmap(dcp, &new_bits, old_bits, mod_name);
*dcp->lvl = inrep;
break;
default:
--
2.54.0
^ permalink raw reply related
* [PATCH v4 14/25] dyndbg: refactor param_set_dyndbg_classes and below
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
Refactor callchain below param_set_dyndbg_classes(1) to allow mod-name
specific settings. Split (1) into upper/lower fns, adding modname
param to lower, and passing NULL in from upper. Below that, add the
same param to ddebug_apply_class_bitmap(), and pass it thru to
_ddebug_queries(), replacing NULL with the param.
This allows the callchain to update the classmap in just one module,
vs just all as currently done. While the sysfs param is unlikely to
ever update just one module, the callchain will be used for modprobe
handling, which should update only that just-probed module.
In ddebug_apply_class_bitmap(), also check for actual changes to the
bits before announcing them, to declutter logs.
No functional change.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
v2: move RvB after SoB
---
lib/dynamic_debug.c | 51 +++++++++++++++++++++++++++++++++++++++------------
1 file changed, 39 insertions(+), 12 deletions(-)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index a967e3ef1dbc..f59fe7b25ea9 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -610,9 +610,10 @@ static int ddebug_exec_queries(char *query, const char *modname)
return nfound;
}
-/* apply a new bitmap to the sys-knob's current bit-state */
+/* apply a new class-param setting */
static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
- unsigned long *new_bits, unsigned long *old_bits)
+ unsigned long *new_bits, unsigned long *old_bits,
+ const char *query_modname)
{
#define QUERY_SIZE 128
char query[QUERY_SIZE];
@@ -620,7 +621,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
int matches = 0;
int bi, ct;
- v2pr_info("apply: 0x%lx to: 0x%lx\n", *new_bits, *old_bits);
+ if (*new_bits != *old_bits)
+ v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
+ *old_bits, query_modname ?: "'*'");
for (bi = 0; bi < map->length; bi++) {
if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
@@ -629,12 +632,16 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi],
test_bit(bi, new_bits) ? '+' : '-', dcp->flags);
- ct = ddebug_exec_queries(query, NULL);
+ ct = ddebug_exec_queries(query, query_modname);
matches += ct;
v2pr_info("bit_%d: %d matches on class: %s -> 0x%lx\n", bi,
ct, map->class_names[bi], *new_bits);
}
+ if (*new_bits != *old_bits)
+ v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits,
+ *old_bits, query_modname ?: "'*'");
+
return matches;
}
@@ -647,6 +654,7 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
* param_set_dyndbg_classes - class FOO >control
* @instr: string echo>d to sysfs, input depends on map_type
* @kp: kp->arg has state: bits/lvl, map, map_type
+ * @mod_name: module name or null for all modules with the classes
*
* Enable/disable prdbgs by their class, as given in the arguments to
* DECLARE_DYNDBG_CLASSMAP. For LEVEL map-types, enforce relative
@@ -654,7 +662,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
*
* Returns: 0 or <0 if error.
*/
-int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
+static int param_set_dyndbg_module_classes(const char *instr,
+ const struct kernel_param *kp,
+ const char *mod_name)
{
const struct ddebug_class_param *dcp = kp->arg;
const struct ddebug_class_map *map = dcp->map;
@@ -677,8 +687,8 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length));
inrep &= CLASSMAP_BITMASK(map->length);
}
- v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp));
- totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits);
+ v2pr_info("bits:0x%lx > %s.%s\n", inrep, mod_name ?: "*", KP_NAME(kp));
+ totct += ddebug_apply_class_bitmap(dcp, &inrep, dcp->bits, mod_name);
*dcp->bits = inrep;
break;
case DD_CLASS_TYPE_LEVEL_NUM:
@@ -691,7 +701,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
old_bits = CLASSMAP_BITMASK(*dcp->lvl);
new_bits = CLASSMAP_BITMASK(inrep);
v2pr_info("lvl:%ld bits:0x%lx > %s\n", inrep, new_bits, KP_NAME(kp));
- totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits);
+ totct += ddebug_apply_class_bitmap(dcp, &new_bits, &old_bits, mod_name);
*dcp->lvl = inrep;
break;
default:
@@ -701,16 +711,33 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct);
return 0;
}
+
+/**
+ * param_set_dyndbg_classes - classmap kparam setter
+ * @instr: string echo>d to sysfs, input depends on map_type
+ * @kp: kp->arg has state: bits/lvl, map, map_type
+ *
+ * enable/disable all class'd pr_debugs in the classmap. For LEVEL
+ * map-types, enforce * relative levels by bitpos.
+ *
+ * Returns: 0 or <0 if error.
+ */
+int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
+{
+ return param_set_dyndbg_module_classes(instr, kp, NULL);
+}
EXPORT_SYMBOL(param_set_dyndbg_classes);
/**
- * param_get_dyndbg_classes - classes reader
+ * param_get_dyndbg_classes - classmap kparam getter
* @buffer: string description of controlled bits -> classes
* @kp: kp->arg has state: bits, map
*
- * Reads last written state, underlying prdbg state may have been
- * altered by direct >control. Displays 0x for DISJOINT, 0-N for
- * LEVEL Returns: #chars written or <0 on error
+ * Reads last written state, underlying pr_debug states may have been
+ * altered by direct >control. Displays 0x for DISJOINT classmap
+ * types, 0-N for LEVEL types.
+ *
+ * Returns: ct of chars written or <0 on error
*/
int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
{
--
2.54.0
^ permalink raw reply related
* [PATCH v4 13/25] dyndbg: reduce verbose/debug clutter
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
currently, for verbose=3, these are logged (blank lines for clarity):
dyndbg: query 0: "class DRM_UT_CORE +p" mod:*
dyndbg: split into words: "class" "DRM_UT_CORE" "+p"
dyndbg: op='+'
dyndbg: flags=0x1
dyndbg: *flagsp=0x1 *maskp=0xffffffff
dyndbg: parsed: func="" file="" module="" format="" lineno=0-0 class=...
dyndbg: no matches for query
dyndbg: no-match: func="" file="" module="" format="" lineno=0-0 class=...
dyndbg: processed 1 queries, with 0 matches, 0 errs
That is excessive, so this patch:
- shrinks 3 lines of 2nd stanza to single line
- drops 1st 2 lines of 3rd stanza
3rd line is like 1st, with result, not procedure.
2nd line is just status, retold in 4th, with more info.
New output:
dyndbg: query 0: "class DRM_UT_CORE +p"
dyndbg: split into words: "class" "DRM_UT_CORE" "+p"
dyndbg: op='+' flags=0x1 maskp=0xffffffff
dyndbg: processed 1 queries, with 0 matches, 0 errs
Also drop several verbose=3 messages in ddebug_add_module
When modprobing a module, dyndbg currently logs/says "add-module", and
then "skipping" if the module has no prdbgs. Instead just check 1st
and return quietly.
no functional change
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
v4: rename vpr_dq_info to v3pr_dq_info to tell its active logging level
adjust some vX levels per doc'd intentions
v2: RvB after SoB
trivial change to verbose-debug output line to output the actual
"module" keyword rather than "mod:", and do so only when the module is
constrained by the callchain (ie as part of a modprobe).
was: query X: "(keyword value)* [+-=]flags" mod:*
now: query X: "(keyword value)* [+-=]flags"
or query X: module FOO "keyword value)* [+-=]flags"
IOW, adjust output to reflect the input grammar more closely.
drop-info-parsed
vinfo-applied-nomatch
dyndbg: tweak verbose-levels per doc
---
lib/dynamic_debug.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 0377d9f8dcd1..a967e3ef1dbc 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -128,7 +128,7 @@ do { \
#define v3pr_info(fmt, ...) vnpr_info(3, fmt, ##__VA_ARGS__)
#define v4pr_info(fmt, ...) vnpr_info(4, fmt, ##__VA_ARGS__)
-static void vpr_info_dq(const struct ddebug_query *query, const char *msg)
+static void v3pr_info_dq(const struct ddebug_query *query, const char *msg)
{
/* trim any trailing newlines */
int fmtlen = 0;
@@ -276,9 +276,6 @@ static int ddebug_change(const struct ddebug_query *query,
}
mutex_unlock(&ddebug_lock);
- if (!nfound && verbose)
- pr_info("no matches for query\n");
-
return nfound;
}
@@ -487,7 +484,6 @@ static int ddebug_parse_query(char *words[], int nwords,
*/
query->module = modname;
- vpr_info_dq(query, "parsed");
return 0;
}
@@ -511,7 +507,6 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
pr_err("bad flag-op %c, at start of %s\n", *str, str);
return -EINVAL;
}
- v3pr_info("op='%c'\n", op);
for (; *str ; ++str) {
for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
@@ -525,7 +520,6 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
return -EINVAL;
}
}
- v3pr_info("flags=0x%x\n", modifiers->flags);
/* calculate final flags, mask based upon op */
switch (op) {
@@ -541,7 +535,7 @@ static int ddebug_parse_flags(const char *str, struct flag_settings *modifiers)
modifiers->flags = 0;
break;
}
- v3pr_info("*flagsp=0x%x *maskp=0x%x\n", modifiers->flags, modifiers->mask);
+ v3pr_info("op='%c' flags=0x%x maskp=0x%x\n", op, modifiers->flags, modifiers->mask);
return 0;
}
@@ -570,7 +564,7 @@ static int ddebug_exec_query(char *query_string, const char *modname)
}
/* actually go and implement the change */
nfound = ddebug_change(&query, &modifiers);
- vpr_info_dq(&query, nfound ? "applied" : "no-match");
+ v3pr_info_dq(&query, nfound ? "applied" : "no-match");
return nfound;
}
@@ -593,7 +587,10 @@ static int ddebug_exec_queries(char *query, const char *modname)
if (!query || !*query || *query == '#')
continue;
- vpr_info("query %d: \"%s\" mod:%s\n", i, query, modname ?: "*");
+ if (modname)
+ v2pr_info("query %d: module %s \"%s\"\n", i, modname, query);
+ else
+ v2pr_info("query %d: \"%s\"\n", i, query);
rc = ddebug_exec_query(query, modname);
if (rc < 0) {
@@ -1159,11 +1156,10 @@ static int ddebug_add_module(struct _ddebug_info *di, 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);
+ if (!di->num_descs)
return 0;
- }
+
+ v3pr_info("add-module: %s %d sites\n", modname, di->num_descs);
dt = kzalloc_obj(*dt);
if (dt == NULL) {
--
2.54.0
^ permalink raw reply related
* [PATCH v4 12/25] dyndbg: drop NUM_TYPE_ARGS
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
ARRAY_SIZE works here, since array decl is complete.
no functional change
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
v2: include linux/array_size.h, correct commit subject
review after sob
---
include/linux/dynamic_debug.h | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 78c22c6d2312..867e3978675f 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -121,11 +121,9 @@ struct ddebug_class_param {
.mod_name = KBUILD_MODNAME, \
.base = _base, \
.map_type = _maptype, \
- .length = NUM_TYPE_ARGS(char*, __VA_ARGS__), \
+ .length = ARRAY_SIZE(_var##_classnames), \
.class_names = _var##_classnames, \
}
-#define NUM_TYPE_ARGS(eltype, ...) \
- (sizeof((eltype[]) {__VA_ARGS__}) / sizeof(eltype))
extern __printf(2, 3)
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
--
2.54.0
^ permalink raw reply related
* [PATCH v4 11/25] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
Remove the DD_CLASS_TYPE_*_NAMES classmap types and code.
These 2 classmap types accept class names at the PARAM interface, for
example:
echo +DRM_UT_CORE,-DRM_UT_KMS > /sys/module/drm/parameters/debug_names
The code works, but its only used by test-dynamic-debug, and wasn't
asked for by anyone else, so reduce LOC & test-surface; simplify things.
Also rename enum class_map_type to enum ddebug_class_map_type.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
v3:
fix name of enum in kdoc
also change name of struct (to future name)
v2:
move RvB after SoB
respect const instr in param_set_dyndbg_module_classes, return -EINVAL on classtype err.
---
include/linux/dynamic_debug.h | 27 ++++--------
lib/dynamic_debug.c | 99 +++----------------------------------------
lib/test_dynamic_debug.c | 26 ------------
3 files changed, 14 insertions(+), 138 deletions(-)
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index a10adac8e8f0..78c22c6d2312 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -59,27 +59,16 @@ struct _ddebug {
#endif
} __attribute__((aligned(8)));
-enum class_map_type {
+enum ddebug_class_map_type {
DD_CLASS_TYPE_DISJOINT_BITS,
/**
- * DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, one per bit.
- * expecting hex input. Built for drm.debug, basis for other types.
+ * DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, mapped to bits[0..N].
+ * Expects hex input. Built for drm.debug, basis for other types.
*/
DD_CLASS_TYPE_LEVEL_NUM,
/**
- * DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0-N.
- * N turns on just bits N-1 .. 0, so N=0 turns all bits off.
- */
- DD_CLASS_TYPE_DISJOINT_NAMES,
- /**
- * DD_CLASS_TYPE_DISJOINT_NAMES: input is a CSV of [+-]CLASS_NAMES,
- * classes are independent, like _DISJOINT_BITS.
- */
- DD_CLASS_TYPE_LEVEL_NAMES,
- /**
- * DD_CLASS_TYPE_LEVEL_NAMES: input is a CSV of [+-]CLASS_NAMES,
- * intended for names like: INFO,DEBUG,TRACE, with a module prefix
- * avoid EMERG,ALERT,CRIT,ERR,WARNING: they're not debug
+ * DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0..N.
+ * Input N turns on bits 0..N-1
*/
};
@@ -90,7 +79,7 @@ struct ddebug_class_map {
const char **class_names;
const int length;
const int base; /* index of 1st .class_id, allows split/shared space */
- enum class_map_type map_type;
+ enum ddebug_class_map_type map_type;
};
/* encapsulate linker provided built-in (or module) dyndbg data */
@@ -119,8 +108,8 @@ struct ddebug_class_param {
/**
* DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
- * @_var: a struct ddebug_class_map, passed to module_param_cb
- * @_type: enum class_map_type, chooses bits/verbose, numeric/symbolic
+ * @_var: a struct _ddebug_class_map, passed to module_param_cb
+ * @_maptype: enum ddebug_class_map_type, chooses bits/verbose
* @_base: offset of 1st class-name. splits .class_id space
* @classes: class-names used to control class'd prdbgs
*/
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index a9caf84ddb22..0377d9f8dcd1 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -646,76 +646,6 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp,
#define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1)
-/* accept comma-separated-list of [+-] classnames */
-static int param_set_dyndbg_classnames(const char *instr, const struct kernel_param *kp)
-{
- const struct ddebug_class_param *dcp = kp->arg;
- const struct ddebug_class_map *map = dcp->map;
- unsigned long curr_bits, old_bits;
- char *cl_str, *p, *tmp;
- int cls_id, totct = 0;
- bool wanted;
-
- cl_str = tmp = kstrdup_and_replace(instr, '\n', '\0', GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- /* start with previously set state-bits, then modify */
- curr_bits = old_bits = *dcp->bits;
- vpr_info("\"%s\" > %s:0x%lx\n", cl_str, KP_NAME(kp), curr_bits);
-
- for (; cl_str; cl_str = p) {
- p = strchr(cl_str, ',');
- if (p)
- *p++ = '\0';
-
- if (*cl_str == '-') {
- wanted = false;
- cl_str++;
- } else {
- wanted = true;
- if (*cl_str == '+')
- cl_str++;
- }
- cls_id = match_string(map->class_names, map->length, cl_str);
- if (cls_id < 0) {
- pr_err("%s unknown to %s\n", cl_str, KP_NAME(kp));
- continue;
- }
-
- /* have one or more valid class_ids of one *_NAMES type */
- switch (map->map_type) {
- case DD_CLASS_TYPE_DISJOINT_NAMES:
- /* the +/- pertains to a single bit */
- if (test_bit(cls_id, &curr_bits) == wanted) {
- v3pr_info("no change on %s\n", cl_str);
- continue;
- }
- curr_bits ^= BIT(cls_id);
- totct += ddebug_apply_class_bitmap(dcp, &curr_bits, dcp->bits);
- *dcp->bits = curr_bits;
- v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id,
- map->class_names[cls_id]);
- break;
- case DD_CLASS_TYPE_LEVEL_NAMES:
- /* cls_id = N in 0..max. wanted +/- determines N or N-1 */
- old_bits = CLASSMAP_BITMASK(*dcp->lvl);
- curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 ));
-
- totct += ddebug_apply_class_bitmap(dcp, &curr_bits, &old_bits);
- *dcp->lvl = (cls_id + (wanted ? 1 : 0));
- v2pr_info("%s: changed bit-%d: \"%s\" %lx->%lx\n", KP_NAME(kp), cls_id,
- map->class_names[cls_id], old_bits, curr_bits);
- break;
- default:
- pr_err("illegal map-type value %d\n", map->map_type);
- }
- }
- kfree(tmp);
- vpr_info("total matches: %d\n", totct);
- return 0;
-}
-
/**
* param_set_dyndbg_classes - class FOO >control
* @instr: string echo>d to sysfs, input depends on map_type
@@ -734,28 +664,14 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
unsigned long inrep, new_bits, old_bits;
int rc, totct = 0;
- switch (map->map_type) {
-
- case DD_CLASS_TYPE_DISJOINT_NAMES:
- case DD_CLASS_TYPE_LEVEL_NAMES:
- /* handle [+-]classnames list separately, we are done here */
- return param_set_dyndbg_classnames(instr, kp);
-
- case DD_CLASS_TYPE_DISJOINT_BITS:
- case DD_CLASS_TYPE_LEVEL_NUM:
- /* numeric input, accept and fall-thru */
- rc = kstrtoul(instr, 0, &inrep);
- if (rc) {
- pr_err("expecting numeric input: %s > %s\n", instr, KP_NAME(kp));
- return -EINVAL;
- }
- break;
- default:
- pr_err("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
+ rc = kstrtoul(instr, 0, &inrep);
+ if (rc) {
+ int len = strcspn(instr, "\n");
+ pr_err("expecting numeric input, not: %.*s > %s\n",
+ len, instr, KP_NAME(kp));
return -EINVAL;
}
- /* only _BITS,_NUM (numeric) map-types get here */
switch (map->map_type) {
case DD_CLASS_TYPE_DISJOINT_BITS:
/* expect bits. mask and warn if too many */
@@ -783,6 +699,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp)
break;
default:
pr_warn("%s: bad map type: %d\n", KP_NAME(kp), map->map_type);
+ return -EINVAL;
}
vpr_info("%s: total matches: %d\n", KP_NAME(kp), totct);
return 0;
@@ -804,12 +721,8 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp)
const struct ddebug_class_map *map = dcp->map;
switch (map->map_type) {
-
- case DD_CLASS_TYPE_DISJOINT_NAMES:
case DD_CLASS_TYPE_DISJOINT_BITS:
return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", *dcp->bits);
-
- case DD_CLASS_TYPE_LEVEL_NAMES:
case DD_CLASS_TYPE_LEVEL_NUM:
return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl);
default:
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 77c2a669b6af..74d183ebf3e0 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -74,13 +74,6 @@ DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, 0,
DD_SYS_WRAP(disjoint_bits, p);
DD_SYS_WRAP(disjoint_bits, T);
-/* symbolic input, independent bits */
-enum cat_disjoint_names { LOW = 11, MID, HI };
-DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10,
- "LOW", "MID", "HI");
-DD_SYS_WRAP(disjoint_names, p);
-DD_SYS_WRAP(disjoint_names, T);
-
/* numeric verbosity, V2 > V1 related */
enum cat_level_num { V0 = 14, V1, V2, V3, V4, V5, V6, V7 };
DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
@@ -88,13 +81,6 @@ DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14,
DD_SYS_WRAP(level_num, p);
DD_SYS_WRAP(level_num, T);
-/* symbolic verbosity */
-enum cat_level_names { L0 = 22, L1, L2, L3, L4, L5, L6, L7 };
-DECLARE_DYNDBG_CLASSMAP(map_level_names, DD_CLASS_TYPE_LEVEL_NAMES, 22,
- "L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7");
-DD_SYS_WRAP(level_names, p);
-DD_SYS_WRAP(level_names, T);
-
/* stand-in for all pr_debug etc */
#define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n")
@@ -102,10 +88,6 @@ static void do_cats(void)
{
pr_debug("doing categories\n");
- prdbg(LOW);
- prdbg(MID);
- prdbg(HI);
-
prdbg(D2_CORE);
prdbg(D2_DRIVER);
prdbg(D2_KMS);
@@ -129,14 +111,6 @@ static void do_levels(void)
prdbg(V5);
prdbg(V6);
prdbg(V7);
-
- prdbg(L1);
- prdbg(L2);
- prdbg(L3);
- prdbg(L4);
- prdbg(L5);
- prdbg(L6);
- prdbg(L7);
}
static void do_prints(void)
--
2.54.0
^ permalink raw reply related
* [PATCH v4 10/25] dyndbg: reword "class unknown," to "class:_UNKNOWN_"
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
When a dyndbg classname is unknown to a kernel module, the callsite is
un-addressable via >control queries.
The control-file displays this condition as "class unknown,"
currently. That spelling is sub-optimal/too-generic, so change it to
"class:_UNKNOWN_" to loudly announce the erroneous situation, and to
make it uniquely greppable.
NB: while this might be seen as a user-visible change, this shouldn't
disqualify the change:
a- it reports classmap coding error condition, which should be
detected before review.
b- SHOUTING the error makes it uniquely greppable.
c- the classmap feature is marked BROKEN for its only current user.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
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 6b1e983cfedc..a9caf84ddb22 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -1166,7 +1166,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
if (class)
seq_printf(m, " class:%s", class);
else
- seq_printf(m, " class unknown, _id:%d", dp->class_id);
+ seq_printf(m, " class:_UNKNOWN_ _id:%d", dp->class_id);
}
seq_putc(m, '\n');
--
2.54.0
^ permalink raw reply related
* [PATCH v4 09/25] dyndbg: add stub macro for DECLARE_DYNDBG_CLASSMAP
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
Add the stub macro for !DYNAMIC_DEBUG builds, after moving the
original macro-defn down under the big ifdef. Do it now so future
changes have a cleaner starting point.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
include/linux/dynamic_debug.h | 43 ++++++++++++++++++++++---------------------
1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 05743900a116..a10adac8e8f0 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -93,27 +93,6 @@ struct ddebug_class_map {
enum class_map_type map_type;
};
-/**
- * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
- * @_var: a struct ddebug_class_map, passed to module_param_cb
- * @_type: enum class_map_type, chooses bits/verbose, numeric/symbolic
- * @_base: offset of 1st class-name. splits .class_id space
- * @classes: class-names used to control class'd prdbgs
- */
-#define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...) \
- static const char *_var##_classnames[] = { __VA_ARGS__ }; \
- static struct ddebug_class_map __aligned(8) __used \
- __section("__dyndbg_classes") _var = { \
- .mod = THIS_MODULE, \
- .mod_name = KBUILD_MODNAME, \
- .base = _base, \
- .map_type = _maptype, \
- .length = NUM_TYPE_ARGS(char*, __VA_ARGS__), \
- .class_names = _var##_classnames, \
- }
-#define NUM_TYPE_ARGS(eltype, ...) \
- (sizeof((eltype[]){__VA_ARGS__}) / sizeof(eltype))
-
/* encapsulate linker provided built-in (or module) dyndbg data */
struct _ddebug_info {
struct _ddebug *descs;
@@ -138,6 +117,27 @@ struct ddebug_class_param {
#if defined(CONFIG_DYNAMIC_DEBUG) || \
(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
+/**
+ * DECLARE_DYNDBG_CLASSMAP - declare classnames known by a module
+ * @_var: a struct ddebug_class_map, passed to module_param_cb
+ * @_type: enum class_map_type, chooses bits/verbose, numeric/symbolic
+ * @_base: offset of 1st class-name. splits .class_id space
+ * @classes: class-names used to control class'd prdbgs
+ */
+#define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...) \
+ static const char *_var##_classnames[] = { __VA_ARGS__ }; \
+ static struct ddebug_class_map __aligned(8) __used \
+ __section("__dyndbg_classes") _var = { \
+ .mod = THIS_MODULE, \
+ .mod_name = KBUILD_MODNAME, \
+ .base = _base, \
+ .map_type = _maptype, \
+ .length = NUM_TYPE_ARGS(char*, __VA_ARGS__), \
+ .class_names = _var##_classnames, \
+ }
+#define NUM_TYPE_ARGS(eltype, ...) \
+ (sizeof((eltype[]) {__VA_ARGS__}) / sizeof(eltype))
+
extern __printf(2, 3)
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
@@ -314,6 +314,7 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)
#define DYNAMIC_DEBUG_BRANCH(descriptor) false
+#define DECLARE_DYNDBG_CLASSMAP(...)
#define dynamic_pr_debug(fmt, ...) \
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
--
2.54.0
^ permalink raw reply related
* [PATCH v4 08/25] dyndbg: factor ddebug_match_desc out from ddebug_change
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
ddebug_change() is a big (~100 lines) function with a nested for loop.
The outer loop walks the per-module ddebug_tables list, and does
module stuff: it filters on a query's "module FOO*" and "class BAR",
failures here skip the entire inner loop.
The inner loop (60 lines) scans a module's descriptors. It starts
with a long block of filters on function, line, format, and the
validated "BAR" class (or the legacy/_DPRINTK_CLASS_DFLT).
These filters "continue" past pr_debugs that don't match the query
criteria, before it falls through the code below that counts matches,
then adjusts the flags and static-keys. This is unnecessarily hard to
think about.
So move the per-descriptor filter-block into a boolean function:
ddebug_match_desc(desc), and change each "continue" to "return false".
This puts a clear interface in place, so any future changes are either
inside, outside, or across this interface.
also fix checkpatch complaints about spaces and braces.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
lib/dynamic_debug.c | 83 ++++++++++++++++++++++++++++++-----------------------
1 file changed, 47 insertions(+), 36 deletions(-)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 18a71a9108d3..6b1e983cfedc 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -172,6 +172,52 @@ static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_table cons
* callsites, normally the same as number of changes. If verbose,
* logs the changes. Takes ddebug_lock.
*/
+static bool ddebug_match_desc(const struct ddebug_query *query,
+ struct _ddebug *dp,
+ int valid_class)
+{
+ /* match site against query-class */
+ if (dp->class_id != valid_class)
+ return false;
+
+ /* match against the source filename */
+ if (query->filename &&
+ !match_wildcard(query->filename, dp->filename) &&
+ !match_wildcard(query->filename,
+ kbasename(dp->filename)) &&
+ !match_wildcard(query->filename,
+ trim_prefix(dp->filename)))
+ return false;
+
+ /* match against the function */
+ if (query->function &&
+ !match_wildcard(query->function, dp->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;
+}
+
static int ddebug_change(const struct ddebug_query *query,
struct flag_settings *modifiers)
{
@@ -204,42 +250,7 @@ static int ddebug_change(const struct ddebug_query *query,
for (i = 0; i < dt->num_ddebugs; i++) {
struct _ddebug *dp = &dt->ddebugs[i];
- /* match site against query-class */
- if (dp->class_id != valid_class)
- continue;
-
- /* match against the source filename */
- if (query->filename &&
- !match_wildcard(query->filename, dp->filename) &&
- !match_wildcard(query->filename,
- kbasename(dp->filename)) &&
- !match_wildcard(query->filename,
- trim_prefix(dp->filename)))
- continue;
-
- /* match against the function */
- if (query->function &&
- !match_wildcard(query->function, dp->function))
- continue;
-
- /* match against the format */
- if (query->format) {
- if (*query->format == '^') {
- char *p;
- /* anchored search. match must be at beginning */
- p = strstr(dp->format, query->format+1);
- if (p != dp->format)
- continue;
- } else if (!strstr(dp->format, query->format))
- continue;
- }
-
- /* match against the line number range */
- if (query->first_lineno &&
- dp->lineno < query->first_lineno)
- continue;
- if (query->last_lineno &&
- dp->lineno > query->last_lineno)
+ if (!ddebug_match_desc(query, dp, valid_class))
continue;
nfound++;
--
2.54.0
^ permalink raw reply related
* [PATCH v4 07/25] dyndbg.lds.S: fix lost dyndbg sections in modules
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
With CONFIG_DRM_USE_DYNAMIC_DEBUG=y, several build configs had
problems with __dyndbg* sections getting lost in drm drivers. Fix
this by following the model demonstrated in codetag.lds.h.
Introduce include/asm-generic/dyndbg.lds.h, to bundle dynamic-debug's
multiple sections together, into 2 macros:
vmlinux.lds.h DATA_DATA: move the 2 BOUNDED_SECTION_BY(__dyndbg*)
calls into dyndbg.lds.h DYNDBG_SECTIONS(). vmlinux.lds.h now includes
the new file and calls the new macro.
MOD_DYNDBG_SECTIONS keeps the 2 sections by name, aligns them and sets
the output address to 0 when the sections are empty.
dyndbg.lds.h includes (reuses) bounded-section.lds.h
scripts/module.lds.S: now calls MOD_DYNDBG_SECTIONS right before the
CODETAG macro (consistent with their placements in vmlinux.lds.h), and
also includes dyndbg.lds.h
This isolates vmlinux.lds.h from further __dyndbg section additions.
CC: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
---
v3: move #includes to top, drop extra ALIGN(8) in DYNDBG_SECTIONS, add RvBy
v2: Address linker script review feedback for relocatable modules.
MOD_DYNDBG_SECTIONS() used the BOUNDED_SECTION_BY() macro, which
proved problematic for kernel modules for two reasons:
1. Unwanted Empty Sections:
BOUNDED_SECTION_BY() automatically generates `__start` and `__stop`
symbols. When applied to `MOD_DYNDBG_SECTIONS()`, the linker assumes
the sections are populated due to the symbol definitions, forcing an
empty `__dyndbg` and `__dyndbg_classes` output section in every
compiled module, even those without dynamic debug configuration.
Since the module loader uses `section_objs()` to locate data via
ELF headers instead of relying on `__start`/`__stop` symbols, these
assignments are completely unnecessary.
2. Non-zero Output Addresses:
During relocatable linking (e.g., `ld.bfd -r`), omitting an explicit
base address causes the section to inherit the current location
counter. This results in non-zero sh_addr values in `.ko` files,
which is confusing, degrades compressibility, and can cause issues
with external tools parsing the ELF.
Fix both issues by dropping `BOUNDED_SECTION_BY()` in favor of a simple
`KEEP(*(...))` constraint and explicitly defining the sections with a `0`
base address: `__dyndbg 0 : ALIGN(8) { ... }`.
fixup-inc-vml
---
MAINTAINERS | 1 +
include/asm-generic/dyndbg.lds.h | 18 ++++++++++++++++++
include/asm-generic/vmlinux.lds.h | 6 ++----
scripts/module.lds.S | 2 ++
4 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44..6cf80e7ac039 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9083,6 +9083,7 @@ DYNAMIC DEBUG
M: Jason Baron <jbaron@akamai.com>
M: Jim Cromie <jim.cromie@gmail.com>
S: Maintained
+F: include/asm-generic/dyndbg.lds.h
F: include/linux/dynamic_debug.h
F: lib/dynamic_debug.c
F: lib/test_dynamic_debug.c
diff --git a/include/asm-generic/dyndbg.lds.h b/include/asm-generic/dyndbg.lds.h
new file mode 100644
index 000000000000..9d8951bef688
--- /dev/null
+++ b/include/asm-generic/dyndbg.lds.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_GENERIC_DYNDBG_LDS_H
+#define __ASM_GENERIC_DYNDBG_LDS_H
+
+#include <asm-generic/bounded_sections.lds.h>
+#define DYNDBG_SECTIONS() \
+ BOUNDED_SECTION_BY(__dyndbg, ___dyndbg) \
+ BOUNDED_SECTION_BY(__dyndbg_classes, ___dyndbg_classes)
+
+#define MOD_DYNDBG_SECTIONS() \
+ __dyndbg 0 : ALIGN(8) { \
+ KEEP(*(__dyndbg)) \
+ } \
+ __dyndbg_classes 0 : ALIGN(8) { \
+ KEEP(*(__dyndbg_classes)) \
+ }
+
+#endif /* __ASM_GENERIC_DYNDBG_LDS_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 2b1becd809be..0a1994bb8793 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -52,6 +52,7 @@
#include <asm-generic/bounded_sections.lds.h>
#include <asm-generic/codetag.lds.h>
+#include <asm-generic/dyndbg.lds.h>
#ifndef LOAD_OFFSET
#define LOAD_OFFSET 0
@@ -344,10 +345,7 @@
*(.data..do_once) \
STRUCT_ALIGN(); \
*(__tracepoints) \
- /* implement dynamic printk debug */ \
- . = ALIGN(8); \
- BOUNDED_SECTION_BY(__dyndbg_classes, ___dyndbg_classes) \
- BOUNDED_SECTION_BY(__dyndbg, ___dyndbg) \
+ DYNDBG_SECTIONS() \
CODETAG_SECTIONS() \
LIKELY_PROFILE() \
BRANCH_PROFILE() \
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index b62683061d79..2e62dc5bd5d4 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -10,6 +10,7 @@
#endif
#include <asm-generic/codetag.lds.h>
+#include <asm-generic/dyndbg.lds.h>
SECTIONS {
/DISCARD/ : {
@@ -61,6 +62,7 @@ SECTIONS {
*(.rodata..L*)
}
+ MOD_DYNDBG_SECTIONS()
MOD_SEPARATE_CODETAG_SECTIONS()
}
--
2.54.0
^ permalink raw reply related
* [PATCH v4 06/25] vmlinux.lds.h: remove redundant ALIGN(8) directives
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
The BOUNDED_SECTION_PRE_LABEL and BOUNDED_SECTION_POST_LABEL macros
were recently updated to inherently enforce an 8-byte alignment. This
makes the explicit '. = ALIGN(8);' statements preceding 'naked' macro
calls in vmlinux.lds.h redundant.
Remove these redundant alignment directives to clean up the file and
clarify that the macros handle their own alignment padding.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
include/asm-generic/vmlinux.lds.h | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 145beb14b94b..2b1becd809be 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -228,7 +228,6 @@
#ifdef CONFIG_KPROBES
#define KPROBE_BLACKLIST() \
- . = ALIGN(8); \
BOUNDED_SECTION(_kprobe_blacklist)
#else
#define KPROBE_BLACKLIST()
@@ -244,7 +243,6 @@
#ifdef CONFIG_EVENT_TRACING
#define FTRACE_EVENTS() \
- . = ALIGN(8); \
BOUNDED_SECTION(_ftrace_events) \
BOUNDED_SECTION_BY(_ftrace_eval_map, _ftrace_eval_maps)
#else
@@ -261,7 +259,6 @@
#ifdef CONFIG_FTRACE_SYSCALLS
#define TRACE_SYSCALLS() \
- . = ALIGN(8); \
BOUNDED_SECTION_BY(__syscalls_metadata, _syscalls_metadata)
#else
#define TRACE_SYSCALLS()
@@ -276,7 +273,6 @@
#ifdef CONFIG_SERIAL_EARLYCON
#define EARLYCON_TABLE() \
- . = ALIGN(8); \
BOUNDED_SECTION_POST_LABEL(__earlycon_table, __earlycon_table, , _end)
#else
#define EARLYCON_TABLE()
@@ -284,11 +280,9 @@
#ifdef CONFIG_SECURITY
#define LSM_TABLE() \
- . = ALIGN(8); \
BOUNDED_SECTION_PRE_LABEL(.lsm_info.init, _lsm_info, __start, __end)
#define EARLY_LSM_TABLE() \
- . = ALIGN(8); \
BOUNDED_SECTION_PRE_LABEL(.early_lsm_info.init, _early_lsm_info, __start, __end)
#else
#define LSM_TABLE()
@@ -314,7 +308,6 @@
#ifdef CONFIG_ACPI
#define ACPI_PROBE_TABLE(name) \
- . = ALIGN(8); \
BOUNDED_SECTION_POST_LABEL(__##name##_acpi_probe_table, \
__##name##_acpi_probe_table,, _end)
#else
@@ -323,7 +316,6 @@
#ifdef CONFIG_THERMAL
#define THERMAL_TABLE(name) \
- . = ALIGN(8); \
BOUNDED_SECTION_POST_LABEL(__##name##_thermal_table, \
__##name##_thermal_table,, _end)
#else
@@ -403,12 +395,10 @@
__end_init_stack = .;
#define JUMP_TABLE_DATA \
- . = ALIGN(8); \
BOUNDED_SECTION_BY(__jump_table, ___jump_table)
#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
#define STATIC_CALL_DATA \
- . = ALIGN(8); \
BOUNDED_SECTION_BY(.static_call_sites, _static_call_sites) \
BOUNDED_SECTION_BY(.static_call_tramp_key, _static_call_tramp_key)
#else
@@ -453,7 +443,6 @@
*(.rodata) *(.rodata.*) *(.data.rel.ro*) \
SCHED_DATA \
RO_AFTER_INIT_DATA /* Read only after init */ \
- . = ALIGN(8); \
BOUNDED_SECTION_BY(__tracepoints_ptrs, ___tracepoints_ptrs) \
*(__tracepoints_strings)/* Tracepoints: strings */ \
} \
@@ -947,12 +936,10 @@
/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
#define KUNIT_TABLE() \
- . = ALIGN(8); \
BOUNDED_SECTION_POST_LABEL(.kunit_test_suites, __kunit_suites, _start, _end)
/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */
#define KUNIT_INIT_TABLE() \
- . = ALIGN(8); \
BOUNDED_SECTION_POST_LABEL(.kunit_init_test_suites, \
__kunit_init_suites, _start, _end)
--
2.54.0
^ permalink raw reply related
* [PATCH v4 05/25] vmlinux.lds.h: Fix ALIGN(8) omission causing NULL ptr on i386
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
Almost all uses of the BOUNDED_SECTION macros are ALIGN(8), either
explicitly, or by being below an aligned section containing x*8 byte
objects. The noteworthy exception is BOUNDED_SECTION(__dyndbg), which
immediately follows BOUNDED_SECTION(__dyndbg_classes).
On i386, struct _ddebug_classmap is 28 bytes, so without an explicit
ALIGN(8) in the macro, the following __dyndbg section gets misaligned,
causing a NULL ptr deref in dynamic_debug_init().
So fix this with an explicit ALIGN(8) in the existing BOUNDED_SECTION
macros, and introduce _ALIGNED variants to handle the cases with an
explicit . = ALIGN(x)
Also add explicit alignments for: EXCEPTION_TABLE, ORC_UNWIND_TABLE,
TRACEDATA, INIT_SETUP, and NOTES.
update BOUNDED_SECTION uses inside . = ALIGN(x) stanzas to use
_ALIGNED variants, but keep the outer ALIGNs so the symbols between
them are not "re-aligned".
In particular, scripts/sorttable.c does not tolerate sloppy padding.
At the top of ORC_UNWIND_TABLE, add . = ALIGN(4) to match the struct
orc_header __align() call in the code:
commit b9f174c811e3 ("x86/unwind/orc: Add ELF section with ORC version identifier")
Suggested-by: Louis Chauvet <louis.chauvet@bootlin.com> # _ALIGNED variants.
Link: https://lore.kernel.org/lkml/177402491426.6181.12855763650074831089.b4-review@b4/
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
v3:
sashiko complained about NOTES and .BTF_ids.
gemini asserts that NOTES are natively 4-byte aligned, add comment repeating it.
.BTF_ids doesnt use BOUNDED_BY, since start/end isnt needed;
sashiko evidently got confused by immediately preceding usage.
v2:
sashiko picked up 2 cases, added to the explicit list above
https://sashiko.dev/#/patchset/20260515-asm-generic-1-v3-0-680b273666d4%40gmail.com
---
include/asm-generic/bounded_sections.lds.h | 17 ++++++++++++++---
include/asm-generic/vmlinux.lds.h | 18 ++++++++++--------
2 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/include/asm-generic/bounded_sections.lds.h b/include/asm-generic/bounded_sections.lds.h
index 268cdc34389b..8ff3e3420f60 100644
--- a/include/asm-generic/bounded_sections.lds.h
+++ b/include/asm-generic/bounded_sections.lds.h
@@ -3,19 +3,30 @@
#ifndef _ASM_GENERIC_BOUNDED_SECTIONS_H
#define _ASM_GENERIC_BOUNDED_SECTIONS_H
-#define BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_) \
+#define BOUNDED_SECTION_PRE_LABEL_ALIGNED(_sec_, _label_, _BEGIN_, _END_, _ALIGNED_) \
+ . = ALIGN(_ALIGNED_); \
_BEGIN_##_label_ = .; \
KEEP(*(_sec_)) \
_END_##_label_ = .;
-#define BOUNDED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_) \
+#define BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_) \
+ BOUNDED_SECTION_PRE_LABEL_ALIGNED(_sec_, _label_, _BEGIN_, _END_, 8)
+
+#define BOUNDED_SECTION_POST_LABEL_ALIGNED(_sec_, _label_, _BEGIN_, _END_, _ALIGNED_) \
+ . = ALIGN(_ALIGNED_); \
_label_##_BEGIN_ = .; \
KEEP(*(_sec_)) \
_label_##_END_ = .;
+#define BOUNDED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_) \
+ BOUNDED_SECTION_POST_LABEL_ALIGNED(_sec_, _label_, _BEGIN_, _END_, 8)
+
#define BOUNDED_SECTION_BY(_sec_, _label_) \
BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, __start, __stop)
-#define BOUNDED_SECTION(_sec) BOUNDED_SECTION_BY(_sec, _sec)
+#define BOUNDED_SECTION_BY_ALIGNED(_sec_, _label_, _ALIGNED_) \
+ BOUNDED_SECTION_PRE_LABEL_ALIGNED(_sec_, _label_, __start, __stop, _ALIGNED_)
+
+#define BOUNDED_SECTION(_sec) BOUNDED_SECTION_BY(_sec, _sec)
#endif /* _ASM_GENERIC_BOUNDED_SECTIONS_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 9c61dd083f26..145beb14b94b 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -640,7 +640,7 @@
#define EXCEPTION_TABLE(align) \
. = ALIGN(align); \
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \
- BOUNDED_SECTION_BY(__ex_table, ___ex_table) \
+ BOUNDED_SECTION_BY_ALIGNED(__ex_table, ___ex_table, align) \
}
/*
@@ -650,7 +650,7 @@
#define BTF \
. = ALIGN(PAGE_SIZE); \
.BTF : AT(ADDR(.BTF) - LOAD_OFFSET) { \
- BOUNDED_SECTION_BY(.BTF, _BTF) \
+ BOUNDED_SECTION_BY_ALIGNED(.BTF, _BTF, PAGE_SIZE) \
} \
. = ALIGN(PAGE_SIZE); \
.BTF_ids : AT(ADDR(.BTF_ids) - LOAD_OFFSET) { \
@@ -832,16 +832,17 @@
#ifdef CONFIG_UNWINDER_ORC
#define ORC_UNWIND_TABLE \
+ . = ALIGN(4); \
.orc_header : AT(ADDR(.orc_header) - LOAD_OFFSET) { \
- BOUNDED_SECTION_BY(.orc_header, _orc_header) \
+ BOUNDED_SECTION_BY_ALIGNED(.orc_header, _orc_header, 4) \
} \
. = ALIGN(4); \
.orc_unwind_ip : AT(ADDR(.orc_unwind_ip) - LOAD_OFFSET) { \
- BOUNDED_SECTION_BY(.orc_unwind_ip, _orc_unwind_ip) \
+ BOUNDED_SECTION_BY_ALIGNED(.orc_unwind_ip, _orc_unwind_ip, 4)\
} \
. = ALIGN(2); \
.orc_unwind : AT(ADDR(.orc_unwind) - LOAD_OFFSET) { \
- BOUNDED_SECTION_BY(.orc_unwind, _orc_unwind) \
+ BOUNDED_SECTION_BY_ALIGNED(.orc_unwind, _orc_unwind, 2) \
} \
text_size = _etext - _stext; \
. = ALIGN(4); \
@@ -869,7 +870,7 @@
#define TRACEDATA \
. = ALIGN(4); \
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \
- BOUNDED_SECTION_POST_LABEL(.tracedata, __tracedata, _start, _end) \
+ BOUNDED_SECTION_POST_LABEL_ALIGNED(.tracedata, __tracedata, _start, _end, 4) \
}
#else
#define TRACEDATA
@@ -898,13 +899,14 @@
*(.note.gnu.property) \
} \
.notes : AT(ADDR(.notes) - LOAD_OFFSET) { \
- BOUNDED_SECTION_BY(.note.*, _notes) \
+ /* *(.note.*) are natively 4-byte aligned */ \
+ BOUNDED_SECTION_BY_ALIGNED(.note.*, _notes, 4) \
} NOTES_HEADERS \
NOTES_HEADERS_RESTORE
#define INIT_SETUP(initsetup_align) \
. = ALIGN(initsetup_align); \
- BOUNDED_SECTION_POST_LABEL(.init.setup, __setup, _start, _end)
+ BOUNDED_SECTION_POST_LABEL_ALIGNED(.init.setup, __setup, _start, _end, initsetup_align)
#define INIT_CALLS_LEVEL(level) \
__initcall##level##_start = .; \
--
2.54.0
^ permalink raw reply related
* [PATCH v4 04/25] vmlinux.lds.h: drop unused HEADERED_SECTION* macros
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
These macros are unused, no point in carrying them any more.
NB: these macros were just moved to bounded_sections.lds.h, from
vmlinux.lds.h, which is the known entity, and therefore more
meaningful in the 1-line summary, so thats what I used as the topic.
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
include/asm-generic/bounded_sections.lds.h | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/include/asm-generic/bounded_sections.lds.h b/include/asm-generic/bounded_sections.lds.h
index 8c29293ca7fb..268cdc34389b 100644
--- a/include/asm-generic/bounded_sections.lds.h
+++ b/include/asm-generic/bounded_sections.lds.h
@@ -18,19 +18,4 @@
#define BOUNDED_SECTION(_sec) BOUNDED_SECTION_BY(_sec, _sec)
-#define HEADERED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_, _HDR_) \
- _HDR_##_label_ = .; \
- KEEP(*(.gnu.linkonce.##_sec_)) \
- BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_)
-
-#define HEADERED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_, _HDR_) \
- _label_##_HDR_ = .; \
- KEEP(*(.gnu.linkonce.##_sec_)) \
- BOUNDED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_)
-
-#define HEADERED_SECTION_BY(_sec_, _label_) \
- HEADERED_SECTION_PRE_LABEL(_sec_, _label_, __start, __stop)
-
-#define HEADERED_SECTION(_sec) HEADERED_SECTION_BY(_sec, _sec)
-
#endif /* _ASM_GENERIC_BOUNDED_SECTIONS_H */
--
2.54.0
^ permalink raw reply related
* [PATCH v4 03/25] vmlinux.lds.h: refactor BOUNDED_SECTION_* macros into bounded_sections.lds.h
From: Jim Cromie @ 2026-06-02 22:48 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
Move BOUNDED_SECTION_* macros to a new helper file:
include/asm-generic/bounded_sections.lds.h and include it back into
vmlinux.lds.h. This allows its reuse later to fix a failure to keep
dyndbg sections in some circumstances.
NOTES:
These macros are only for use in vmlinux.lds.h, where the _start &
_end symbols are needed. Modules keep sections separate in ELF
sections, with their boundaries known, so the _start and _end are not
useful, and may confuse tools not expecting them.
This patch ignores a checkpatch warning, because new file is covered
by "GENERIC INCLUDE/ASM HEADER FILES" in MAINTAINERS
CC: Arnd Bergmann <arnd@arndb.de>
CC: linux-arch@vger.kernel.org
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
v3: move include to top
---
include/asm-generic/bounded_sections.lds.h | 36 ++++++++++++++++++++++++++++++
include/asm-generic/vmlinux.lds.h | 31 +------------------------
2 files changed, 37 insertions(+), 30 deletions(-)
diff --git a/include/asm-generic/bounded_sections.lds.h b/include/asm-generic/bounded_sections.lds.h
new file mode 100644
index 000000000000..8c29293ca7fb
--- /dev/null
+++ b/include/asm-generic/bounded_sections.lds.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _ASM_GENERIC_BOUNDED_SECTIONS_H
+#define _ASM_GENERIC_BOUNDED_SECTIONS_H
+
+#define BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_) \
+ _BEGIN_##_label_ = .; \
+ KEEP(*(_sec_)) \
+ _END_##_label_ = .;
+
+#define BOUNDED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_) \
+ _label_##_BEGIN_ = .; \
+ KEEP(*(_sec_)) \
+ _label_##_END_ = .;
+
+#define BOUNDED_SECTION_BY(_sec_, _label_) \
+ BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, __start, __stop)
+
+#define BOUNDED_SECTION(_sec) BOUNDED_SECTION_BY(_sec, _sec)
+
+#define HEADERED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_, _HDR_) \
+ _HDR_##_label_ = .; \
+ KEEP(*(.gnu.linkonce.##_sec_)) \
+ BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_)
+
+#define HEADERED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_, _HDR_) \
+ _label_##_HDR_ = .; \
+ KEEP(*(.gnu.linkonce.##_sec_)) \
+ BOUNDED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_)
+
+#define HEADERED_SECTION_BY(_sec_, _label_) \
+ HEADERED_SECTION_PRE_LABEL(_sec_, _label_, __start, __stop)
+
+#define HEADERED_SECTION(_sec) HEADERED_SECTION_BY(_sec, _sec)
+
+#endif /* _ASM_GENERIC_BOUNDED_SECTIONS_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 60c8c22fd3e4..9c61dd083f26 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -50,6 +50,7 @@
* [__nosave_begin, __nosave_end] for the nosave data
*/
+#include <asm-generic/bounded_sections.lds.h>
#include <asm-generic/codetag.lds.h>
#ifndef LOAD_OFFSET
@@ -211,36 +212,6 @@
# endif
#endif
-#define BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_) \
- _BEGIN_##_label_ = .; \
- KEEP(*(_sec_)) \
- _END_##_label_ = .;
-
-#define BOUNDED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_) \
- _label_##_BEGIN_ = .; \
- KEEP(*(_sec_)) \
- _label_##_END_ = .;
-
-#define BOUNDED_SECTION_BY(_sec_, _label_) \
- BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, __start, __stop)
-
-#define BOUNDED_SECTION(_sec) BOUNDED_SECTION_BY(_sec, _sec)
-
-#define HEADERED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_, _HDR_) \
- _HDR_##_label_ = .; \
- KEEP(*(.gnu.linkonce.##_sec_)) \
- BOUNDED_SECTION_PRE_LABEL(_sec_, _label_, _BEGIN_, _END_)
-
-#define HEADERED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_, _HDR_) \
- _label_##_HDR_ = .; \
- KEEP(*(.gnu.linkonce.##_sec_)) \
- BOUNDED_SECTION_POST_LABEL(_sec_, _label_, _BEGIN_, _END_)
-
-#define HEADERED_SECTION_BY(_sec_, _label_) \
- HEADERED_SECTION_PRE_LABEL(_sec_, _label_, __start, __stop)
-
-#define HEADERED_SECTION(_sec) HEADERED_SECTION_BY(_sec, _sec)
-
#ifdef CONFIG_TRACE_BRANCH_PROFILING
#define LIKELY_PROFILE() \
BOUNDED_SECTION_BY(_ftrace_annotated_branch, _annotated_branch_profile)
--
2.54.0
^ permalink raw reply related
* [PATCH v4 02/25] docs/dyndbg: explain flags parse 1st
From: Jim Cromie @ 2026-06-02 22:47 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
When writing queries to >control, flags are parsed 1st, since they are
the only required field, and they require specific compositions. So
if the flags draw an error (on those specifics), then keyword errors
aren't reported. This can be mildly confusing/annoying, so explain it
instead.
cc: linux-doc@vger.kernel.org
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
Documentation/admin-guide/dynamic-debug-howto.rst | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 4b14d9fd0300..9c2f096ed1d8 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -109,10 +109,19 @@ The match-spec's select *prdbgs* from the catalog, upon which to apply
the flags-spec, all constraints are ANDed together. An absent keyword
is the same as keyword "*".
-
-A match specification is a keyword, which selects the attribute of
-the callsite to be compared, and a value to compare against. Possible
-keywords are:::
+Note that since the match-spec can be empty, the flags are checked 1st,
+then the pairs of keyword and value. Flag errs will hide keyword errs::
+
+ bash-5.2# ddcmd mod bar +foo
+ dyndbg: read 13 bytes from userspace
+ dyndbg: query 0: "mod bar +foo" mod:*
+ dyndbg: unknown flag 'o'
+ dyndbg: flags parse failed
+ dyndbg: processed 1 queries, with 0 matches, 1 errs
+
+So a match-spec is a keyword, which selects the attribute of the
+callsite to be compared, and a value to compare against. Possible
+keywords are::
match-spec ::= 'func' string |
'file' string |
--
2.54.0
^ permalink raw reply related
* [PATCH v4 01/25] docs/dyndbg: update examples \012 to \n
From: Jim Cromie @ 2026-06-02 22:47 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet
In-Reply-To: <20260602-dd-maint-2-v4-0-19a1445585a8@gmail.com>
commit 47ea6f99d06e ("dyndbg: use ESCAPE_SPACE for cat control")
changed the control-file to display format strings with "\n" rather
than "\012". Update the docs to match the new reality.
Reviewed-by: Louis Chauvet <louis.chauvet@bootlin.com>
Tested-by: Louis Chauvet <louis.chauvet@bootlin.com>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
Documentation/admin-guide/dynamic-debug-howto.rst | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 095a63892257..4b14d9fd0300 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -38,12 +38,12 @@ You can view the currently configured behaviour in the *prdbg* catalog::
:#> 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"
+ 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"
The 3rd space-delimited column shows the current flags, preceded by
a ``=`` for easy use with grep/cut. ``=p`` shows enabled callsites.
@@ -59,10 +59,10 @@ query/commands to the control file. Example::
:#> ddcmd '-p; module main func run* +p'
:#> grep =p /proc/dynamic_debug/control
- init/main.c:1424 [main]run_init_process =p " with arguments:\012"
- init/main.c:1426 [main]run_init_process =p " %s\012"
- init/main.c:1427 [main]run_init_process =p " with environment:\012"
- init/main.c:1429 [main]run_init_process =p " %s\012"
+ init/main.c:1424 [main]run_init_process =p " with arguments:\n"
+ init/main.c:1426 [main]run_init_process =p " %s\n"
+ init/main.c:1427 [main]run_init_process =p " with environment:\n"
+ init/main.c:1429 [main]run_init_process =p " %s\n"
Error messages go to console/syslog::
--
2.54.0
^ permalink raw reply related
* [PATCH v4 00/25] dynamic-debug cleanups refactors maintenance + alignment fix
From: Jim Cromie @ 2026-06-02 22:47 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Arnd Bergmann, Jason Baron,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Andrew Morton, Shuah Khan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
Cc: linux-doc, linux-kernel, linux-arch, linux-modules,
linux-kselftest, dri-devel, Jim Cromie, Louis Chauvet,
Łukasz Bartosik
V4 of this series drops 2 doc-only patches in v3, recently picked up
by linux-doc, thx Jonathan
So new 1st 5 are a fix to a linker-script alignment problem in 32bit
arches causing a null-ptr scanning dyndbg-descriptor section on i386.
These were reviewed by Petr Pavlu.
V4 main change is addition and use of match_wildcard_hyphen(), which
allows that "i2c_hid" is same as "i2c-hid" wrt to modname comparison.
This addresses sashiko-dev's feedback on V3.
v3:
The remaining patches are cleanups, refactors in preparation for an
API change needed to fix a regression in DRM when it uses classmaps.
I split these out for easier review, I will follow up with the API
change afterwards.
The biggest revision vs V2 is the new patch: 25. It addresses a flaw
detected by sashiko which is best described by example.
Dyndbg uses KBUILD_MODNAME to provide module-name, this works well for
loadable modules (module loader requires unique module names), but for
builtin modules, is effectively kbasename, and not unique.
So we get 4 modules named "main": init/main, kernel/power/main,
kernel/base/poser/main. This ambiguity is visible in user-space since
the beginning of dyndbg.
Now suppose kernel/{,base}/power/main want to define classmaps to
categorize the various pr-debugs they have. The current code finds a
module's classmaps by strcmp on modname, so init/main will match
against classmaps defined by both kernel/{,base}/power/main.
The current code will also map "main" classes to kernel/*/power/main,
so they will probably work at first, but 2 independent classmaps can
both use class-ids 0-N, but will conflict if they're both used by a
module. Then we have classmap overlaps and unpredictable results.
patch-24 eliminates the ambiguity by using KBUILD_MODFILE to provide a
unique module-name, then adds matching against kbasename(modname) to
restore the legacy query behavior. It *does* change the modname
exposed in /proc/dynamic_debug/control, but not the result of a query
like "module main +p".
OLDER VERSIONS:
V2 primarily revises:
https://lore.kernel.org/lkml/20260504-dd-cleanups-2-v1-0-6fdd24040642@gmail.com/
V2 addressed most of sashiko's feedback on V1:
https://sashiko.dev/#/patchset/20260504-dd-cleanups-2-v1-0-6fdd24040642%40gmail.com
It dropped the pr-fmt patch, as not reproducible,
advanced the drop-NAMES patch to reduce subsequent churn,
and fixed the classmaps PARAMs to u64 to avoid 32bit flags on 32bit arches
For easy one-stop-shopping, V2 also included 2 smaller series:
1st fixes a section alignment problem, with Reviewed-by from Petr Pavlu
https://lore.kernel.org/lkml/20260515-asm-generic-1-v3-0-680b273666d4@gmail.com/
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
Changes in v4:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- Link to v3: https://lore.kernel.org/r/20260601-dd-maint-2-v3-0-4a15b241bd3c@gmail.com
Changes in v3:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- Link to v2: https://lore.kernel.org/r/20260523-dd-maint-2-v2-0-b937312aa083@gmail.com
---
Jim Cromie (25):
docs/dyndbg: update examples \012 to \n
docs/dyndbg: explain flags parse 1st
vmlinux.lds.h: refactor BOUNDED_SECTION_* macros into bounded_sections.lds.h
vmlinux.lds.h: drop unused HEADERED_SECTION* macros
vmlinux.lds.h: Fix ALIGN(8) omission causing NULL ptr on i386
vmlinux.lds.h: remove redundant ALIGN(8) directives
dyndbg.lds.S: fix lost dyndbg sections in modules
dyndbg: factor ddebug_match_desc out from ddebug_change
dyndbg: add stub macro for DECLARE_DYNDBG_CLASSMAP
dyndbg: reword "class unknown," to "class:_UNKNOWN_"
dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
dyndbg: drop NUM_TYPE_ARGS
dyndbg: reduce verbose/debug clutter
dyndbg: refactor param_set_dyndbg_classes and below
dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
dyndbg: replace classmap list with an array-slice
dyndbg: macrofy a 2-index for-loop pattern
dyndbg: Upgrade class param storage to u64 for 64-bit classmaps
dyndbg,module: make proper substructs in _ddebug_info
dyndbg: move mod_name down from struct ddebug_table to _ddebug_info
dyndbg: hoist classmap-filter-by-modname up to ddebug_add_module
selftests-dyndbg: add a dynamic_debug run_tests target
dyndbg: change __dynamic_func_call_cls* macros into expressions
lib/parser: add match_wildcard_hyphen() for agnostic matching
dynamic_debug: use KBUILD_MODFILE for unique builtin module names
Documentation/admin-guide/dynamic-debug-howto.rst | 55 ++-
MAINTAINERS | 2 +
drivers/gpu/drm/drm_print.c | 6 +-
include/asm-generic/bounded_sections.lds.h | 32 ++
include/asm-generic/dyndbg.lds.h | 18 +
include/asm-generic/vmlinux.lds.h | 68 +--
include/drm/drm_print.h | 2 +-
include/linux/dynamic_debug.h | 133 +++---
include/linux/parser.h | 1 +
kernel/module/main.c | 12 +-
lib/dynamic_debug.c | 507 ++++++++++-----------
lib/parser.c | 58 ++-
lib/test_dynamic_debug.c | 30 +-
scripts/module.lds.S | 2 +
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/dynamic_debug/Makefile | 9 +
tools/testing/selftests/dynamic_debug/config | 8 +
.../selftests/dynamic_debug/dyndbg_selftest.sh | 343 ++++++++++++++
18 files changed, 833 insertions(+), 454 deletions(-)
---
base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
change-id: 20260521-dd-maint-2-76c542079420
Best regards,
--
Jim Cromie <jim.cromie@gmail.com>
^ permalink raw reply
* Re: [PATCH v7 07/42] KVM: guest_memfd: Only prepare folios for private pages
From: Ackerley Tng @ 2026-06-02 22:41 UTC (permalink / raw)
To: Suzuki K Poulose, aik, andrew.jones, binbin.wu, brauner,
chao.p.peng, david, ira.weiny, jmattson, jthoughton, michael.roth,
oupton, pankaj.gupta, qperret, rick.p.edgecombe, rientjes,
shivankg, steven.price, tabba, willy, wyihan, yan.y.zhao,
forkloop, pratyush, aneesh.kumar, liam, Paolo Bonzini,
Sean Christopherson, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Jonathan Corbet, Shuah Khan,
Shuah Khan, Vishal Annapurve, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Youngjun Park, Qi Zheng,
Shakeel Butt, Kiryl Shutsemau, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, linux-coco
In-Reply-To: <144bbb9f-39a2-4c90-8903-51521e022da0@arm.com>
Suzuki K Poulose <suzuki.poulose@arm.com> writes:
>
> [...snip...]
>
>>> @@ -914,7 +916,8 @@ int kvm_gmem_get_pfn(struct kvm *kvm, struct
>>> kvm_memory_slot *slot,
>>> folio_mark_uptodate(folio);
>>> }
>>> - r = kvm_gmem_prepare_folio(kvm, slot, gfn, folio);
>>> + if (kvm_gmem_is_private_mem(inode, index))
>>
>> Don't we need to make sure the entire folio is private ? Not just the
>> page at the index ?
>> if (kvm_gmem_range_is_private(, index, folio_nr_pages(folio)) ?
I was thinking to fix this when I do huge pages, for now guest_memfd is
always just PAGE_SIZE, so just looking up index is fine.
Is that okay?
>
> Or rather, we should go through the individual pages and apply the
> prepare for ones that are private ?
>
> Suzuki
>
IIRC the plan was to make kvm_gmem_prepare_folio() idempotent, as in, if
a page is already private, just skip. Currently sev_gmem_prepare() does
a pr_debug(), which I guess is technically still idempotent.
I'm thinking that the information tha needs tracking to make
.gmem_prepare() idempotent should be tracked by arch code.
Does this work for ARM CCA?
>>
>> [...snip...]
>>
^ permalink raw reply
* Re: [PATCH v6 14/15] selftests/mm: add userfaultfd RWP tests
From: Askar Safin @ 2026-06-02 22:18 UTC (permalink / raw)
To: kas
Cc: Liam.Howlett, aarcange, akpm, corbet, david, jthoughton,
kernel-team, kvm, linux-doc, linux-kernel, linux-kselftest,
linux-mm, ljs, pbonzini, peterx, rppt, seanjc, sj, skhan, surenb,
usama.arif, vbabka, ziy
In-Reply-To: <20260529172716.357179-15-kas@kernel.org>
"Kiryl Shutsemau (Meta)" <kas@kernel.org>:
> +/*
> + * Test that GUP resolves through protnone PTEs (async mode).
> + * vmsplice() into a pipe pins user pages via get_user_pages_fast() --
> + * unlike write(), which goes through copy_from_user() and ordinary
> + * hardware page faults -- so it exercises gup_can_follow_protnone() on
> + * the RW-protected PTE. In async mode the kernel auto-restores
> + * permissions and GUP returns the page.
> + */
Note that I recently submitted a patch, which makes vmsplice equivalent to
preadv2/pwritev2, and it was accepted to next.
For now it is just an experiment, it is possible it will be reverted.
https://lore.kernel.org/all/20260601-aufweichen-dissens-ausrechnen-0d9b84728113@brauner/
--
Askar Safin
^ permalink raw reply
* Re: [PATCH net-next v07 1/6] hinic3: Add ethtool queue ops
From: Jakub Kicinski @ 2026-06-02 21:38 UTC (permalink / raw)
To: gongfan1
Cc: Jakub Kicinski, zhuyikai1, netdev, davem, edumazet, pabeni, horms,
andrew+netdev, ioana.ciornei, mohsin.bashr, linux-kernel,
linux-doc, luosifu, guoxin09, zhoushuai28, wulike1, shijing34,
zhengjiezhen, maxime.chevallier
In-Reply-To: <1323cad7ba784efa29a3fd1475b744974e0a0cf5.1779940072.git.zhuyikai1@h-partners.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
hinic3: Add ethtool queue ops
This patch implements .get_ringparam and .set_ringparam for hinic3,
introduces a hinic3_change_channel_settings() helper plus a new
HINIC3_CHANGE_RES_INVALID flag, and refactors hinic3_open_channel() into
a hinic3_prepare_channel()/hinic3_open_channel() pair.
A few observations and questions on the patch as posted.
> hinic3: Add ethtool queue ops
Could the subject line be more accurate? The patch also introduces
hinic3_change_channel_settings(), the HINIC3_CHANGE_RES_INVALID flag with
checks injected into hinic3_link_status_change() and
hinic3_set_interrupt_moder(), splits hinic3_open_channel() into
hinic3_prepare_channel()+hinic3_open_channel(), renames hinic3_uninit_qps()
to hinic3_get_cur_qps(), and adds new hinic3_free_nicio_res() and
hinic3_destroy_num_qps() calls in hinic3_close() that look like a
pre-existing leak fix. Could these be split into separate commits, with
the leak fix carrying a Fixes: tag so it can be backported?
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
> index 90fc16288de9..e594bcbc8153 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
> @@ -10,6 +10,7 @@
> #include <linux/etherdevice.h>
> #include <linux/netdevice.h>
> #include <linux/ethtool.h>
> +#include <net/devlink.h>
[Low]
Is net/devlink.h actually needed here? The new code uses
NL_SET_ERR_MSG_MOD / NL_SET_ERR_MSG_FMT_MOD (from linux/netlink.h) and
netif_running() / netdev_info(), none of which require devlink.
> @@ -409,6 +410,103 @@ hinic3_get_link_ksettings(struct net_device *netdev,
> return 0;
> }
>
> +static void hinic3_get_ringparam(struct net_device *netdev,
> + struct ethtool_ringparam *ring,
> + struct kernel_ethtool_ringparam *kernel_ring,
> + struct netlink_ext_ack *extack)
> +{
> + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> +
> + ring->rx_max_pending = HINIC3_MAX_RX_QUEUE_DEPTH;
> + ring->tx_max_pending = HINIC3_MAX_TX_QUEUE_DEPTH;
> + ring->rx_pending = nic_dev->rxqs[0].q_depth;
> + ring->tx_pending = nic_dev->txqs[0].q_depth;
> +}
[Low]
Should the getter and setter consult the same canonical depth field? The
getter reads nic_dev->rxqs[0].q_depth / nic_dev->txqs[0].q_depth, while
hinic3_set_ringparam() compares against and updates
nic_dev->q_params.sq_depth / rq_depth. They are kept consistent today by
hinic3_alloc_rxqs() and hinic3_update_qp_depth(), but the asymmetry is
fragile to future refactors. Would it be clearer to read q_params here too?
[ ... ]
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
> index e7d6c2033b45..cc43773c1984 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
> @@ -137,7 +137,8 @@ static int hinic3_set_interrupt_moder(struct net_device *netdev, u16 q_id,
> struct hinic3_interrupt_info info = {};
> int err;
>
> - if (q_id >= nic_dev->q_params.num_qps)
> + if (test_bit(HINIC3_CHANGE_RES_INVALID, &nic_dev->flags) ||
> + q_id >= nic_dev->q_params.num_qps)
> return 0;
[High]
Is HINIC3_CHANGE_RES_INVALID being used as an ad-hoc lock to coordinate
readers (this function, hinic3_link_status_change(), hinic3_close()) with
the teardown path in hinic3_change_channel_settings()?
The networking subsystem guidance flags exactly this pattern — bit flags
with set_bit()/test_bit()/clear_bit() guarding code sections rather than
expressing state — and recommends a real lock or RCU.
Concretely for hinic3_link_status_change(), can this race happen?
CPU0 (auxiliary event) CPU1 (set_ringparam under RTNL)
test_bit(...) -> 0
fall through test_and_set_bit(...) was 0, now 1
hinic3_vport_down()
netif_carrier_off()
msleep(100)
netif_carrier_on()
nic_dev->link_status_up = true
End state would be carrier reported up while the device is mid-reconfigure
with the old channel torn down. The validation check runs outside any
exclusion region with the writer.
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> index 0a888fe4c975..8cf605a0a5d2 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> @@ -315,6 +315,9 @@ static void hinic3_link_status_change(struct net_device *netdev,
> {
> struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
>
> + if (test_bit(HINIC3_CHANGE_RES_INVALID, &nic_dev->flags))
> + return;
> +
(see comment above on the bit-as-lock pattern.)
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
> index da73811641a9..b7f9ba8ce43f 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
[ ... ]
> @@ -428,6 +439,72 @@ static void hinic3_vport_down(struct net_device *netdev)
> }
> }
>
> +int
> +hinic3_change_channel_settings(struct net_device *netdev,
> + struct hinic3_dyna_txrxq_params *trxq_params)
> +{
> + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> + struct hinic3_dyna_txrxq_params cur_trxq_params = {};
> + struct hinic3_dyna_qp_params new_qp_params = {};
> + struct hinic3_dyna_qp_params cur_qp_params = {};
> + int err;
> +
> + cur_trxq_params = nic_dev->q_params;
> +
> + hinic3_config_num_qps(netdev, trxq_params);
> +
> + err = hinic3_alloc_channel_resources(netdev, &new_qp_params,
> + trxq_params);
> + if (err) {
> + netdev_err(netdev, "Failed to alloc channel resources\n");
> + return err;
> + }
> +
> + if (!test_and_set_bit(HINIC3_CHANGE_RES_INVALID, &nic_dev->flags)) {
> + hinic3_vport_down(netdev);
> + hinic3_close_channel(netdev);
> + hinic3_get_cur_qps(nic_dev, &cur_qp_params);
> + }
> +
> + hinic3_init_qps(nic_dev, &new_qp_params);
> +
> + err = hinic3_prepare_channel(netdev, trxq_params);
> + if (err)
> + goto err_uninit_qps;
> +
> + if (nic_dev->num_qp_irq > trxq_params->num_qps)
> + hinic3_qp_irq_change(netdev, trxq_params->num_qps);
> +
> + nic_dev->q_params = *trxq_params;
> +
> + err = hinic3_open_channel(netdev);
> + if (err)
> + goto err_qp_irq_reset;
> +
> + err = hinic3_vport_up(netdev);
> + if (err)
> + goto err_close_channel;
> +
> + hinic3_free_channel_resources(netdev, &cur_qp_params, &cur_trxq_params);
> +
> + clear_bit(HINIC3_CHANGE_RES_INVALID, &nic_dev->flags);
> +
> + return 0;
> +
> +err_close_channel:
> + hinic3_close_channel(netdev);
> +err_qp_irq_reset:
> + nic_dev->q_params = cur_trxq_params;
> +
> + if (trxq_params->num_qps > cur_trxq_params.num_qps)
> + hinic3_qp_irq_change(netdev, cur_trxq_params.num_qps);
> +err_uninit_qps:
> + hinic3_get_cur_qps(nic_dev, &new_qp_params);
> + hinic3_free_channel_resources(netdev, &new_qp_params, trxq_params);
> +
> + return err;
> +}
[High]
Do the error paths leak the OLD QP resources?
After the test_and_set_bit() block runs, hinic3_close_channel() and
hinic3_get_cur_qps(&cur_qp_params) capture the OLD nic_io->sq/rq into
cur_qp_params. hinic3_init_qps(&new_qp_params) then overwrites nic_io with
the NEW pointers.
On the success path, cur_qp_params is freed via:
hinic3_free_channel_resources(netdev, &cur_qp_params, &cur_trxq_params);
But err_close_channel, err_qp_irq_reset and err_uninit_qps only free
new_qp_params/trxq_params. cur_qp_params is never referenced again on these
paths, so the kzalloc'd sqs/rqs arrays plus the per-QP DMA-coherent WQ pages
created by hinic3_create_qp() appear to leak per failed ringparam change.
[High]
Is HINIC3_CHANGE_RES_INVALID ever cleared on failure?
Only the success path runs:
clear_bit(HINIC3_CHANGE_RES_INVALID, &nic_dev->flags);
err_close_channel, err_qp_irq_reset and err_uninit_qps return without
clearing. Once stuck high:
- hinic3_link_status_change() returns immediately on every event, so
carrier transitions stop propagating;
- hinic3_set_interrupt_moder() returns 0 without applying changes;
- hinic3_close() takes the test_and_clear_bit() goto-out branch and
skips hinic3_vport_down()/hinic3_close_channel()/free_channel_resources
entirely while still calling hinic3_free_nicio_res() and
hinic3_destroy_num_qps().
After a failed ethtool -G, would the only recovery be a driver reload or
device reset?
[High]
Does hinic3_free_qp_ctxts() get called when hinic3_open_channel() fails
here?
hinic3_prepare_channel() programs the HW root context via
hinic3_set_root_ctxt() and per-SQ hinic3_set_ci_table(); the matching
teardown is hinic3_free_qp_ctxts() -> hinic3_clean_root_ctxt(). On
hinic3_open_channel() failure this jumps to err_qp_irq_reset ->
err_uninit_qps, which only does hinic3_get_cur_qps() +
hinic3_free_channel_resources(). The latter dma_free's the WQ pages whose
physical addresses the firmware still has.
The pre-patch hinic3_open_channel() had an explicit err_free_qp_ctxts label
covering this case; was the symmetry intentionally dropped?
> @@ -458,6 +535,10 @@ static int hinic3_open(struct net_device *netdev)
>
> hinic3_init_qps(nic_dev, &qp_params);
>
> + err = hinic3_prepare_channel(netdev, &nic_dev->q_params);
> + if (err)
> + goto err_uninit_qps;
> +
> err = hinic3_open_channel(netdev);
> if (err)
> goto err_uninit_qps;
> @@ -473,7 +554,7 @@ static int hinic3_open(struct net_device *netdev)
> err_close_channel:
> hinic3_close_channel(netdev);
> err_uninit_qps:
> - hinic3_uninit_qps(nic_dev, &qp_params);
> + hinic3_get_cur_qps(nic_dev, &qp_params);
> hinic3_free_channel_resources(netdev, &qp_params, &nic_dev->q_params);
[High]
Same observation as above for the open() path: when hinic3_open_channel()
fails after hinic3_prepare_channel() succeeded, control jumps to
err_uninit_qps which does not call hinic3_free_qp_ctxts(), so the HW root
context and per-SQ CI table programming is left in place while the WQ
pages backing the addresses are freed. Should hinic3_free_qp_ctxts() be
called in this path?
> @@ -493,10 +574,18 @@ static int hinic3_close(struct net_device *netdev)
> return 0;
> }
>
> + if (test_and_clear_bit(HINIC3_CHANGE_RES_INVALID, &nic_dev->flags))
> + goto out;
> +
> hinic3_vport_down(netdev);
> hinic3_close_channel(netdev);
> - hinic3_uninit_qps(nic_dev, &qp_params);
> - hinic3_free_channel_resources(netdev, &qp_params, &nic_dev->q_params);
> + hinic3_get_cur_qps(nic_dev, &qp_params);
> + hinic3_free_channel_resources(netdev, &qp_params,
> + &nic_dev->q_params);
> +
> +out:
> + hinic3_free_nicio_res(nic_dev);
> + hinic3_destroy_num_qps(netdev);
>
> return 0;
> }
(see the high-severity comments above on HINIC3_CHANGE_RES_INVALID never
being cleared on failure — the goto-out branch here is the path that
silently skips channel teardown when that happens.)
[ ... ]
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c
> index 309ab5901379..b5b601469517 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c
> @@ -541,7 +541,7 @@ int hinic3_configure_rxqs(struct net_device *netdev, u16 num_rq,
> rq_associate_cqes(rxq);
>
> pkts = hinic3_rx_fill_buffers(rxq);
> - if (!pkts) {
> + if (pkts < rxq->q_depth - 1) {
> netdev_err(netdev, "Failed to fill Rx buffer\n");
> return -ENOMEM;
> }
[Medium]
Could this hunk be called out in the commit message? The success criterion
for hinic3_rx_fill_buffers() changes from "any buffers filled" to "almost
all buffers filled" (q_depth - 1). hinic3_rx_fill_buffers() loops up to
q_depth - 1 entries and breaks on the first allocation failure, so any
short fill — for example a single page allocation failure under transient
memory pressure — now returns -ENOMEM and aborts hinic3_open() or
hinic3_change_channel_settings(). This seems unrelated to "Add ethtool
queue ops"; was the behavior change intentional?
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH v7 34/42] KVM: selftests: Test conversion with elevated page refcount
From: Askar Safin @ 2026-06-02 21:26 UTC (permalink / raw)
To: devnull+ackerleytng.google.com
Cc: ackerleytng, aik, akpm, andrew.jones, aneesh.kumar, axelrasmussen,
baohua, bhe, binbin.wu, bp, brauner, chao.p.peng, chrisl, corbet,
dave.hansen, david, forkloop, hpa, ira.weiny, jgg, jmattson,
jthoughton, kas, kasong, kvm, liam, linux-coco, linux-doc,
linux-kernel, linux-kselftest, linux-mm, linux-trace-kernel,
mathieu.desnoyers, mhiramat, michael.roth, mingo, nphamcs, oupton,
pankaj.gupta, pbonzini, pratyush, qi.zheng, qperret,
rick.p.edgecombe, rientjes, rostedt, seanjc, shakeel.butt,
shikemeng, shivankg, shuah, skhan, steven.price, suzuki.poulose,
tabba, tglx, vannapurve, vbabka, weixugc, willy, wyihan, x86,
yan.y.zhao, youngjun.park, yuanchu
In-Reply-To: <20260522-gmem-inplace-conversion-v7-34-2f0fae496530@google.com>
Ackerley Tng via B4 Relay <devnull+ackerleytng.google.com@kernel.org>:
> This test uses vmsplice to increment the refcount of a specific page
I recently submitted a patch, which makes vmsplice equivalent to
preadv2/pwritev2, and it was accepted to next.
For now it is just an experiment, it is possible it will be reverted.
https://lore.kernel.org/all/20260601-aufweichen-dissens-ausrechnen-0d9b84728113@brauner/
--
Askar Safin
^ permalink raw reply
* Re: [PATCH v15 03/12] lib: kstrtox: add kstrtoudec64() and kstrtodec64()
From: Andy Shevchenko @ 2026-06-02 21:00 UTC (permalink / raw)
To: rodrigo.alencar
Cc: linux-kernel, linux-iio, devicetree, linux-doc, Jonathan Cameron,
David Lechner, Andy Shevchenko, Lars-Peter Clausen,
Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Jonathan Corbet, Andrew Morton, Petr Mladek, Steven Rostedt,
Rasmus Villemoes, Sergey Senozhatsky, Shuah Khan
In-Reply-To: <20260531-adf41513-iio-driver-v15-3-da09adf1c0dd@analog.com>
On Sun, May 31, 2026 at 09:30:46AM +0100, Rodrigo Alencar via B4 Relay wrote:
>
> Add helpers that parses decimal numbers into 64-bit number, i.e., decimal
> point numbers with pre-defined scale are parsed into a 64-bit value (fixed
> precision). After the decimal point, digits beyond the specified scale
> are ignored.
...
> +static int _kstrtoudec64(const char *s, unsigned int scale, u64 *res)
> +{
> + u64 _res = 0;
> + unsigned int rv_int, rv_frac;
> +
> + rv_int = _parse_integer(s, 10, &_res);
> + if (rv_int & KSTRTOX_OVERFLOW)
> + return -ERANGE;
> + s += rv_int;
> +
> + if (*s == '.')
> + s++; /* skip decimal point */
> +
> + rv_frac = _parse_integer_limit_init(s, 10, _res, &_res, scale);
> + if (rv_frac & KSTRTOX_OVERFLOW)
> + return -ERANGE;
> + s += rv_frac;
> + if (!rv_int && !rv_frac && !isdigit(*s))
Do we care about isdigit() here? Why?
> + return -EINVAL; /* no digits at all */
> + while (isdigit(*s)) /* truncate digits */
> + s++;
> + if (*s == '\n')
> + s++;
> + if (*s)
> + return -EINVAL;
> +
> + if (_res && (scale > (19 + rv_frac) || /* log10(2^64) = 19.26 */
It's better to make comment closer to the operand
if (_res && (scale > (19 + rv_frac) /* log10(2^64) = 19.26 */ ||
> + check_mul_overflow(_res, int_pow(10, scale - rv_frac), &_res)))
Can we deduplicate the scale - rv_frac?
I mean, would it be possible to do
if (_res && ((scale - rv_frac) > 19 /* log10(2^64) = 19.26 */ ||
without possible wraparound?
> + return -ERANGE;
> +
> + *res = _res;
> + return 0;
> +}
...
> +/**
> + * kstrtoudec64() - Convert a string to an unsigned 64-bit value that represents
> + * a scaled decimal number.
> + * @s: The start of the string. The string must be null-terminated, and may also
> + * include a single newline before its terminating null. The first character
> + * may also be a plus sign, but not a minus sign. Digits beyond the specified
> + * scale are ignored.
> + * @scale: The number of digits to the right of the decimal point. For example,
> + * a scale of 2 would mean the number is represented with two decimal places,
> + * so "123.45" would be represented as 12345.
> + * @res: Where to write the result of the conversion on success.
I believe it's better to leave short descriptions short and describe the
examples and other considerations here, in the description section.
All the same for the second one below.
> + * Return: 0 on success, -ERANGE on overflow and -EINVAL on parsing error.
> + */
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH 00/11] net: wwan: t9xx: Add MediaTek T9XX WWAN driver
From: Sergey Ryazanov @ 2026-06-02 20:46 UTC (permalink / raw)
To: Wu. JackBB (GSM), Jakub Kicinski, Jack Wu via B4 Relay
Cc: Loic Poulain, Johannes Berg, Andrew Lunn, David S. Miller,
Eric Dumazet, Paolo Abeni, Wen-Zhi Huang, Shi-Wei Yeh,
Minano Tseng, Matthias Brugger, AngeloGioacchino Del Regno,
Simon Horman, Jonathan Corbet, Shuah Khan,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-mediatek@lists.infradead.org, linux-doc@vger.kernel.org
In-Reply-To: <c279aea41ecf41c6aca4314a2f4e306b@compal.com>
Hi,
let me join the discussion and put my 2c.
On 6/2/26 13:58, Wu. JackBB (GSM) wrote:
> Hi Jakub,
>
>> On Fri, 29 May 2026 18:31:39 +0800 Jack Wu via B4 Relay wrote:
>>> 43 files changed, 14761 insertions(+)
>>
>> Please try to cut this down to ~5kLoC for the initial submission.
>> Whatever the absolute minimum sensible chunk of code is.
>>
>> Each patch must build cleanly with W=1
>
> We've already reduced this significantly from the original 41k LoC
> down to ~14.7k by stripping out non-essential features such as
> exception handling, memory logging, devlink, statistics, debug
> tracing, and others.
>
> We even removed some arguably necessary features (PM, mdlog,
> throughput optimizations) that we plan to submit as follow-up
> series.
Great work. Highly appreciate!
> Note that the line count may slightly increase in v2, as we plan
> to add missing kdoc comments based on review feedback.
>
> For reference, the t7xx driver (two generations older, simpler HW)
> had an initial submission of ~11.3k LoC [1]. The t9xx hardware is
> more complex, so we believe being in a similar range is reasonable.
Let me elaborate a bit here. The size problem is not due to a git or a
mailbox limitation. It arise due to the human limitation. The T7xx
submission review took something about 4 months and 8 iterations. And it
was 'only' 11.3k lines. Let's do some extrapolation assuming that
function is linear. 14.7k is 30% bigger, thus, estimated reviewing time
should be 5 months and 2 weeks. And this looks optimistic.
Recommendation, shared by Jakub, is practical. 5k lines might be
reviewed in a reasonable time and merged with the full confidence of the
quality.
> We'd like to keep the driver functional and reviewable in its
> current scope. Do you have any suggestions on how we could further
> reduce the size while maintaining a working initial submission?
Off the top of my head, I would suggest joining T7xx and T9xx code
bases. It could be done through factoring out a core functionality of
T7xx into a library, or through making the driver layered.
I am not pretending being an expert in any of these drivers, but
generally divide-n-conqueror together with code reuse work reliable. As
an alternative, I could spend a couple of weeks reviewing the new
submission and will come with more specific ideas on what can be thrown
away or reused.
> [1] https://patchwork.kernel.org/project/netdevbpf/cover/20220506181310.2183829-1-ricardo.martinez@linux.intel.com/
>
> Thanks.
>
>
> ================================================================================================================================================================
> This message may contain information which is private, privileged or confidential of Compal Electronics, Inc. If you are not the intended recipient of this message, please notify the sender and destroy/delete the message. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon this information, by persons or entities other than the intended recipient is prohibited.
> ================================================================================================================================================================
And this disclaimer does not facilitate the review. Am I 'intended'
recipient or should I destroy the message ASAP?
--
Sergey
^ permalink raw reply
* Re: [PATCH v7 07/42] KVM: guest_memfd: Only prepare folios for private pages
From: Ackerley Tng @ 2026-06-02 20:46 UTC (permalink / raw)
To: Suzuki K Poulose, aik, andrew.jones, binbin.wu, brauner,
chao.p.peng, david, ira.weiny, jmattson, jthoughton, michael.roth,
oupton, pankaj.gupta, qperret, rick.p.edgecombe, rientjes,
shivankg, steven.price, tabba, willy, wyihan, yan.y.zhao,
forkloop, pratyush, aneesh.kumar, liam, Paolo Bonzini,
Sean Christopherson, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Jonathan Corbet, Shuah Khan,
Shuah Khan, Vishal Annapurve, Andrew Morton, Chris Li,
Kairui Song, Kemeng Shi, Nhat Pham, Baoquan He, Barry Song,
Axel Rasmussen, Yuanchu Xie, Wei Xu, Youngjun Park, Qi Zheng,
Shakeel Butt, Kiryl Shutsemau, Jason Gunthorpe, Vlastimil Babka
Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
linux-mm, linux-coco
In-Reply-To: <d01cf1ec-b85d-4af6-9810-8107c0e2a4ec@arm.com>
Suzuki K Poulose <suzuki.poulose@arm.com> writes:
> On 23/05/2026 01:17, Ackerley Tng via B4 Relay wrote:
>> From: Ackerley Tng <ackerleytng@google.com>
>>
>> All-shared guest_memfd used to be only supported for non-CoCo VMs where
>> preparation doesn't apply. INIT_SHARED is about to be supported for
>> non-CoCo VMs in a later patch in this series.
>
> nit: s/non-CoCo/CoCo ?
>
Yes, thanks!
>>
>> In addition, KVM_SET_MEMORY_ATTRIBUTES2 is about to be supported in
>> guest_memfd in a later patch in this series.
>>
>> This means that the kvm fault handler may now call kvm_gmem_get_pfn() on a
>> shared folio for a CoCo VM where preparation applies.
>>
>> Add a check to make sure that preparation is only performed for private
>> folios.
>>
>> Preparation will be undone on freeing (see kvm_gmem_free_folio()) and on
>> conversion to shared.
>>
>> Signed-off-by: Michael Roth <michael.roth@amd.com>
>
> nit: Missing Co-Developed-by: ?
>
IIRC this should have been
Suggested-by: Michael Roth <michael.roth@amd.com>
IIRC Michael suggested this on one of the guest_memfd calls, Michael
please let me know if you remember otherwise!
>>
>> [...snip...]
>>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox