Hi Greg, Jason,
Please consider these for char/misc or linux-next/soon/mumble.
This patchset adds exclusive class support to dyndbg, allowing it to
directly represent drm's debug_category.
It is the dyndbg half of:
https://lore.kernel.org/lkml/[email protected]/
The DRM half of that patchset uses this support to reimplement
drm.debug on dyndbg, and uses its callsite patching to avoid the
runtime checking done by drm_debug_enabled().
Background:
In the past, various extensions to dyndbg/pr_debug have been proposed,
none seemed to gain any consensus. This list is certainly incomplete.
https://lore.kernel.org/lkml/[email protected]/
pr_levels was discussed around this patchset, in revs 3,4,5
This search helps:
s:venus: s:dynamic f:[email protected]
IMO, pr_levels suffers from implied meaning between the levels: 2 > 1.
In contrast, DRM has logically disjoint categories, and is implemented
in an enum (despite its flag/mask values, a micro-optimization).
https://lore.kernel.org/lkml/[email protected]/
That patchset used pr_debug in DRM, and prepended "drm:kms:" etc to
the format strings so each category was selectable; "format drm:kms:"
in the query. This worked, but it made the format config-dependent,
and was hard to explain without undue "artifact".
So this patchset adds .class_id field (4-bits) to dynamic-debug
callsites, and 'class N' query/command support to select upon it.
Existing callsites and queries get .class_id=15, so 0-14 are available
for use by the client (DRM wants 0-10).
The DRM patchset then:
. renumbers drm_debug_category to fit into the 4-bit .class_id
the new enumerations *are* the bit-positions in drm/parameters/debug.
. adapts the category-macro layer to use _CLS macros, mapping categories.
. adds macro layer under the category-macro layer
which wraps drm_*dbg inside a dyndbg Factory macro
. uses DEFINE_DYNAMIC_DEBUG_CLASSBITS to tie to __drm_debug
callbacks ref the var, so drm_debug_enabled(cat) just works.
Jim Cromie (5):
dyndbg: fix static_branch manipulation
fixes a latent bug, before a 2nd "enable" flag exposes it.
dyndbg: add class_id field and query support
will allow (with that drm patchset):
#> # turn on DRM_ATOMIC in amdgpu
#> echo module amdgpu class 4 +p > /proc/dynamic_debug/control
#> # turn on DRM_CORE in drm
#> echo module drm class 0 +p > /proc/dynamic_debug/control
dyndbg: add DEFINE_DYNAMIC_DEBUG_CLASSBITS macro
adds macro & callbacks to support drm.debug bitmap
#> echo 4 > /sys/module/drm/parameters/debug
dyndbg: drop EXPORTed dynamic_debug_exec_queries
unused yet, obsoleted by 2,3
dyndbg: show both old and new in change-info
minor debug improvement
.../admin-guide/dynamic-debug-howto.rst | 7 +
include/linux/dynamic_debug.h | 111 ++++++++++---
lib/dynamic_debug.c | 150 ++++++++++++++----
3 files changed, 213 insertions(+), 55 deletions(-)
--
2.35.1
DEFINE_DYNAMIC_DEBUG_CLASSBITS(fsname, var, bitmap_desc, classes..)
allows users to create a drm.debug style (bitmap) sysfs interface, to
control sets of pr_debug's according to their .class_id's
This wraps existing "class" keyword and behavior:
bash-5.1# echo <<END > /proc/dynamic_debug/control
> module drm class 0 +p
> module drm class 2 +p
> END
With the macro used (in a client), this is basically equivalent:
# but this also clears other flags, if theyre set
echo 0x05 > /sys/module/drm/parameters/debug
To use:
DEFINE_DYNAMIC_DEBUG_CLASSBITS(debug, __drm_debug, "pmfl",
"drm.debug - bits => categories:",
/* vector of uint:4 symbols, ala enum drm_debug_category, 15 is EOL */
DRM_UT_CORE,
DRM_UT_DRIVER,
DRM_UT_KMS ... );
The 3rd arg is a string with any of the dyndbg.flags [pmflt_]+
Full exposure of the flags here lets the module author:
- fully customize/take-over the decorations of enabled sites.
generally leaving decorations to user is preferred.
- aim the debug-stream:
now printk, later tracefs.
using both together means more work (p or T, in practice)
iface doesn't care about new flags added later
- declare 2 separate sysfs-knobs, one each for p, T, if desired.
- decorations are per callsite,
shared across sysfs-knobs for any controlled classes
To support the macro, the patch adds:
- int param_set_dyndbg_classbits()
- int param_get_dyndbg_classbits()
- struct kernel_param_ops param_ops_dyndbg_classbits
Following the model of kernel/params.c STANDARD_PARAM_DEFS, these are
non-static and exported.
get/set use an augmented kernel_param; the arg refs a new struct
dyndbg_bitmap_param containing:
A- the vector of classes (drm.debug "categories") being controlled
This in-line vector of constants (uint [0-14]) specifies a sequence of
controlling bits (by position, starting at 0) with the values naming
the class_id's mapped to that bit.
A value of _DPRINTK_SITE_UNCLASSED terminates the vector processing by
param_set_dyndbg_classbits(), and is appended by the macro to insure a
defined termination after max 15 classes are applied.
Technically, the vector is a flex-array, but its size is practically
limited to max 15 in length (repeats are pointless).
B- a pointer to the user module's ulong holding the bits/state.
By accessing client's bit-state, we coordinate with existing code
that still uses drm_debug_enabled(), so they work unchanged.
The change to ulong allows use of BIT() etc.
NOTES:
_DPRINTK_SITE_UNCLASSED = 15, ie 2**CLS_BITS-1, deserves special
mention; it already marks all existing pr-debug callsites, only the
new drm.debug callsites are initialized to other (DRM_UT_*) values.
_DPRINTK_SITE_UNCLASSED is used in param_set_dyndbg_classbits() to
limit the range of bits that are processed to what fits in uint:4.
It also terminates the class-id list passed into the macro, so dont
use it halfway through your list of classes-to-control.
param_set_dyndbg_classbits() compares new vs old bits, and only
updates each class on changes. This maximally preserves the
underlying state, which may have been customized at some point via
`echo $cmd >control`. So if users really want to know that all
prdbgs are set precisely, they must pre-clear then set.
Identity mapping in (A) is encouraged. Your vector should exclude 15,
if used, it terminates the list prematurely; any following bit
mappings will be ignored (it is the default/non category).
The whole (A) vector/list passed to the macro is:
- not strictly needed: 0-N bits are scanned, only N is needed in the
macro interface to do this, not the whole list.
- 0-N list allows juggling the bit->class map
Identity map is preferred.
15 terminates list if used. (macro impl does this)
That said, (A) is self-documenting; the explicit list is greppable,
'DRM_UT_*' provides lots of clues. Further, it could be upgraded,
something like:
_pick_sym_(DRM_UT_CORE, "mumble something useful about CORE debug")
_pick_sym_(a,b) a // gives us what we need here
_pick_help_(a,b) #a " : " b // mod-info fodder
Signed-off-by: Jim Cromie <[email protected]>
---
include/linux/dynamic_debug.h | 50 +++++++++++++++++++++++
lib/dynamic_debug.c | 77 +++++++++++++++++++++++++++++++++++
2 files changed, 127 insertions(+)
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index d4b48f3cc6e8..e83c4e36ad29 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -209,6 +209,10 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
KERN_DEBUG, prefix_str, prefix_type, \
rowsize, groupsize, buf, len, ascii)
+struct kernel_param;
+int param_set_dyndbg_classbits(const char *instr, const struct kernel_param *kp);
+int param_get_dyndbg_classbits(char *buffer, const struct kernel_param *kp);
+
#else /* !CONFIG_DYNAMIC_DEBUG_CORE */
#include <linux/string.h>
@@ -255,6 +259,52 @@ static inline int dynamic_debug_exec_queries(const char *query, const char *modn
return 0;
}
+struct kernel_param;
+static inline int param_set_dyndbg_classbits(const char *instr, const struct kernel_param *kp)
+{ return 0; }
+static inline int param_get_dyndbg_classbits(char *buffer, const struct kernel_param *kp)
+{ return 0; }
+
#endif /* !CONFIG_DYNAMIC_DEBUG_CORE */
+#define FLAGS_LEN 8
+struct dyndbg_classbits_param {
+ unsigned long *bits; /* ref to shared state */
+ const char flags[FLAGS_LEN]; /* toggle these flags on bit-changes */
+ const int classes[]; /* indexed by bitpos */
+};
+
+#if defined(CONFIG_DYNAMIC_DEBUG) || defined(CONFIG_DYNAMIC_DEBUG_CORE)
+/**
+ * DEFINE_DYNAMIC_DEBUG_CLASSBITS() - bitmap control of classed pr_debugs
+ * @sysname: sysfs-node name
+ * @_var: C-identifier holding bit-vector (Bits 0-14 are usable)
+ * @_flgs: string with dyndbg flags: 'p' and/or 'T', and maybe "fmlt" also.
+ * @desc: string summarizing the controls provided
+ * @classes: vector of callsite.class_id's (uint:4, 15 is reserved)
+ *
+ * This macro implements a DRM.debug API style bitmap, mapping bits
+ * 0-14 to classes of prdbg's, as initialized in their .class_id fields.
+ * @_flgs chooses the debug recipient; p - syslog, T - tracefs, and
+ * can include log decorations; m - module, f - function, l - line_num
+ */
+#define DEFINE_DYNAMIC_DEBUG_CLASSBITS(fsname, _var, _flgs, desc, ...) \
+ MODULE_PARM_DESC(fsname, desc); \
+ static struct dyndbg_classbits_param ddcats_##_var = { \
+ .bits = &(_var), \
+ .flags = _flgs, \
+ .classes = { __VA_ARGS__, _DPRINTK_SITE_UNCLASSED } \
+ }; \
+ module_param_cb(fsname, ¶m_ops_dyndbg_classbits, \
+ &ddcats_##_var, 0644)
+
+extern const struct kernel_param_ops param_ops_dyndbg_classbits;
+
+#else /* no dyndbg configured, throw error on macro use */
+
+#define DEFINE_DYNAMIC_DEBUG_CLASSBITS(fsname, var, bitmap_desc, ...) \
+ BUILD_BUG_ON_MSG(1, "CONFIG_DYNAMIC_DEBUG* needed to use this macro: " #fsname)
+
+#endif
+
#endif
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index ee2129becacc..704361af5b23 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -611,6 +611,83 @@ int dynamic_debug_exec_queries(const char *query, const char *modname)
}
EXPORT_SYMBOL_GPL(dynamic_debug_exec_queries);
+#ifdef CONFIG_MODULES
+#define KP_MOD_NAME kp->mod->name
+#else
+#define KP_MOD_NAME NULL /* wildcard */
+#endif
+#define FMT_QUERY_SIZE 128 /* typically need <40 */
+/**
+ * param_set_dyndbg_classbits - bits => categories >control setter
+ * @instr: string echo>d to sysfs
+ * @kp: kp->arg has state: bits, map
+ *
+ * Enable/disable prdbgs by their "category", as specified in the
+ * DEFINE_DYNAMIC_DEBUG_BITGRPS.classbits argument.
+ *
+ * Returns: 0 or <0 if error.
+ */
+int param_set_dyndbg_classbits(const char *instr, const struct kernel_param *kp)
+{
+ unsigned long inbits;
+ int rc, i, matches = 0, totct = 0;
+ char query[FMT_QUERY_SIZE];
+ const struct dyndbg_classbits_param *dcp = kp->arg;
+
+ if (!dcp) {
+ pr_err("set_dyndbg_classbits: no bits=>queries map\n");
+ return -EINVAL;
+ }
+ rc = kstrtoul(instr, 0, &inbits);
+ if (rc) {
+ pr_err("set_dyndbg_classbits: expecting unsigned int\n");
+ return rc;
+ }
+ vpr_info("set_dyndbg_classbits: new 0x%lx old 0x%lx\n", inbits, *dcp->bits);
+
+ for (i = 0; (i < _DPRINTK_SITE_UNCLASSED &&
+ dcp->classes[i] < _DPRINTK_SITE_UNCLASSED); i++) {
+
+ if (test_bit(i, &inbits) == test_bit(i, dcp->bits))
+ continue;
+ snprintf(query, FMT_QUERY_SIZE, "class %d %cT",
+ dcp->classes[i], test_bit(i, &inbits) ? '+' : '-');
+
+ matches = ddebug_exec_queries(query, KP_MOD_NAME);
+
+ v2pr_info("bit-%d: %d matches on class:%u\n", i,
+ matches, dcp->classes[i]);
+ totct += matches;
+ }
+ *dcp->bits = inbits;
+ vpr_info("total matches: %d\n", totct);
+ return 0;
+}
+EXPORT_SYMBOL(param_set_dyndbg_classbits);
+
+/**
+ * param_get_dyndbg_classbits - classbits reader
+ * @buffer: string description of controlled bits -> classes
+ * @kp: kp->arg has state: bits, map
+ *
+ * Reads last written bits, underlying prdbg state may have changed since.
+ * Returns: #chars written or <0 on error
+ */
+int param_get_dyndbg_classbits(char *buffer, const struct kernel_param *kp)
+{
+ const struct dyndbg_classbits_param *p = kp->arg;
+ unsigned long val = *p->bits;
+
+ return scnprintf(buffer, PAGE_SIZE, "0x%lx\n", val);
+}
+EXPORT_SYMBOL(param_get_dyndbg_classbits);
+
+const struct kernel_param_ops param_ops_dyndbg_classbits = {
+ .set = param_set_dyndbg_classbits,
+ .get = param_get_dyndbg_classbits,
+};
+EXPORT_SYMBOL(param_ops_dyndbg_classbits);
+
#define PREFIX_SIZE 64
static int remaining(int wrote)
--
2.35.1