Received: by 2002:ab2:6816:0:b0:1f9:5764:f03e with SMTP id t22csp3021763lqo; Tue, 21 May 2024 04:47:10 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCXKt8nh1W8opOreEEhb4xhTqDmu785DxBMmPNEygIW45qQeF2D4HXoVw3w5eTn86zfZuRB+Qv+2Rt4KHP3RrWR3nMfvWeajUWmlV3tOPQ== X-Google-Smtp-Source: AGHT+IG9pdIlo/iJjTX2PwHFUnBSUMbHWQ3DnF0BK7XqhS7gT0t52oXcjeEfA1SC5xHUmslk0Hn+ X-Received: by 2002:a05:6214:459d:b0:6a9:bf6d:27f5 with SMTP id 6a1803df08f44-6a9bf7c6a97mr69852426d6.6.1716292029979; Tue, 21 May 2024 04:47:09 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1716292029; cv=pass; d=google.com; s=arc-20160816; b=ny20JTkwzb/MGWxVEdoSkItV+N6HR7s6FXd2LUDuJ7RAiOcqHvw+URaMifxJ7FMOTC 2bNKyrlXHXEiDjud5v5do6N+MYiULwsCAMzLJjEG95hNoziVC0D5NwxFfCTBVfx8vg5t 37utc3O40+J9WzuSztsuG1jjzw5TL8RQ6UKB1XZZNaKhxGwu3dBvESY9IxcsKZ3P4YHS aRWkLyOjuMs3uhBtP5s/GDQpbpR42v86RVJieN9lCiyu7+PpE8/AgZmRJS46+S0R7Yd2 bEENjVtAS8/Flp8nHXFpH9UrfcK1DxsdWOE0YtsoeHdqT8mpCkiXlq+nevNsPfxK5ezZ Ucbg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:list-unsubscribe:list-subscribe :list-id:precedence:dkim-signature; bh=dmFi0hxbl04gPLScekKDZDupMtX2UmH7vhRKYlMM9IA=; fh=4aBayQ2sCU7OH2HPHlte5YB9U45PiMY5dq7YiXOhrSE=; b=MMYJ5wt/5GUWa9rWFO/7rWGWjjXejaQdLcNnDIew+FnKNVHB+/JWhPUM2AafrQ4Bs3 qxWN/lNqGgpzAvzllIMr7DmnbGtqrwJrxOA8MjjhOHGaZIYn4wJ8paBDF425YioUYXtA XCVutxrxGiAmOJjMM7SiYmBRGwnnCTvW9bNNi97t6/mz07pT/rIkuGFdzkbL6d+q4Wlz KDO7b5utkTysix/1FBSUsjRkIfIB0gCwrXjBuP5TNjZRUIidQYUn868GnuVY1NRgSzMg LINsjsTjsRPWr3tPX6yPlYR3Qz2qwUU7jSGIAXE2J7F8vvmyUD1YLm9socy2dxWuOekR wtqw==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=fGjU85xt; arc=pass (i=1 spf=pass spfdomain=chromium.org dkim=pass dkdomain=chromium.org dmarc=pass fromdomain=chromium.org); spf=pass (google.com: domain of linux-kernel+bounces-184893-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-184893-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id d75a77b69052e-43df56d0620si4306401cf.652.2024.05.21.04.47.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 May 2024 04:47:09 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-184893-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=fGjU85xt; arc=pass (i=1 spf=pass spfdomain=chromium.org dkim=pass dkdomain=chromium.org dmarc=pass fromdomain=chromium.org); spf=pass (google.com: domain of linux-kernel+bounces-184893-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-184893-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 9FA511C21C57 for ; Tue, 21 May 2024 11:47:09 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 65DB36EB6E; Tue, 21 May 2024 11:47:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="fGjU85xt" Received: from mail-lj1-f171.google.com (mail-lj1-f171.google.com [209.85.208.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 28FD747A74 for ; Tue, 21 May 2024 11:46:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.171 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716292022; cv=none; b=YgO2SQgecV3upaZCJ3utSrAausdbiULKijl3dBIJUwRvqDkIFZVxL7VBveuY9i8C1uCnraHcwxfZdj8XoB21ZxEJgX6gvjZ9xcElYM2OpG5X3YxGEIO35ySBVljL1urj0O1KoYHIE3SqpIFtrJ8uCU7Gb7z6pWmRNqs8m2BiqpY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716292022; c=relaxed/simple; bh=M88UfRvYWz7YOocEHGZam92i8/EPKQyefuS24MSLFwo=; h=MIME-Version:References:In-Reply-To:From:Date:Message-ID:Subject: To:Cc:Content-Type; b=GyRtrM8rxpILpcUGEYhDTOKAltPAnEE21CJAN7VuGCw6oinE/Akuj+YAmpWObnMOB0FTjHlu5OKftco0rKmqENA9P+CGIGh3zVMVAubX8vuAKIlzS6unVARBu5+MzKZDAQE2IVadP0CIqpN+9AxzeR4XWWJkwj73lh4zsxuzOyQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org; spf=pass smtp.mailfrom=chromium.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b=fGjU85xt; arc=none smtp.client-ip=209.85.208.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chromium.org Received: by mail-lj1-f171.google.com with SMTP id 38308e7fff4ca-2e576057c06so45413831fa.0 for ; Tue, 21 May 2024 04:46:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1716292018; x=1716896818; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=dmFi0hxbl04gPLScekKDZDupMtX2UmH7vhRKYlMM9IA=; b=fGjU85xtvTlI/wK5wjkBVWq+kVfoH9OI4zVbamMhGuuqHLUjB5gHZaeVj2d5sKseSI 68XV9uhU4NTqQaQo7PlXCGushTeABBwKQlIYcHh2RrKIrQLpUcpf1+B3t1lYqyndLi7R fTOd2Ry7v0AXqx+7Ac5DrcdKe4QSc/e3jMFQE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716292018; x=1716896818; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=dmFi0hxbl04gPLScekKDZDupMtX2UmH7vhRKYlMM9IA=; b=eOFhBABPBqbRSIXudkML3cqYJcEc/OjHNDE0SKHOfeE64hCIi7ex+RfstImuhm82Js EHF9M9gcKq7s3O9NoxxhvYSjJT0ZpZGjuKZmpPQ9bDnL6BYE0RVLfQg7hDS43wbRIYJQ bmDLpX8VR02xYkR9wnEnvPXlv30HMpMlmxiH0LnMBLKVz0u59DlEI2pj1pHuDkKxtVY7 x2cDE49A3j7n+Ri/PNkGqDG6L6xlNnjjGPCBvrnlsulLGwdrWJamJU9AnfTXHOC7+wm/ AFkmSIBYLQvPAI0BNnD/ApfneJLTBYDYQ2vMBZkUe274HP98/3GbvvX8Mh/QG6zO0B+N o3wA== X-Forwarded-Encrypted: i=1; AJvYcCUaL2sFb2pKvdhf10CYe4Yq203bIorQwb6LRS5iiCR+xEvlfoDbL9pqo8s0rBBRl+7O6rdkMYCbT1ssrP+YdRZ9dYn1EZdyKmhFuBIT X-Gm-Message-State: AOJu0YwKaD2WsmmXRfhHreRBKKHUY624OcisEOqtyaMweFpJpbWpECfv uKi+kaelpC1Oq7VbswhET1FkqFMD5uGI17VSTMRibfLYyGAgfDxkYp7TXhLcWWmG9zQznwRLqz0 zLPrEfFlEayFbfWYEj4n9trbqcHX4W8ofylA= X-Received: by 2002:a2e:a6a6:0:b0:2e2:72a7:8435 with SMTP id 38308e7fff4ca-2e5204b2e7emr178022581fa.45.1716292018067; Tue, 21 May 2024 04:46:58 -0700 (PDT) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 References: <20240516174357.26755-1-jim.cromie@gmail.com> <20240516174357.26755-16-jim.cromie@gmail.com> In-Reply-To: <20240516174357.26755-16-jim.cromie@gmail.com> From: =?UTF-8?Q?=C5=81ukasz_Bartosik?= Date: Tue, 21 May 2024 13:46:47 +0200 Message-ID: Subject: Re: [PATCH v8-RESEND 15/33] dyndbg-API: fix DECLARE_DYNDBG_CLASSMAP To: Jim Cromie Cc: jbaron@akamai.com, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, linux@rasmusvillemoes.dk, joe@perches.com, mcgrof@kernel.org, daniel.vetter@ffwll.ch, tvrtko.ursulin@linux.intel.com, jani.nikula@intel.com, ville.syrjala@linux.intel.com, seanpaul@chromium.org, robdclark@gmail.com, groeck@google.com, yanivt@google.com, bleung@google.com Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, May 16, 2024 at 7:44=E2=80=AFPM Jim Cromie w= rote: > > DECLARE_DYNDBG_CLASSMAP() has a design error; its usage fails a basic > K&R rule: "define once, refer many times". > > It is used across DRM core & drivers, each use re-defines the classmap > understood by that module; and all must match for the modules to > respond together when DRM.debug categories are enabled. This is > brittle; a maintenance foot-gun. > > Worse, it causes the CONFIG_DRM_USE_DYNAMIC_DEBUG=3DY regression; 1st > drm.ko loads, and dyndbg initializes its DRM.debug callsites, then a > drm-driver loads, but too late - it missed the DRM.debug enablement. > > So replace it with 2 macros: > DYNDBG_CLASSMAP_DEFINE - invoked once from core - drm.ko > DYNDBG_CLASSMAP_USE - from all drm drivers and helpers. > > DYNDBG_CLASSMAP_DEFINE: it reuses a renamed DECLARE_DYNDBG_CLASSMAP to > construct the struct classmap variable, but it drops the static > qualifier, and exports it instead. > > DYNDBG_CLASSMAP_USE: then refers to the exported var by name: > * used from drivers, helper-mods > * lets us drop the repetitive "classname" args > * fixes 2nd-defn problem > * creates a ddebug_class_user record in new __dyndbg_class_users section > this allows ddebug_add_module(etal) to handle them per-module. > > DECLARE_DYNDBG_CLASSMAP is preserved temporarily, to decouple DRM > adaptation work and avoid compile-errs before its done. IOW, DRM > gets fixed when they commit the adopt-new-api patches. > > The DEFINE,USE distinction, and the separate usage record, allows > dyndbg to initialize the drivers & helpers DRM.debug callsites > separately after each is modprobed. > > Basically, the classmap init-scan repeated for classmap-users. > > To review, dyndbg's existing __dyndbg_classes[] section does: > > . catalogs the classmaps defined by a module (or builtin modules) > . authorizes dyndbg to >control those class'd prdbgs for the module. > . DYNDBG_CLASSMAP_DEFINE creates classmaps in this section. > > This patch adds __dyndbg_class_users[] section: > > . catalogs uses/references to the classmap definitions. > . authorizes dyndbg to >control those class'd prdbgs in ref'g module. > . DYNDBG_CLASSMAP_USE() creates classmap-user records in this new section= . > > Now ddebug_add_module(etal) can handle classmap-uses similar to (and > after) classmaps; when a dependent module is loaded, its parent's > kernel params are scanned to find if a param is wired to dyndbg's > param-ops, whose classmap ref is the one being looked for. > > To support this, theres a few data/header changes: > > new struct ddebug_class_user > contains: user-module-name, &classmap-defn > it records drm-driver's use of a classmap in the section, allowing look= up > > struct ddebug_info gets 2 new fields to contain the new section: > class_users, num_class_users. > set by dynamic_debug_init() for builtins. > or by kernel/module/main:load_info() for loadable modules. > > vmlinux.lds.h: new BOUNDED_SECTION for __dyndbg_class_users > > dynamic_debug.c has 2 changes in ddebug_add_module(), ddebug_change(): > > ddebug_add_module() already calls ddebug_attach_module_classes() > to handle classmaps DEFINEd by a module, now it also calls > ddebug_attach_user_module_classes() to handle USEd classmaps. To > avoid this work when possible, 1st scan the module's descriptors and > count the number of class'd pr_debugs. > > ddebug_attach_user_module_classes() scans the module's class_users > section, follows the refs to the parent's classmap, and calls > ddebug_apply_params() on each. It also avoids work by checking the > module's class-ct. > > ddebug_apply_params(new fn): > > It scans module's/builtin kernel-params, calls ddebug_match_apply_kparam > for each to find the params/sysfs-nodes which may be wired to a classmap. > > ddebug_match_apply_kparam(new fn): > > 1st, it tests the kernel-param.ops is dyndbg's; this guarantees that > the attached arg is a struct ddebug_class_param, which has a ref to > the param's state, and to the classmap defining the param's handling. > > 2nd, it requires that the classmap ref'd by the kparam is the one > we're called for; modules can use many separate classmaps (as > test_dynamic_debug does). > > Then apply the "parent" kparam's setting to the dependent module, > using ddebug_apply_class_bitmap(). > > ddebug_change(and callees) also gets adjustments: > > ddebug_find_valid_class(): This does a search over the module's > classmaps, looking for the class FOO echo'd to >control. So now it > searches over __dyndbg_class_users[] after __dyndbg_classes[]. > > ddebug_class_name(): return class-names for defined AND used classes. > > test_dynamic_debug.c, test_dynamic_debug_submod.c: > > This demonstrates the 2 types of classmaps & sysfs-params, following > the 4-part recipe: > > 1. define an enum for the classmap: DRM.debug has DRM_UT_{CORE,KMS,...} > multiple classes must share 0-62 classid space. > 2. DYNDBG_CLASSMAP_DEFINE(.. DRM_UT_{CORE,KMS,...}) > 3. DYNDBG_CLASSMAP_PARAM* (classmap) > 4. DYNDBG_CLASSMAP_USE() > by _submod only, skipping 2,3 > > Move all the enum declarations together, to better explain how they > share the 0..62 class-id space available to a module (non-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=3Dy 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 a class'd > pr_debug is via the classmap-kparam or using "class foo" in control > queries, to address the classes by name. > > NB: this patch ignores a checkpatch do-while warning; which is wrong > for declarative macros like these: > > arch/powerpc/platforms/cell/spu_base.c > 48:static DEFINE_SPINLOCK(spu_lock); > 62:static DEFINE_SPINLOCK(spu_full_list_lock); > 63:static DEFINE_MUTEX(spu_full_list_mutex); > > Fixes: aad0214f3026 ("dyndbg: add DECLARE_DYNDBG_CLASSMAP macro") > Signed-off-by: Jim Cromie > --- > v8 - split drm parts to separate commits. > preserve DECLARE_DYNDBG_CLASSMAP to decouple DRM, no flag day. > fixup block comment > > 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 | 62 ++++++++-- > 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, 331 insertions(+), 68 deletions(-) > create mode 100644 lib/test_dynamic_debug_submod.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 28e20975c26f..c9ed48109ff5 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -7526,7 +7526,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/vmli= nux.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 */ \ > . =3D 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..2c6944c0d6cd 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/s= hared space */ > @@ -81,11 +81,34 @@ 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 modu= le. > + * @_var: name of the classmap, exported for other modules coordinated= use. > + * @_type: enum ddebug_class_map_type, chooses bits/verbose, numeric/na= mes. > + * @_base: offset of 1st class-name, used to share 0..62 classid space > + * @classes: vals are stringified enum-vals, like DRM_UT_* > + * Why does DYNDBG_CLASSMAP_DEFINE take "stringified" enum name-vals ? > + * Defines and exports a struct ddebug_class_map whose @classes are > + * used to validate a "class FOO .." >control command on the module > + */ > +#define __DYNDBG_CLASSMAP_DEFINE(_var, _maptype, _base, ...) \ > + const char *_var##_classnames[] =3D { __VA_ARGS__ }; = \ > + struct ddebug_class_map __aligned(8) __used \ > + __section("__dyndbg_classes") _var =3D { = \ > + .mod =3D THIS_MODULE, = \ > + .mod_name =3D KBUILD_MODNAME, = \ > + .base =3D _base, = \ > + .map_type =3D _maptype, = \ > + .length =3D ARRAY_SIZE(_var##_classnames), = \ > + .class_names =3D _var##_classnames, = \ > + } > +#define DYNDBG_CLASSMAP_DEFINE(_var, ...) \ > + __DYNDBG_CLASSMAP_DEFINE(_var, __VA_ARGS__); \ > + EXPORT_SYMBOL(_var) > + > +/* > + * XXX: keep this until DRM adapts to use the DEFINE/USE api, it > + * differs from __DYNDBG_CLASSMAP_DEFINE only in the static on the > + * struct decl. > */ > #define DECLARE_DYNDBG_CLASSMAP(_var, _maptype, _base, ...) \ > static const char *_var##_classnames[] =3D { __VA_ARGS__ }; = \ > @@ -99,12 +122,37 @@ struct ddebug_class_map { > .class_names =3D _var##_classnames, = \ > } > > +struct ddebug_class_user { > + char *user_mod_name; > + struct ddebug_class_map *map; > +}; > + > +/** > + * DYNDBG_CLASSMAP_USE - refer to a classmap, DEFINEd elsewhere. > + * @_var: name of the exported classmap var > + * > + * This registers a module's use of another module's classmap defn, so > + * dyndbg can authorize "class DRM_CORE ..." >control commands upon > + * this module. > + */ > +#define DYNDBG_CLASSMAP_USE(_var) \ > + DYNDBG_CLASSMAP_USE_(_var, __UNIQUE_ID(ddebug_class_user)) > +#define DYNDBG_CLASSMAP_USE_(_var, _uname) \ > + extern struct ddebug_class_map _var; \ > + static struct ddebug_class_user __aligned(8) __used \ > + __section("__dyndbg_class_users") _uname =3D { = \ > + .user_mod_name =3D KBUILD_MODNAME, = \ > + .map =3D &(_var), = \ > + } > + > /* 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; > unsigned int num_descs; > unsigned int num_classes; > + unsigned int num_class_users; > }; > > struct ddebug_class_param { > diff --git a/kernel/module/main.c b/kernel/module/main.c > index e1e8a7a9d6c1..9f7ce0f0e6e5 100644 > --- a/kernel/module/main.c > +++ b/kernel/module/main.c > @@ -2217,6 +2217,9 @@ static int find_module_sections(struct module *mod,= struct load_info *info) > mod->dyndbg_info.classes =3D section_objs(info, "__dyndbg_classes= ", > sizeof(*mod->dyndbg_info.= classes), > &mod->dyndbg_info.num_cla= sses); > + mod->dyndbg_info.class_users =3D section_objs(info, "__dyndbg_cla= ss_users", > + sizeof(*mod->dyndbg_i= nfo.class_users), > + &mod->dyndbg_info.num_= class_users); > #endif > > return 0; > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug > index 291185f54ee4..7acca866bb22 100644 > --- a/lib/Kconfig.debug > +++ b/lib/Kconfig.debug > @@ -2797,12 +2797,26 @@ config TEST_STATIC_KEYS > If unsure, say N. > > config TEST_DYNAMIC_DEBUG > - tristate "Test DYNAMIC_DEBUG" > - depends on DYNAMIC_DEBUG > + tristate "Build test-dynamic-debug module" > + depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE > help > - This module registers a tracer callback to count enabled > - pr_debugs in a 'do_debugging' function, then alters their > - enablements, calls the function, and compares counts. > + This module exersizes/demonstrates dyndbg's classmap API, by Typo exersizes -> exercises > + creating 2 classes: a DISJOINT classmap (supporting DRM.debug) > + and a LEVELS/VERBOSE classmap (like verbose2 > verbose1). > + > + If unsure, say N. > + > +config TEST_DYNAMIC_DEBUG_SUBMOD > + tristate "Build test-dynamic-debug submodule" > + default m > + depends on DYNAMIC_DEBUG || DYNAMIC_DEBUG_CORE > + depends on TEST_DYNAMIC_DEBUG > + help > + This sub-module uses a classmap defined and exported by the > + parent module, recapitulating drm & driver's shared use of > + drm.debug to control enabled debug-categories. > + It is tristate, independent of parent, to allow testing all > + proper combinations of parent=3Dy/m submod=3Dy/m. > > If unsure, say N. > > diff --git a/lib/Makefile b/lib/Makefile > index ffc6b2341b45..d3e6a48f202b 100644 > --- a/lib/Makefile > +++ b/lib/Makefile > @@ -82,6 +82,7 @@ obj-$(CONFIG_TEST_USER_COPY) +=3D test_user_copy.o > obj-$(CONFIG_TEST_STATIC_KEYS) +=3D test_static_keys.o > obj-$(CONFIG_TEST_STATIC_KEYS) +=3D test_static_key_base.o > obj-$(CONFIG_TEST_DYNAMIC_DEBUG) +=3D test_dynamic_debug.o > +obj-$(CONFIG_TEST_DYNAMIC_DEBUG_SUBMOD) +=3D test_dynamic_debug_submod.o > obj-$(CONFIG_TEST_PRINTF) +=3D test_printf.o > obj-$(CONFIG_TEST_SCANF) +=3D test_scanf.o > > @@ -240,6 +241,8 @@ obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) +=3D syscall.o > obj-$(CONFIG_DYNAMIC_DEBUG_CORE) +=3D dynamic_debug.o > #ensure exported functions have prototypes > CFLAGS_dynamic_debug.o :=3D -DDYNAMIC_DEBUG_MODULE > +CFLAGS_test_dynamic_debug.o :=3D -DDYNAMIC_DEBUG_MODULE > +CFLAGS_test_dynamic_debug_submod.o :=3D -DDYNAMIC_DEBUG_MODULE > > obj-$(CONFIG_SYMBOLIC_ERRNAME) +=3D errname.o > > diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c > index d5701207febc..f0a274a3cc9e 100644 > --- a/lib/dynamic_debug.c > +++ b/lib/dynamic_debug.c > @@ -43,13 +43,16 @@ extern struct _ddebug __start___dyndbg[]; > extern struct _ddebug __stop___dyndbg[]; > extern struct ddebug_class_map __start___dyndbg_classes[]; > extern struct ddebug_class_map __stop___dyndbg_classes[]; > +extern struct ddebug_class_user __start___dyndbg_class_users[]; > +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; > - unsigned int num_ddebugs, num_classes; > + struct ddebug_class_user *class_users; > + unsigned int num_ddebugs, num_classes, num_class_users; > }; > > struct ddebug_query { > @@ -148,21 +151,39 @@ static void vpr_info_dq(const struct ddebug_query *= query, const char *msg) > query->first_lineno, query->last_lineno, query->class_s= tring); > } > > +#define vpr_dt_info(dt_p, msg_p, ...) ({ \ > + struct ddebug_table const *_dt =3D dt_p; = \ > + v2pr_info(msg_p " module:%s nd:%d nc:%d nu:%d\n", ##__VA_ARGS__, = \ > + _dt->mod_name, _dt->num_ddebugs, _dt->num_classes, \ > + _dt->num_class_users); \ > + }) > + > #define __outvar /* filled by callee */ > static struct ddebug_class_map *ddebug_find_valid_class(struct ddebug_ta= ble const *dt, > const char *class= _string, > __outvar int *cla= ss_id) > { > struct ddebug_class_map *map; > + struct ddebug_class_user *cli; > int i, idx; > > - for (map =3D dt->classes, i =3D 0; i < dt->num_classes; i++, map+= +) { > + for (i =3D 0, map =3D dt->classes; i < dt->num_classes; i++, map+= +) { > idx =3D match_string(map->class_names, map->length, class= _string); > if (idx >=3D 0) { > *class_id =3D idx + map->base; > + vpr_dt_info(dt, "good-class: %s.%s ", map->mod_na= me, class_string); > return map; > } > } > + for (i =3D 0, cli =3D dt->class_users; i < dt->num_class_users; i= ++, cli++) { > + idx =3D match_string(cli->map->class_names, cli->map->len= gth, class_string); > + if (idx >=3D 0) { > + *class_id =3D idx + cli->map->base; > + vpr_dt_info(dt, "class-ref: %s.%s ", > + cli->user_mod_name, class_string); > + return cli->map; > + } > + } > *class_id =3D -ENOENT; > return NULL; > } > @@ -559,7 +580,7 @@ static int ddebug_exec_query(char *query_string, cons= t char *modname) > > /* handle multiple queries in query string, continue on error, return > last error or number of matching callsites. Module name is either > - in param (for boot arg) or perhaps in query string. > + in the modname arg (for boot args) or perhaps in query string. > */ > static int ddebug_exec_queries(char *query, const char *modname) > { > @@ -688,12 +709,12 @@ static int param_set_dyndbg_module_classes(const ch= ar *instr, > } > > /** > - * param_set_dyndbg_classes - class FOO >control > + * param_set_dyndbg_classes - set all classes in a classmap > * @instr: string echo>d to sysfs, input depends on map_type > - * @kp: kp->arg has state: bits/lvl, map, map_type > + * @kp: kp->arg has state: bits/lvl, classmap, map_type > * > - * Enable/disable prdbgs by their class, as given in the arguments to > - * DECLARE_DYNDBG_CLASSMAP. For LEVEL map-types, enforce relative > + * For all classes in the classmap, enable/disable them per the input > + * (depending on map_type). For LEVEL map-types, enforce relative > * levels by bitpos. > * > * Returns: 0 or <0 if error. > @@ -1038,12 +1059,17 @@ static void *ddebug_proc_next(struct seq_file *m,= void *p, loff_t *pos) > static const char *ddebug_class_name(struct ddebug_table *dt, struct _dd= ebug *dp) > { > struct ddebug_class_map *map =3D dt->classes; > + struct ddebug_class_user *cli =3D dt->class_users; > int i; > > for (i =3D 0; i < dt->num_classes; i++, map++) > if (class_in_range(dp->class_id, map)) > return map->class_names[dp->class_id - map->base]= ; > > + for (i =3D 0; i < dt->num_class_users; i++, cli++) > + if (class_in_range(dp->class_id, cli->map)) > + return cli->map->class_names[dp->class_id - cli->= map->base]; > + > return NULL; > } > > @@ -1124,31 +1150,133 @@ static const struct proc_ops proc_fops =3D { > .proc_write =3D ddebug_proc_write > }; > > +static const char * const ddebug_classmap_typenames[] =3D { > + "DISJOINT_BITS", "LEVEL_NUM" > +}; > + > +#define vpr_cm_info(cm_p, msg_p, ...) ({ \ > + struct ddebug_class_map const *_cm =3D cm_p; = \ > + v2pr_info(msg_p " module:%s base:%d len:%d type:%s\n", ##__VA_ARG= S__, \ > + _cm->mod_name, _cm->base, _cm->length, \ > + ddebug_classmap_typenames[_cm->map_type]); \ > + }) > + > +static void ddebug_sync_classbits(const struct ddebug_class_param *dcp, = const char *modname) > +{ > + /* clamp initial bitvec, mask off hi-bits */ > + if (*dcp->bits & ~CLASSMAP_BITMASK(dcp->map->length)) { > + *dcp->bits &=3D CLASSMAP_BITMASK(dcp->map->length); > + v2pr_info("preset classbits: %lx\n", *dcp->bits); > + } > + /* force class'd prdbgs (in USEr module) to match (DEFINEr module= ) class-param */ > + ddebug_apply_class_bitmap(dcp, dcp->bits, ~0, modname); > + ddebug_apply_class_bitmap(dcp, dcp->bits, 0, modname); > +} > + > +static void ddebug_match_apply_kparam(const struct kernel_param *kp, > + const struct ddebug_class_map *map, > + const char *modnm) > +{ > + struct ddebug_class_param *dcp; > + > + if (kp->ops !=3D ¶m_ops_dyndbg_classes) > + return; > + > + dcp =3D (struct ddebug_class_param *)kp->arg; > + > + if (map =3D=3D dcp->map) { > + v2pr_info("found kp:%s =3D0x%lx", kp->name, *dcp->bits); > + vpr_cm_info(map, "mapped to:"); > + ddebug_sync_classbits(dcp, modnm); > + } > +} > + > +static void ddebug_apply_params(const struct ddebug_class_map *cm, const= char *modnm) > +{ > + const struct kernel_param *kp; > +#if IS_ENABLED(CONFIG_MODULES) Instead of the above maybe use "if (IS_ENABLED(CONFIG_MODULES)) {" ? This will allow to get rid of #if and #endif which make code less readable. > + int i; > + > + if (cm->mod) { > + vpr_cm_info(cm, "loaded class:"); > + for (i =3D 0, kp =3D cm->mod->kp; i < cm->mod->num_kp; i+= +, kp++) > + ddebug_match_apply_kparam(kp, cm, modnm); > + } > +#endif > + if (!cm->mod) { > + vpr_cm_info(cm, "builtin class:"); > + for (kp =3D __start___param; kp < __stop___param; kp++) > + ddebug_match_apply_kparam(kp, cm, modnm); > + } > +} > + > +/* > + * Find this module's classmaps in a sub/whole-range of the builtin/ > + * modular classmap vector/section. Save the start and length of the > + * subrange at its edges. > + */ > static void ddebug_attach_module_classes(struct ddebug_table *dt, struct= _ddebug_info *di) > { > struct ddebug_class_map *cm; > int i, nc =3D 0; > > - /* > - * Find this module's classmaps in a subrange/wholerange of > - * the builtin/modular classmap vector/section. Save the start > - * and length of the subrange at its edges. > - */ > - for (cm =3D di->classes, i =3D 0; i < di->num_classes; i++, cm++)= { > + for (i =3D 0, cm =3D di->classes; i < di->num_classes; i++, cm++)= { > > if (!strcmp(cm->mod_name, dt->mod_name)) { > - if (!nc) { > - v2pr_info("start subrange, class[%d]: mod= ule:%s base:%d len:%d ty:%d\n", > - i, cm->mod_name, cm->base, cm->= length, cm->map_type); > + vpr_cm_info(cm, "classes[%d]:", i); > + if (!nc++) > dt->classes =3D cm; > - } > - nc++; > } > } > - if (nc) { > - dt->num_classes =3D nc; > - vpr_info("module:%s attached %d classes\n", dt->mod_name,= nc); > + if (!nc) > + return; > + > + vpr_info("module:%s attached %d classes\n", dt->mod_name, nc); > + dt->num_classes =3D nc; > + > + for (i =3D 0, cm =3D dt->classes; i < dt->num_classes; i++, cm++) > + ddebug_apply_params(cm, cm->mod_name); > +} > + > +/* > + * propagates class-params thru their classmaps to class-users. this > + * means a query against the dt/module, which means it must be on the > + * list to be seen by ddebug_change. > + */ > +static void ddebug_attach_user_module_classes(struct ddebug_table *dt, > + const struct _ddebug_info *= di) > +{ > + struct ddebug_class_user *cli; > + int i, nc =3D 0; > + > + /* > + * For builtins: scan the array, find start/length of this > + * module's refs, save to dt. For loadables, this is the > + * whole array. > + */ > + for (i =3D 0, cli =3D di->class_users; i < di->num_class_users; i= ++, cli++) { > + > + if (WARN_ON_ONCE(!cli || !cli->map || !cli->user_mod_name= )) > + continue; > + > + if (!strcmp(cli->user_mod_name, dt->mod_name)) { > + > + vpr_cm_info(cli->map, "class_ref[%d] %s -> %s", i= , > + cli->user_mod_name, cli->map->mod_nam= e); > + if (!nc++) > + dt->class_users =3D cli; > + } > } > + if (!nc) > + return; > + > + dt->num_class_users =3D nc; > + > + /* now iterate dt */ > + for (i =3D 0, cli =3D dt->class_users; i < dt->num_class_users; i= ++, cli++) > + ddebug_apply_params(cli->map, cli->user_mod_name); > + > + vpr_dt_info(dt, "attach-client-module: "); > } > > /* > @@ -1158,6 +1286,8 @@ static void ddebug_attach_module_classes(struct dde= bug_table *dt, struct _ddebug > static int ddebug_add_module(struct _ddebug_info *di, const char *modnam= e) > { > struct ddebug_table *dt; > + struct _ddebug *iter; > + int i, class_ct =3D 0; > > if (!di->num_descs) > return 0; > @@ -1181,13 +1311,20 @@ static int ddebug_add_module(struct _ddebug_info = *di, const char *modname) > > INIT_LIST_HEAD(&dt->link); > > - if (di->classes && di->num_classes) > + for (i =3D 0, iter =3D di->descs; i < di->num_descs; i++, iter++) > + if (iter->class_id !=3D _DPRINTK_CLASS_DFLT) > + class_ct++; > + > + if (class_ct && di->num_classes) > ddebug_attach_module_classes(dt, di); > > mutex_lock(&ddebug_lock); > list_add_tail(&dt->link, &ddebug_tables); > mutex_unlock(&ddebug_lock); > > + if (class_ct && di->num_class_users) > + ddebug_attach_user_module_classes(dt, di); > + > vpr_info("%3u debug prints in module %s\n", di->num_descs, modnam= e); > return 0; > } > @@ -1337,8 +1474,10 @@ static int __init dynamic_debug_init(void) > struct _ddebug_info di =3D { > .descs =3D __start___dyndbg, > .classes =3D __start___dyndbg_classes, > + .class_users =3D __start___dyndbg_class_users, > .num_descs =3D __stop___dyndbg - __start___dyndbg, > .num_classes =3D __stop___dyndbg_classes - __start___dynd= bg_classes, > + .num_class_users =3D __stop___dyndbg_class_users - __star= t___dyndbg_class_users, > }; > > #ifdef CONFIG_MODULES > diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c > index 9e950a911b6c..ff9b879286d5 100644 > --- a/lib/test_dynamic_debug.c > +++ b/lib/test_dynamic_debug.c > @@ -6,11 +6,15 @@ > * Jim Cromie > */ > > -#define pr_fmt(fmt) "test_dd: " fmt > +#if defined(TEST_DYNAMIC_DEBUG_SUBMOD) > + #define pr_fmt(fmt) "test_dd_submod: " fmt > +#else > + #define pr_fmt(fmt) "test_dd: " fmt > +#endif > > #include > > -/* run tests by reading or writing sysfs node: do_prints */ > +/* re-gen output by reading or writing sysfs node: do_prints */ > > static void do_prints(void); /* device under test */ > static int param_set_do_prints(const char *instr, const struct kernel_pa= ram *kp) > @@ -29,24 +33,39 @@ static const struct kernel_param_ops param_ops_do_pri= nts =3D { > }; > module_param_cb(do_prints, ¶m_ops_do_prints, NULL, 0600); > > -/* > - * Using the CLASSMAP api: > - * - classmaps must have corresponding enum > - * - enum symbols must match/correlate with class-name strings in the ma= p. > - * - base must equal enum's 1st value > - * - multiple maps must set their base to share the 0-30 class_id space = !! > - * (build-bug-on tips welcome) > - * Additionally, here: > - * - tie together sysname, mapname, bitsname, flagsname > - */ > -#define DD_SYS_WRAP(_model, _flags) \ > - static unsigned long bits_##_model; \ > - static struct ddebug_class_param _flags##_model =3D { = \ > +#define CLASSMAP_BITMASK(width, base) (((1UL << (width)) - 1) << base) > + > +/* sysfs param wrapper, proto-API */ > +#define DYNDBG_CLASSMAP_PARAM_(_model, _flags, _init) \ > + static unsigned long bits_##_model =3D _init; = \ > + static struct ddebug_class_param _flags##_##_model =3D { = \ > .bits =3D &bits_##_model, = \ > .flags =3D #_flags, = \ > .map =3D &map_##_model, = \ > }; \ > - module_param_cb(_flags##_##_model, ¶m_ops_dyndbg_classes, &_f= lags##_model, 0600) > + module_param_cb(_flags##_##_model, ¶m_ops_dyndbg_classes, \ > + &_flags##_##_model, 0600) > +#ifdef DEBUG > +#define DYNDBG_CLASSMAP_PARAM(_model, _flags) DYNDBG_CLASSMAP_PARAM_(_m= odel, _flags, ~0) > +#else > +#define DYNDBG_CLASSMAP_PARAM(_model, _flags) DYNDBG_CLASSMAP_PARAM_(_m= odel, _flags, 0) > +#endif > + > +/* > + * Demonstrate/test all 4 class-typed classmaps with a sys-param. > + * > + * Each is 3 part: client-enum decl, _DEFINE, _PARAM. > + * Declare them in blocks to show patterns of use (repetitions and > + * changes) within each. > + * > + * 1st, dyndbg expects a client-provided enum-type as source of > + * category/classid truth. DRM has DRM_UT_. > + * > + * Modules with multiple CLASSMAPS must have enums with distinct > + * value-ranges, arranged below with explicit enum_sym =3D X inits. > + * > + * Declare all 4 enums now, for different types > + */ > > /* numeric input, independent bits */ > enum cat_disjoint_bits { > @@ -60,26 +79,51 @@ enum cat_disjoint_bits { > D2_LEASE, > D2_DP, > D2_DRMRES }; > -DECLARE_DYNDBG_CLASSMAP(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, = 0, > - "D2_CORE", > - "D2_DRIVER", > - "D2_KMS", > - "D2_PRIME", > - "D2_ATOMIC", > - "D2_VBL", > - "D2_STATE", > - "D2_LEASE", > - "D2_DP", > - "D2_DRMRES"); > -DD_SYS_WRAP(disjoint_bits, p); > -DD_SYS_WRAP(disjoint_bits, T); > > /* numeric verbosity, V2 > V1 related */ > enum cat_level_num { V0 =3D 14, V1, V2, V3, V4, V5, V6, V7 }; > -DECLARE_DYNDBG_CLASSMAP(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, 14, > - "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7"); > -DD_SYS_WRAP(level_num, p); > -DD_SYS_WRAP(level_num, T); > + > +/* recapitulate DRM's parent(drm.ko) <-- _submod(drivers,helpers) */ > +#if !defined(TEST_DYNAMIC_DEBUG_SUBMOD) > +/* > + * In single user, or parent / coordinator (drm.ko) modules, define > + * classmaps on the client enums above, and then declares the PARAMS > + * ref'g the classmaps. Each is exported. > + */ > +DYNDBG_CLASSMAP_DEFINE(map_disjoint_bits, DD_CLASS_TYPE_DISJOINT_BITS, > + D2_CORE, > + "D2_CORE", > + "D2_DRIVER", > + "D2_KMS", > + "D2_PRIME", > + "D2_ATOMIC", > + "D2_VBL", > + "D2_STATE", > + "D2_LEASE", > + "D2_DP", > + "D2_DRMRES"); > + > +DYNDBG_CLASSMAP_DEFINE(map_level_num, DD_CLASS_TYPE_LEVEL_NUM, > + V0, "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7"= ); > + > +/* > + * now add the sysfs-params > + */ > + > +DYNDBG_CLASSMAP_PARAM(disjoint_bits, p); > +DYNDBG_CLASSMAP_PARAM(level_num, p); > + > +#else /* TEST_DYNAMIC_DEBUG_SUBMOD */ > + > +/* > + * in submod/drm-drivers, use the classmaps defined in top/parent > + * module above. > + */ > + > +DYNDBG_CLASSMAP_USE(map_disjoint_bits); > +DYNDBG_CLASSMAP_USE(map_level_num); > + > +#endif > > /* stand-in for all pr_debug etc */ > #define prdbg(SYM) __pr_debug_cls(SYM, #SYM " msg\n") > @@ -115,6 +159,7 @@ static void do_levels(void) > > static void do_prints(void) > { > + pr_debug("do_prints:\n"); > do_cats(); > do_levels(); > } > diff --git a/lib/test_dynamic_debug_submod.c b/lib/test_dynamic_debug_sub= mod.c > new file mode 100644 > index 000000000000..9a893402ce1a > --- /dev/null > +++ b/lib/test_dynamic_debug_submod.c > @@ -0,0 +1,10 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Kernel module for testing dynamic_debug > + * > + * Authors: > + * Jim Cromie > + */ > + > +#define TEST_DYNAMIC_DEBUG_SUBMOD > +#include "test_dynamic_debug.c" > -- > 2.45.0 >