Re: [PATCH v8 00/35] fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression
On Mon, Apr 29, 2024 at 1:32 PM Jim Cromie wrote: > > hi Greg, Jason, DRM-folk, > > This patchset fixes the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression, > Fixes: bb2ff6c27bc9 ("drm: Disable dynamic debug as broken") > > this is v8. > Its also here: > https://github.com/jimc/linux/tree/dd-classmap-fix-8a > This patchset didnt get picked up by drm patchwork maybe its tired my stochastic renaming, sorry about that https://patchwork.freedesktop.org/project/intel-gfx/series/?ordering=-last_updated 125063fix DRM_USE_DYNAMIC_DEBUG=y regressionwarningNew23jim.cromie@gmail.comNone2023-11-01 123572fix DRM_USE_DYNAMIC_DEBUG regressionfailureNew22jim.cromie@gmail.comNone2023-09-11 113363fix DRM_USE_DYNAMIC_DEBUG regressionwarningIn progress 22jim.cromie@gmail.comNone2023-08-01 111651DRM_USE_DYNAMIC_DEBUG regressionfailureNew20jim.cromie@gmail.comNone2023-01-13 111631DRM - avoid regression in -rc, fix comment is there something missing for a DRM patchwork run ? does it kick out because theres non-drm subsystem stuff in there ? thanks > v7 had at least 2 problems: > > https://lore.kernel.org/lkml/20231101002609.3533731-1-jim.cro...@gmail.com/ > https://patchwork.freedesktop.org/series/125066/ > > 1. missing __align(8) in METATDATA macro, giving too much placement > freedom to linker, caused weird segvs following non-ptr vals, but for > builtin modules only. found by lkp-test. > > 2. the main patch changed both the dyndbg API, and the drm/drivers. > This was a flag-day annoyance, and not practical. Fix by preserving > old API macro until "later", and splitting the patch and set into 2 > sequential subsets. removal can wait. > > What was broken ? > > Booting a modular kernel with drm.debug=0x1ff, this enabled pr_debugs > only in drm itself, not the yet-to-be loaded driver + helpers. I had > tested with scripts doing lots of modprobes with dyndbg=<> options > permuting. I didn't notice that I didn't really test without them. > > The deeper cause was my design error, a violation of the K rule: > "define once, refer many times". > > DECLARE_DYNDBG_CLASSMAP defined the classmap, and was used everywhere, > re-declaring the same static classmap repeatedly. Jani Nikula actually > picked up on this at the time, but didn't scream loudly enough for > anyone to notice, I know I didn't get it then. One patchset across 2 > trees didn't help either. > > The revised classmap API "splits" it to def & ref. > > DYNDBG_CLASSMAP_DEFINE fixes & updates the busted macro, EXPORTing the > classmap instead. It gets invoked once per subsystem, by the > parent/builtin, drm.ko for DRM. > > DYNDBG_CLASSMAP_USE in drivers and helpers refer to the classmap by > name, which links the 2 modules (like __drm_debug already does). > > These 2 tell dyndbg to map "class FOO" to the defined FOO_ID, which > allows it to make those changes via >control. > > DYNDBG_CLASSMAP_PARAM*, defines the controlling kparam, and binds it > to both the _var, and the _DEFINEd classmap. So drm uses this to bind > the classmap to __drm_debug. > > It provides the common control-point for the sub-system; it is applied > to the classmaps during modprobe of both _DEFINEr and USErs. It also > enforces the relative nature of LEVEL classmaps, ie V3>V2. > > DECLARE_DYNDBG_CLASSMAP is preserved to decouple the DRM patches. > > A new struct and elf section contain the _USEs; on modprobe, these are > scanned similarly to the _DEFINEs, but follow the references to their > defining modules, find the kparam wired to the classmap, and apply its > classmap settings to the USEr. This action is what V1 missed, which > is why drivers failed to enable debug during modprobe. > > In order to recapitulate the regression scenario without involving > DRM, the patchset (v6 I think) adds test_dynamic_debug_submod, which > is a duplicate of its parent; _submod.c #defines _SUBMOD, and then > includes parent. > > This puts _DEFINE and _USE close together in the same file, for > obviousness. It also guarantees that the submod always has the same > complement of debug()s, giving consistent output from both when > classmaps are working properly, as tested when changing callsites via > both param and >control. > > To provide a turn-key selftest, the patchset also adds > ./tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh, pilfered > from a debug-to-trace patchset I and Lukasz Bartozik have been working > out. It starts with basic_tests, then to test 2 new parsing > delimiters, which simplify testing of the classmap functionality. > > It works nicely from virtme-ng: > > [jimc@frodo vx]$ vrun_ -- > ./tools/testing/selftests/dynamic_debug/dy
Re: [PATCH v8 29/35] dyndbg: add __counted_by annotations
On Mon, Apr 29, 2024 at 1:39 PM Jim Cromie wrote: > > Tell the compiler about our vectors (array,length), in 2 places: > these are not flex-arrays, using counted-by is wrong here. Ive dropped this commit, series rebases clean wo it. > h: struct _ddebug_info, which keeps refs to the __dyndbg_* ELF/DATA > sections, these are all vectors with a length. >
[PATCH v8 35/35] drm-print: workaround compiler meh
For some reason I cannot grok, I get an unused variable 'category' warning/error, though the usage follows immediately. This drops the local var and directly derefs in the macro-call, which somehow avoids the warning. commit 9fd6f61a297e ("drm/print: add drm_dbg_printer() for drm device specific printer") CC: Jani Nikula Signed-off-by: Jim Cromie --- drivers/gpu/drm/drm_print.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index efdf82f8cbbb..c400441cd77e 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -183,11 +183,10 @@ void __drm_printfn_dbg(struct drm_printer *p, struct va_format *vaf) { const struct drm_device *drm = p->arg; const struct device *dev = drm ? drm->dev : NULL; - enum drm_debug_category category = p->category; const char *prefix = p->prefix ?: ""; const char *prefix_pad = p->prefix ? " " : ""; - if (!__drm_debug_enabled(category)) + if (!__drm_debug_enabled(p->category)) return; /* Note: __builtin_return_address(0) is useless here. */ -- 2.44.0
[PATCH v8 25/35] docs/dyndbg: explain new delimiters: comma, percent
Add mention of comma and percent delimiters into the respective paragraphs describing their equivalents: space and newline. Signed-off-by: Jim Cromie --- .../admin-guide/dynamic-debug-howto.rst| 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 742eb4230c6e..7b570f29ae98 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -73,16 +73,18 @@ Command Language Reference == At the basic lexical level, a command is a sequence of words separated -by spaces or tabs. So these are all equivalent:: +by spaces, tabs, or commas. So these are all equivalent:: :#> ddcmd file svcsock.c line 1603 +p :#> ddcmd "file svcsock.c line 1603 +p" :#> ddcmd ' file svcsock.c line 1603 +p ' + :#> ddcmd file,svcsock.c,line,1603,+p -Command submissions are bounded by a write() system call. -Multiple commands can be written together, separated by ``;`` or ``\n``:: +Command submissions are bounded by a write() system call. Multiple +commands can be written together, separated by ``%``, ``;`` or ``\n``:: - :#> ddcmd "func pnpacpi_get_resources +p; func pnp_assign_mem +p" + :#> ddcmd func foo +p % func bar +p + :#> ddcmd func foo +p \; func bar +p :#> ddcmd <<"EOC" func pnpacpi_get_resources +p func pnp_assign_mem +p @@ -104,7 +106,6 @@ 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::: @@ -128,7 +129,6 @@ keywords are::: ``line-range`` cannot contain space, e.g. "1-30" is valid range but "1 - 30" is not. - The meanings of each keyword are: func @@ -153,9 +153,11 @@ module The given string is compared against the module name of each callsite. The module name is the string as seen in ``lsmod``, i.e. without the directory or the ``.ko`` -suffix and with ``-`` changed to ``_``. Examples:: +suffix and with ``-`` changed to ``_``. + +Examples:: - module sunrpc + module,sunrpc # with ',' as token separator module nfsd module drm* # both drm, drm_kms_helper -- 2.44.0
[PATCH v8 34/35] drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN
Time for some quality CI Signed-off-by: Jim Cromie --- drivers/gpu/drm/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 5a0c476361c3..b2ea73ae48f0 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -54,8 +54,7 @@ config DRM_DEBUG_MM config DRM_USE_DYNAMIC_DEBUG bool "use dynamic debug to implement drm.debug" - default n - depends on BROKEN + default y depends on DRM depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE depends on JUMP_LABEL -- 2.44.0
[PATCH v8 32/35] drm: use correct ccflags-y spelling
Incorrectly spelled CFLAGS- failed to add -DDYNAMIC_DEBUG_MODULE, which broke builds with: CONFIG_DRM_USE_DYNAMIC_DEBUG=y CONFIG_DYNAMIC_DEBUG_CORE=y CONFIG_DYNAMIC_DEBUG=n Also add subdir-ccflags so that all drivers pick up the addition. Fixes: 84ec67288c10 ("drm_print: wrap drm_*_dbg in dyndbg descriptor factory macro") Signed-off-by: Jim Cromie --- drivers/gpu/drm/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 104b42df2e95..313516fc2ad5 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,7 +3,8 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE +ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG)+= -DDYNAMIC_DEBUG_MODULE +subdir-ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE drm-y := \ drm_aperture.o \ -- 2.44.0
[PATCH v8 31/35] drm-dyndbg: adapt to use DYNDBG_CLASSMAP_PARAM
use new export --- drivers/gpu/drm/drm_print.c | 8 ++-- include/drm/drm_print.h | 6 -- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 4a5f2317229b..efdf82f8cbbb 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -69,12 +69,8 @@ DRM_CLASSMAP_DEFINE(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, "DRM_UT_DP", "DRM_UT_DRMRES"); -static struct ddebug_class_param drm_debug_bitmap = { - .bits = &__drm_debug, - .flags = "p", - .map = _debug_classes, -}; -module_param_cb(debug, _ops_dyndbg_classes, _debug_bitmap, 0600); +DRM_CLASSMAP_PARAM_REF(debug, __drm_debug, drm_debug_classes, p); + #endif void __drm_puts_coredump(struct drm_printer *p, const char *str) diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 905fc25bf65a..95c667934bbb 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -141,11 +141,13 @@ enum drm_debug_category { }; #ifdef CONFIG_DRM_USE_DYNAMIC_DEBUG -#define DRM_CLASSMAP_DEFINE(...) DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__) -#define DRM_CLASSMAP_USE(name) DYNDBG_CLASSMAP_USE(name) +#define DRM_CLASSMAP_DEFINE(...)DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__) +#define DRM_CLASSMAP_USE(name) DYNDBG_CLASSMAP_USE(name) +#define DRM_CLASSMAP_PARAM_REF(...) DYNDBG_CLASSMAP_PARAM_REF(__VA_ARGS__) #else #define DRM_CLASSMAP_DEFINE(...) #define DRM_CLASSMAP_USE(name) +#define DRM_CLASSMAP_PARAM_REF(...) #endif static inline bool drm_debug_enabled_raw(enum drm_debug_category category) -- 2.44.0
[PATCH v8 27/35] selftests-dyndbg: test dyndbg-to-tracefs
Add a series of trace-tests: test_actual_trace() etc, to validate that the dyndbg-to-tracefs feature (using +T flag) works as intended. The 1st test uses the global tracebuf, the rest use/excercise private tracebufs. These tests are currently optional, via "TRACE" arg1, because the feature code is in-the-lab. But its an objective test, and pretty user-interface oriented. IOW this passes: :#> ./tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh but this fails: :#> ./tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh TRACE So its won't break selftests success. This allows the patch to be committed now w/o inducing selftest failures, and the tests enabled later, with the promised code. Signed-off-by: Jim Cromie Co-developed-by: Łukasz Bartosik Signed-off-by: Łukasz Bartosik --- .../dynamic_debug/dyndbg_selftest.sh | 435 ++ 1 file changed, 435 insertions(+) diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh index 54acee58cb4e..65f31418870f 100755 --- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh +++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh @@ -308,6 +308,405 @@ function test_mod_submod { check_match_ct =p 14 -v } +# tests below here are all actually using dyndbg->trace, +# and verifying the writes + +function test_actual_trace { +echo -e "${GREEN}# TEST_ACTUAL_TRACE ${NC}" +ddcmd =_ +echo > /sys/kernel/tracing/trace +echo 1 >/sys/kernel/tracing/tracing_on +echo 1 >/sys/kernel/tracing/events/dyndbg/enable +modprobe test_dynamic_debug dyndbg=class,D2_CORE,+T:0 +search_trace "D2_CORE msg" +search_trace_name 0 1 "D2_CORE msg" +check_match_ct =T 1 +tmark "trace-mark" +search_trace "trace-mark" +doprints +search_trace "D2_CORE msg" +ifrmmod test_dynamic_debug +} + +function self_start { +echo \# open, modprobe +T:selftest +ddcmd open selftest +check_trace_instance_dir selftest 1 +is_trace_instance_opened selftest +modprobe test_dynamic_debug dyndbg=+T:selftest.mf +check_match_ct =T:selftest.mf 5 +} + +function self_end_normal { +echo \# disable -T:selftest, rmmod, close +ddcmd module test_dynamic_debug -T:selftest # leave mf +check_match_ct =:selftest.mf 5 -v +ddcmd module test_dynamic_debug +:0 +ddcmd close selftest +is_trace_instance_closed selftest +ifrmmod test_dynamic_debug +} + +function self_end_disable_anon { +echo \# disable, close, rmmod +ddcmd module test_dynamic_debug -T +check_match_ct =:selftest.mf 5 +ddcmd module test_dynamic_debug +:0 +ddcmd close selftest +is_trace_instance_closed selftest +ifrmmod test_dynamic_debug +} + +function self_end_disable_anon_mf { +echo \# disable, close, rmmod +ddcmd module test_dynamic_debug -Tf +check_match_ct =:selftest.m 5 +ddcmd module test_dynamic_debug +:0 +ddcmd close selftest +is_trace_instance_closed selftest +ifrmmod test_dynamic_debug +} + +function self_end_nodisable { +echo \# SKIPPING: ddcmd module test_dynamic_debug -T:selftest +ddcmd close selftest fail # close fails because selftest is still being used +check_err_msg "Device or resource busy" +check_match_ct =T:selftest.mf 5 +rmmod test_dynamic_debug +ddcmd close selftest # now selftest can be closed because rmmod removed + # all callsites which were using it +is_trace_instance_closed selftest +} + +function self_end_delete_directory { +del_trace_instance_dir selftest 0 +check_err_msg "Device or resource busy" +ddcmd module test_dynamic_debug -mT:selftest +check_match_ct =:selftest.f 5 +del_trace_instance_dir selftest 0 +check_err_msg "Device or resource busy" +ddcmd module test_dynamic_debug +:0 +ddcmd close selftest +check_trace_instance_dir selftest 1 +is_trace_instance_closed selftest +del_trace_instance_dir selftest 1 +check_trace_instance_dir selftest 0 +} + +function test_early_close () { +ddcmd open kparm_stream +ddcmd module usbcore +T:kparm_stream.mf +check_match_ct =T:usb_stream.mf 161 +echo ":not-running # ddcmd module usbcore -T:kparm_stream.mf" +ddcmd close kparm_stream +} + +function self_test_ { +echo "# SELFTEST $1" +self_start +self_end_$1 +} + +function cycle_tests_normal { +echo -e "${GREEN}# CYCLE_TESTS_NORMAL ${NC}" +self_test_ normal # ok +self_test_ disable_anon # ok +self_test_ normal # ok +self_test_ disable_anon_mf # ok +} + +function cycle_not_best_practices { +echo -e "${GREEN}# CYCLE_TESTS_PROBLEMS ${NC}" +self_test_ nodisable +self_test_ normal +self_test_ delete_directory +} + +# proper life
[PATCH v8 33/35] drm-drivers: DRM_CLASSMAP_USE in 2nd batch of drivers, helpers
Add a DRM_CLASSMAP_USE declaration to 2nd batch of helpers and *_drv.c files. For drivers, add the decl just above the module's PARAMs, since it identifies the "inherited" drm.debug param. Note: with CONFIG_DRM_USE_DYNAMIC_DEBUG=y, a module not also declaring DRM_CLASSMAP_USE will have its class'd prdbgs stuck in the initial (disabled, but for DEBUG) state. The stuck sites are evident in /proc/dynamic_debug/control as: class:_UNKNOWN_ _id:N# control's last column rather than a proper "enumeration": class:DRM_UT_CORE TLDR: This set of updates was found by choosing M for all DRM-config items I found (not allmodconfig), building & modprobing them, and grepping "class unknown," control. There may yet be others. Signed-off-by: Jim Cromie --- drivers/gpu/drm/drm_gem_shmem_helper.c | 2 ++ drivers/gpu/drm/gud/gud_drv.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_drv.c | 2 ++ drivers/gpu/drm/qxl/qxl_drv.c | 2 ++ drivers/gpu/drm/radeon/radeon_drv.c| 2 ++ drivers/gpu/drm/udl/udl_main.c | 2 ++ drivers/gpu/drm/vkms/vkms_drv.c| 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.c| 2 ++ 8 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index e435f986cd13..066d906e3199 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -23,6 +23,8 @@ #include #include +DRM_CLASSMAP_USE(drm_debug_classes); + MODULE_IMPORT_NS(DMA_BUF); /** diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index 9d7bf8ee45f1..5b555045fce4 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -31,6 +31,8 @@ #include "gud_internal.h" +DRM_CLASSMAP_USE(drm_debug_classes); + /* Only used internally */ static const struct drm_format_info gud_drm_format_r1 = { .format = GUD_DRM_FORMAT_R1, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 573dbe256aa8..88c5e24cc894 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -25,6 +25,8 @@ static int mgag200_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, mgag200_modeset, int, 0400); +DRM_CLASSMAP_USE(drm_debug_classes); + int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2) { struct device *dev = >dev; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index beee5563031a..1971bfa8a8a6 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -65,6 +65,8 @@ module_param_named(modeset, qxl_modeset, int, 0400); MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)"); module_param_named(num_heads, qxl_num_crtc, int, 0400); +DRM_CLASSMAP_USE(drm_debug_classes); + static struct drm_driver qxl_driver; static struct pci_driver qxl_pci_driver; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 7bf08164140e..d22308328c76 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -247,6 +247,8 @@ int radeon_cik_support = 1; MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled (default), 0 = disabled)"); module_param_named(cik_support, radeon_cik_support, int, 0444); +DRM_CLASSMAP_USE(drm_debug_classes); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 3ebe2ce55dfd..ba57c14454e5 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -19,6 +19,8 @@ #define NR_USB_REQUEST_CHANNEL 0x12 +DRM_CLASSMAP_USE(drm_debug_classes); + #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE) #define WRITES_IN_FLIGHT (20) #define MAX_VENDOR_DESCRIPTOR_SIZE 256 diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index dd0af086e7fa..086797c4b82b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -39,6 +39,8 @@ static struct vkms_config *default_config; +DRM_CLASSMAP_USE(drm_debug_classes); + static bool enable_cursor = true; module_param_named(enable_cursor, enable_cursor, bool, 0444); MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 58fb40c93100..c159f4d186a3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -275,6 +275,8 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, void *ptr); +DRM_CLASSMAP_USE(drm_debug_classes); + MODULE_PARM_DESC(restrict_iommu, "Try to li
[PATCH v8 28/35] dyndbg-doc: explain flags parse 1st
When writing queries to >control, flags are parsed 1st, since they are the only required field. So if the flags draw an error, then keyword errors aren't reported. This can be mildly confusing/annoying, so explain it instead. This note could be moved up to just after the grammar id's the flags, and before the match-spec is detailed. Opinions ? Signed-off-by: Jim Cromie --- Documentation/admin-guide/dynamic-debug-howto.rst | 10 ++ 1 file changed, 10 insertions(+) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 7b570f29ae98..ccf3704f2143 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -106,6 +106,16 @@ 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 "*". +Note: because the match-spec can be empty, the flags are checked 1st, +then the pairs of keyword values. 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 + 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::: -- 2.44.0
[PATCH v8 30/35] drm+drivers: adapt to use DYNDBG_CLASSMAP_{DEFINE, USE}
Follow dynamic_debug API change from DECLARE_DYNDBG_CLASSMAP to DYNDBG_CLASSMAP_{DEFINE,USE}. Prior to this, we used DECLARE_DYNDBG_CLASSMAP, which was preserved to decouple DRM conversion. I'm unsure of the full functionality in-between, a round of lkp-testing will help. Fixes: f158936b60a7 ("drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.") Signed-off-by: Jim Cromie --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 +--- drivers/gpu/drm/display/drm_dp_helper.c | 12 +--- drivers/gpu/drm/drm_crtc_helper.c | 12 +--- drivers/gpu/drm/drm_print.c | 25 + drivers/gpu/drm/i915/i915_params.c | 12 +--- drivers/gpu/drm/nouveau/nouveau_drm.c | 12 +--- include/drm/drm_print.h | 8 7 files changed, 26 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index e4277298cf1a..b287f0cfd8fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -217,17 +217,7 @@ int amdgpu_damage_clips = -1; /* auto */ static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); -DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, - "DRM_UT_CORE", - "DRM_UT_DRIVER", - "DRM_UT_KMS", - "DRM_UT_PRIME", - "DRM_UT_ATOMIC", - "DRM_UT_VBL", - "DRM_UT_STATE", - "DRM_UT_LEASE", - "DRM_UT_DP", - "DRM_UT_DRMRES"); +DRM_CLASSMAP_USE(drm_debug_classes); struct amdgpu_mgpu_info mgpu_info = { .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex), diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index f5d4be897866..d3a7df09846f 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -41,17 +41,7 @@ #include "drm_dp_helper_internal.h" -DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, - "DRM_UT_CORE", - "DRM_UT_DRIVER", - "DRM_UT_KMS", - "DRM_UT_PRIME", - "DRM_UT_ATOMIC", - "DRM_UT_VBL", - "DRM_UT_STATE", - "DRM_UT_LEASE", - "DRM_UT_DP", - "DRM_UT_DRMRES"); +DRM_CLASSMAP_USE(drm_debug_classes); struct dp_aux_backlight { struct backlight_device *base; diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 2dafc39a27cb..e9d229a393f4 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -50,17 +50,7 @@ #include "drm_crtc_helper_internal.h" -DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, - "DRM_UT_CORE", - "DRM_UT_DRIVER", - "DRM_UT_KMS", - "DRM_UT_PRIME", - "DRM_UT_ATOMIC", - "DRM_UT_VBL", - "DRM_UT_STATE", - "DRM_UT_LEASE", - "DRM_UT_DP", - "DRM_UT_DRMRES"); +DRM_CLASSMAP_USE(drm_debug_classes); /** * DOC: overview diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 699b7dbffd7b..4a5f2317229b 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -55,18 +55,19 @@ MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug cat #if !defined(CONFIG_DRM_USE_DYNAMIC_DEBUG) module_param_named(debug, __drm_debug, ulong, 0600); #else -/* classnames must match vals of enum drm_debug_category */ -DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, - "DRM_UT_CORE", - "DRM_UT_DRIVER", - "DRM_UT_KMS", - "DRM_UT_PRIME", - "DRM_UT_ATOMIC", - "DRM_UT_VBL", - "DRM_UT_STATE", - "DRM_UT_LEASE", - "DRM_UT_DP", - "DRM_UT_DRMRES"); +/* classnames must match value-symbols of enum drm_debug_category */ +DRM_CLASSMAP_DEFINE(drm_debug_classes, DD_CLASS_TYPE_DISJ
[PATCH v8 29/35] dyndbg: add __counted_by annotations
Tell the compiler about our vectors (array,length), in 2 places: h: struct _ddebug_info, which keeps refs to the __dyndbg_* ELF/DATA sections, these are all vectors with a length. c: struct ddebug_table, which has sub-refs into _ddebug_info.* Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 6 +++--- lib/dynamic_debug.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 090fe9554db7..c54d2a4e1d48 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -146,9 +146,9 @@ struct ddebug_class_user { /* encapsulate linker provided built-in (or module) dyndbg data */ struct _ddebug_info { - struct _ddebug *descs; - struct ddebug_class_map *classes; - struct ddebug_class_user *class_users; + struct _ddebug *descs __counted_by(num_descs); + struct ddebug_class_map *classes __counted_by(num_classes); + struct ddebug_class_user *class_users __counted_by(num_class_users); unsigned int num_descs; unsigned int num_classes; unsigned int num_class_users; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 625838bd74aa..390a35508fb6 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -49,9 +49,9 @@ extern struct ddebug_class_user __stop___dyndbg_class_users[]; struct ddebug_table { struct list_head link; const char *mod_name; - struct _ddebug *ddebugs; - struct ddebug_class_map *classes; - struct ddebug_class_user *class_users; + struct _ddebug *ddebugs __counted_by(num_ddebugs); + struct ddebug_class_map *classes __counted_by(num_classes); + struct ddebug_class_user *class_users __counted_by(num_class_users); unsigned int num_ddebugs, num_classes, num_class_users; }; -- 2.44.0
[PATCH v8 26/35] selftests-dyndbg: add test_mod_submod
This new test-fn runs 3 module/submodule modprobe scenarios, variously using both the generic dyndbg= modprobe arg, and the test-module's classmap-params to manipulate the test-mod*'s pr_debugs. In all cases, the current flag-settings are counted and tested vs expectations. The 3rd scenario recapitulates the DRM_USE_DYNAMIC_DEBUG=y failure. 1. 2 modprobes (super then sub), with separate dyndbg=class-settings check module specific flag settings 2. modprobe submod, supermod is auto-loaded set supermod class-params check expected enablements in super & submod 3. modprobe super, with param=setting (like drm.debug=0x1ef) modprobe submod validate submod's class'd pr_debugs get properly enabled The test uses multi-queries, with both commas and percents (to avoid spaces and quoting). This is the main reason the test wasn't earlier in the patchset, closer to the classmap patches its validating. With some tedium, the tests could be refactored to split out early tests which avoid multi-cmds, and test only the class-params. Signed-off-by: Jim Cromie --- .../dynamic_debug/dyndbg_selftest.sh | 60 +++ 1 file changed, 60 insertions(+) diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh index ddb04c0a7fd2..54acee58cb4e 100755 --- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh +++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh @@ -250,10 +250,70 @@ function test_percent_splitting { ifrmmod test_dynamic_debug } +function test_mod_submod { +echo -e "${GREEN}# TEST_MOD_SUBMOD ${NC}" +ifrmmod test_dynamic_debug_submod +ifrmmod test_dynamic_debug +ddcmd =_ + +# modprobe with class enablements +modprobe test_dynamic_debug dyndbg=class,D2_CORE,+pf%class,D2_KMS,+pt%class,D2_ATOMIC,+pm +check_match_ct '\[test_dynamic_debug\]' 23 -r +check_match_ct =pf 1 +check_match_ct =pt 1 +check_match_ct =pm 1 + +modprobe test_dynamic_debug_submod +check_match_ct test_dynamic_debug_submod 23 -r +check_match_ct '\[test_dynamic_debug\]' 23 -r +check_match_ct test_dynamic_debug 46 -r + +# change classes again, this time submod too +ddcmd class,D2_CORE,+mf%class,D2_KMS,+lt%class,D2_ATOMIC,+ml "# add some prefixes" +check_match_ct =pmf 1 -v +check_match_ct =plt 1 -v +check_match_ct =pml 1 -v +# submod changed too +check_match_ct =mf 1 -v +check_match_ct =lt 1 -v +check_match_ct =ml 1 -v + +# now work the classmap-params +# fresh start, to clear all above flags (test-fn limits) +ifrmmod test_dynamic_debug_submod +ifrmmod test_dynamic_debug +modprobe test_dynamic_debug_submod # get supermod too + +echo 1 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits +echo 4 > /sys/module/test_dynamic_debug/parameters/p_level_num +# 2 mods * ( V1-3 + D2_CORE ) +check_match_ct =p 8 -v +echo 3 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits +echo 0 > /sys/module/test_dynamic_debug/parameters/p_level_num +# 2 mods * ( D2_CORE, D2_DRIVER ) +check_match_ct =p 4 -v +echo 0x16 > /sys/module/test_dynamic_debug/parameters/p_disjoint_bits +echo 0 > /sys/module/test_dynamic_debug/parameters/p_level_num +# 2 mods * ( D2_DRIVER, D2_KMS, D2_ATOMIC ) +check_match_ct =p 6 -v + +# recap DRM_USE_DYNAMIC_DEBUG regression +ifrmmod test_dynamic_debug_submod +ifrmmod test_dynamic_debug +# set super-mod params +modprobe test_dynamic_debug p_disjoint_bits=0x16 p_level_num=5 +check_match_ct =p 7 -v +modprobe test_dynamic_debug_submod +# see them picked up by submod +check_match_ct =p 14 -v +} + tests_list=( basic_tests +# these require test_dynamic_debug*.ko comma_terminator_tests test_percent_splitting +test_mod_submod ) # Run tests -- 2.44.0
[PATCH v8 21/35] dyndbg: treat comma as a token separator
Treat comma as a token terminator, just like a space. This allows a user to avoid quoting hassles when spaces are otherwise needed: :#> modprobe drm dyndbg=class,DRM_UT_CORE,+p\;class,DRM_UT_KMS,+p or as a boot arg: drm.dyndbg=class,DRM_UT_CORE,+p # todo: support multi-query here Given the many ways a boot-line +args can be assembled and then passed in/down/around shell based tools, this may allow side-stepping all sorts of quoting hassles thru those layers. existing query format: modprobe test_dynamic_debug dyndbg="class D2_CORE +p" new format: modprobe test_dynamic_debug dyndbg=class,D2_CORE,+p Signed-off-by: Jim Cromie Co-developed-by: Łukasz Bartosik Signed-off-by: Łukasz Bartosik --- lib/dynamic_debug.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 31fd67597928..c1bc728cb050 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -290,6 +290,14 @@ static int ddebug_change(const struct ddebug_query *query, return nfound; } +static char *skip_spaces_and_commas(const char *str) +{ + str = skip_spaces(str); + while (*str == ',') + str = skip_spaces(++str); + return (char *)str; +} + /* * Split the buffer `buf' into space-separated words. * Handles simple " and ' quoting, i.e. without nested, @@ -303,8 +311,8 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords) while (*buf) { char *end; - /* Skip leading whitespace */ - buf = skip_spaces(buf); + /* Skip leading whitespace and comma */ + buf = skip_spaces_and_commas(buf); if (!*buf) break; /* oh, it was trailing whitespace */ if (*buf == '#') @@ -320,7 +328,7 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords) return -EINVAL; /* unclosed quote */ } } else { - for (end = buf; *end && !isspace(*end); end++) + for (end = buf; *end && !isspace(*end) && *end != ','; end++) ; if (end == buf) { pr_err("parse err after word:%d=%s\n", nwords, @@ -592,7 +600,8 @@ static int ddebug_exec_queries(char *query, const char *modname) if (split) *split++ = '\0'; - query = skip_spaces(query); + query = skip_spaces_and_commas(query); + if (!query || !*query || *query == '#') continue; -- 2.44.0
[PATCH v8 24/35] selftests-dyndbg: test_percent_splitting multi-cmds on module classes
New fn tests multi-queries composed with % splitters. It uses both test_dynamic_debug and test_dynamic_debug_submod, and manipulates several classes at once. So despite the syntactic-oriented name, it also tests classmaps. Signed-off-by: Jim Cromie --- .../dynamic_debug/dyndbg_selftest.sh | 20 +++ 1 file changed, 20 insertions(+) diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh index 7a7d437e948b..ddb04c0a7fd2 100755 --- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh +++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh @@ -231,9 +231,29 @@ function comma_terminator_tests { ddcmd =_ } +function test_percent_splitting { +echo -e "${GREEN}# TEST_PERCENT_SPLITTING - multi-command splitting on % ${NC}" +ifrmmod test_dynamic_debug_submod +ifrmmod test_dynamic_debug +ddcmd =_ +modprobe test_dynamic_debug dyndbg=class,D2_CORE,+pf%class,D2_KMS,+pt%class,D2_ATOMIC,+pm +check_match_ct =pf 1 +check_match_ct =pt 1 +check_match_ct =pm 1 +check_match_ct test_dynamic_debug 23 -r +# add flags to those callsites +ddcmd class,D2_CORE,+mf%class,D2_KMS,+lt%class,D2_ATOMIC,+ml +check_match_ct =pmf 1 +check_match_ct =plt 1 +check_match_ct =pml 1 +check_match_ct test_dynamic_debug 23 -r +ifrmmod test_dynamic_debug +} + tests_list=( basic_tests comma_terminator_tests +test_percent_splitting ) # Run tests -- 2.44.0
[PATCH v8 23/35] dyndbg: split multi-query strings with %
Multi-query strings have long allowed: modprobe drm dyndbg="class DRM_UT_CORE +p; class DRM_UT_KMS +p" modprobe drm dyndbg=< [ 203.902703] dyndbg: query parse failed [ 203.902871] dyndbg: processed 2 queries, with 0 matches, 2 errs bash: echo: write error: Invalid argument The '%' splits the input into 2 queries, and both fail. Given the limited utility of matching against the working parts of a format string "foo: %d bar %s", nothing is actually lost here. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index c1bc728cb050..625838bd74aa 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -596,7 +596,7 @@ static int ddebug_exec_queries(char *query, const char *modname) int i, errs = 0, exitcode = 0, rc, nfound = 0; for (i = 0; query; query = split) { - split = strpbrk(query, ";\n"); + split = strpbrk(query, "%;\n"); if (split) *split++ = '\0'; -- 2.44.0
[PATCH v8 22/35] selftests-dyndbg: add comma_terminator_tests
New fn validates parsing and effect of queries using combinations of commas and spaces to delimit the tokens. It manipulates pr-debugs in builtin module/params, so might have deps I havent foreseen on odd configurations. Signed-off-by: Jim Cromie --- .../selftests/dynamic_debug/dyndbg_selftest.sh | 14 ++ 1 file changed, 14 insertions(+) diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh index cb77ae142520..7a7d437e948b 100755 --- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh +++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh @@ -217,9 +217,23 @@ EOF ddcmd =_ } +function comma_terminator_tests { +echo -e "${GREEN}# COMMA_TERMINATOR_TESTS ${NC}" +# try combos of spaces & commas +check_match_ct '\[params\]' 4 -r +ddcmd module,params,=_ # commas as spaces +ddcmd module,params,+mpf # turn on module's pr-debugs +check_match_ct =pmf 4 +ddcmd ,module ,, , params, -p +check_match_ct =mf 4 +ddcmd " , module ,,, , params, -m"# +check_match_ct =f 4 +ddcmd =_ +} tests_list=( basic_tests +comma_terminator_tests ) # Run tests -- 2.44.0
[PATCH v8 20/35] dyndbg-doc: add classmap info to howto
Describe the 3 API macros providing dynamic_debug's classmaps DYNDBG_CLASSMAP_DEFINE - create, exports a module's classmap DYNDBG_CLASSMAP_USE- refer to exported map DYNDBG_CLASSMAP_PARAM - bind control param to the classmap DYNDBG_CLASSMAP_PARAM_REF + use module's storage - __drm_debug cc: linux-...@vger.kernel.org Signed-off-by: Jim Cromie --- v5 adjustments per Randy Dunlap v7 checkpatch fixes v8 more --- .../admin-guide/dynamic-debug-howto.rst | 63 ++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 6a8ce5a34382..742eb4230c6e 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -225,7 +225,6 @@ the ``p`` flag has meaning, other flags are ignored. Note the regexp ``^[-+=][fslmpt_]+$`` matches a flags specification. To clear all flags at once, use ``=_`` or ``-fslmpt``. - Debug messages during Boot Process == @@ -375,3 +374,65 @@ just a shortcut for ``print_hex_dump(KERN_DEBUG)``. For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is its ``prefix_str`` argument, if it is constant string; or ``hexdump`` in case ``prefix_str`` is built dynamically. + +Dynamic Debug classmaps +=== + +Dyndbg allows selection/grouping of *prdbg* callsites using structural +info: module, file, function, line. Classmaps allow authors to add +their own domain-oriented groupings using class-names. Classmaps are +exported, so they referencable from other modules. + + # enable classes individually + :#> ddcmd class DRM_UT_CORE +p + :#> ddcmd class DRM_UT_KMS +p + # or more selectively + :#> ddcmd class DRM_UT_CORE module drm +p + +The "class FOO" syntax protects class'd prdbgs from generic overwrite:: + + # IOW this doesn't wipe any DRM.debug settings + :#> ddcmd -p + +To support the DRM.debug parameter, DYNDBG_CLASSMAP_PARAM* updates all +classes in a classmap, mapping param-bits 0..N onto the classes: +DRM_UT_<*> for the DRM use-case. + +Dynamic Debug Classmap API +== + +DYNDBG_CLASSMAP_DEFINE - modules use this to create classmaps, naming +each of the classes (stringified enum-symbols: "DRM_UT_<*>"), and +type, and mapping the class-names to consecutive _class_ids. + +By doing so, modules tell dyndbg that they have prdbgs with those +class_ids, and they authorize dyndbg to accept "class FOO" for the +module defining the classmap, and its contained classnames. + +DYNDBG_CLASSMAP_USE - drm drivers invoke this to ref the CLASSMAP that +drm DEFINEs. This shares the classmap definition, and authorizes +dyndbg to apply changes to the user module's class'd pr_debugs. It +also tells dyndbg how to initialize the user's prdbgs at modprobe, +based upon the current setting of the parent's controlling param. + +There are 2 types of classmaps: + + DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, like DRM.debug + DD_CLASS_TYPE_LEVEL_NUM: classes are relative, ordered (V3 > V2) + +DYNDBG_CLASSMAP_PARAM - modelled after module_param_cb, it refers to a +DEFINEd classmap, and associates it to the param's data-store. This +state is then applied to DEFINEr and USEr modules when they're modprobed. + +This interface also enforces the DD_CLASS_TYPE_LEVEL_NUM relation +amongst the contained classnames; all classes are independent in the +control parser itself. + +Modules or module-groups (drm & drivers) can define multiple +classmaps, as long as they share the limited 0..62 per-module-group +_class_id range, without overlap. + +``#define DEBUG`` will enable all pr_debugs in scope, including any +class'd ones. This won't be reflected in the PARAM readback value, +but the class'd pr_debug callsites can be forced off by toggling the +classmap-kparam all-on then all-off. -- 2.44.0
[PATCH v8 21/35] dyndbg: treat comma as a token separator
Treat comma as a token terminator, just like a space. This allows a user to avoid quoting hassles when spaces are otherwise needed: :#> modprobe drm dyndbg=class,DRM_UT_CORE,+p\;class,DRM_UT_KMS,+p or as a boot arg: drm.dyndbg=class,DRM_UT_CORE,+p # todo: support multi-query here Given the many ways a boot-line +args can be assembled and then passed in/down/around shell based tools, this may allow side-stepping all sorts of quoting hassles thru those layers. existing query format: modprobe test_dynamic_debug dyndbg="class D2_CORE +p" new format: modprobe test_dynamic_debug dyndbg=class,D2_CORE,+p Signed-off-by: Jim Cromie Co-developed-by: Łukasz Bartosik Signed-off-by: Łukasz Bartosik --- lib/dynamic_debug.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 31fd67597928..c1bc728cb050 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -290,6 +290,14 @@ static int ddebug_change(const struct ddebug_query *query, return nfound; } +static char *skip_spaces_and_commas(const char *str) +{ + str = skip_spaces(str); + while (*str == ',') + str = skip_spaces(++str); + return (char *)str; +} + /* * Split the buffer `buf' into space-separated words. * Handles simple " and ' quoting, i.e. without nested, @@ -303,8 +311,8 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords) while (*buf) { char *end; - /* Skip leading whitespace */ - buf = skip_spaces(buf); + /* Skip leading whitespace and comma */ + buf = skip_spaces_and_commas(buf); if (!*buf) break; /* oh, it was trailing whitespace */ if (*buf == '#') @@ -320,7 +328,7 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords) return -EINVAL; /* unclosed quote */ } } else { - for (end = buf; *end && !isspace(*end); end++) + for (end = buf; *end && !isspace(*end) && *end != ','; end++) ; if (end == buf) { pr_err("parse err after word:%d=%s\n", nwords, @@ -592,7 +600,8 @@ static int ddebug_exec_queries(char *query, const char *modname) if (split) *split++ = '\0'; - query = skip_spaces(query); + query = skip_spaces_and_commas(query); + if (!query || !*query || *query == '#') continue; -- 2.44.0
[PATCH v8 22/35] selftests-dyndbg: add comma_terminator_tests
New fn validates parsing and effect of queries using combinations of commas and spaces to delimit the tokens. It manipulates pr-debugs in builtin module/params, so might have deps I havent foreseen on odd configurations. Signed-off-by: Jim Cromie --- .../selftests/dynamic_debug/dyndbg_selftest.sh | 14 ++ 1 file changed, 14 insertions(+) diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh index cb77ae142520..7a7d437e948b 100755 --- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh +++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh @@ -217,9 +217,23 @@ EOF ddcmd =_ } +function comma_terminator_tests { +echo -e "${GREEN}# COMMA_TERMINATOR_TESTS ${NC}" +# try combos of spaces & commas +check_match_ct '\[params\]' 4 -r +ddcmd module,params,=_ # commas as spaces +ddcmd module,params,+mpf # turn on module's pr-debugs +check_match_ct =pmf 4 +ddcmd ,module ,, , params, -p +check_match_ct =mf 4 +ddcmd " , module ,,, , params, -m"# +check_match_ct =f 4 +ddcmd =_ +} tests_list=( basic_tests +comma_terminator_tests ) # Run tests -- 2.44.0
[PATCH v8 11/35] dyndbg: silence debugs with no-change updates
In ddebug_apply_class_bitmap(), check for actual changes to the bits before announcing them, to declutter logs. no functional change. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 368381dbd266..8320cadeb251 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -595,7 +595,7 @@ 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, const char *query_modname) @@ -606,8 +606,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp, int matches = 0; int bi, ct; - v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, - query_modname ?: ""); + 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)) @@ -622,8 +623,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); } - v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, - query_modname ?: ""); + 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; } -- 2.44.0
[PATCH v8 13/35] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
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 --- lib/dynamic_debug.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 882354e1e78f..d4a0ae31d059 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -597,7 +597,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 @@ -606,12 +607,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, _bits)) continue; snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi], @@ -623,9 +624,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; } @@ -681,7 +682,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa continue; } curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, *dcp->bits, NULL); *dcp->bits = curr_bits; v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id, map->class_names[cls_id]); @@ -691,7 +692,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa old_bits = CLASSMAP_BITMASK(*dcp->lvl); curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 )); - totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, old_bits, NULL); *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); @@ -745,7 +746,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, modnm ?: "*", KP_NAME(kp)); - totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, modnm); + totct += ddebug_apply_class_bitmap(dcp, , *dcp->bits, modnm); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -758,7 +759,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, _bits, _bits, modnm); + totct += ddebug_apply_class_bitmap(dcp, _bits, old_bits, modnm); *dcp->lvl = inrep; break; default: -- 2.44.0
[PATCH v8 20/35] dyndbg-doc: add classmap info to howto
Describe the 3 API macros providing dynamic_debug's classmaps DYNDBG_CLASSMAP_DEFINE - create, exports a module's classmap DYNDBG_CLASSMAP_USE- refer to exported map DYNDBG_CLASSMAP_PARAM - bind control param to the classmap DYNDBG_CLASSMAP_PARAM_REF + use module's storage - __drm_debug cc: linux-...@vger.kernel.org Signed-off-by: Jim Cromie --- v5 adjustments per Randy Dunlap v7 checkpatch fixes v8 more --- .../admin-guide/dynamic-debug-howto.rst | 63 ++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 6a8ce5a34382..742eb4230c6e 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -225,7 +225,6 @@ the ``p`` flag has meaning, other flags are ignored. Note the regexp ``^[-+=][fslmpt_]+$`` matches a flags specification. To clear all flags at once, use ``=_`` or ``-fslmpt``. - Debug messages during Boot Process == @@ -375,3 +374,65 @@ just a shortcut for ``print_hex_dump(KERN_DEBUG)``. For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is its ``prefix_str`` argument, if it is constant string; or ``hexdump`` in case ``prefix_str`` is built dynamically. + +Dynamic Debug classmaps +=== + +Dyndbg allows selection/grouping of *prdbg* callsites using structural +info: module, file, function, line. Classmaps allow authors to add +their own domain-oriented groupings using class-names. Classmaps are +exported, so they referencable from other modules. + + # enable classes individually + :#> ddcmd class DRM_UT_CORE +p + :#> ddcmd class DRM_UT_KMS +p + # or more selectively + :#> ddcmd class DRM_UT_CORE module drm +p + +The "class FOO" syntax protects class'd prdbgs from generic overwrite:: + + # IOW this doesn't wipe any DRM.debug settings + :#> ddcmd -p + +To support the DRM.debug parameter, DYNDBG_CLASSMAP_PARAM* updates all +classes in a classmap, mapping param-bits 0..N onto the classes: +DRM_UT_<*> for the DRM use-case. + +Dynamic Debug Classmap API +== + +DYNDBG_CLASSMAP_DEFINE - modules use this to create classmaps, naming +each of the classes (stringified enum-symbols: "DRM_UT_<*>"), and +type, and mapping the class-names to consecutive _class_ids. + +By doing so, modules tell dyndbg that they have prdbgs with those +class_ids, and they authorize dyndbg to accept "class FOO" for the +module defining the classmap, and its contained classnames. + +DYNDBG_CLASSMAP_USE - drm drivers invoke this to ref the CLASSMAP that +drm DEFINEs. This shares the classmap definition, and authorizes +dyndbg to apply changes to the user module's class'd pr_debugs. It +also tells dyndbg how to initialize the user's prdbgs at modprobe, +based upon the current setting of the parent's controlling param. + +There are 2 types of classmaps: + + DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, like DRM.debug + DD_CLASS_TYPE_LEVEL_NUM: classes are relative, ordered (V3 > V2) + +DYNDBG_CLASSMAP_PARAM - modelled after module_param_cb, it refers to a +DEFINEd classmap, and associates it to the param's data-store. This +state is then applied to DEFINEr and USEr modules when they're modprobed. + +This interface also enforces the DD_CLASS_TYPE_LEVEL_NUM relation +amongst the contained classnames; all classes are independent in the +control parser itself. + +Modules or module-groups (drm & drivers) can define multiple +classmaps, as long as they share the limited 0..62 per-module-group +_class_id range, without overlap. + +``#define DEBUG`` will enable all pr_debugs in scope, including any +class'd ones. This won't be reflected in the PARAM readback value, +but the class'd pr_debug callsites can be forced off by toggling the +classmap-kparam all-on then all-off. -- 2.44.0
[PATCH v8 19/35] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
move the DYNDBG_CLASSMAP_PARAM macro from test-dynamic-debug.c into the header, and refine it, by distinguishing the 2 use cases: 1.DYNDBG_CLASSMAP_PARAM_REF for DRM, to pass in extern __drm_debug by name. dyndbg keeps bits in it, so drm can still use it as before 2.DYNDBG_CLASSMAP_PARAM new user (test_dynamic_debug) doesn't need to share state, decls a static long unsigned int to store the bitvec. __DYNDBG_CLASSMAP_PARAM bottom layer - allocate,init a ddebug-class-param, module-param-cb. Also clean up and improve comments in test-code, and add MODULE_DESCRIPTIONs. Signed-off-by: Jim Cromie --- fixup drm-print.h add PARAM_REF forwarding macros with DYNDBG_CLASSMAP_PARAM_REF in the API, add DRM_ variant --- include/linux/dynamic_debug.h | 37 - lib/dynamic_debug.c | 70 ++--- lib/test_dynamic_debug.c| 50 +-- lib/test_dynamic_debug_submod.c | 9 - 4 files changed, 110 insertions(+), 56 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index d1fc3035e19c..090fe9554db7 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -91,7 +91,7 @@ struct ddebug_class_map { * used to validate a "class FOO .." >control command on the module */ #define __DYNDBG_CLASSMAP_DEFINE(_var, _maptype, _base, ...) \ - const char *_var##_classnames[] = { __VA_ARGS__ }; \ + static const char *_var##_classnames[] = { __VA_ARGS__ }; \ struct ddebug_class_map __aligned(8) __used \ __section("__dyndbg_classes") _var = { \ .mod = THIS_MODULE, \ @@ -163,6 +163,41 @@ struct ddebug_class_param { const struct ddebug_class_map *map; }; +/** + * DYNDBG_CLASSMAP_PARAM - wrap a dyndbg-classmap with a controlling sys-param + * @_name sysfs node name + * @_var name of the struct classmap var defining the controlled classes + * @_flags flags to be toggled, typically just 'p' + * + * Creates a sysfs-param to control the classes defined by the + * classmap. Keeps bits in a private/static + */ +#define DYNDBG_CLASSMAP_PARAM(_name, _var, _flags) \ + static unsigned long _name##_bvec; \ + __DYNDBG_CLASSMAP_PARAM(_name, _name##_bvec, _var, _flags) + +/** + * DYNDBG_CLASSMAP_PARAM_REF - wrap a dyndbg-classmap with a controlling sys-param + * @_name sysfs node name + * @_bits name of the module's unsigned long bit-vector, ex: __drm_debug + * @_var name of the struct classmap var defining the controlled classes + * @_flags flags to be toggled, typically just 'p' + * + * Creates a sysfs-param to control the classmap, keeping bitvec in user @_bits. + * This lets drm use __drm_debug elsewhere too. + */ +#define DYNDBG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags) \ + __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags) + +#define __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)\ + static struct ddebug_class_param _name##_##_flags = { \ + .bits = &(_bits), \ + .flags = #_flags, \ + .map = &(_var), \ + }; \ + module_param_cb(_name, _ops_dyndbg_classes, \ + &_name##_##_flags, 0600) + /* * pr_debug() and friends are globally enabled or modules have selectively * enabled them. diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index f0a274a3cc9e..31fd67597928 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -657,6 +657,30 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp, #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1) +static void ddebug_class_param_clamp_input(unsigned long *inrep, const struct kernel_param *kp) +{ + const struct ddebug_class_param *dcp = kp->arg; + const struct ddebug_class_map *map = dcp->map; + + switch (map->map_type) { + case DD_CLASS_TYPE_DISJOINT_BITS: + /* expect bits. mask and warn if too many */ + if (*inrep & ~CLASSMAP_BITMASK(map->length)) { + pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n", + KP_NAME(kp), *inrep, CLASSMAP_BITMASK(map->length)); + *inrep &= CLASSMAP_BITMASK(map->length); + } + break; + case DD_CLASS_TYPE_LEVEL_NUM: + /* input is bitpos, of highest verbosity to be enabled */ + if (*inrep > map->length) { + pr_warn("%s: level:%
[PATCH v8 18/35] selftests-dyndbg: exit 127 if no facility
Test if /proc/dynamic_debug/control exists, exit 127 otherwise. This distinguishes an untestable config from both pass & fail. The 127 choice is pretty arbitrary, but imitating bisect. That control file's presense guarantees that dynamic-debugging is configured (unless /proc is off, unusually), without dealing with the mount. Signed-off-by: Jim Cromie --- tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh | 5 + 1 file changed, 5 insertions(+) diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh index 1be70af26a38..cb77ae142520 100755 --- a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh +++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh @@ -11,6 +11,11 @@ CYAN="\033[0;36m" NC="\033[0;0m" error_msg="" +[ -e /proc/dynamic_debug/control ] || { +echo -e "${RED}: kernel not configured for this test ${NC}" +exit 127 +} + function vx () { echo $1 > /sys/module/dynamic_debug/parameters/verbose } -- 2.44.0
[PATCH v8 14/35] dyndbg: reduce 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 --- lib/dynamic_debug.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index d4a0ae31d059..43a8e04b8599 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1245,11 +1245,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(sizeof(*dt), GFP_KERNEL); if (dt == NULL) { -- 2.44.0
[PATCH v8 09/35] dyndbg: drop NUM_TYPE_ARRAY
ARRAY_SIZE works here, since array decl is complete. no functional change Signed-off-by: Jim Cromie --- 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 b53217e4b711..8116d0a0d33a 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -106,11 +106,9 @@ struct ddebug_class_map { .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)) /* encapsulate linker provided built-in (or module) dyndbg data */ struct _ddebug_info { -- 2.44.0
[PATCH v8 10/35] dyndbg: reduce verbose/debug clutter
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=0x 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" mod:* dyndbg: split into words: "class" "DRM_UT_CORE" "+p" dyndbg: op='+' flags=0x1 *flagsp=0x1 *maskp=0x dyndbg: no-match: func="" file="" module="" format="" lineno=0-0 class=... dyndbg: processed 1 queries, with 0 matches, 0 errs no functional change. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 14 +++--- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 4a48f830507f..368381dbd266 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -266,9 +266,6 @@ static int ddebug_change(const struct ddebug_query *query, } mutex_unlock(_lock); - if (!nfound && verbose) - pr_info("no matches for query\n"); - return nfound; } @@ -501,7 +498,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--) { @@ -515,7 +511,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) { @@ -531,7 +526,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; } @@ -541,7 +536,7 @@ static int ddebug_exec_query(char *query_string, const char *modname) struct flag_settings modifiers = {}; struct ddebug_query query = {}; #define MAXWORDS 9 - int nwords, nfound; + int nwords; char *words[MAXWORDS]; nwords = ddebug_tokenize(query_string, words, MAXWORDS); @@ -559,10 +554,7 @@ static int ddebug_exec_query(char *query_string, const char *modname) return -EINVAL; } /* actually go and implement the change */ - nfound = ddebug_change(, ); - vpr_info_dq(, nfound ? "applied" : "no-match"); - - return nfound; + return ddebug_change(, ); } /* handle multiple queries in query string, continue on error, return -- 2.44.0
[PATCH v8 17/35] selftests-dyndbg: add tools/testing/selftests/dynamic_debug/*
Add a selftest script for dynamic-debug. The config requires CONFIG_TEST_DYNAMIC_DEBUG=m (and CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m), which tacitly requires either CONFIG_DYNAMIC_DEBUG=y or CONFIG_DYNAMIC_DEBUG_CORE=y ATM this has just basic_tests(), it modifies pr_debug flags in a few builtins (init/main, params), counts the callsite flags changed, and verifies against expected values. This is backported from another feature branch; the support-fns (thx Lukas) have unused features at the moment, they'll get used shortly. The script enables simple virtme-ng testing: $> vng --verbose --name v6.8-32-g30d431000676 --user root \ --cwd ../.. -a dynamic_debug.verbose=2 -p 4 \ ./tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh virtme: waiting for virtiofsd to start virtme: use 'microvm' QEMU architecture ... [4.136168] virtme-init: Setting hostname to v6.8-32-g30d431000676... [4.240874] virtme-init: starting script test_dynamic_debug_submod not there test_dynamic_debug not there ... [4.474435] virtme-init: script returned {0} Powering off. [4.529318] ACPI: PM: Preparing to enter system sleep state S5 [4.529991] kvm: exiting hardware virtualization [4.530428] reboot: Power down And add dynamic_debug to TARGETS, so `make run_tests` sees it properly for the impatient, set TARGETS explicitly: bash-5.2# make TARGETS=dynamic_debug run_tests make[1]: ... TAP version 13 1..1 [ 35.552922] dyndbg: read 3 bytes from userspace [ 35.553099] dyndbg: query 0: "=_" mod:* [ 35.553544] dyndbg: processed 1 queries, with 1778 matches, 0 errs ... TLDR: This selftest is slightly naive wrt the init state of call-site flags. In particular, it fails if class'd pr_debugs have been set $ cat /etc/modprobe.d/drm-test.conf options drm dyndbg=class,DRM_UT_CORE,+mfslt%class,DRM_UT_KMS,+mf By Contract, class'd pr_debugs are protected from alteration by default (only by direct "class FOO" queries), so the "=_" logged above (TAP version 13) cannot affect the DRM_UT_CORE,KMS pr_debugs. These class'd flag-settings, added by modprobe, alter the counts of flag-matching patterns, breaking the tests' expectations. Signed-off-by: Jim Cromie Co-developed-by: Łukasz Bartosik Signed-off-by: Łukasz Bartosik --- MAINTAINERS | 1 + tools/testing/selftests/Makefile | 1 + .../testing/selftests/dynamic_debug/Makefile | 9 + tools/testing/selftests/dynamic_debug/config | 2 + .../dynamic_debug/dyndbg_selftest.sh | 231 ++ 5 files changed, 244 insertions(+) create mode 100644 tools/testing/selftests/dynamic_debug/Makefile create mode 100644 tools/testing/selftests/dynamic_debug/config create mode 100755 tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh diff --git a/MAINTAINERS b/MAINTAINERS index cf9fccbc6bde..bdffd192d3df 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7526,6 +7526,7 @@ S:Maintained F: include/linux/dynamic_debug.h F: lib/dynamic_debug.c F: lib/test_dynamic_debug*.c +F: tools/testing/selftest/dynamic_debug/* DYNAMIC INTERRUPT MODERATION M: Tal Gilboa diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index e1504833654d..84edf0bd8e80 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -20,6 +20,7 @@ TARGETS += drivers/s390x/uvdevice TARGETS += drivers/net/bonding TARGETS += drivers/net/team TARGETS += dt +TARGETS += dynamic_debug TARGETS += efivarfs TARGETS += exec TARGETS += fchmodat2 diff --git a/tools/testing/selftests/dynamic_debug/Makefile b/tools/testing/selftests/dynamic_debug/Makefile new file mode 100644 index ..6d06fa7f1040 --- /dev/null +++ b/tools/testing/selftests/dynamic_debug/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +# borrowed from Makefile for user memory selftests + +# No binaries, but make sure arg-less "make" doesn't trigger "run_tests" +all: + +TEST_PROGS := dyndbg_selftest.sh + +include ../lib.mk diff --git a/tools/testing/selftests/dynamic_debug/config b/tools/testing/selftests/dynamic_debug/config new file mode 100644 index ..d080da571ac0 --- /dev/null +++ b/tools/testing/selftests/dynamic_debug/config @@ -0,0 +1,2 @@ +CONFIG_TEST_DYNAMIC_DEBUG=m +CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD=m diff --git a/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh new file mode 100755 index ..1be70af26a38 --- /dev/null +++ b/tools/testing/selftests/dynamic_debug/dyndbg_selftest.sh @@ -0,0 +1,231 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only + +V=${V:=0} # invoke as V=1 $0 for global verbose +RED="\033[0;31m" +GREEN="\033[0;32m" +YELLOW="\033[0;33m" +BLUE="\033[0;34m" +MAGENTA="\033[0;35m" +CYAN="\033[0;36m" +NC="\033[0;0
[PATCH v8 08/35] dyndbg: split param_set_dyndbg_classes to _module & wrapper fns
Split api-fn: param_set_dyndbg_classes(), adding modname param and passing NULL in from api-fn. The new arg allows caller to specify that only one module is affected by a prdbgs update. This selectivity will be used later to narrow the scope of changes made. no functional change. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 37 ++--- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index a1fd2e9dbafb..4a48f830507f 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -711,18 +711,9 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa return 0; } -/** - * 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 - * - * Enable/disable prdbgs by their class, as given in the arguments to - * DECLARE_DYNDBG_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) +static int param_set_dyndbg_module_classes(const char *instr, + const struct kernel_param *kp, + const char *modnm) { const struct ddebug_class_param *dcp = kp->arg; const struct ddebug_class_map *map = dcp->map; @@ -759,8 +750,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, , dcp->bits, NULL); + v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp)); + totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, modnm); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -773,7 +764,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, _bits, _bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, modnm); *dcp->lvl = inrep; break; default: @@ -782,6 +773,22 @@ 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 - class FOO >control + * @instr: string echo>d to sysfs, input depends on map_type + * @kp:kp->arg has state: bits/lvl, map, map_type + * + * Enable/disable prdbgs by their class, as given in the arguments to + * DECLARE_DYNDBG_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); /** -- 2.44.0
[PATCH v8 15/35] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
Remove the NAMED class types; 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 test-surface, simplify things. also rename enum class_map_type to enum ddebug_class_map_type. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 23 ++-- lib/dynamic_debug.c | 102 +++--- lib/test_dynamic_debug.c | 26 - 3 files changed, 14 insertions(+), 137 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 8116d0a0d33a..dd304e231f08 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -58,27 +58,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 */ }; @@ -88,7 +77,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; }; /** diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 43a8e04b8599..d5701207febc 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -636,76 +636,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, _bits) == wanted) { - v3pr_info("no change on %s\n", cl_str); - continue; - } - curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, *dcp->bits, NULL); - *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_
[PATCH v8 12/35] dyndbg: tighten ddebug_class_name() 1st arg type
Change function's 1st arg-type, and deref in the caller. The fn doesn't need any other fields in the struct. no functional change. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 8320cadeb251..882354e1e78f 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1120,12 +1120,12 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos) #define class_in_range(class_id, map) \ (class_id >= map->base && class_id < map->base + map->length) -static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp) +static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp) { - struct ddebug_class_map *map = iter->table->classes; - int i, nc = iter->table->num_classes; + struct ddebug_class_map *map = dt->classes; + int i; - for (i = 0; i < nc; i++, map++) + for (i = 0; i < dt->num_classes; i++, map++) if (class_in_range(dp->class_id, map)) return map->class_names[dp->class_id - map->base]; @@ -1159,7 +1159,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p) seq_puts(m, "\""); if (dp->class_id != _DPRINTK_CLASS_DFLT) { - class = ddebug_class_name(iter, dp); + class = ddebug_class_name(iter->table, dp); if (class) seq_printf(m, " class:%s", class); else -- 2.44.0
[PATCH v8 16/35] dyndbg-API: fix DECLARE_DYNDBG_CLASSMAP
n-overlapping subranges). reorg macros 2,3 by name. This gives a tabular format, making it easy to see the pattern of repetition, and the points of change. And extend the test to replicate the 2-module (parent & dependent) scenario which caused the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression seen in drm & drivers. The _submod.c is a 2-line file: #define _SUBMOD, #include parent. This gives identical complements of prdbgs in parent & _submod, and thus identical print behavior when all of: >control, >params, and parent->_submod propagation are working correctly. It also puts all the parent/_submod declarations together in the same source, with the new ifdef _SUBMOD block invoking DYNDBG_CLASSMAP_USE for the 2 test-interfaces. I think this is clearer. These 2 modules are both tristate, allowing 3 super/sub combos: Y/Y, Y/M, M/M (not N/N). Y/Y testing exposed a missing __align(8) in the _METADATA macro, which M/M didn't see because the module-loader memory placement constrains it instead. DEBUG details: ``#define DEBUG`` in src enables all pr_debugs after it, including any class'd pr_debugs; its not necessarily all-or-nothing, unless you do the define in a header. Also, the only way to disable them is with the classmap-kparam or using "class foo -p" >control queries. Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro") Ref: bb2ff6c27bc9 ("drm: Disable dynamic debug as broken") Signed-off-by: Jim Cromie --- v8 - split drm parts to separate commits. preserve DECLARE_DYNDBG_CLASSMAP to decouple DRM, no flag day. v7 - previous submission-blocking bug: missing __align(8) in DYNAMIC_DEBUG_DECLARE_METADATA on ddebug_class_user caused corrupt records, but only for builtin modules; module loader code probably pinned allocations to the right alignment naturally, hiding the bug for typical builds. v6- get rid of WARN_ON_ONCE v?- fix _var expanded 2x in macro --- MAINTAINERS | 2 +- include/asm-generic/vmlinux.lds.h | 1 + include/linux/dynamic_debug.h | 61 -- kernel/module/main.c | 3 + lib/Kconfig.debug | 24 +++- lib/Makefile | 3 + lib/dynamic_debug.c | 183 ++ lib/test_dynamic_debug.c | 111 -- lib/test_dynamic_debug_submod.c | 10 ++ 9 files changed, 330 insertions(+), 68 deletions(-) create mode 100644 lib/test_dynamic_debug_submod.c diff --git a/MAINTAINERS b/MAINTAINERS index ebf03f5f0619..cf9fccbc6bde 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7525,7 +7525,7 @@ M:Jim Cromie S: Maintained F: include/linux/dynamic_debug.h F: lib/dynamic_debug.c -F: lib/test_dynamic_debug.c +F: lib/test_dynamic_debug*.c DYNAMIC INTERRUPT MODERATION M: Tal Gilboa diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index f7749d0f2562..f1d8e64b244c 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -365,6 +365,7 @@ /* implement dynamic printk debug */\ . = ALIGN(8); \ BOUNDED_SECTION_BY(__dyndbg_classes, ___dyndbg_classes) \ + BOUNDED_SECTION_BY(__dyndbg_class_users, ___dyndbg_class_users) \ BOUNDED_SECTION_BY(__dyndbg, ___dyndbg) \ LIKELY_PROFILE()\ BRANCH_PROFILE()\ diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index dd304e231f08..d1fc3035e19c 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -72,8 +72,8 @@ enum ddebug_class_map_type { }; struct ddebug_class_map { - struct module *mod; - const char *mod_name; /* needed for builtins */ + const struct module *mod; /* NULL for builtins */ + const char *mod_name; const char **class_names; const int length; const int base; /* index of 1st .class_id, allows split/shared space */ @@ -81,11 +81,33 @@ struct ddebug_class_map { }; /** - * 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 + * DYNDBG_CLASSMAP_DEFINE - define a set of debug-classes used by a module. + * @_var: name of the classmap, exported for other modules coordinated use. + * @_type: enum ddebug_class_map_type, chooses bits/verbose, numeric/names. + * @_base: offset of 1st class-name, used to share 0..62 classid space + * @classes: vals are stringified enum-vals, like DRM_UT_* + * + * Defines and ex
[PATCH v8 06/35] dyndbg: replace classmap list with a vector
Classmaps are stored in an elf section/array, but are individually list-linked onto dyndbg's per-module ddebug_table for operation. This is unnecessary; even when ddebug_attach_classmap() is handling the builtin section (with classmaps for multiple builtin modules), its contents are ordered, so a module's possibly multiple classmaps will be consecutive in the section, and could be treated as a vector/block, since both start-addy and subrange length are in the ddebug_info arg. IOW, this treats classmaps similarly to _ddebugs, which are already kept as vector-refs (address+len). So this changes: struct ddebug_class_map drops list-head link. struct ddebug_table drops the list-head maps, and gets: classes & num_classes for the start-addy and num_classes, placed to improve struct packing. The loading: in ddebug_attach_module_classes(), replace the for-the-modname list-add loop, with a forloop that finds the module's subrange (start,length) of matching classmaps within the possibly builtin classmaps vector, and saves those to the ddebug_table. The reading/using: change list-foreach loops in ddebug_class_name() & ddebug_find_valid_class() to walk the array from start to length. Also: Move #define __outvar up, above an added use in a fn-prototype. Simplify ddebug_attach_module_classes args, ref has both addy,len. no functional changes Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 1 - lib/dynamic_debug.c | 61 ++- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 5231aaf361c4..b53217e4b711 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -83,7 +83,6 @@ enum 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 152b04c05981..46e4cdd8e6be 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 { @@ -147,13 +148,15 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg) query->first_lineno, query->last_lineno, query->class_string); } +#define __outvar /* filled by callee */ 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, + __outvar int *class_id) { struct ddebug_class_map *map; - int idx; + int i, idx; - list_for_each_entry(map, >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; @@ -164,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 @@ -1114,9 +1116,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, >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]; @@ -1200,30 +1203,31 @@ 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;
[PATCH v8 04/35] dyndbg: reword "class unknown, " to "class:_UNKNOWN_"
When a dyndbg classname is unknown to a kernel module (as before previous patch), the callsite is un-addressable via >control queries. The control-file displays this condition as "class unknown," currently. That spelling is sub-optimal, so change it to "class:_UNKNOWN_" to loudly announce the erroneous situation, and to make it exceedingly greppable. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index f2c5e7910bb1..73ccf947d4aa 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1154,7 +1154,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_puts(m, "\n"); -- 2.44.0
[PATCH v8 05/35] dyndbg: make ddebug_class_param union members same size
struct ddebug_class_param keeps a ref to the state-storage of the param; make both class-types use the same unsigned long storage type. ISTM this is simpler and safer. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 2 +- lib/dynamic_debug.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 4fcbf4d4fd0a..5231aaf361c4 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -124,7 +124,7 @@ struct _ddebug_info { struct ddebug_class_param { union { unsigned long *bits; - unsigned int *lvl; + unsigned long *lvl; }; char flags[8]; const struct ddebug_class_map *map; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 73ccf947d4aa..152b04c05981 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -799,7 +799,7 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp) case DD_CLASS_TYPE_LEVEL_NAMES: case DD_CLASS_TYPE_LEVEL_NUM: - return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl); + return scnprintf(buffer, PAGE_SIZE, "%ld\n", *dcp->lvl); default: return -1; } -- 2.44.0
[PATCH v8 07/35] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it
Add param: query_module to ddebug_apply_class_bitmap(), and pass it thru to _ddebug_queries(), replacing NULL with query_module. This allows its caller to update just one module, or all (as currently). We'll use this later to propagate drm.debug to each USEr as they're modprobed. No functional change. Signed-off-by: Jim Cromie --- after `modprobe i915`, heres the module dependencies, though not all on drm.debug. bash-5.2# lsmod Module Size Used by i915 3133440 0 drm_buddy 20480 1 i915 ttm90112 1 i915 i2c_algo_bit 16384 1 i915 video 61440 1 i915 wmi32768 1 video drm_display_helper200704 1 i915 drm_kms_helper208896 2 drm_display_helper,i915 drm 606208 5 drm_kms_helper,drm_display_helper,drm_buddy,i915,ttm cec57344 2 drm_display_helper,i915 --- lib/dynamic_debug.c | 19 --- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 46e4cdd8e6be..a1fd2e9dbafb 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -605,7 +605,8 @@ static int ddebug_exec_queries(char *query, const char *modname) /* apply a new bitmap to the sys-knob's current bit-state */ 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]; @@ -613,7 +614,8 @@ 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); + 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)) @@ -622,12 +624,15 @@ 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); } + v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, + query_modname ?: ""); + return matches; } @@ -682,7 +687,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa continue; } curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits); + totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits, NULL); *dcp->bits = curr_bits; v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id, map->class_names[cls_id]); @@ -692,7 +697,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa old_bits = CLASSMAP_BITMASK(*dcp->lvl); curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 )); - totct += ddebug_apply_class_bitmap(dcp, _bits, _bits); + totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, NULL); *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); @@ -755,7 +760,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp) inrep &= CLASSMAP_BITMASK(map->length); } v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp)); - totct += ddebug_apply_class_bitmap(dcp, , dcp->bits); + totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, NULL); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -768,7 +773,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp) old_bits = CLASSMAP_BITMASK(*dcp->lvl); new_bits = CLASSM
[PATCH v8 03/35] test-dyndbg: fixup CLASSMAP usage error
A more careful reading of logging output from test_dynamic_debug.ko reveals: lib/test_dynamic_debug.c:103 [test_dynamic_debug]do_cats =pmf "doing categories\n" lib/test_dynamic_debug.c:105 [test_dynamic_debug]do_cats =p "LOW msg\n" class:MID lib/test_dynamic_debug.c:106 [test_dynamic_debug]do_cats =p "MID msg\n" class:HI lib/test_dynamic_debug.c:107 [test_dynamic_debug]do_cats =_ "HI msg\n" class unknown, _id:13 107 says: HI is unknown, 105,106 have LOW/MID and MID/HI skew. The enum's 1st val (explicitly initialized) was wrong; it must be _base, not _base+1 (a DECLARE_DYNDBG_CLASSMAP param). So the last enumeration exceeded the range of mapped class-id's, which triggered the "class unknown" report. I coded in an error, intending to verify err detection, then forgot, and missed that it was there. So this patch fixes a bad usage of DECLARE_DYNDBG_CLASSMAP(), showing that it is too error-prone. As noted in test-mod comments: * Using the CLASSMAP api: * - classmaps must have corresponding enum * - enum symbols must match/correlate with class-name strings in the map. * - base must equal enum's 1st value * - multiple maps must set their base to share the 0-62 class_id space !! Signed-off-by: Jim Cromie --- lib/test_dynamic_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c index 8dd250ad022b..a01f0193a419 100644 --- a/lib/test_dynamic_debug.c +++ b/lib/test_dynamic_debug.c @@ -75,7 +75,7 @@ DD_SYS_WRAP(disjoint_bits, p); DD_SYS_WRAP(disjoint_bits, T); /* symbolic input, independent bits */ -enum cat_disjoint_names { LOW = 11, MID, HI }; +enum cat_disjoint_names { LOW = 10, MID, HI }; DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10, "LOW", "MID", "HI"); DD_SYS_WRAP(disjoint_names, p); -- 2.44.0
[PATCH v8 02/35] docs/dyndbg: update examples \012 to \n
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. Signed-off-by: Jim Cromie --- Documentation/admin-guide/dynamic-debug-howto.rst | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 0e9b48daf690..6a8ce5a34382 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -52,12 +52,12 @@ query/commands to the control file. Example:: # grease the interface :#> alias ddcmd='echo $* > /proc/dynamic_debug/control' - :#> ddcmd '-p; module main func run* +p' + :#> ddcmd '-p; module main func run* +p' # disable all, then enable main :#> 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.44.0
[PATCH v8 01/35] dyndbg: fix old BUG_ON in >control parser
Fix a BUG_ON from 2009. Even if it looks "unreachable" (I didn't really look), lets make sure by removing it, doing pr_err and return -EINVAL instead. cc: sta...@vger.kernel.org Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index c78f335fa981..f2c5e7910bb1 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -302,7 +302,11 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords) } else { for (end = buf; *end && !isspace(*end); end++) ; - BUG_ON(end == buf); + if (end == buf) { + pr_err("parse err after word:%d=%s\n", nwords, + nwords ? words[nwords - 1] : ""); + return -EINVAL; + } } /* `buf' is start of word, `end' is one past its end */ -- 2.44.0
[PATCH v8 00/35] fix CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression
u nd:4754 nc:0 nu:1 [9.020012] gandalf kernel: dyndbg: processed 1 queries, with 21 matches, 0 errs [9.020017] gandalf kernel: dyndbg: bit_4: 21 matches on class: DRM_UT_ATOMIC -> 0x1f [9.020021] gandalf kernel: dyndbg: applied bitmap: 0x1f to: 0x0 for amdgpu [9.020026] gandalf kernel: dyndbg: attach-client-module: module:amdgpu nd:4754 nc:0 nu:1 [9.020031] gandalf kernel: dyndbg: 4754 debug prints in module amdgpu [9.055065] gandalf kernel: [drm] amdgpu kernel modesetting enabled. [9.055138] gandalf kernel: [drm:amdgpu_acpi_detect [amdgpu]] No matching acpi device found for AMD3000 [9.055564] gandalf kernel: amdgpu: Virtual CRAT table created for CPU [9.055585] gandalf kernel: amdgpu: Topology: Add CPU node [9.055752] gandalf kernel: amdgpu :0c:00.0: enabling device (0006 -> 0007) [9.055821] gandalf kernel: [drm] initializing kernel modesetting (NAVI10 0x1002:0x731F 0x148C:0x2398 0xC1). [9.055835] gandalf kernel: [drm] register mmio base: 0xFCB0 [9.055839] gandalf kernel: [drm] register mmio size: 524288 [9.059148] gandalf kernel: [drm:amdgpu_discovery_set_ip_blocks [amdgpu]] number of dies: 1 [9.059387] gandalf kernel: [drm:amdgpu_discovery_set_ip_blocks [amdgpu]] number of hardware IPs on die0: 39 [9.059623] gandalf kernel: [drm:amdgpu_discovery_set_ip_blocks [amdgpu]] ATHUB(35) #0 v2.0.0: [9.059856] gandalf kernel: [drm:amdgpu_discovery_set_ip_blocks [amdgpu]] 0x0c00 [9.060096] gandalf kernel: [drm:amdgpu_discovery_set_ip_blocks [amdgpu]] 0x02408c00 [9.060328] gandalf kernel: [drm:amdgpu_discovery_set_ip_blocks [amdgpu]] set register base offset for ATHUB a startup script, after sleep 15, turns off the logging: echo 0 > /sys/module/drm/parameters/debug heres 1st 2 bits/classes/categories being turned off: [ 29.105991] gandalf kernel: [drm:amdgpu_ih_process [amdgpu]] amdgpu_ih_process: rptr 90752, wptr 90784 [ 29.118086] gandalf kernel: dyndbg: bits:0x0 > *.debug [ 29.118096] gandalf kernel: dyndbg: apply bitmap: 0x0 to: 0x1f for '*' [ 29.118102] gandalf kernel: dyndbg: query 0: "class DRM_UT_CORE -p" mod:* [ 29.118122] gandalf kernel: dyndbg: good-class: drm.DRM_UT_CORE module:drm nd:338 nc:1 nu:0 [ 29.119548] gandalf kernel: dyndbg: class-ref: drm_kms_helper.DRM_UT_CORE module:drm_kms_helper nd:93 nc:0 nu:1 [ 29.119552] gandalf kernel: dyndbg: class-ref: drm_display_helper.DRM_UT_CORE module:drm_display_helper nd:151 nc:0 nu:1 [ 29.119737] gandalf kernel: dyndbg: class-ref: amdgpu.DRM_UT_CORE module:amdgpu nd:4754 nc:0 nu:1 [ 29.122181] gandalf kernel: [drm:amdgpu_ih_process [amdgpu]] amdgpu_ih_process: rptr 90784, wptr 90816 [ 29.127687] gandalf kernel: dyndbg: processed 1 queries, with 466 matches, 0 errs [ 29.127690] gandalf kernel: dyndbg: bit_0: 466 matches on class: DRM_UT_CORE -> 0x0 [ 29.127692] gandalf kernel: dyndbg: query 0: "class DRM_UT_DRIVER -p" mod:* [ 29.127696] gandalf kernel: dyndbg: good-class: drm.DRM_UT_DRIVER module:drm nd:338 nc:1 nu:0 [ 29.127699] gandalf kernel: dyndbg: class-ref: drm_kms_helper.DRM_UT_DRIVER module:drm_kms_helper nd:93 nc:0 nu:1 [ 29.127701] gandalf kernel: dyndbg: class-ref: drm_display_helper.DRM_UT_DRIVER module:drm_display_helper nd:151 nc:0 nu:1 [ 29.127885] gandalf kernel: dyndbg: class-ref: amdgpu.DRM_UT_DRIVER module:amdgpu nd:4754 nc:0 nu:1 [ 29.152925] gandalf kernel: dyndbg: processed 1 queries, with 1384 matches, 0 errs The resulting journal is ~14.6k lines, written in the 1st 15 (29) seconds of startup. I'm unsure what the 15/29 discrepancy might indicate/betray, besides a lot of logging work. sleep 15 is not the best stopwatch. recent spins thru lkp-test have also been SUCCESS-ful. Jim Cromie (35): old-bugs & cleanups: dyndbg: fix old BUG_ON in >control parser docs/dyndbg: update examples \012 to \n test-dyndbg: fixup CLASSMAP usage error dyndbg: reword "class unknown," to "class:_UNKNOWN_" dyndbg: make ddebug_class_param union members same size dyndbg: replace classmap list with a vector dyndbg: ddebug_apply_class_bitmap - add module arg, select on it dyndbg: split param_set_dyndbg_classes to _module & wrapper fns dyndbg: drop NUM_TYPE_ARRAY dyndbg: reduce verbose/debug clutter dyndbg: silence debugs with no-change updates dyndbg: tighten ddebug_class_name() 1st arg type dyndbg: tighten fn-sig of ddebug_apply_class_bitmap dyndbg: reduce verbose=3 messages in ddebug_add_module dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code core fix & selftests: dyndbg-API: fix DECLARE_DYNDBG_CLASSMAP selftests-dyndbg: add tools/testing/selftests/dynamic_debug/* selftests-dyndbg: exit 127 if no facility dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API dyndbg-doc: add classmap info to howto dyndbg: treat comma as a token separator selftests-dyndbg: add com
[PATCH v7d 23/23] drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN
Lots of burn-in testing needed before signing, upstreaming. NOTE: I set default Y to maximize testing by default. Is there a better way to do this ? Signed-off-by: Jim Cromie --- drivers/gpu/drm/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3caa020391c7..708f5e8cb205 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -55,8 +55,7 @@ config DRM_DEBUG_MM config DRM_USE_DYNAMIC_DEBUG bool "use dynamic debug to implement drm.debug" - default n - depends on BROKEN + default y depends on DRM depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE depends on JUMP_LABEL -- 2.41.0
[PATCH v7d 22/23] drm-drivers: DRM_CLASSMAP_USE in 2nd batch of drivers, helpers
Add a DRM_CLASSMAP_USE declaration to 2nd batch of helpers and *_drv.c files. For drivers, add the decl just above the module's PARAMs, since it identifies the "inherited" drm.debug param. Note: with CONFIG_DRM_USE_DYNAMIC_DEBUG=y, a module not also declaring DRM_CLASSMAP_USE will have its class'd prdbgs stuck in the initial (disabled, but for DEBUG) state. The stuck sites are evident in /proc/dynamic_debug/control as: class:_UNKNOWN_ _id:N# control's last column rather than a proper "enumeration": class:DRM_UT_CORE This set of updates was found by choosing M for all DRM-config items I found (not allmodconfig), building & modprobing them, and grepping "class unknown," control. There may yet be others. Signed-off-by: Jim Cromie --- drivers/gpu/drm/drm_gem_shmem_helper.c | 2 ++ drivers/gpu/drm/gud/gud_drv.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_drv.c | 2 ++ drivers/gpu/drm/qxl/qxl_drv.c | 2 ++ drivers/gpu/drm/radeon/radeon_drv.c| 2 ++ drivers/gpu/drm/udl/udl_main.c | 2 ++ drivers/gpu/drm/vkms/vkms_drv.c| 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.c| 2 ++ 8 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index e435f986cd13..066d906e3199 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -23,6 +23,8 @@ #include #include +DRM_CLASSMAP_USE(drm_debug_classes); + MODULE_IMPORT_NS(DMA_BUF); /** diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index 9d7bf8ee45f1..5b555045fce4 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -31,6 +31,8 @@ #include "gud_internal.h" +DRM_CLASSMAP_USE(drm_debug_classes); + /* Only used internally */ static const struct drm_format_info gud_drm_format_r1 = { .format = GUD_DRM_FORMAT_R1, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index abddf37f0ea1..d678eb8e028d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -24,6 +24,8 @@ static int mgag200_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, mgag200_modeset, int, 0400); +DRM_CLASSMAP_USE(drm_debug_classes); + int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2) { struct device *dev = >dev; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index b30ede1cf62d..91942ffcc2b4 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -65,6 +65,8 @@ module_param_named(modeset, qxl_modeset, int, 0400); MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)"); module_param_named(num_heads, qxl_num_crtc, int, 0400); +DRM_CLASSMAP_USE(drm_debug_classes); + static struct drm_driver qxl_driver; static struct pci_driver qxl_pci_driver; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index fa531493b111..ab29945af657 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -247,6 +247,8 @@ int radeon_cik_support = 1; MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled (default), 0 = disabled)"); module_param_named(cik_support, radeon_cik_support, int, 0444); +DRM_CLASSMAP_USE(drm_debug_classes); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 3ebe2ce55dfd..ba57c14454e5 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -19,6 +19,8 @@ #define NR_USB_REQUEST_CHANNEL 0x12 +DRM_CLASSMAP_USE(drm_debug_classes); + #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE) #define WRITES_IN_FLIGHT (20) #define MAX_VENDOR_DESCRIPTOR_SIZE 256 diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index dd0af086e7fa..086797c4b82b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -39,6 +39,8 @@ static struct vkms_config *default_config; +DRM_CLASSMAP_USE(drm_debug_classes); + static bool enable_cursor = true; module_param_named(enable_cursor, enable_cursor, bool, 0444); MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 8b24ecf60e3e..9cb6be422621 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -275,6 +275,8 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, void *ptr); +DRM_CLASSMAP_USE(drm_debug_classes); + MODULE_PARM_DESC(restrict_iommu, "Try to limit IO
[PATCH v7d 21/23] drm: use correct ccflags-y spelling
Incorrectly spelled CFLAGS- failed to add -DDYNAMIC_DEBUG_MODULE, which broke builds with: CONFIG_DRM_USE_DYNAMIC_DEBUG=y CONFIG_DYNAMIC_DEBUG_CORE=y CONFIG_DYNAMIC_DEBUG=n Also add subdir-ccflags so that all drivers pick up the addition. Fixes: 84ec67288c10 ("drm_print: wrap drm_*_dbg in dyndbg descriptor factory macro") Signed-off-by: Jim Cromie --- drivers/gpu/drm/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 215e78e79125..22b1984cc982 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,7 +3,8 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE +ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG)+= -DDYNAMIC_DEBUG_MODULE +subdir-ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE drm-y := \ drm_aperture.o \ -- 2.41.0
[PATCH v7d 19/23] dyndbg: add _DPRINTK_FLAGS_INCL_LOOKUP
dyndbg's dynamic prefixing (by +tmfsl flags) is needlessly expensive. When an enabled (with +p) pr_debug is called, _DPRINTK_FLAGS_INCL_ANY prefix decorations are sprintf'd into stack-mem for every call. This string (or part of it) could be cached once its 1st generated, and retrieved thereafter, as long as its deleted any time the callsite's flags are changed afterwards. So consider the prefix/decoration flags: 'tmfsl', and what should be in the cache: -t thread-id. not part of the "callsite" info, derived from current. doesn't belong in the cache. it would be wrong. can be done in outer: dynamic_emit_prefix() -l line number this could be part of the prefix, but would bloat the cache can also be done in outer: dynamic_emit_prefix() -mfs module, function, source-file we cache these, composed into a sub-string. they are "lookups", currently to descriptor fields, could be accessor macros to "compressed" tables. cache saves more access work. All enabled together, they compose a prefix string like: # outer -inner-- outer "[tid] module:function:sourcfile:line: " So this patch extracts _DPRINTK_FLAGS_INCL_LOOKUP macro out of _DPRINTK_FLAGS_INCL_ANY macro, then redefs latter. Next re-refactor dynamic_emit_prefix inner/outer fns accordingly. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 4ffddf5e9152..b4550f80cfd5 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -40,10 +40,12 @@ struct _ddebug { #define _DPRINTK_FLAGS_INCL_SOURCENAME (1<<5) #define _DPRINTK_FLAGS_PREFIX_CACHED (1<<7) -#define _DPRINTK_FLAGS_INCL_ANY\ - (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\ -_DPRINTK_FLAGS_INCL_LINENO | _DPRINTK_FLAGS_INCL_TID |\ +#define _DPRINTK_FLAGS_INCL_LOOKUP \ + (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME | \ _DPRINTK_FLAGS_INCL_SOURCENAME) +#define _DPRINTK_FLAGS_INCL_ANY \ + (_DPRINTK_FLAGS_INCL_LINENO | _DPRINTK_FLAGS_INCL_TID | \ +_DPRINTK_FLAGS_INCL_LOOKUP) #if defined DEBUG #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT -- 2.41.0
[PATCH v7d 20/23] dyndbg: refactor *dynamic_emit_prefix
Refactor the split of duties between outer & inner fns. The outer fn was previously just an inline unlikely forward to inner, which did all the work. Now, outer handles +t and +l flags itself, and calls inner only when _DPRINTK_FLAGS_INCL_LOOKUP is needed. No functional change. But it does make the results of the inner-fn more cache-friendly (fewer entries, reused more often): 1- no spurious [TID] or noise 2- no LINE-number to bloat the cache (avg 9 pr_debugs/fn) 3- only LOOKUP stuff Currently LOOKUPs are descriptor-field refs but could be replaced by accessor functions. This would allow the __dyndbg_sites section to be de-duplicated and reclaimed; currently module, filename fields are ~90% repeated. As the accessors get more expensive, the value of caching part of the prefix goes up. Also change inner-fn to return count of extra chars written to the buffer, and drop "inline" from outer, let the compiler decide. Maybe also change name accordingly. Signed-off-by: Jim Cromie --- fixup whitespace --- lib/dynamic_debug.c | 39 ++- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index f878a6f09fc8..213110ec1e9c 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -774,11 +774,28 @@ static int remaining(int wrote) return 0; } -static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) +static int __dynamic_emit_prefix(const struct _ddebug *desc, char *buf, int pos) +{ + if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + desc->modname); + if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + desc->function); + if (desc->flags & _DPRINTK_FLAGS_INCL_SOURCENAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + trim_prefix(desc->filename)); + return pos; +} + +static char *dynamic_emit_prefix(struct _ddebug *desc, char *buf) { int pos_after_tid; int pos = 0; + if (likely(!(desc->flags & _DPRINTK_FLAGS_INCL_ANY))) + return buf; + if (desc->flags & _DPRINTK_FLAGS_INCL_TID) { if (in_interrupt()) pos += snprintf(buf + pos, remaining(pos), " "); @@ -787,15 +804,10 @@ static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) task_pid_vnr(current)); } pos_after_tid = pos; - if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - desc->modname); - if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - desc->function); - if (desc->flags & _DPRINTK_FLAGS_INCL_SOURCENAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - trim_prefix(desc->filename)); + + if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_LOOKUP)) + pos += __dynamic_emit_prefix(desc, buf, pos); + if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO) pos += snprintf(buf + pos, remaining(pos), "%d:", desc->lineno); @@ -807,13 +819,6 @@ static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) return buf; } -static inline char *dynamic_emit_prefix(struct _ddebug *desc, char *buf) -{ - if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_ANY)) - return __dynamic_emit_prefix(desc, buf); - return buf; -} - void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...) { va_list args; -- 2.41.0
[PATCH v7d 18/23] dyndbg: reserve flag bit _DPRINTK_FLAGS_PREFIX_CACHED
Reserve bit 7 to remember that a pr-debug callsite is/was: - enabled, with +p - wants a dynamic-prefix, with one+ of module:function:sourcfile - was previously called - was thus saved in the cache. NOT YET. Its unclear whether any cache fetch would be faster than 2-3 field fetches, but theres another factor; the 3 columns in the __dyndbg section are highly redundant and compressible, but to get the compression, we need field accessors, which will rebalance the tradeoff. So, for now, its just the bit reservation. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 2a7832b1ba5b..4ffddf5e9152 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -38,6 +38,7 @@ struct _ddebug { #define _DPRINTK_FLAGS_INCL_LINENO (1<<3) #define _DPRINTK_FLAGS_INCL_TID(1<<4) #define _DPRINTK_FLAGS_INCL_SOURCENAME (1<<5) +#define _DPRINTK_FLAGS_PREFIX_CACHED (1<<7) #define _DPRINTK_FLAGS_INCL_ANY\ (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\ -- 2.41.0
[PATCH v7d 15/23] dyndbg: refactor ddebug_classparam_clamp_input
Extract input validation code, from param_set_dyndbg_module_classes() (the sys-node >handler) to new: ddebug_classparam_clamp_input(kp), call it from former. It takes kernel-param arg, so it can complain about "foo: bad input". Reuse ddparam_clamp_input(kp) in ddebug_sync_classbits(), to validate inputs from parent's params, just like our own. To support that reuse, alter ddebug_sync_classbits() and caller to pass kp instead of kp->arg. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 70 ++--- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 7d3261dede77..f878a6f09fc8 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -653,6 +653,30 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp, #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1) +static void ddebug_class_param_clamp_input(unsigned long *inrep, const struct kernel_param *kp) +{ + const struct ddebug_class_param *dcp = kp->arg; + const struct ddebug_class_map *map = dcp->map; + + switch (map->map_type) { + case DD_CLASS_TYPE_DISJOINT_BITS: + /* expect bits. mask and warn if too many */ + if (*inrep & ~CLASSMAP_BITMASK(map->length)) { + pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n", + KP_NAME(kp), *inrep, CLASSMAP_BITMASK(map->length)); + *inrep &= CLASSMAP_BITMASK(map->length); + } + break; + case DD_CLASS_TYPE_LEVEL_NUM: + /* input is bitpos, of highest verbosity to be enabled */ + if (*inrep > map->length) { + pr_warn("%s: level:%ld exceeds max:%d, clamping\n", + KP_NAME(kp), *inrep, map->length); + *inrep = map->length; + } + break; + } +} static int param_set_dyndbg_module_classes(const char *instr, const struct kernel_param *kp, const char *modnm) @@ -671,26 +695,15 @@ static int param_set_dyndbg_module_classes(const char *instr, pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp)); return -EINVAL; } + ddebug_class_param_clamp_input(, kp); switch (map->map_type) { case DD_CLASS_TYPE_DISJOINT_BITS: - /* expect bits. mask and warn if too many */ - if (inrep & ~CLASSMAP_BITMASK(map->length)) { - pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n", - KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length)); - inrep &= CLASSMAP_BITMASK(map->length); - } v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp)); totct += ddebug_apply_class_bitmap(dcp, , *dcp->bits, modnm); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: - /* input is bitpos, of highest verbosity to be enabled */ - if (inrep > map->length) { - pr_warn("%s: level:%ld exceeds max:%d, clamping\n", - KP_NAME(kp), inrep, map->length); - inrep = map->length; - } 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)); @@ -1157,16 +1170,27 @@ static const char * const ddebug_classmap_typenames[] = { ddebug_classmap_typenames[_cm->map_type]);\ }) -static void ddebug_sync_classbits(const struct ddebug_class_param *dcp, const char *modname) +static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname) { - /* clamp initial bitvec, mask off hi-bits */ - if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) { - *dcp->bits &= CLASSMAP_BITMASK(dcp->map->length); - v2pr_info("preset classbits: %lx\n", *dcp->bits); + struct ddebug_class_param *dcp = kp->arg; + unsigned long new_bits; + + ddebug_class_param_clamp_input(dcp->bits, kp); + + switch (dcp->map->map_type) { + case DD_CLASS_TYPE_DISJOINT_BITS: + v2pr_info(" %s: classbits: 0x%lx\n", KP_NAME(kp), *dcp->bits); + ddebug_apply_class_bitmap(dcp, dcp->bits, 0UL, modname); + break; + case DD_CLASS_TYPE_LEVEL_
[PATCH v7d 17/23] dyndbg-doc: add classmap info to howto
Add some basic info on classmap usage and api cc: linux-...@vger.kernel.org Signed-off-by: Jim Cromie --- v5- adjustments per Randy Dunlap, me v7b- checkpatch fixes --- .../admin-guide/dynamic-debug-howto.rst | 60 ++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 0b3d39c610d9..028c2cb5b4c5 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -225,7 +225,6 @@ the ``p`` flag has meaning, other flags are ignored. Note the regexp ``^[-+=][fslmpt_]+$`` matches a flags specification. To clear all flags at once, use ``=_`` or ``-fslmpt``. - Debug messages during Boot Process == @@ -375,3 +374,62 @@ just a shortcut for ``print_hex_dump(KERN_DEBUG)``. For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is its ``prefix_str`` argument, if it is constant string; or ``hexdump`` in case ``prefix_str`` is built dynamically. + +Dynamic Debug classmaps +=== + +Dyndbg allows selection/grouping of *prdbg* callsites using structural +info: module, file, function, line. Classmaps allow authors to add +their own domain-oriented groupings using class-names. Classmaps are +exported, so they referencable from other modules. + + # enable classes individually + :#> ddcmd class DRM_UT_CORE +p + :#> ddcmd class DRM_UT_KMS +p + # or more selectively + :#> ddcmd class DRM_UT_CORE module drm +p + +The "class FOO" syntax protects class'd prdbgs from generic overwrite:: + + # IOW this doesn't wipe any DRM.debug settings + :#> ddcmd -p + +To support the DRM.debug parameter, DYNDBG_CLASSMAP_PARAM* updates all +classes in a classmap, mapping param-bits 0..N onto the classes: +DRM_UT_<*> for the DRM use-case. + +Dynamic Debug Classmap API +== + +DYNDBG_CLASSMAP_DEFINE - modules use this to create classmaps, naming +each of the classes (stringified enum-symbols: "DRM_UT_<*>"), and +type, and mapping the class-names to consecutive _class_ids. + +By doing so, modules tell dyndbg that they are have prdbgs with those +class_ids, and they authorize dyndbg to accept "class FOO" for the +module defining that classname. + +There are 2 types of classmaps: + + DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, like DRM.debug + DD_CLASS_TYPE_LEVEL_NUM: classes are relative, ordered (V3 > V2) + +DYNDBG_CLASSMAP_PARAM - refers to a DEFINEd classmap, exposing the set +of defined classes to manipulation as a group. This interface +enforces the relatedness of classes of DD_CLASS_TYPE_LEVEL_NUM typed +classmaps; all classes are independent in the >control parser itself. + +DYNDBG_CLASSMAP_USE - drm drivers invoke this to ref the CLASSMAP that +drm DEFINEs. This shares the classmap definition, and authorizes +dyndbg to apply changes to the user module's class'd pr_debugs. It +also tells dyndbg how to initialize the user's prdbgs at modprobe, +based upon the current setting of the parent's controlling param. + +Modules or module-groups (drm & drivers) can define multiple +classmaps, as long as they share the limited 0..62 per-module-group +_class_id range, without overlap. + +``#define DEBUG`` will enable all pr_debugs in scope, including any +class'd ones. This won't be reflected in the PARAM readback value, +but the pr_debug callsites can be toggled into agreement with the +param. -- 2.41.0
[PATCH v7d 16/23] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
move the DYNDBG_CLASSMAP_PARAM macro from test-dynamic-debug.c into the header, and refine it, by distinguishing the 2 use cases: 1.DYNDBG_CLASSMAP_PARAM_REF for DRM, to pass in extern __drm_debug by name. dyndbg keeps bits in it, so drm can still use it as before 2.DYNDBG_CLASSMAP_PARAM new user (test_dynamic_debug) doesn't need to share state, decls a static long unsigned int to store the bitvec. __DYNDBG_CLASSMAP_PARAM bottom layer - allocate,init a ddebug-class-param, module-param-cb. Also clean up and improve comments in test-code, and add MODULE_DESCRIPTIONs. Signed-off-by: Jim Cromie --- --- drivers/gpu/drm/drm_print.c | 8 ++ include/drm/drm_print.h | 6 ++-- include/linux/dynamic_debug.h | 37 +++- lib/test_dynamic_debug.c| 50 + lib/test_dynamic_debug_submod.c | 9 +- 5 files changed, 69 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index dabcfa0dd279..8f4b609353a5 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -69,12 +69,8 @@ DRM_CLASSMAP_DEFINE(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, "DRM_UT_DP", "DRM_UT_DRMRES"); -static struct ddebug_class_param drm_debug_bitmap = { - .bits = &__drm_debug, - .flags = "p", - .map = _debug_classes, -}; -module_param_cb(debug, _ops_dyndbg_classes, _debug_bitmap, 0600); +DRM_CLASSMAP_PARAM_REF(debug, __drm_debug, drm_debug_classes, p); + #endif void __drm_puts_coredump(struct drm_printer *p, const char *str) diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 706afc97c79c..94d4f5500030 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -322,11 +322,13 @@ enum drm_debug_category { }; #ifdef CONFIG_DRM_USE_DYNAMIC_DEBUG -#define DRM_CLASSMAP_DEFINE(...) DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__) -#define DRM_CLASSMAP_USE(name) DYNDBG_CLASSMAP_USE(name) +#define DRM_CLASSMAP_DEFINE(...) DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__) +#define DRM_CLASSMAP_USE(name) DYNDBG_CLASSMAP_USE(name) +#define DRM_CLASSMAP_PARAM_REF(...)DYNDBG_CLASSMAP_PARAM_REF(__VA_ARGS__) #else #define DRM_CLASSMAP_DEFINE(...) #define DRM_CLASSMAP_USE(name) +#define DRM_CLASSMAP_PARAM_REF(...) #endif static inline bool drm_debug_enabled_raw(enum drm_debug_category category) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 373d152f4285..2a7832b1ba5b 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -91,7 +91,7 @@ struct ddebug_class_map { * used to validate a "class FOO .." >control command on the module */ #define DYNDBG_CLASSMAP_DEFINE(_var, _maptype, _base, ...) \ - const char *_var##_classnames[] = { __VA_ARGS__ }; \ + static const char *_var##_classnames[] = { __VA_ARGS__ }; \ struct ddebug_class_map __aligned(8) __used \ __section("__dyndbg_classes") _var = { \ .mod = THIS_MODULE, \ @@ -145,6 +145,41 @@ struct ddebug_class_param { const struct ddebug_class_map *map; }; +/** + * DYNDBG_CLASSMAP_PARAM - wrap a dyndbg-classmap with a controlling sys-param + * @_name sysfs node name + * @_var name of the struct classmap var defining the controlled classes + * @_flags flags to be toggled, typically just 'p' + * + * Creates a sysfs-param to control the classes defined by the + * classmap. Keeps bits in a private/static + */ +#define DYNDBG_CLASSMAP_PARAM(_name, _var, _flags) \ + static unsigned long _name##_bvec; \ + __DYNDBG_CLASSMAP_PARAM(_name, _name##_bvec, _var, _flags) + +/** + * DYNDBG_CLASSMAP_PARAM_REF - wrap a dyndbg-classmap with a controlling sys-param + * @_name sysfs node name + * @_bits name of the module's unsigned long bit-vector, ex: __drm_debug + * @_var name of the struct classmap var defining the controlled classes + * @_flags flags to be toggled, typically just 'p' + * + * Creates a sysfs-param to control the classmap, keeping bitvec in user @_bits. + * This lets drm use __drm_debug elsewhere too. + */ +#define DYNDBG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags) \ + __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags) + +#define __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)\ + static struct ddebug_class_param _name##_##_flags = { \ + .bits = &(_bits), \ + .flags = #_flags, \ + .map = &(_var), \ + };
[PATCH v7d 14/23] dyndbg-API: fix CONFIG_DRM_USE_DYNAMIC_DEBUG regression
making it easy to see the pattern of repetition, and the points of change. And extend the test to replicate the 2-module (parent & dependent) scenario which caused the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression seen in drm & drivers. The _submod.c is a 2-line file: #define _SUBMOD, #include parent. This gives identical complements of prdbgs in parent & _submod, and thus identical print behavior when all of: >control, >params, and parent->_submod propagation are working correctly. It also puts all the parent/_submod declarations together in the same source, with the new ifdef _SUBMOD block invoking DYNDBG_CLASSMAP_USE for the 2 test-interfaces. I think this is clearer. These 2 modules are independently configurable, allowing builtin parent and loadable submod, which recapitulates a troublesome build combo for drm & drivers. DEBUG details: ``#define DEBUG`` in src enables all pr_debugs after it, including any class'd pr_debugs; its not necessarily all-or-nothing, unless its a one-file-module with DEBUG at the top. If a CLASSMAP_PARAM is defined on a classmap, its readback value cannot describe the set of enablements. The param is basically write-only; it cannot know if `echo $cmd >control` was done since. To know the exact pr-debug state with certainty, toggle to both: echo 0x3ff > /sys/module/drm/parameters/debug echo 0 > /sys/module/drm/parameters/debug Cc: Daniel Vetter Cc: Jani Nikula Cc: Tvrtko Ursulin Cc: Rob Clark Cc: Sean Paul Cc: Luis Chamberlain Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro") Fixes: f158936b60a7 ("drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.") Ref: commit bb2ff6c27bc9 ("drm: Disable dynamic debug as broken") Signed-off-by: Jim Cromie --- last submission-blocking bug: missing __align(8) in DYNAMIC_DEBUG_DECLARE_METADATA on ddebug_class_user caused corrupt records, but only for builtin modules; module loader code probably pinned allocations to the right alignment naturally, hiding the bug for typical builds. v7e- squash patch 21 into 14 - WARN_ON_ONCE v7d- fix _var expanded 2x in macro, by wrapping with () v6?- fix kconfig description too short --- MAINTAINERS | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 +- drivers/gpu/drm/display/drm_dp_helper.c | 12 +- drivers/gpu/drm/drm_crtc_helper.c | 12 +- drivers/gpu/drm/drm_print.c | 25 ++-- drivers/gpu/drm/i915/i915_params.c | 12 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 12 +- include/asm-generic/vmlinux.lds.h | 1 + include/drm/drm_print.h | 10 +- include/linux/dynamic_debug.h | 53 +-- kernel/module/main.c| 3 + lib/Kconfig.debug | 24 +++- lib/Makefile| 3 + lib/dynamic_debug.c | 183 +--- lib/test_dynamic_debug.c| 111 +- lib/test_dynamic_debug_submod.c | 10 ++ 16 files changed, 344 insertions(+), 141 deletions(-) create mode 100644 lib/test_dynamic_debug_submod.c diff --git a/MAINTAINERS b/MAINTAINERS index dd5de540ec0b..2f8e5a79d982 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7321,7 +7321,7 @@ M:Jim Cromie S: Maintained F: include/linux/dynamic_debug.h F: lib/dynamic_debug.c -F: lib/test_dynamic_debug.c +F: lib/test_dynamic_debug*.c DYNAMIC INTERRUPT MODERATION M: Tal Gilboa diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 81edf66dbea8..efba99c9393e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -197,17 +197,7 @@ int amdgpu_user_partt_mode = AMDGPU_AUTO_COMPUTE_PARTITION_MODE; static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); -DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, - "DRM_UT_CORE", - "DRM_UT_DRIVER", - "DRM_UT_KMS", - "DRM_UT_PRIME", - "DRM_UT_ATOMIC", - "DRM_UT_VBL", - "DRM_UT_STATE", - "DRM_UT_LEASE", - "DRM_UT_DP", - "DRM_UT_DRMRES"); +DRM_CLASSMAP_USE(drm_debug_classes); struct amdgpu_mgpu_info mgpu_info = { .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex), diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index e6a78fd32380..d97de1a27939 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -41,17 +41,7 @@ #include "drm_dp_helper_internal.h" -DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLAS
[PATCH v7d 13/23] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
Remove the NAMED class types; 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 simplify things for now. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 19 ++- lib/dynamic_debug.c | 103 +++--- lib/test_dynamic_debug.c | 26 - 3 files changed, 12 insertions(+), 136 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 8116d0a0d33a..8eaf8eabdc8d 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -61,24 +61,13 @@ struct _ddebug { enum 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 */ }; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 45870a699507..91c8b67fd8f8 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -632,77 +632,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(instr, GFP_KERNEL); - p = strchr(cl_str, '\n'); - if (p) - *p = '\0'; - - /* 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, _bits) == wanted) { - v3pr_info("no change on %s\n", cl_str); - continue; - } - curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, *dcp->bits, NULL); - *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, _bits, old_bits, NULL); - *dcp->lvl = (cls_id + (wanted ? 1 : 0)); - v2pr_info("%s: chang
[PATCH v7d 12/23] dyndbg: reduce verbose=3 messages in ddebug_add_module
The fn currently says "add-module", then "skipping" if the module has no prdbgs. Just check 1st and return quietly. no functional change Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 8beb98a831f5..45870a699507 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1242,11 +1242,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(sizeof(*dt), GFP_KERNEL); if (dt == NULL) { -- 2.41.0
[PATCH v7d 09/23] dyndbg: silence debugs with no-change updates
check for actual changes before announcing them, declutter logs. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index b0e11f6bfaa2..b07aab422604 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -591,7 +591,7 @@ 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, const char *query_modname) @@ -602,8 +602,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp, int matches = 0; int bi, ct; - v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, - query_modname ?: ""); + 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)) @@ -618,8 +619,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); } - v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, - query_modname ?: ""); + 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; } -- 2.41.0
[PATCH v7d 11/23] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
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 --- lib/dynamic_debug.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 8158943b350d..8beb98a831f5 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -593,7 +593,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 @@ -602,12 +603,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, _bits)) continue; snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi], @@ -619,9 +620,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; } @@ -678,7 +679,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa continue; } curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, *dcp->bits, NULL); *dcp->bits = curr_bits; v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id, map->class_names[cls_id]); @@ -688,7 +689,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa old_bits = CLASSMAP_BITMASK(*dcp->lvl); curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 )); - totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, old_bits, NULL); *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); @@ -742,7 +743,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, modnm ?: "*", KP_NAME(kp)); - totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, modnm); + totct += ddebug_apply_class_bitmap(dcp, , *dcp->bits, modnm); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -755,7 +756,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, _bits, _bits, modnm); + totct += ddebug_apply_class_bitmap(dcp, _bits, old_bits, modnm); *dcp->lvl = inrep; break; default: -- 2.41.0
[PATCH v7d 10/23] dyndbg: tighten ddebug_class_name() 1st arg type
Change function's 1st arg-type, and deref in the caller. The fn doesn't need any other fields in the struct. no functional change. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index b07aab422604..8158943b350d 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1117,12 +1117,12 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos) #define class_in_range(class_id, map) \ (class_id >= map->base && class_id < map->base + map->length) -static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp) +static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp) { - struct ddebug_class_map *map = iter->table->classes; - int i, nc = iter->table->num_classes; + struct ddebug_class_map *map = dt->classes; + int i; - for (i = 0; i < nc; i++, map++) + for (i = 0; i < dt->num_classes; i++, map++) if (class_in_range(dp->class_id, map)) return map->class_names[dp->class_id - map->base]; @@ -1156,7 +1156,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p) seq_puts(m, "\""); if (dp->class_id != _DPRINTK_CLASS_DFLT) { - class = ddebug_class_name(iter, dp); + class = ddebug_class_name(iter->table, dp); if (class) seq_printf(m, " class:%s", class); else -- 2.41.0
[PATCH v7d 08/23] dyndbg: reduce verbose/debug clutter
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=0x 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 is like 1st, with result, not procedure. 2nd is just status, retold in 4th, with more info. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 14 +++--- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index b67c9b137447..b0e11f6bfaa2 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -266,9 +266,6 @@ static int ddebug_change(const struct ddebug_query *query, } mutex_unlock(_lock); - if (!nfound && verbose) - pr_info("no matches for query\n"); - return nfound; } @@ -497,7 +494,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--) { @@ -511,7 +507,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) { @@ -527,7 +522,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; } @@ -537,7 +532,7 @@ static int ddebug_exec_query(char *query_string, const char *modname) struct flag_settings modifiers = {}; struct ddebug_query query = {}; #define MAXWORDS 9 - int nwords, nfound; + int nwords; char *words[MAXWORDS]; nwords = ddebug_tokenize(query_string, words, MAXWORDS); @@ -555,10 +550,7 @@ static int ddebug_exec_query(char *query_string, const char *modname) return -EINVAL; } /* actually go and implement the change */ - nfound = ddebug_change(, ); - vpr_info_dq(, nfound ? "applied" : "no-match"); - - return nfound; + return ddebug_change(, ); } /* handle multiple queries in query string, continue on error, return -- 2.41.0
[PATCH v7d 07/23] dyndbg: drop NUM_TYPE_ARRAY
ARRAY_SIZE works here, since array decl is complete. no functional change Signed-off-by: Jim Cromie --- 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 b53217e4b711..8116d0a0d33a 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -106,11 +106,9 @@ struct ddebug_class_map { .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)) /* encapsulate linker provided built-in (or module) dyndbg data */ struct _ddebug_info { -- 2.41.0
[PATCH v7d 06/23] dyndbg: split param_set_dyndbg_classes to module/wrapper fns
rename param_set_dyndbg_classes: add _module_ name & arg, old name is wrapper to new. New arg allows caller to specify that only one module is affected by a prdbgs update. Outer fn preserves kernel_param interface, passing NULL to inner fn. This selectivity will be used later to narrow the scope of changes made. no functional change. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 37 ++--- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index ba41fdeaaf98..b67c9b137447 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -708,18 +708,9 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa return 0; } -/** - * 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 - * - * Enable/disable prdbgs by their class, as given in the arguments to - * DECLARE_DYNDBG_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) +static int param_set_dyndbg_module_classes(const char *instr, + const struct kernel_param *kp, + const char *modnm) { const struct ddebug_class_param *dcp = kp->arg; const struct ddebug_class_map *map = dcp->map; @@ -756,8 +747,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, , dcp->bits, NULL); + v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp)); + totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, modnm); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -770,7 +761,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, _bits, _bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, modnm); *dcp->lvl = inrep; break; default: @@ -779,6 +770,22 @@ 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 - class FOO >control + * @instr: string echo>d to sysfs, input depends on map_type + * @kp:kp->arg has state: bits/lvl, map, map_type + * + * Enable/disable prdbgs by their class, as given in the arguments to + * DECLARE_DYNDBG_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); /** -- 2.41.0
[PATCH v7d 05/23] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it
Add query_module param to ddebug_apply_class_bitmap(). This allows its caller to update just one module, or all (as currently). We'll use this later to propagate drm.debug to each USEr as they're modprobed. No functional change. Signed-off-by: Jim Cromie --- after `modprobe i915`, heres the module dependencies, though not all on drm.debug. bash-5.2# lsmod Module Size Used by i915 3133440 0 drm_buddy 20480 1 i915 ttm90112 1 i915 i2c_algo_bit 16384 1 i915 video 61440 1 i915 wmi32768 1 video drm_display_helper200704 1 i915 drm_kms_helper208896 2 drm_display_helper,i915 drm 606208 5 drm_kms_helper,drm_display_helper,drm_buddy,i915,ttm cec57344 2 drm_display_helper,i915 --- lib/dynamic_debug.c | 19 --- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index a3be2e7c8c84..ba41fdeaaf98 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -601,7 +601,8 @@ static int ddebug_exec_queries(char *query, const char *modname) /* apply a new bitmap to the sys-knob's current bit-state */ 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]; @@ -609,7 +610,8 @@ 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); + 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)) @@ -618,12 +620,15 @@ 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); } + v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, + query_modname ?: ""); + return matches; } @@ -679,7 +684,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa continue; } curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits); + totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits, NULL); *dcp->bits = curr_bits; v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id, map->class_names[cls_id]); @@ -689,7 +694,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa old_bits = CLASSMAP_BITMASK(*dcp->lvl); curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 )); - totct += ddebug_apply_class_bitmap(dcp, _bits, _bits); + totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, NULL); *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); @@ -752,7 +757,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp) inrep &= CLASSMAP_BITMASK(map->length); } v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp)); - totct += ddebug_apply_class_bitmap(dcp, , dcp->bits); + totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, NULL); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -765,7 +770,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\
[PATCH v7d 04/23] dyndbg: replace classmap list with a vector
Classmaps are stored/linked in a section/array, but are each added to the module's ddebug_table.maps list-head. This is unnecessary; even when ddebug_attach_classmap() is handling the builtin section (with classmaps for multiple builtin modules), its contents are ordered, so a module's possibly multiple classmaps will be consecutive in the section, and could be treated as a vector/block, since both start-addy and subrange length are in the ddebug_info arg. So this changes: struct ddebug_class_map drops list-head link. struct ddebug_table drops the list-head maps, and gets: classes & num_classes for the start-addy and num_classes, placed to improve struct packing. The loading: in ddebug_attach_module_classes(), replace the for-the-modname list-add loop, with a forloop that finds the module's subrange (start,length) of matching classmaps within the possibly builtin classmaps vector, and saves those to the ddebug_table. The reading/using: change list-foreach loops in ddebug_class_name() & ddebug_find_valid_class() to walk the array from start to length. Also: Move #define __outvar up, above an added use in a fn-prototype. Simplify ddebug_attach_module_classes args, ref has both addy,len. no functional changes Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 1 - lib/dynamic_debug.c | 61 ++- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 5231aaf361c4..b53217e4b711 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -83,7 +83,6 @@ enum 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 b984ce338921..a3be2e7c8c84 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 { @@ -147,13 +148,15 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg) query->first_lineno, query->last_lineno, query->class_string); } +#define __outvar /* filled by callee */ 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, + __outvar int *class_id) { struct ddebug_class_map *map; - int idx; + int i, idx; - list_for_each_entry(map, >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; @@ -164,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 @@ -,9 +1113,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, >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]; @@ -1197,30 +1200,31 @@ 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 c
[PATCH v7d 02/23] dyndbg: reword "class unknown, " to "class:_UNKNOWN_"
This appears in the control-file to report an unknown class-name, which indicates that the class_id is not authorized, and dyndbg will ignore changes to it. Generally, this means that a DYNDBG_CLASSMAP_DEFINE or DYNDBG_CLASSMAP_USE is missing. But the word "unknown" appears in quite a few prdbg formats, so thats a suboptimal search term to find occurrences of the problem. Thus change it to "_UNKNOWN_" which properly shouts the condition. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 6fba6423cc10..ceb3067a5c83 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1151,7 +1151,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_puts(m, "\n"); -- 2.41.0
[PATCH v7d 03/23] dyndbg: make ddebug_class_param union members same size
struct ddebug_class_param keeps a ref to the state-storage of the param, make both flavors use the same unsigned long under-type. ISTM this is simpler and safer. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 2 +- lib/dynamic_debug.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 4fcbf4d4fd0a..5231aaf361c4 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -124,7 +124,7 @@ struct _ddebug_info { struct ddebug_class_param { union { unsigned long *bits; - unsigned int *lvl; + unsigned long *lvl; }; char flags[8]; const struct ddebug_class_map *map; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index ceb3067a5c83..b984ce338921 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -796,7 +796,7 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp) case DD_CLASS_TYPE_LEVEL_NAMES: case DD_CLASS_TYPE_LEVEL_NUM: - return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl); + return scnprintf(buffer, PAGE_SIZE, "%ld\n", *dcp->lvl); default: return -1; } -- 2.41.0
[PATCH v7d 01/23] test-dyndbg: fixup CLASSMAP usage error
more careful reading of test output reveals: lib/test_dynamic_debug.c:103 [test_dynamic_debug]do_cats =pmf "doing categories\n" lib/test_dynamic_debug.c:105 [test_dynamic_debug]do_cats =p "LOW msg\n" class:MID lib/test_dynamic_debug.c:106 [test_dynamic_debug]do_cats =p "MID msg\n" class:HI lib/test_dynamic_debug.c:107 [test_dynamic_debug]do_cats =_ "HI msg\n" class unknown, _id:13 That last line is wrong, the HI class is declared. But the enum's 1st val (explicitly initialized) was wrong; it must be _base, not _base+1 (a DECLARE_DYNDBG_CLASSMAP[1] param). So the last enumeration exceeded the range of mapped class-id's, which triggered the "class unknown" report. I intentionally coded in an error, but forgot to verify its detection and remove it. RFC: This patch fixes a bad usage of DECLARE_DYNDBG_CLASSMAP(), showing that it is too error-prone. As noted in test-mod comments: * Using the CLASSMAP api: * - classmaps must have corresponding enum * - enum symbols must match/correlate with class-name strings in the map. * - base must equal enum's 1st value * - multiple maps must set their base to share the 0-62 class_id space !! * (build-bug-on tips welcome) Those shortcomings could largely be fixed with a __stringify_list (which doesn't exist,) used in DECLARE_DYNDBG_CLASSMAP to stringify __VA_ARGS__. Then, API would accept DRM_UT_* values literally; all the categories, in order, and not their stringifications, which created all the usage complications above. [1] name changes later to DYNDBG_CLASSMAP_DEFINE Signed-off-by: Jim Cromie --- lib/test_dynamic_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c index 8dd250ad022b..a01f0193a419 100644 --- a/lib/test_dynamic_debug.c +++ b/lib/test_dynamic_debug.c @@ -75,7 +75,7 @@ DD_SYS_WRAP(disjoint_bits, p); DD_SYS_WRAP(disjoint_bits, T); /* symbolic input, independent bits */ -enum cat_disjoint_names { LOW = 11, MID, HI }; +enum cat_disjoint_names { LOW = 10, MID, HI }; DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10, "LOW", "MID", "HI"); DD_SYS_WRAP(disjoint_names, p); -- 2.41.0
[PATCH v7d 00/23] fix DRM_USE_DYNAMIC_DEBUG=y regression
hi Jason, DRM-folk (v7d - refreshed onto v6.6, patch-21 squashed into 14) This patchest fixes the chicken-egg initialization problem in the 1st version of ddebug-class-maps, that DRM-CI uncovered. The root-problem was DECLARE_DYNDBG_CLASSMAP, which broke the K rule: "define once, refer many". In patch 14 it is replaced by: DYNDBG_CLASSMAP_DEFINE - define and export a struct ddebug_class_map DYNDBG_CLASSMAP_USE - ref the exported struct test-dynamic-debug is also extended with a -submod.ko, in order to recapitulate the drm & drivers initialization scenario. The final blocking bug was a missing __align(8) on the ddebug_class_user record inserted by DYNDBG_CLASSMAP_USE. This caused DRM=y (builtin only) to have a corrupt record for drm_kms_helper (a builtin dependent). Curiously, a clang build did not exhibit this problem. Heres a part of dmesg, for a DRM=y kernel, booted with dynamic_debug.verbose=3 drm.debug=0x10 [0.466747] dyndbg: add-module: drm 406 sites [0.467569] dyndbg: classes[0]: module:drm base:0 len:10 type:DISJOINT_BITS [0.467743] dyndbg: module:drm attached 1 classes [0.468557] dyndbg: builtin class: module:drm base:0 len:10 type:DISJOINT_BITS [0.468742] dyndbg: found kp:drm.debug =0x10 [0.468743] dyndbg: mapped to: module:drm base:0 len:10 type:DISJOINT_BITS [0.469742] dyndbg: drm.debug: classbits: 0x10 [0.470573] dyndbg: apply bitmap: 0x10 to: 0x0 for drm [0.470743] dyndbg: query 0: "class DRM_UT_ATOMIC +p" mod:drm [0.471743] dyndbg: split into words: "class" "DRM_UT_ATOMIC" "+p" [0.472743] dyndbg: op='+' flags=0x1 maskp=0x [0.473679] dyndbg: parsed: func="" file="" module="drm" format="" lineno=0-0 class=DRM_UT_ATOMIC [0.473749] dyndbg: processed 1 queries, with 0 matches, 0 errs [0.474742] dyndbg: bit_4: 0 matches on class: DRM_UT_ATOMIC -> 0x10 [0.475742] dyndbg: applied bitmap: 0x10 to: 0x0 for drm [0.476686] dyndbg: 406 debug prints in module drm [0.476743] dyndbg: add-module: drm_kms_helper 93 sites [0.477727] dyndbg: class_ref[0] drm_kms_helper -> drm module:drm base:0 len:10 type:DISJOINT_BITS [0.477743] dyndbg: builtin class: module:drm base:0 len:10 type:DISJOINT_BITS [0.478742] dyndbg: found kp:drm.debug =0x10 [0.478743] dyndbg: mapped to: module:drm base:0 len:10 type:DISJOINT_BITS [0.479743] dyndbg: drm.debug: classbits: 0x10 [0.480592] dyndbg: apply bitmap: 0x10 to: 0x0 for drm_kms_helper [0.480743] dyndbg: query 0: "class DRM_UT_ATOMIC +p" mod:drm_kms_helper [0.481743] dyndbg: split into words: "class" "DRM_UT_ATOMIC" "+p" [0.482743] dyndbg: op='+' flags=0x1 maskp=0x [0.483743] dyndbg: parsed: func="" file="" module="drm_kms_helper" format="" lineno=0-0 class=DRM_UT_ATOMIC [0.484750] dyndbg: class-ref: drm_kms_helper.DRM_UT_ATOMIC module:drm_kms_helper nd:93 nc:0 nu:1 [0.485809] dyndbg: processed 1 queries, with 44 matches, 0 errs [0.486742] dyndbg: bit_4: 44 matches on class: DRM_UT_ATOMIC -> 0x10 [0.487742] dyndbg: applied bitmap: 0x10 to: 0x0 for drm_kms_helper [0.488743] dyndbg: attach-client-module: module:drm_kms_helper nd:93 nc:0 nu:1 [0.489742] dyndbg: 93 debug prints in module drm_kms_helper Id like to get this into linux-next, so widespread testing is appreciated. lkp-robot reported BUILD SUCCESS on it, Im running it on my amdgpu desktop. I have scripts to operate the test-module if anyone wants them. Patches are also at https://github.com/jimc/linux/tree/dd-fix-7d Jim Cromie (23): test-dyndbg: fixup CLASSMAP usage error dyndbg: reword "class unknown," to "class:_UNKNOWN_" dyndbg: make ddebug_class_param union members same size dyndbg: replace classmap list with a vector dyndbg: ddebug_apply_class_bitmap - add module arg, select on it dyndbg: split param_set_dyndbg_classes to module/wrapper fns dyndbg: drop NUM_TYPE_ARRAY dyndbg: reduce verbose/debug clutter dyndbg: silence debugs with no-change updates dyndbg: tighten ddebug_class_name() 1st arg type dyndbg: tighten fn-sig of ddebug_apply_class_bitmap dyndbg: reduce verbose=3 messages in ddebug_add_module dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code dyndbg-API: fix CONFIG_DRM_USE_DYNAMIC_DEBUG regression dyndbg: refactor ddebug_classparam_clamp_input dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API dyndbg-doc: add classmap info to howto dyndbg: reserve flag bit _DPRINTK_FLAGS_PREFIX_CACHED dyndbg: add _DPRINTK_FLAGS_INCL_LOOKUP dyndbg: refactor *dynamic_emit_prefix drm: use correct ccflags-y spelling drm-drivers: DRM_CLASSMAP_USE in 2nd batch of drivers, helpers drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN .../admin-guide/dynamic-debug-howto.rst |
[PATCH v7c 23/24] drm-drivers: DRM_CLASSMAP_USE in 2nd batch of drivers, helpers
Add a DRM_CLASSMAP_USE declaration to 2nd batch of helpers and *_drv.c files. For drivers, add the decl just above the module's PARAMs, since it identifies the "inherited" drm.debug param. Note: with CONFIG_DRM_USE_DYNAMIC_DEBUG=y, a module not also declaring DRM_CLASSMAP_USE will have its class'd prdbgs stuck in the initial (disabled, but for DEBUG) state. The stuck sites are evident in /proc/dynamic_debug/control as: class:_UNKNOWN_ _id:N# control's last column rather than a proper "enumeration": class:DRM_UT_CORE This set of updates was found by choosing M for all DRM-config items I found (not allmodconfig), building & modprobing them, and grepping "class unknown," control. There may yet be others. Signed-off-by: Jim Cromie --- drivers/gpu/drm/drm_gem_shmem_helper.c | 2 ++ drivers/gpu/drm/gud/gud_drv.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_drv.c | 2 ++ drivers/gpu/drm/qxl/qxl_drv.c | 2 ++ drivers/gpu/drm/radeon/radeon_drv.c| 2 ++ drivers/gpu/drm/udl/udl_main.c | 2 ++ drivers/gpu/drm/vkms/vkms_drv.c| 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.c| 2 ++ 8 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index e435f986cd13..066d906e3199 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -23,6 +23,8 @@ #include #include +DRM_CLASSMAP_USE(drm_debug_classes); + MODULE_IMPORT_NS(DMA_BUF); /** diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index 9d7bf8ee45f1..5b555045fce4 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -31,6 +31,8 @@ #include "gud_internal.h" +DRM_CLASSMAP_USE(drm_debug_classes); + /* Only used internally */ static const struct drm_format_info gud_drm_format_r1 = { .format = GUD_DRM_FORMAT_R1, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index abddf37f0ea1..d678eb8e028d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -24,6 +24,8 @@ static int mgag200_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, mgag200_modeset, int, 0400); +DRM_CLASSMAP_USE(drm_debug_classes); + int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2) { struct device *dev = >dev; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index b30ede1cf62d..91942ffcc2b4 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -65,6 +65,8 @@ module_param_named(modeset, qxl_modeset, int, 0400); MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)"); module_param_named(num_heads, qxl_num_crtc, int, 0400); +DRM_CLASSMAP_USE(drm_debug_classes); + static struct drm_driver qxl_driver; static struct pci_driver qxl_pci_driver; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index fa531493b111..ab29945af657 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -247,6 +247,8 @@ int radeon_cik_support = 1; MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled (default), 0 = disabled)"); module_param_named(cik_support, radeon_cik_support, int, 0444); +DRM_CLASSMAP_USE(drm_debug_classes); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 3ebe2ce55dfd..ba57c14454e5 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -19,6 +19,8 @@ #define NR_USB_REQUEST_CHANNEL 0x12 +DRM_CLASSMAP_USE(drm_debug_classes); + #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE) #define WRITES_IN_FLIGHT (20) #define MAX_VENDOR_DESCRIPTOR_SIZE 256 diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index dd0af086e7fa..086797c4b82b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -39,6 +39,8 @@ static struct vkms_config *default_config; +DRM_CLASSMAP_USE(drm_debug_classes); + static bool enable_cursor = true; module_param_named(enable_cursor, enable_cursor, bool, 0444); MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 8b24ecf60e3e..9cb6be422621 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -275,6 +275,8 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, void *ptr); +DRM_CLASSMAP_USE(drm_debug_classes); + MODULE_PARM_DESC(restrict_iommu, "Try to limit IO
[PATCH v7c 24/24] drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN
Lots of burn-in testing needed before signing, upstreaming. NOTE: I set default Y to maximize testing by default. Is there a better way to do this ? Signed-off-by: Jim Cromie --- drivers/gpu/drm/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3caa020391c7..708f5e8cb205 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -55,8 +55,7 @@ config DRM_DEBUG_MM config DRM_USE_DYNAMIC_DEBUG bool "use dynamic debug to implement drm.debug" - default n - depends on BROKEN + default y depends on DRM depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE depends on JUMP_LABEL -- 2.41.0
[PATCH v7c 20/24] dyndbg: refactor *dynamic_emit_prefix
Refactor the split of duties between outer & inner fns. The outer fn was previously just an inline unlikely forward to inner, which did all the work. Now, outer handles +t and +l flags itself, and calls inner only when _DPRINTK_FLAGS_INCL_LOOKUP is needed. No functional change. But it does make the results of the inner-fn more cache-friendly (fewer entries, reused more often): 1- no spurious [TID] or noise 2- no LINE-number to bloat the cache (avg 9 pr_debugs/fn) 3- only LOOKUP stuff Currently LOOKUPs are descriptor-field refs but could be replaced by accessor functions. This would allow the __dyndbg_sites section to be de-duplicated and reclaimed; currently module, filename fields are ~90% repeated. As the accessors get more expensive, the value of caching part of the prefix goes up. Also change inner-fn to return count of extra chars written to the buffer, and drop "inline" from outer, let the compiler decide. Maybe also change name accordingly. Signed-off-by: Jim Cromie --- fixup whitespace --- lib/dynamic_debug.c | 39 ++- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index a6ee142668bf..9db797a0cf82 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -774,11 +774,28 @@ static int remaining(int wrote) return 0; } -static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) +static int __dynamic_emit_prefix(const struct _ddebug *desc, char *buf, int pos) +{ + if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + desc->modname); + if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + desc->function); + if (desc->flags & _DPRINTK_FLAGS_INCL_SOURCENAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + trim_prefix(desc->filename)); + return pos; +} + +static char *dynamic_emit_prefix(struct _ddebug *desc, char *buf) { int pos_after_tid; int pos = 0; + if (likely(!(desc->flags & _DPRINTK_FLAGS_INCL_ANY))) + return buf; + if (desc->flags & _DPRINTK_FLAGS_INCL_TID) { if (in_interrupt()) pos += snprintf(buf + pos, remaining(pos), " "); @@ -787,15 +804,10 @@ static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) task_pid_vnr(current)); } pos_after_tid = pos; - if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - desc->modname); - if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - desc->function); - if (desc->flags & _DPRINTK_FLAGS_INCL_SOURCENAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - trim_prefix(desc->filename)); + + if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_LOOKUP)) + pos += __dynamic_emit_prefix(desc, buf, pos); + if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO) pos += snprintf(buf + pos, remaining(pos), "%d:", desc->lineno); @@ -807,13 +819,6 @@ static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) return buf; } -static inline char *dynamic_emit_prefix(struct _ddebug *desc, char *buf) -{ - if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_ANY)) - return __dynamic_emit_prefix(desc, buf); - return buf; -} - void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...) { va_list args; -- 2.41.0
[PATCH v7c 18/24] dyndbg: reserve flag bit _DPRINTK_FLAGS_PREFIX_CACHED
Reserve bit 7 to remember that a pr-debug callsite is/was: - enabled, with +p - wants a dynamic-prefix, with one+ of module:function:sourcfile - was previously called - was thus saved in the cache. NOT YET. Its unclear whether any cache fetch would be faster than 2-3 field fetches, but theres another factor; the 3 columns in the __dyndbg section are highly redundant and compressible, but to get the compression, we need field accessors, which will rebalance the tradeoff. So, for now, its just the bit reservation. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index f182f95caabb..927cb14f24e0 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -38,6 +38,7 @@ struct _ddebug { #define _DPRINTK_FLAGS_INCL_LINENO (1<<3) #define _DPRINTK_FLAGS_INCL_TID(1<<4) #define _DPRINTK_FLAGS_INCL_SOURCENAME (1<<5) +#define _DPRINTK_FLAGS_PREFIX_CACHED (1<<7) #define _DPRINTK_FLAGS_INCL_ANY\ (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\ -- 2.41.0
[PATCH v7c 22/24] drm: use correct ccflags-y spelling
Incorrectly spelled CFLAGS- failed to add -DDYNAMIC_DEBUG_MODULE, which broke builds with: CONFIG_DRM_USE_DYNAMIC_DEBUG=y CONFIG_DYNAMIC_DEBUG_CORE=y CONFIG_DYNAMIC_DEBUG=n Also add subdir-ccflags so that all drivers pick up the addition. Fixes: 84ec67288c10 ("drm_print: wrap drm_*_dbg in dyndbg descriptor factory macro") Signed-off-by: Jim Cromie --- drivers/gpu/drm/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 215e78e79125..22b1984cc982 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,7 +3,8 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE +ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG)+= -DDYNAMIC_DEBUG_MODULE +subdir-ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE drm-y := \ drm_aperture.o \ -- 2.41.0
[PATCH v7c 21/24] dyndbg: change WARN_ON to WARN_ON_ONCE
This shouldn't ever happen, and 1st 2 conditions never have. The 3rd condition did happen, due to corrupt linkage due to a missing align(8) in DYNDBG_CLASSMAP_USE, on the static struct allocation into the __dyndbg_class_users section. Not sure whether changing to _ONCE is appropriate - this is a module-load activity, so it won't continuously spam syslog. Signed-off-by: Jim Cromie --- undo BUG_ON addition --- 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 9db797a0cf82..213110ec1e9c 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1281,7 +1281,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt, */ for (i = 0, cli = di->class_users; i < di->num_class_users; i++, cli++) { - if (WARN_ON(!cli || !cli->map || !cli->user_mod_name)) + if (WARN_ON_ONCE(!cli || !cli->map || !cli->user_mod_name)) continue; if (!strcmp(cli->user_mod_name, dt->mod_name)) { -- 2.41.0
[PATCH v7c 13/24] dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code
Remove the NAMED class types; 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 simplify things for now. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 19 ++- lib/dynamic_debug.c | 103 +++--- lib/test_dynamic_debug.c | 26 - 3 files changed, 12 insertions(+), 136 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 8116d0a0d33a..8eaf8eabdc8d 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -61,24 +61,13 @@ struct _ddebug { enum 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 */ }; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 45870a699507..91c8b67fd8f8 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -632,77 +632,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(instr, GFP_KERNEL); - p = strchr(cl_str, '\n'); - if (p) - *p = '\0'; - - /* 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, _bits) == wanted) { - v3pr_info("no change on %s\n", cl_str); - continue; - } - curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, *dcp->bits, NULL); - *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, _bits, old_bits, NULL); - *dcp->lvl = (cls_id + (wanted ? 1 : 0)); - v2pr_info("%s: chang
[PATCH v7c 19/24] dyndbg: add _DPRINTK_FLAGS_INCL_LOOKUP
dyndbg's dynamic prefixing (by +tmfsl flags) is needlessly expensive. When an enabled (with +p) pr_debug is called, _DPRINTK_FLAGS_INCL_ANY prefix decorations are sprintf'd into stack-mem for every call. This string (or part of it) could be cached once its 1st generated, and retrieved thereafter, as long as its deleted any time the callsite's flags are changed afterwards. So consider the prefix/decoration flags: 'tmfsl', and what should be in the cache: -t thread-id. not part of the "callsite" info, derived from current. doesn't belong in the cache. it would be wrong. can be done in outer: dynamic_emit_prefix() -l line number this could be part of the prefix, but would bloat the cache can also be done in outer: dynamic_emit_prefix() -mfs module, function, source-file we cache these, composed into a sub-string. they are "lookups", currently to descriptor fields, could be accessor macros to "compressed" tables. cache saves more access work. All enabled together, they compose a prefix string like: # outer -inner-- outer "[tid] module:function:sourcfile:line: " So this patch extracts _DPRINTK_FLAGS_INCL_LOOKUP macro out of _DPRINTK_FLAGS_INCL_ANY macro, then redefs latter. Next re-refactor dynamic_emit_prefix inner/outer fns accordingly. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 927cb14f24e0..2237d454bc19 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -40,10 +40,12 @@ struct _ddebug { #define _DPRINTK_FLAGS_INCL_SOURCENAME (1<<5) #define _DPRINTK_FLAGS_PREFIX_CACHED (1<<7) -#define _DPRINTK_FLAGS_INCL_ANY\ - (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\ -_DPRINTK_FLAGS_INCL_LINENO | _DPRINTK_FLAGS_INCL_TID |\ +#define _DPRINTK_FLAGS_INCL_LOOKUP \ + (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME | \ _DPRINTK_FLAGS_INCL_SOURCENAME) +#define _DPRINTK_FLAGS_INCL_ANY \ + (_DPRINTK_FLAGS_INCL_LINENO | _DPRINTK_FLAGS_INCL_TID | \ +_DPRINTK_FLAGS_INCL_LOOKUP) #if defined DEBUG #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT -- 2.41.0
[PATCH v7c 17/24] dyndbg-doc: add classmap info to howto
Add some basic info on classmap usage and api cc: linux-...@vger.kernel.org Signed-off-by: Jim Cromie --- v5- adjustments per Randy Dunlap, me v7b- checkpatch fixes --- .../admin-guide/dynamic-debug-howto.rst | 60 ++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 0b3d39c610d9..028c2cb5b4c5 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -225,7 +225,6 @@ the ``p`` flag has meaning, other flags are ignored. Note the regexp ``^[-+=][fslmpt_]+$`` matches a flags specification. To clear all flags at once, use ``=_`` or ``-fslmpt``. - Debug messages during Boot Process == @@ -375,3 +374,62 @@ just a shortcut for ``print_hex_dump(KERN_DEBUG)``. For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is its ``prefix_str`` argument, if it is constant string; or ``hexdump`` in case ``prefix_str`` is built dynamically. + +Dynamic Debug classmaps +=== + +Dyndbg allows selection/grouping of *prdbg* callsites using structural +info: module, file, function, line. Classmaps allow authors to add +their own domain-oriented groupings using class-names. Classmaps are +exported, so they referencable from other modules. + + # enable classes individually + :#> ddcmd class DRM_UT_CORE +p + :#> ddcmd class DRM_UT_KMS +p + # or more selectively + :#> ddcmd class DRM_UT_CORE module drm +p + +The "class FOO" syntax protects class'd prdbgs from generic overwrite:: + + # IOW this doesn't wipe any DRM.debug settings + :#> ddcmd -p + +To support the DRM.debug parameter, DYNDBG_CLASSMAP_PARAM* updates all +classes in a classmap, mapping param-bits 0..N onto the classes: +DRM_UT_<*> for the DRM use-case. + +Dynamic Debug Classmap API +== + +DYNDBG_CLASSMAP_DEFINE - modules use this to create classmaps, naming +each of the classes (stringified enum-symbols: "DRM_UT_<*>"), and +type, and mapping the class-names to consecutive _class_ids. + +By doing so, modules tell dyndbg that they are have prdbgs with those +class_ids, and they authorize dyndbg to accept "class FOO" for the +module defining that classname. + +There are 2 types of classmaps: + + DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, like DRM.debug + DD_CLASS_TYPE_LEVEL_NUM: classes are relative, ordered (V3 > V2) + +DYNDBG_CLASSMAP_PARAM - refers to a DEFINEd classmap, exposing the set +of defined classes to manipulation as a group. This interface +enforces the relatedness of classes of DD_CLASS_TYPE_LEVEL_NUM typed +classmaps; all classes are independent in the >control parser itself. + +DYNDBG_CLASSMAP_USE - drm drivers invoke this to ref the CLASSMAP that +drm DEFINEs. This shares the classmap definition, and authorizes +dyndbg to apply changes to the user module's class'd pr_debugs. It +also tells dyndbg how to initialize the user's prdbgs at modprobe, +based upon the current setting of the parent's controlling param. + +Modules or module-groups (drm & drivers) can define multiple +classmaps, as long as they share the limited 0..62 per-module-group +_class_id range, without overlap. + +``#define DEBUG`` will enable all pr_debugs in scope, including any +class'd ones. This won't be reflected in the PARAM readback value, +but the pr_debug callsites can be toggled into agreement with the +param. -- 2.41.0
[PATCH v7c 09/24] dyndbg: silence debugs with no-change updates
check for actual changes before announcing them, declutter logs. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index b0e11f6bfaa2..b07aab422604 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -591,7 +591,7 @@ 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, const char *query_modname) @@ -602,8 +602,9 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp, int matches = 0; int bi, ct; - v2pr_info("apply bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, - query_modname ?: ""); + 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)) @@ -618,8 +619,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); } - v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, - query_modname ?: ""); + 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; } -- 2.41.0
[PATCH v7c 16/24] dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API
move the DYNDBG_CLASSMAP_PARAM macro from test-dynamic-debug.c into the header, and refine it, by distinguishing the 2 use cases: 1.DYNDBG_CLASSMAP_PARAM_REF for DRM, to pass in extern __drm_debug by name. dyndbg keeps bits in it, so drm can still use it as before 2.DYNDBG_CLASSMAP_PARAM new user (test_dynamic_debug) doesn't need to share state, decls a static long unsigned int to store the bitvec. __DYNDBG_CLASSMAP_PARAM bottom layer - allocate,init a ddebug-class-param, module-param-cb. Also clean up and improve comments in test-code, and add MODULE_DESCRIPTIONs. Signed-off-by: Jim Cromie --- --- drivers/gpu/drm/drm_print.c | 8 ++ include/drm/drm_print.h | 6 ++-- include/linux/dynamic_debug.h | 37 +++- lib/test_dynamic_debug.c| 50 + lib/test_dynamic_debug_submod.c | 9 +- 5 files changed, 69 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index dabcfa0dd279..8f4b609353a5 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -69,12 +69,8 @@ DRM_CLASSMAP_DEFINE(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, "DRM_UT_DP", "DRM_UT_DRMRES"); -static struct ddebug_class_param drm_debug_bitmap = { - .bits = &__drm_debug, - .flags = "p", - .map = _debug_classes, -}; -module_param_cb(debug, _ops_dyndbg_classes, _debug_bitmap, 0600); +DRM_CLASSMAP_PARAM_REF(debug, __drm_debug, drm_debug_classes, p); + #endif void __drm_puts_coredump(struct drm_printer *p, const char *str) diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 706afc97c79c..94d4f5500030 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -322,11 +322,13 @@ enum drm_debug_category { }; #ifdef CONFIG_DRM_USE_DYNAMIC_DEBUG -#define DRM_CLASSMAP_DEFINE(...) DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__) -#define DRM_CLASSMAP_USE(name) DYNDBG_CLASSMAP_USE(name) +#define DRM_CLASSMAP_DEFINE(...) DYNDBG_CLASSMAP_DEFINE(__VA_ARGS__) +#define DRM_CLASSMAP_USE(name) DYNDBG_CLASSMAP_USE(name) +#define DRM_CLASSMAP_PARAM_REF(...)DYNDBG_CLASSMAP_PARAM_REF(__VA_ARGS__) #else #define DRM_CLASSMAP_DEFINE(...) #define DRM_CLASSMAP_USE(name) +#define DRM_CLASSMAP_PARAM_REF(...) #endif static inline bool drm_debug_enabled_raw(enum drm_debug_category category) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 1b027be2cdc4..f182f95caabb 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -91,7 +91,7 @@ struct ddebug_class_map { * used to validate a "class FOO .." >control command on the module */ #define DYNDBG_CLASSMAP_DEFINE(_var, _maptype, _base, ...) \ - const char *_var##_classnames[] = { __VA_ARGS__ }; \ + static const char *_var##_classnames[] = { __VA_ARGS__ }; \ struct ddebug_class_map __aligned(8) __used \ __section("__dyndbg_classes") _var = { \ .mod = THIS_MODULE, \ @@ -145,6 +145,41 @@ struct ddebug_class_param { const struct ddebug_class_map *map; }; +/** + * DYNDBG_CLASSMAP_PARAM - wrap a dyndbg-classmap with a controlling sys-param + * @_name sysfs node name + * @_var name of the struct classmap var defining the controlled classes + * @_flags flags to be toggled, typically just 'p' + * + * Creates a sysfs-param to control the classes defined by the + * classmap. Keeps bits in a private/static + */ +#define DYNDBG_CLASSMAP_PARAM(_name, _var, _flags) \ + static unsigned long _name##_bvec; \ + __DYNDBG_CLASSMAP_PARAM(_name, _name##_bvec, _var, _flags) + +/** + * DYNDBG_CLASSMAP_PARAM_REF - wrap a dyndbg-classmap with a controlling sys-param + * @_name sysfs node name + * @_bits name of the module's unsigned long bit-vector, ex: __drm_debug + * @_var name of the struct classmap var defining the controlled classes + * @_flags flags to be toggled, typically just 'p' + * + * Creates a sysfs-param to control the classmap, keeping bitvec in user @_bits. + * This lets drm use __drm_debug elsewhere too. + */ +#define DYNDBG_CLASSMAP_PARAM_REF(_name, _bits, _var, _flags) \ + __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags) + +#define __DYNDBG_CLASSMAP_PARAM(_name, _bits, _var, _flags)\ + static struct ddebug_class_param _name##_##_flags = { \ + .bits = &(_bits), \ + .flags = #_flags, \ + .map = &(_var), \ + };
[PATCH v7c 14/24] dyndbg-API: fix CONFIG_DRM_USE_DYNAMIC_DEBUG regression
pattern of repetition, and the points of change. And extend the test to replicate the 2-module (parent & dependent) scenario which caused the CONFIG_DRM_USE_DYNAMIC_DEBUG=y regression seen in drm & drivers. The _submod.c is a 2-line file: #define _SUBMOD, #include parent. This gives identical complements of prdbgs in parent & _submod, and thus identical print behavior when all of: >control, >params, and parent->_submod propagation are working correctly. It also puts all the parent/_submod declarations together in the same source, with the new ifdef _SUBMOD block invoking DYNDBG_CLASSMAP_USE for the 2 test-interfaces. I think this is clearer. These 2 modules are independently configurable, allowing builtin parent and loadable submod, which recapitulates a troublesome build combo for drm & drivers. DEBUG details: ``#define DEBUG`` in src enables all pr_debugs after it, including any class'd pr_debugs; its not necessarily all-or-nothing, unless its a one-file-module with DEBUG at the top. If a CLASSMAP_PARAM is defined on a classmap, its readback value cannot describe the set of enablements. The param is basically write-only; it cannot know if `echo $cmd >control` was done since. To know the exact pr-debug state with certainty, toggle to both: echo 0x3ff > /sys/module/drm/parameters/debug echo 0 > /sys/module/drm/parameters/debug Cc: Daniel Vetter Cc: Jani Nikula Cc: Tvrtko Ursulin Cc: Rob Clark Cc: Sean Paul Cc: Luis Chamberlain Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro") Fixes: f158936b60a7 ("drm: POC drm on dyndbg - use in core, 2 helpers, 3 drivers.") Ref: commit bb2ff6c27bc9 ("drm: Disable dynamic debug as broken") Signed-off-by: Jim Cromie --- fixup-kconfig description too short --- MAINTAINERS | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 +- drivers/gpu/drm/display/drm_dp_helper.c | 12 +- drivers/gpu/drm/drm_crtc_helper.c | 12 +- drivers/gpu/drm/drm_print.c | 25 ++-- drivers/gpu/drm/i915/i915_params.c | 12 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 12 +- include/asm-generic/vmlinux.lds.h | 1 + include/drm/drm_print.h | 10 +- include/linux/dynamic_debug.h | 53 +-- kernel/module/main.c| 3 + lib/Kconfig.debug | 24 +++- lib/Makefile| 3 + lib/dynamic_debug.c | 183 +--- lib/test_dynamic_debug.c| 111 +- lib/test_dynamic_debug_submod.c | 10 ++ 16 files changed, 344 insertions(+), 141 deletions(-) create mode 100644 lib/test_dynamic_debug_submod.c diff --git a/MAINTAINERS b/MAINTAINERS index 7a7bd8bd80e9..ac0b6a4e4ee7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7320,7 +7320,7 @@ M:Jim Cromie S: Maintained F: include/linux/dynamic_debug.h F: lib/dynamic_debug.c -F: lib/test_dynamic_debug.c +F: lib/test_dynamic_debug*.c DYNAMIC INTERRUPT MODERATION M: Tal Gilboa diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 81edf66dbea8..efba99c9393e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -197,17 +197,7 @@ int amdgpu_user_partt_mode = AMDGPU_AUTO_COMPUTE_PARTITION_MODE; static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); -DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, - "DRM_UT_CORE", - "DRM_UT_DRIVER", - "DRM_UT_KMS", - "DRM_UT_PRIME", - "DRM_UT_ATOMIC", - "DRM_UT_VBL", - "DRM_UT_STATE", - "DRM_UT_LEASE", - "DRM_UT_DP", - "DRM_UT_DRMRES"); +DRM_CLASSMAP_USE(drm_debug_classes); struct amdgpu_mgpu_info mgpu_info = { .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex), diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index e6a78fd32380..d97de1a27939 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -41,17 +41,7 @@ #include "drm_dp_helper_internal.h" -DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, - "DRM_UT_CORE", - "DRM_UT_DRIVER", - "DRM_UT_KMS", - "DRM_UT_PRIME", - "DRM_UT_ATOMIC", - "DRM_UT_VBL", - "DRM_UT_STATE", - "DRM_UT
[PATCH v7c 15/24] dyndbg: refactor ddebug_classparam_clamp_input
Extract input validation code, from param_set_dyndbg_module_classes() (the sys-node >handler) to new: ddebug_classparam_clamp_input(kp), call it from former. It takes kernel-param arg, so it can complain about "foo: bad input". Reuse ddparam_clamp_input(kp) in ddebug_sync_classbits(), to validate inputs from parent's params, just like our own. To support that reuse, alter ddebug_sync_classbits() and caller to pass kp instead of kp->arg. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 70 ++--- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index c9517d403e06..a6ee142668bf 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -653,6 +653,30 @@ static int ddebug_apply_class_bitmap(const struct ddebug_class_param *dcp, #define CLASSMAP_BITMASK(width) ((1UL << (width)) - 1) +static void ddebug_class_param_clamp_input(unsigned long *inrep, const struct kernel_param *kp) +{ + const struct ddebug_class_param *dcp = kp->arg; + const struct ddebug_class_map *map = dcp->map; + + switch (map->map_type) { + case DD_CLASS_TYPE_DISJOINT_BITS: + /* expect bits. mask and warn if too many */ + if (*inrep & ~CLASSMAP_BITMASK(map->length)) { + pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n", + KP_NAME(kp), *inrep, CLASSMAP_BITMASK(map->length)); + *inrep &= CLASSMAP_BITMASK(map->length); + } + break; + case DD_CLASS_TYPE_LEVEL_NUM: + /* input is bitpos, of highest verbosity to be enabled */ + if (*inrep > map->length) { + pr_warn("%s: level:%ld exceeds max:%d, clamping\n", + KP_NAME(kp), *inrep, map->length); + *inrep = map->length; + } + break; + } +} static int param_set_dyndbg_module_classes(const char *instr, const struct kernel_param *kp, const char *modnm) @@ -671,26 +695,15 @@ static int param_set_dyndbg_module_classes(const char *instr, pr_err("expecting numeric input, not: %s > %s\n", instr, KP_NAME(kp)); return -EINVAL; } + ddebug_class_param_clamp_input(, kp); switch (map->map_type) { case DD_CLASS_TYPE_DISJOINT_BITS: - /* expect bits. mask and warn if too many */ - if (inrep & ~CLASSMAP_BITMASK(map->length)) { - pr_warn("%s: input: 0x%lx exceeds mask: 0x%lx, masking\n", - KP_NAME(kp), inrep, CLASSMAP_BITMASK(map->length)); - inrep &= CLASSMAP_BITMASK(map->length); - } v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp)); totct += ddebug_apply_class_bitmap(dcp, , *dcp->bits, modnm); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: - /* input is bitpos, of highest verbosity to be enabled */ - if (inrep > map->length) { - pr_warn("%s: level:%ld exceeds max:%d, clamping\n", - KP_NAME(kp), inrep, map->length); - inrep = map->length; - } 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)); @@ -1157,16 +1170,27 @@ static const char * const ddebug_classmap_typenames[] = { ddebug_classmap_typenames[_cm->map_type]);\ }) -static void ddebug_sync_classbits(const struct ddebug_class_param *dcp, const char *modname) +static void ddebug_sync_classbits(const struct kernel_param *kp, const char *modname) { - /* clamp initial bitvec, mask off hi-bits */ - if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) { - *dcp->bits &= CLASSMAP_BITMASK(dcp->map->length); - v2pr_info("preset classbits: %lx\n", *dcp->bits); + struct ddebug_class_param *dcp = kp->arg; + unsigned long new_bits; + + ddebug_class_param_clamp_input(dcp->bits, kp); + + switch (dcp->map->map_type) { + case DD_CLASS_TYPE_DISJOINT_BITS: + v2pr_info(" %s: classbits: 0x%lx\n", KP_NAME(kp), *dcp->bits); + ddebug_apply_class_bitmap(dcp, dcp->bits, 0UL, modname); + break; + case DD_CLASS_TYPE_LEVEL_
[PATCH v7c 08/24] dyndbg: reduce verbose/debug clutter
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=0x 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 is like 1st, with result, not procedure. 2nd is just status, retold in 4th, with more info. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 14 +++--- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index b67c9b137447..b0e11f6bfaa2 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -266,9 +266,6 @@ static int ddebug_change(const struct ddebug_query *query, } mutex_unlock(_lock); - if (!nfound && verbose) - pr_info("no matches for query\n"); - return nfound; } @@ -497,7 +494,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--) { @@ -511,7 +507,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) { @@ -527,7 +522,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; } @@ -537,7 +532,7 @@ static int ddebug_exec_query(char *query_string, const char *modname) struct flag_settings modifiers = {}; struct ddebug_query query = {}; #define MAXWORDS 9 - int nwords, nfound; + int nwords; char *words[MAXWORDS]; nwords = ddebug_tokenize(query_string, words, MAXWORDS); @@ -555,10 +550,7 @@ static int ddebug_exec_query(char *query_string, const char *modname) return -EINVAL; } /* actually go and implement the change */ - nfound = ddebug_change(, ); - vpr_info_dq(, nfound ? "applied" : "no-match"); - - return nfound; + return ddebug_change(, ); } /* handle multiple queries in query string, continue on error, return -- 2.41.0
[PATCH v7c 12/24] dyndbg: reduce verbose=3 messages in ddebug_add_module
The fn currently says "add-module", then "skipping" if the module has no prdbgs. Just check 1st and return quietly. no functional change Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 8beb98a831f5..45870a699507 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1242,11 +1242,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(sizeof(*dt), GFP_KERNEL); if (dt == NULL) { -- 2.41.0
[PATCH v7c 11/24] dyndbg: tighten fn-sig of ddebug_apply_class_bitmap
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 --- lib/dynamic_debug.c | 21 +++-- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 8158943b350d..8beb98a831f5 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -593,7 +593,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 @@ -602,12 +603,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, _bits)) continue; snprintf(query, QUERY_SIZE, "class %s %c%s", map->class_names[bi], @@ -619,9 +620,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; } @@ -678,7 +679,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa continue; } curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, *dcp->bits, NULL); *dcp->bits = curr_bits; v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id, map->class_names[cls_id]); @@ -688,7 +689,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa old_bits = CLASSMAP_BITMASK(*dcp->lvl); curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 )); - totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, old_bits, NULL); *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); @@ -742,7 +743,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, modnm ?: "*", KP_NAME(kp)); - totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, modnm); + totct += ddebug_apply_class_bitmap(dcp, , *dcp->bits, modnm); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -755,7 +756,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, _bits, _bits, modnm); + totct += ddebug_apply_class_bitmap(dcp, _bits, old_bits, modnm); *dcp->lvl = inrep; break; default: -- 2.41.0
[PATCH v7c 10/24] dyndbg: tighten ddebug_class_name() 1st arg type
Change function's 1st arg-type, and deref in the caller. The fn doesn't need any other fields in the struct. no functional change. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index b07aab422604..8158943b350d 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1117,12 +1117,12 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos) #define class_in_range(class_id, map) \ (class_id >= map->base && class_id < map->base + map->length) -static const char *ddebug_class_name(struct ddebug_iter *iter, struct _ddebug *dp) +static const char *ddebug_class_name(struct ddebug_table *dt, struct _ddebug *dp) { - struct ddebug_class_map *map = iter->table->classes; - int i, nc = iter->table->num_classes; + struct ddebug_class_map *map = dt->classes; + int i; - for (i = 0; i < nc; i++, map++) + for (i = 0; i < dt->num_classes; i++, map++) if (class_in_range(dp->class_id, map)) return map->class_names[dp->class_id - map->base]; @@ -1156,7 +1156,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p) seq_puts(m, "\""); if (dp->class_id != _DPRINTK_CLASS_DFLT) { - class = ddebug_class_name(iter, dp); + class = ddebug_class_name(iter->table, dp); if (class) seq_printf(m, " class:%s", class); else -- 2.41.0
[PATCH v7c 07/24] dyndbg: drop NUM_TYPE_ARRAY
ARRAY_SIZE works here, since array decl is complete. no functional change Signed-off-by: Jim Cromie --- 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 b53217e4b711..8116d0a0d33a 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -106,11 +106,9 @@ struct ddebug_class_map { .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)) /* encapsulate linker provided built-in (or module) dyndbg data */ struct _ddebug_info { -- 2.41.0
[PATCH v7c 05/24] dyndbg: ddebug_apply_class_bitmap - add module arg, select on it
Add query_module param to ddebug_apply_class_bitmap(). This allows its caller to update just one module, or all (as currently). We'll use this later to propagate drm.debug to each USEr as they're modprobed. No functional change. Signed-off-by: Jim Cromie --- after `modprobe i915`, heres the module dependencies, though not all on drm.debug. bash-5.2# lsmod Module Size Used by i915 3133440 0 drm_buddy 20480 1 i915 ttm90112 1 i915 i2c_algo_bit 16384 1 i915 video 61440 1 i915 wmi32768 1 video drm_display_helper200704 1 i915 drm_kms_helper208896 2 drm_display_helper,i915 drm 606208 5 drm_kms_helper,drm_display_helper,drm_buddy,i915,ttm cec57344 2 drm_display_helper,i915 --- lib/dynamic_debug.c | 19 --- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index a3be2e7c8c84..ba41fdeaaf98 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -601,7 +601,8 @@ static int ddebug_exec_queries(char *query, const char *modname) /* apply a new bitmap to the sys-knob's current bit-state */ 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]; @@ -609,7 +610,8 @@ 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); + 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)) @@ -618,12 +620,15 @@ 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); } + v2pr_info("applied bitmap: 0x%lx to: 0x%lx for %s\n", *new_bits, *old_bits, + query_modname ?: ""); + return matches; } @@ -679,7 +684,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa continue; } curr_bits ^= BIT(cls_id); - totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits); + totct += ddebug_apply_class_bitmap(dcp, _bits, dcp->bits, NULL); *dcp->bits = curr_bits; v2pr_info("%s: changed bit %d:%s\n", KP_NAME(kp), cls_id, map->class_names[cls_id]); @@ -689,7 +694,7 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa old_bits = CLASSMAP_BITMASK(*dcp->lvl); curr_bits = CLASSMAP_BITMASK(cls_id + (wanted ? 1 : 0 )); - totct += ddebug_apply_class_bitmap(dcp, _bits, _bits); + totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, NULL); *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); @@ -752,7 +757,7 @@ int param_set_dyndbg_classes(const char *instr, const struct kernel_param *kp) inrep &= CLASSMAP_BITMASK(map->length); } v2pr_info("bits:%lx > %s\n", inrep, KP_NAME(kp)); - totct += ddebug_apply_class_bitmap(dcp, , dcp->bits); + totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, NULL); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -765,7 +770,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\
[PATCH v7c 06/24] dyndbg: split param_set_dyndbg_classes to module/wrapper fns
rename param_set_dyndbg_classes: add _module_ name & arg, old name is wrapper to new. New arg allows caller to specify that only one module is affected by a prdbgs update. Outer fn preserves kernel_param interface, passing NULL to inner fn. This selectivity will be used later to narrow the scope of changes made. no functional change. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 37 ++--- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index ba41fdeaaf98..b67c9b137447 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -708,18 +708,9 @@ static int param_set_dyndbg_classnames(const char *instr, const struct kernel_pa return 0; } -/** - * 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 - * - * Enable/disable prdbgs by their class, as given in the arguments to - * DECLARE_DYNDBG_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) +static int param_set_dyndbg_module_classes(const char *instr, + const struct kernel_param *kp, + const char *modnm) { const struct ddebug_class_param *dcp = kp->arg; const struct ddebug_class_map *map = dcp->map; @@ -756,8 +747,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, , dcp->bits, NULL); + v2pr_info("bits:0x%lx > %s.%s\n", inrep, modnm ?: "*", KP_NAME(kp)); + totct += ddebug_apply_class_bitmap(dcp, , dcp->bits, modnm); *dcp->bits = inrep; break; case DD_CLASS_TYPE_LEVEL_NUM: @@ -770,7 +761,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, _bits, _bits, NULL); + totct += ddebug_apply_class_bitmap(dcp, _bits, _bits, modnm); *dcp->lvl = inrep; break; default: @@ -779,6 +770,22 @@ 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 - class FOO >control + * @instr: string echo>d to sysfs, input depends on map_type + * @kp:kp->arg has state: bits/lvl, map, map_type + * + * Enable/disable prdbgs by their class, as given in the arguments to + * DECLARE_DYNDBG_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); /** -- 2.41.0
[PATCH v7c 04/24] dyndbg: replace classmap list with a vector
Classmaps are stored/linked in a section/array, but are each added to the module's ddebug_table.maps list-head. This is unnecessary; even when ddebug_attach_classmap() is handling the builtin section (with classmaps for multiple builtin modules), its contents are ordered, so a module's possibly multiple classmaps will be consecutive in the section, and could be treated as a vector/block, since both start-addy and subrange length are in the ddebug_info arg. So this changes: struct ddebug_class_map drops list-head link. struct ddebug_table drops the list-head maps, and gets: classes & num_classes for the start-addy and num_classes, placed to improve struct packing. The loading: in ddebug_attach_module_classes(), replace the for-the-modname list-add loop, with a forloop that finds the module's subrange (start,length) of matching classmaps within the possibly builtin classmaps vector, and saves those to the ddebug_table. The reading/using: change list-foreach loops in ddebug_class_name() & ddebug_find_valid_class() to walk the array from start to length. Also: Move #define __outvar up, above an added use in a fn-prototype. Simplify ddebug_attach_module_classes args, ref has both addy,len. no functional changes Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 1 - lib/dynamic_debug.c | 61 ++- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 5231aaf361c4..b53217e4b711 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -83,7 +83,6 @@ enum 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 b984ce338921..a3be2e7c8c84 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 { @@ -147,13 +148,15 @@ static void vpr_info_dq(const struct ddebug_query *query, const char *msg) query->first_lineno, query->last_lineno, query->class_string); } +#define __outvar /* filled by callee */ 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, + __outvar int *class_id) { struct ddebug_class_map *map; - int idx; + int i, idx; - list_for_each_entry(map, >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; @@ -164,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 @@ -,9 +1113,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, >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]; @@ -1197,30 +1200,31 @@ 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 c
[PATCH v7c 02/24] dyndbg: reword "class unknown, " to "class:_UNKNOWN_"
This appears in the control-file to report an unknown class-name, which indicates that the class_id is not authorized, and dyndbg will ignore changes to it. Generally, this means that a DYNDBG_CLASSMAP_DEFINE or DYNDBG_CLASSMAP_USE is missing. But the word "unknown" appears in quite a few prdbg formats, so thats a suboptimal search term to find occurrences of the problem. Thus change it to "_UNKNOWN_" which properly shouts the condition. Signed-off-by: Jim Cromie --- lib/dynamic_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 6fba6423cc10..ceb3067a5c83 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1151,7 +1151,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_puts(m, "\n"); -- 2.41.0
[PATCH v7c 03/24] dyndbg: make ddebug_class_param union members same size
struct ddebug_class_param keeps a ref to the state-storage of the param, make both flavors use the same unsigned long under-type. ISTM this is simpler and safer. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 2 +- lib/dynamic_debug.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 4fcbf4d4fd0a..5231aaf361c4 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -124,7 +124,7 @@ struct _ddebug_info { struct ddebug_class_param { union { unsigned long *bits; - unsigned int *lvl; + unsigned long *lvl; }; char flags[8]; const struct ddebug_class_map *map; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index ceb3067a5c83..b984ce338921 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -796,7 +796,7 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp) case DD_CLASS_TYPE_LEVEL_NAMES: case DD_CLASS_TYPE_LEVEL_NUM: - return scnprintf(buffer, PAGE_SIZE, "%d\n", *dcp->lvl); + return scnprintf(buffer, PAGE_SIZE, "%ld\n", *dcp->lvl); default: return -1; } -- 2.41.0
[PATCH v7c 01/24] test-dyndbg: fixup CLASSMAP usage error
more careful reading of test output reveals: lib/test_dynamic_debug.c:103 [test_dynamic_debug]do_cats =pmf "doing categories\n" lib/test_dynamic_debug.c:105 [test_dynamic_debug]do_cats =p "LOW msg\n" class:MID lib/test_dynamic_debug.c:106 [test_dynamic_debug]do_cats =p "MID msg\n" class:HI lib/test_dynamic_debug.c:107 [test_dynamic_debug]do_cats =_ "HI msg\n" class unknown, _id:13 That last line is wrong, the HI class is declared. But the enum's 1st val (explicitly initialized) was wrong; it must be _base, not _base+1 (a DECLARE_DYNDBG_CLASSMAP[1] param). So the last enumeration exceeded the range of mapped class-id's, which triggered the "class unknown" report. I intentionally coded in an error, but forgot to verify its detection and remove it. RFC: This patch fixes a bad usage of DECLARE_DYNDBG_CLASSMAP(), showing that it is too error-prone. As noted in test-mod comments: * Using the CLASSMAP api: * - classmaps must have corresponding enum * - enum symbols must match/correlate with class-name strings in the map. * - base must equal enum's 1st value * - multiple maps must set their base to share the 0-62 class_id space !! * (build-bug-on tips welcome) Those shortcomings could largely be fixed with a __stringify_list (which doesn't exist,) used in DECLARE_DYNDBG_CLASSMAP to stringify __VA_ARGS__. Then, API would accept DRM_UT_* values literally; all the categories, in order, and not their stringifications, which created all the usage complications above. [1] name changes later to DYNDBG_CLASSMAP_DEFINE Signed-off-by: Jim Cromie --- lib/test_dynamic_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c index 8dd250ad022b..a01f0193a419 100644 --- a/lib/test_dynamic_debug.c +++ b/lib/test_dynamic_debug.c @@ -75,7 +75,7 @@ DD_SYS_WRAP(disjoint_bits, p); DD_SYS_WRAP(disjoint_bits, T); /* symbolic input, independent bits */ -enum cat_disjoint_names { LOW = 11, MID, HI }; +enum cat_disjoint_names { LOW = 10, MID, HI }; DECLARE_DYNDBG_CLASSMAP(map_disjoint_names, DD_CLASS_TYPE_DISJOINT_NAMES, 10, "LOW", "MID", "HI"); DD_SYS_WRAP(disjoint_names, p); -- 2.41.0
[PATCH v7c 00/24] fix DRM_USE_DYNAMIC_DEBUG=y regression
hi Jason, DRM-folk (v7c now with all checkpatch fixes) This patchest fixes the chicken-egg initialization problem in the 1st version of ddebug-class-maps, that DRM-CI uncovered. The root-problem was DECLARE_DYNDBG_CLASSMAP, which broke the K rule: "define once, refer many". In patch 14 it is replaced by: DYNDBG_CLASSMAP_DEFINE - define and export a struct ddebug_class_map DYNDBG_CLASSMAP_USE - ref the exported struct test-dynamic-debug is also extended with a -submod.ko, in order to recapitulate the drm & drivers initialization scenario. They're on v6.6-rc6 now, and recently applied cleanly to drm-tip/drm-tip. Ive been running recent revs on rc3+, on my desktop and laptop. The final blocker was a missing __align(8) on the ddebug_class_user record inserted by DYNDBG_CLASSMAP_USE. This caused DRM=y (builtin only) to have a corrupt record for drm_kms_helper (a builtin dependent). Curiously, a clang build did not exhibit this problem. Heres a part of dmesg, for a DRM=y kernel, booted with dynamic_debug.verbose=3 drm.debug=0x10 [0.466747] dyndbg: add-module: drm 406 sites [0.467569] dyndbg: classes[0]: module:drm base:0 len:10 type:DISJOINT_BITS [0.467743] dyndbg: module:drm attached 1 classes [0.468557] dyndbg: builtin class: module:drm base:0 len:10 type:DISJOINT_BITS [0.468742] dyndbg: found kp:drm.debug =0x10 [0.468743] dyndbg: mapped to: module:drm base:0 len:10 type:DISJOINT_BITS [0.469742] dyndbg: drm.debug: classbits: 0x10 [0.470573] dyndbg: apply bitmap: 0x10 to: 0x0 for drm [0.470743] dyndbg: query 0: "class DRM_UT_ATOMIC +p" mod:drm [0.471743] dyndbg: split into words: "class" "DRM_UT_ATOMIC" "+p" [0.472743] dyndbg: op='+' flags=0x1 maskp=0x [0.473679] dyndbg: parsed: func="" file="" module="drm" format="" lineno=0-0 class=DRM_UT_ATOMIC [0.473749] dyndbg: processed 1 queries, with 0 matches, 0 errs [0.474742] dyndbg: bit_4: 0 matches on class: DRM_UT_ATOMIC -> 0x10 [0.475742] dyndbg: applied bitmap: 0x10 to: 0x0 for drm [0.476686] dyndbg: 406 debug prints in module drm [0.476743] dyndbg: add-module: drm_kms_helper 93 sites [0.477727] dyndbg: class_ref[0] drm_kms_helper -> drm module:drm base:0 len:10 type:DISJOINT_BITS [0.477743] dyndbg: builtin class: module:drm base:0 len:10 type:DISJOINT_BITS [0.478742] dyndbg: found kp:drm.debug =0x10 [0.478743] dyndbg: mapped to: module:drm base:0 len:10 type:DISJOINT_BITS [0.479743] dyndbg: drm.debug: classbits: 0x10 [0.480592] dyndbg: apply bitmap: 0x10 to: 0x0 for drm_kms_helper [0.480743] dyndbg: query 0: "class DRM_UT_ATOMIC +p" mod:drm_kms_helper [0.481743] dyndbg: split into words: "class" "DRM_UT_ATOMIC" "+p" [0.482743] dyndbg: op='+' flags=0x1 maskp=0x [0.483743] dyndbg: parsed: func="" file="" module="drm_kms_helper" format="" lineno=0-0 class=DRM_UT_ATOMIC [0.484750] dyndbg: class-ref: drm_kms_helper.DRM_UT_ATOMIC module:drm_kms_helper nd:93 nc:0 nu:1 [0.485809] dyndbg: processed 1 queries, with 44 matches, 0 errs [0.486742] dyndbg: bit_4: 44 matches on class: DRM_UT_ATOMIC -> 0x10 [0.487742] dyndbg: applied bitmap: 0x10 to: 0x0 for drm_kms_helper [0.488743] dyndbg: attach-client-module: module:drm_kms_helper nd:93 nc:0 nu:1 [0.489742] dyndbg: 93 debug prints in module drm_kms_helper Widespread testing is appreciated. I have scripts if anyone wants them. lkp-robot reported success on dd-fix-7b, no report yet on 7c Patches are also at https://github.com/jimc/linux/tree/dd-fix-7c Jim Cromie (24): test-dyndbg: fixup CLASSMAP usage error dyndbg: reword "class unknown," to "class:_UNKNOWN_" dyndbg: make ddebug_class_param union members same size dyndbg: replace classmap list with a vector dyndbg: ddebug_apply_class_bitmap - add module arg, select on it dyndbg: split param_set_dyndbg_classes to module/wrapper fns dyndbg: drop NUM_TYPE_ARRAY dyndbg: reduce verbose/debug clutter dyndbg: silence debugs with no-change updates dyndbg: tighten ddebug_class_name() 1st arg type dyndbg: tighten fn-sig of ddebug_apply_class_bitmap dyndbg: reduce verbose=3 messages in ddebug_add_module dyndbg-API: remove DD_CLASS_TYPE_(DISJOINT|LEVEL)_NAMES and code dyndbg-API: fix CONFIG_DRM_USE_DYNAMIC_DEBUG regression dyndbg: refactor ddebug_classparam_clamp_input dyndbg-API: promote DYNDBG_CLASSMAP_PARAM to API dyndbg-doc: add classmap info to howto dyndbg: reserve flag bit _DPRINTK_FLAGS_PREFIX_CACHED dyndbg: add _DPRINTK_FLAGS_INCL_LOOKUP dyndbg: refactor *dynamic_emit_prefix dyndbg: change WARN_ON to WARN_ON_ONCE drm: use correct ccflags-y spelling drm-drivers: DRM_CLASSMAP_USE in 2nd batch of drivers, helpers drm: restore CONFIG_DRM_USE_DYN
Re: [PATCH v1] dynamic_debug: add support for logs destination
adding in Jason, not sure how he got missed. On Mon, Oct 16, 2023 at 9:13 AM Łukasz Bartosik wrote: > > czw., 12 paź 2023 o 20:48 napisał(a): > > > > > If you want the kernel to keep separate flight recorders I guess we could > > > add that, but I don't think it currently exists for the dyndbg stuff at > > > least. Maybe a flight recorder v2 feature, once the basics are in. > > > > > > > dyndbg has +pwrites to syslog > > +T would separately independently write the same to global trace > > > > This would allow graceful switchover to tracefs, > > without removing logging from dmesg, where most folks > > (and any monitor tools) would expect it. > > > > Lukas (iiuc) wants to steer each site to just 1 destination. > > Or maybe (in addition to +p > syslog) one trace destination, > > either global via events, or a separate tracebuf > > > > Im ambivalent, but thinking the smooth rollover from syslog to trace > > might be worth having to ease migration / weaning off syslog. > > > > And we have a 4 byte hole in struct _ddebug we could just use. > > I'm glad you brought that up. This means we can leave class_id field > untouched, have separate +T in flags (for consistency) > and dst_id can be easily 8 bits wide. > > Also can you point me to the latest version of writing debug logs to > trace events (+T option). > I would like to base trace instances work on that because both are > closely related. > Ive got 3 branches, all stacked up on rc6 (last I checked, they were clean on drm-tip) https://github.com/jimc/linux/tree/dd-fix-7c the regression fix, reposting this version next. it also grabs another flag bit: _DPRINTK_FLAGS_INCL_LOOKUP https://github.com/jimc/linux/tree/dd-shrink-3b split modname,filename,function to new __dyndbg_sites section loads the 3 column values and their intervals into 3 maple trees and implements 3 accessor functions to retrieve the vals from the descriptor addresses. it "works" but doesnt erase intervals properly on rmmod it also claims another flag - _DPRINTK_FLAGS_PREFIX_CACHED and uses it to mark cached prefix fragment that get created for enabled calls. https://github.com/jimc/linux/tree/dd-kitchen-sink this adds the +T flag stuff. its still a little fuzzy, esp around the descriptor arg - using it to render the prefix str at buffer-render time got UNSAFE warnings - likely due to loadable module descriptors which could or did go away between capture and render (after rmmod) > > Unless the align 8 is optional on 32-bits, > > I verified with "gcc -g -m32 ..." that the align(8) is honored on 32 bits. > this is sorta the opposite of what I was probing, but I think result is the same. istm align(8) is only for JUMP_LABEL, nothing else in the struct appears to need it so moving it to the top trades the hole for padding. > > I think we're never gonna close the hole anywhere. > > > > :) > > > is align 8 a generic expression of an architectural simplifying constraint ? > > or a need for 1-7 ptr offsets ? > > > > > > > > > > > > That's my idea of it. It is interesting to see how far the requirements > > > > can be reasonably realised. > > > > > > I think aside from the "make it available directly to unpriviledged > > > userspace" everything sounds reasonable and doable. > > > > > > More on the process side of things, I think Jim is very much looking for > > > acks and tested-by by people who are interested in better drm logging > > > infra. That should help that things are moving in a direction that's > > > actually useful, even when it's not yet entirely complete. > > > > > > > yes, please. Now posted at > > > > https://lore.kernel.org/lkml/20231012172137.3286566-1-jim.cro...@gmail.com/T/#t > > > > Lukas, I managed to miss your email in the send phase. > > please consider yourself a direct recipient :-) > > > > thanks everyone > > > > > Cheers, Sima > > > -- > > > Daniel Vetter > > > Software Engineer, Intel Corporation > > > http://blog.ffwll.ch
Re: [PATCH v7b 00/25] fix DRM_USE_DYNAMIC_DEBUG=y regression
On Fri, Oct 13, 2023 at 4:48 PM Jim Cromie wrote: > > hi Jason, DRM-folk > > (now with checkpatch fixes) I missed fixing boxed-vector, am just dropping it. > > This patchest fixes the chicken-egg initialization problem in the 1st > version of ddebug-class-maps, that DRM-CI uncovered. > > The root-problem was DECLARE_DYNDBG_CLASSMAP, which broke the K rule: > "define once, refer many". In patch 14 it is replaced by: > > DYNDBG_CLASSMAP_DEFINE - define and export a struct ddebug_class_map > DYNDBG_CLASSMAP_USE - ref the exported struct > > test-dynamic-debug is also extended with a -submod.ko, in order to > recapitulate the drm & drivers initialization scenario. > > They're on v6.6-rc5 now, and apply cleanly to drm-tip/drm-tip. > > Ive been running recent revs on rc3+, on my desktop and laptop. > > The final blocker was a missing __align(8) on the ddebug_class_user > record inserted by DYNDBG_CLASSMAP_USE. This caused DRM=y (builtin > only) to have a corrupt record for drm_kms_helper (builtin dependent). > Curiously, a clang build did not exhibit this problem. > > > Widespread testing is appreciated. > I have scripts if anyone wants them. > > I'll forward lkp-robot reports here when I get them. > Patches also at https://github.com/jimc/linux (dd-fix-7b) > Date: Sat, 14 Oct 2023 18:22:28 +0800 From: kernel test robot To: Jim Cromie Subject: [jimc:dd-fix-7a] BUILD SUCCESS 8e96f63f570a462b859876601a5f795a15999f6b Message-ID: <202310141826.an7mad40-...@intel.com> User-Agent: s-nail v14.9.24 tree/branch: https://github.com/jimc/linux.git dd-fix-7a branch HEAD: 8e96f63f570a462b859876601a5f795a15999f6b drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN elapsed time: 3187m configs tested: 103 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. tested configs: alpha allnoconfig gcc alphaallyesconfig gcc alpha defconfig gcc arc allmodconfig gcc arc allnoconfig gcc arc allyesconfig gcc arc defconfig gcc arc randconfig-001-20231012 gcc arm allmodconfig gcc arm allnoconfig gcc arm allyesconfig gcc arm defconfig gcc arm randconfig-001-20231013 gcc arm64allmodconfig gcc arm64 allnoconfig gcc arm64allyesconfig gcc arm64 defconfig gcc csky allmodconfig gcc csky allnoconfig gcc csky allyesconfig gcc cskydefconfig gcc i386 allmodconfig gcc i386 allnoconfig gcc i386 allyesconfig gcc i386 debian-10.3 gcc i386defconfig gcc i386 randconfig-001-20231013 gcc i386 randconfig-002-20231013 gcc i386 randconfig-003-20231013 gcc i386 randconfig-004-20231013 gcc i386 randconfig-005-20231013 gcc i386 randconfig-006-20231013 gcc loongarchallmodconfig gcc loongarch allnoconfig gcc loongarchallyesconfig gcc loongarch defconfig gcc loongarch randconfig-001-20231012 gcc m68k allmodconfig gcc m68k allnoconfig gcc m68k allyesconfig gcc m68kdefconfig gcc microblaze allmodconfig gcc microblazeallnoconfig gcc microblaze allyesconfig gcc microblaze defconfig gcc mips allmodconfig gcc mips allnoconfig gcc mips allyesconfig gcc nios2allmodconfig gcc nios2 allnoconfig gcc nios2allyesconfig gcc nios2 defconfig gcc openrisc allmodconfig gcc openrisc allnoconfig gcc openrisc allyesconfig gcc openriscdefconfig gcc parisc allmodconfig gcc pariscallnoconfig
[PATCH v7b 25/25] drm: restore CONFIG_DRM_USE_DYNAMIC_DEBUG un-BROKEN
Lots of burn-in testing needed before signing, upstreaming. NOTE: I set default Y to maximize testing by default. Is there a better way to do this ? Signed-off-by: Jim Cromie --- drivers/gpu/drm/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3caa020391c7..708f5e8cb205 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -55,8 +55,7 @@ config DRM_DEBUG_MM config DRM_USE_DYNAMIC_DEBUG bool "use dynamic debug to implement drm.debug" - default n - depends on BROKEN + default y depends on DRM depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE depends on JUMP_LABEL -- 2.41.0
[PATCH v7b 20/25] dyndbg: add _DPRINTK_FLAGS_INCL_LOOKUP
dyndbg's dynamic prefixing (by +tmfsl flags) is needlessly expensive. When an enabled (with +p) pr_debug is called, _DPRINTK_FLAGS_INCL_ANY prefix decorations are sprintf'd into stack-mem for every call. This string (or part of it) could be cached once its 1st generated, and retrieved thereafter, as long as its deleted any time the callsite's flags are changed afterwards. So consider the prefix/decoration flags: 'tmfsl', and what should be in the cache: -t thread-id. not part of the "callsite" info, derived from current. doesn't belong in the cache. it would be wrong. can be done in outer: dynamic_emit_prefix() -l line number this could be part of the prefix, but would bloat the cache can also be done in outer: dynamic_emit_prefix() -mfs module, function, source-file we cache these, composed into a sub-string. they are "lookups", currently to descriptor fields, could be accessor macros to "compressed" tables. cache saves more access work. All enabled together, they compose a prefix string like: # outer -inner-- outer "[tid] module:function:sourcfile:line: " So this patch extracts _DPRINTK_FLAGS_INCL_LOOKUP macro out of _DPRINTK_FLAGS_INCL_ANY macro, then redefs latter. Next re-refactor dynamic_emit_prefix inner/outer fns accordingly. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 927cb14f24e0..2237d454bc19 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -40,10 +40,12 @@ struct _ddebug { #define _DPRINTK_FLAGS_INCL_SOURCENAME (1<<5) #define _DPRINTK_FLAGS_PREFIX_CACHED (1<<7) -#define _DPRINTK_FLAGS_INCL_ANY\ - (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\ -_DPRINTK_FLAGS_INCL_LINENO | _DPRINTK_FLAGS_INCL_TID |\ +#define _DPRINTK_FLAGS_INCL_LOOKUP \ + (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME | \ _DPRINTK_FLAGS_INCL_SOURCENAME) +#define _DPRINTK_FLAGS_INCL_ANY \ + (_DPRINTK_FLAGS_INCL_LINENO | _DPRINTK_FLAGS_INCL_TID | \ +_DPRINTK_FLAGS_INCL_LOOKUP) #if defined DEBUG #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT -- 2.41.0
[PATCH v7b 21/25] dyndbg: refactor *dynamic_emit_prefix
Refactor the split of duties between outer & inner fns. The outer fn was previously just an inline unlikely forward to inner, which did all the work. Now, outer handles +t and +l flags itself, and calls inner only when _DPRINTK_FLAGS_INCL_LOOKUP is needed. No functional change. But it does make the results of the inner-fn more cache-friendly (fewer entries, reused more often): 1- no spurious [TID] or noise 2- no LINE-number to bloat the cache (avg 9 pr_debugs/fn) 3- only LOOKUP stuff Currently LOOKUPs are descriptor-field refs but could be replaced by accessor functions. This would allow the __dyndbg_sites section to be de-duplicated and reclaimed; currently module, filename fields are ~90% repeated. As the accessors get more expensive, the value of caching part of the prefix goes up. Also change inner-fn to return count of extra chars written to the buffer, and drop "inline" from outer, let the compiler decide. Maybe also change name accordingly. Signed-off-by: Jim Cromie --- fixup whitespace --- lib/dynamic_debug.c | 39 ++- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 17eefb35ac96..5825b58043a6 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -777,11 +777,28 @@ static int remaining(int wrote) return 0; } -static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) +static int __dynamic_emit_prefix(const struct _ddebug *desc, char *buf, int pos) +{ + if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + desc->modname); + if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + desc->function); + if (desc->flags & _DPRINTK_FLAGS_INCL_SOURCENAME) + pos += snprintf(buf + pos, remaining(pos), "%s:", + trim_prefix(desc->filename)); + return pos; +} + +static char *dynamic_emit_prefix(struct _ddebug *desc, char *buf) { int pos_after_tid; int pos = 0; + if (likely(!(desc->flags & _DPRINTK_FLAGS_INCL_ANY))) + return buf; + if (desc->flags & _DPRINTK_FLAGS_INCL_TID) { if (in_interrupt()) pos += snprintf(buf + pos, remaining(pos), " "); @@ -790,15 +807,10 @@ static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) task_pid_vnr(current)); } pos_after_tid = pos; - if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - desc->modname); - if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - desc->function); - if (desc->flags & _DPRINTK_FLAGS_INCL_SOURCENAME) - pos += snprintf(buf + pos, remaining(pos), "%s:", - trim_prefix(desc->filename)); + + if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_LOOKUP)) + pos += __dynamic_emit_prefix(desc, buf, pos); + if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO) pos += snprintf(buf + pos, remaining(pos), "%d:", desc->lineno); @@ -810,13 +822,6 @@ static char *__dynamic_emit_prefix(const struct _ddebug *desc, char *buf) return buf; } -static inline char *dynamic_emit_prefix(struct _ddebug *desc, char *buf) -{ - if (unlikely(desc->flags & _DPRINTK_FLAGS_INCL_ANY)) - return __dynamic_emit_prefix(desc, buf); - return buf; -} - void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...) { va_list args; -- 2.41.0
[PATCH v7b 23/25] drm: use correct ccflags-y spelling
Incorrectly spelled CFLAGS- failed to add -DDYNAMIC_DEBUG_MODULE, which broke builds with: CONFIG_DRM_USE_DYNAMIC_DEBUG=y CONFIG_DYNAMIC_DEBUG_CORE=y CONFIG_DYNAMIC_DEBUG=n Also add subdir-ccflags so that all drivers pick up the addition. Fixes: 84ec67288c10 ("drm_print: wrap drm_*_dbg in dyndbg descriptor factory macro") Signed-off-by: Jim Cromie --- drivers/gpu/drm/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 215e78e79125..22b1984cc982 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -3,7 +3,8 @@ # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE +ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG)+= -DDYNAMIC_DEBUG_MODULE +subdir-ccflags-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE drm-y := \ drm_aperture.o \ -- 2.41.0
[PATCH v7b 24/25] drm-drivers: DRM_CLASSMAP_USE in 2nd batch of drivers, helpers
Add a DRM_CLASSMAP_USE declaration to 2nd batch of helpers and *_drv.c files. For drivers, add the decl just above the module's PARAMs, since it identifies the "inherited" drm.debug param. Note: with CONFIG_DRM_USE_DYNAMIC_DEBUG=y, a module not also declaring DRM_CLASSMAP_USE will have its class'd prdbgs stuck in the initial (disabled, but for DEBUG) state. The stuck sites are evident in /proc/dynamic_debug/control as: class:_UNKNOWN_ _id:N# control's last column rather than a proper "enumeration": class:DRM_UT_CORE This set of updates was found by choosing M for all DRM-config items I found (not allmodconfig), building & modprobing them, and grepping "class unknown," control. There may yet be others. Signed-off-by: Jim Cromie --- drivers/gpu/drm/drm_gem_shmem_helper.c | 2 ++ drivers/gpu/drm/gud/gud_drv.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_drv.c | 2 ++ drivers/gpu/drm/qxl/qxl_drv.c | 2 ++ drivers/gpu/drm/radeon/radeon_drv.c| 2 ++ drivers/gpu/drm/udl/udl_main.c | 2 ++ drivers/gpu/drm/vkms/vkms_drv.c| 2 ++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.c| 2 ++ 8 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index e435f986cd13..066d906e3199 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -23,6 +23,8 @@ #include #include +DRM_CLASSMAP_USE(drm_debug_classes); + MODULE_IMPORT_NS(DMA_BUF); /** diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c index 9d7bf8ee45f1..5b555045fce4 100644 --- a/drivers/gpu/drm/gud/gud_drv.c +++ b/drivers/gpu/drm/gud/gud_drv.c @@ -31,6 +31,8 @@ #include "gud_internal.h" +DRM_CLASSMAP_USE(drm_debug_classes); + /* Only used internally */ static const struct drm_format_info gud_drm_format_r1 = { .format = GUD_DRM_FORMAT_R1, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index abddf37f0ea1..d678eb8e028d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -24,6 +24,8 @@ static int mgag200_modeset = -1; MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); module_param_named(modeset, mgag200_modeset, int, 0400); +DRM_CLASSMAP_USE(drm_debug_classes); + int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2) { struct device *dev = >dev; diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index b30ede1cf62d..91942ffcc2b4 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -65,6 +65,8 @@ module_param_named(modeset, qxl_modeset, int, 0400); MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)"); module_param_named(num_heads, qxl_num_crtc, int, 0400); +DRM_CLASSMAP_USE(drm_debug_classes); + static struct drm_driver qxl_driver; static struct pci_driver qxl_pci_driver; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index fa531493b111..ab29945af657 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -247,6 +247,8 @@ int radeon_cik_support = 1; MODULE_PARM_DESC(cik_support, "CIK support (1 = enabled (default), 0 = disabled)"); module_param_named(cik_support, radeon_cik_support, int, 0444); +DRM_CLASSMAP_USE(drm_debug_classes); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 3ebe2ce55dfd..ba57c14454e5 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -19,6 +19,8 @@ #define NR_USB_REQUEST_CHANNEL 0x12 +DRM_CLASSMAP_USE(drm_debug_classes); + #define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE) #define WRITES_IN_FLIGHT (20) #define MAX_VENDOR_DESCRIPTOR_SIZE 256 diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index dd0af086e7fa..086797c4b82b 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -39,6 +39,8 @@ static struct vkms_config *default_config; +DRM_CLASSMAP_USE(drm_debug_classes); + static bool enable_cursor = true; module_param_named(enable_cursor, enable_cursor, bool, 0444); MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 8b24ecf60e3e..9cb6be422621 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -275,6 +275,8 @@ static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, void *ptr); +DRM_CLASSMAP_USE(drm_debug_classes); + MODULE_PARM_DESC(restrict_iommu, "Try to limit IO
[PATCH v7b 22/25] dyndbg: change WARN_ON to WARN_ON_ONCE
This shouldn't ever happen, and 1st 2 conditions never have. The 3rd condition did happen, due to corrupt linkage due to a missing align(8) in DYNDBG_CLASSMAP_USE, on the static struct allocation into the __dyndbg_class_users section. Not sure whether changing to _ONCE is appropriate - this is a module-load activity, so it won't continuously spam syslog. Signed-off-by: Jim Cromie --- undo BUG_ON addition --- 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 5825b58043a6..2a5eb64dbc27 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -1284,7 +1284,7 @@ static void ddebug_attach_user_module_classes(struct ddebug_table *dt, */ for_each_boxed_vector(di, class_users, num_class_users, i, cli) { - if (WARN_ON(!cli || !cli->map || !cli->user_mod_name)) + if (WARN_ON_ONCE(!cli || !cli->map || !cli->user_mod_name)) continue; if (!strcmp(cli->user_mod_name, dt->mod_name)) { -- 2.41.0
[PATCH v7b 19/25] dyndbg: reserve flag bit _DPRINTK_FLAGS_PREFIX_CACHED
Reserve bit 7 to remember that a pr-debug callsite is/was: - enabled, with +p - wants a dynamic-prefix, with one+ of module:function:sourcfile - was previously called - was thus saved in the cache. NOT YET. Its unclear whether any cache fetch would be faster than 2-3 field fetches, but theres another factor; the 3 columns in the __dyndbg section are highly redundant and compressible, but to get the compression, we need field accessors, which will rebalance the tradeoff. So, for now, its just the bit reservation. Signed-off-by: Jim Cromie --- include/linux/dynamic_debug.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index f182f95caabb..927cb14f24e0 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -38,6 +38,7 @@ struct _ddebug { #define _DPRINTK_FLAGS_INCL_LINENO (1<<3) #define _DPRINTK_FLAGS_INCL_TID(1<<4) #define _DPRINTK_FLAGS_INCL_SOURCENAME (1<<5) +#define _DPRINTK_FLAGS_PREFIX_CACHED (1<<7) #define _DPRINTK_FLAGS_INCL_ANY\ (_DPRINTK_FLAGS_INCL_MODNAME | _DPRINTK_FLAGS_INCL_FUNCNAME |\ -- 2.41.0
[PATCH v7b 18/25] dyndbg-doc: add classmap info to howto
Add some basic info on classmap usage and api cc: linux-...@vger.kernel.org Signed-off-by: Jim Cromie --- v5- adjustments per Randy Dunlap, me v7b- checkpatch fixes --- .../admin-guide/dynamic-debug-howto.rst | 60 ++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 0b3d39c610d9..028c2cb5b4c5 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -225,7 +225,6 @@ the ``p`` flag has meaning, other flags are ignored. Note the regexp ``^[-+=][fslmpt_]+$`` matches a flags specification. To clear all flags at once, use ``=_`` or ``-fslmpt``. - Debug messages during Boot Process == @@ -375,3 +374,62 @@ just a shortcut for ``print_hex_dump(KERN_DEBUG)``. For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is its ``prefix_str`` argument, if it is constant string; or ``hexdump`` in case ``prefix_str`` is built dynamically. + +Dynamic Debug classmaps +=== + +Dyndbg allows selection/grouping of *prdbg* callsites using structural +info: module, file, function, line. Classmaps allow authors to add +their own domain-oriented groupings using class-names. Classmaps are +exported, so they referencable from other modules. + + # enable classes individually + :#> ddcmd class DRM_UT_CORE +p + :#> ddcmd class DRM_UT_KMS +p + # or more selectively + :#> ddcmd class DRM_UT_CORE module drm +p + +The "class FOO" syntax protects class'd prdbgs from generic overwrite:: + + # IOW this doesn't wipe any DRM.debug settings + :#> ddcmd -p + +To support the DRM.debug parameter, DYNDBG_CLASSMAP_PARAM* updates all +classes in a classmap, mapping param-bits 0..N onto the classes: +DRM_UT_<*> for the DRM use-case. + +Dynamic Debug Classmap API +== + +DYNDBG_CLASSMAP_DEFINE - modules use this to create classmaps, naming +each of the classes (stringified enum-symbols: "DRM_UT_<*>"), and +type, and mapping the class-names to consecutive _class_ids. + +By doing so, modules tell dyndbg that they are have prdbgs with those +class_ids, and they authorize dyndbg to accept "class FOO" for the +module defining that classname. + +There are 2 types of classmaps: + + DD_CLASS_TYPE_DISJOINT_BITS: classes are independent, like DRM.debug + DD_CLASS_TYPE_LEVEL_NUM: classes are relative, ordered (V3 > V2) + +DYNDBG_CLASSMAP_PARAM - refers to a DEFINEd classmap, exposing the set +of defined classes to manipulation as a group. This interface +enforces the relatedness of classes of DD_CLASS_TYPE_LEVEL_NUM typed +classmaps; all classes are independent in the >control parser itself. + +DYNDBG_CLASSMAP_USE - drm drivers invoke this to ref the CLASSMAP that +drm DEFINEs. This shares the classmap definition, and authorizes +dyndbg to apply changes to the user module's class'd pr_debugs. It +also tells dyndbg how to initialize the user's prdbgs at modprobe, +based upon the current setting of the parent's controlling param. + +Modules or module-groups (drm & drivers) can define multiple +classmaps, as long as they share the limited 0..62 per-module-group +_class_id range, without overlap. + +``#define DEBUG`` will enable all pr_debugs in scope, including any +class'd ones. This won't be reflected in the PARAM readback value, +but the pr_debug callsites can be toggled into agreement with the +param. -- 2.41.0