[lkml]   [2022]   [Aug]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
Subject[PATCH v5 14/33] dyndbg: add DECLARE_DYNDBG_CLASSMAP macro
With DECLARE_DYNDBG_CLASSMAP modules can declare up to 31 classnames.
By doing so, they authorize dyndbg to manipulate class'd prdbgs (ie:
__pr_debug_cls, and soon drm_*dbg)

:#> echo class DRM_UT_KMS +p > /proc/dynamic_debug/control

The macro declares and initializes a static struct ddebug_class_map:

- maps approved class-names to class_ids used in module,
by array order. forex: DRM_UT_*
- class-name vals allow validation of "class FOO" queries
using macro is opt-in
- enum class_map_type - determines interface, behavior

Each module has its own .class_id space, and only known class-names
will be authorized for a manipulation. Only DRM stuff should know this:

:#> echo class DRM_UT_CORE +p > control # across all modules

pr_debugs (with default class_id) are still controllable as before.

DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, classes...) is::

_var: name of the static struct var. user passes to module_param_cb()
if they want a sysfs node.

_maptype: this is hard-coded to DD_CLASS_TYPE_DISJOINT_BITS for now.

_base: usually 0, it allows splitting 31 classes into subranges, so
that multiple classes / sysfs-nodes can share the module's
class-id space.

classes: list of class_name strings, these are mapped to class-ids
starting at _base. This class-names list must have a
corresponding ENUM, with SYMBOLS that match the literals,
and 1st enum val = _base.

enum class_map_type has 4 values, on 2 factors::

- classes are disjoint/independent vs relative/x<y/verbosity.
disjoint is basis, verbosity by overlay.

- input NUMBERS vs [+-]CLASS_NAMES
uints, ideally hex. vs +DRM_UT_CORE,-DRM_UT_KMS

DD_CLASS_TYPE_DISJOINT_BITS: classes are separate, one per bit.
expecting hex input. built for drm.debug, basis for other types.

classes are independent, like DISJOINT

DD_CLASS_TYPE_LEVEL_NUM: input is numeric level, 0-N.
0 implies silence. use printk to break that.
relative levels applied on bitmaps.

avoiding EMERG,ALERT,CRIT,ERR - no point.


The macro places the initialized struct ddebug_class_map into the
__dyndbg_classes section. That draws a 'orphan' warning which we
handle in next commit. The struct attributes are necessary:
__aligned(8) stopped null-ptr derefs (why?), __used is needed by drm
drivers, which declare class-maps, but don't also declare a
sysfs-param, and thus dont ref the classmap; __used insures that the
linkage is made, then the class-map is found at load-time.

While its possible to handle both NAMES and NUMBERS in the same
sys-interface, there is ambiguity to avoid, by disallowing them
together. Later, if ambiguities are resolved, 2 new enums can permit
both inputs, on verbose & independent types separately, and authors
can select the interface they like.

The plan is to implement LEVELS in the callbacks, outside of
ddebug_exec_query(), which for simplicity will treat the CLASSES in
the map as disjoint. The callbacks can see map-type, and apply ++/--
loops (or bitops) to force the relative meanings across the

RFC: That leaves 2 issues:

1. doing LEVELs in callbacks means that the native >control interface
doesn't enforce the LEVELS relationship, so you could confusingly have
V3 enabled, but V1 disabled. OTOH, the control iface already allows
infinite tweaking of the underlying callsites; sysfs node readback can
only tell the user what they previously wrote.

2. All dyndbg >control reduces to a query/command, includes +/-, which
is at-root a kernel patching operation with +/- semantics. And the
_NAMES handling exposes it to the user, making it API-adjacent.

And its not just >control where +/- gets used (which is settled), the
new place is with sysfs-nodes exposing _*_NAMES classes, and here its
subtly different.

_DISJOINT_NAMES: is simple, independent
_LEVEL_NAMES: masks-on bits 0 .. N-1, N..max off

# turn on L3,L2,L1 others off
echo +L3 > /sys/module/test_dynamic_debug/parameters/p_level_names

# turn on L2,L1 others off
echo -L3 > /sys/module/test_dynamic_debug/parameters/p_level_names

IOW, the - changes the threshold-on bitpos by 1.

Alternatively, we could treat the +/- as half-duplex, where -L3 turns
off L>2 (and ignores L1), and +L2 would turn on L<=2 (and ignore others).

Signed-off-by: Jim Cromie <>
. revised DD_CLASS_TYPE_{DISJOINT,LEVEL}_* names
. reorder-enum by necessity - _NAMES feature is extra.
include/linux/dynamic_debug.h | 56 +++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index cb4696c91901..71cdc8612257 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -56,6 +56,62 @@ struct _ddebug {
} __attribute__((aligned(8)));

+enum class_map_type {
+ /**
+ * 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_LEVEL_NUM: input is numeric level, 0-N.
+ * N turns on just bits N-1 .. 0, so N=0 turns all bits off.
+ */
+ /**
+ * classes are independent, like _DISJOINT_BITS. Model user
+ * would be /sys/module/drm/parameters/debug_categories.
+ */
+ /**
+ * intended for names like: INFO,DEBUG,TRACE, with a module prefix
+ * avoid EMERG,ALERT,CRIT,ERR,WARNING: they're not debug
+ */
+struct ddebug_class_map {
+ struct list_head link;
+ struct module *mod;
+ const char *mod_name; /* needed for builtins */
+ 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;
+ * 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;
 \ /
  Last update: 2022-08-05 23:57    [W:0.122 / U:1.812 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site