Now that the DECLARE_DYNDBG_CLASSMAP macro has been split into
DYNDBG_CLASSMAP_DEFINE and DYNDBG_CLASSMAP_USE variants, lets
differentiate them according to their separate jobs.

Dyndbg's existing __dyndbg_classes[] section does:

. catalogs the classmaps defined by the module (or builtin modules)
. authorizes dyndbg to >control those class'd prdbgs for the module.

This patch adds __dyndbg_class_refs[] section:

. catalogs references/uses of the above classmap definitions.
. authorizes dyndbg to >control those class'd prdbgs in ref'g module.
. maps the client module to classmap definitions
  this allows dyndbg to propagate drm.debug to the client module.

The distinction of the 2 roles yields 2 gains:

It follows the define-once-declare-elsewhere pattern that K&R gave us,
dumping the weird coordinated-changes-by-identical-classmaps API.

It should help solve the chicken-egg problem that drm.debug-on-dyndbg
has; the _USEr module must propagate the drm.debug setting once the
using module has loaded.

The new DYNDBG_CLASSMAP macros add records to the sections:

DYNDBG_CLASSMAP_DEFINE:
  invoked by drm_print, just once per sub-system.
  defines the classmap, names "DRM_UT_*", maps to class_id's
  authorizes dyndbg to exert >control
  populates __dyndbg_classes[] "section", __used.
  exports the classmap.

DYNDBG_CLASSMAP_USE:
  invoked by modules using classmaps defined & exported elsewhere
  populates __dyndbg_class_refs[] "section", __used.
  maps client-module name to the extern'd classmap.
  no client-name yet, but will need it.

also:

struct ddebug_info gets 2 new fields to encapsulate the new section:
  class_refs, num_class_refs.
  set by dynamic_debug_init() for builtins.
  or by kernel/module/main:load_info() for loadable modules.

. struct ddebug_class_user
  contains: user-module-name, ref to classmap-defn
  dyndbg finds drm-driver's use of a classmap, gets/applies its settings

. struct ddebug_class_map gets .knob ptr to ddebug_class_param.
  compiled null, init'd under ddebug_add_module()
  allows finding drm.debug setting.

. vmlinux.lds.h additions: linker symbols, KEEP for new section

dynamic_debug.c:

ddebug_attach_module_classes():
  as before
  foreach __dyndbg_classes: ddebug_find_kparam(classmap*)

ddebug_attach_client_module_classes():
  foreach __dyndbg_class_refs: ddebug_param_load_dependent_class(classmap*)
  called after list-add to ddebug-tables.

ddebug_load_dependent_class():

This applies >controls to the module, it needs the module to be
present in the ddebug-tables list so that ddebug_change can apply the
changes to it.  So in ddebug_add_module, call 2nd fn *after* adding
the ddebug_table to the list.

ddebug_find_kparam(classmap*):

Finds the kernel-param / sysfs-node that controls the classmap, by
verifying that dyndbg's kparam-ops are used by the kparam.  The found
kparams arg is our ddebug_class_param, and has a ref to the state-var
under the sysfs-node.

ddebug_match_attach_kparam():

tests that kparam.ops == dyndbg's, then casts arg to
ddebug_class_param, and tests modnames for equality.

ddebug_param_load_dependent_class(struct ddebug_class_user*):

Called on class_refs entries, these classmaps have already been seen
by ddebug_find_kparam() which has wired the classmap.knob to the kparam.
So this fn just calls ddebug_apply_class_bitmap() on the state-var.

ddebug_find_valid_class():

This helps ddebug_change(), doing the search over classmaps, looking
for the class given to >control.  So now it searches over
__dyndbg_class_refs[] after __dyndbg_classes[].

Thats the theory anyway.  things are still broken (differently) for
both builtins and loadables.  For loadables, the >control is applied,
but doesnt alter any callsites.

Signed-off-by: Jim Cromie <jim.cro...@gmail.com>
---
 include/asm-generic/vmlinux.lds.h |   3 +
 include/linux/dynamic_debug.h     |  41 ++++++---
 kernel/module/main.c              |   2 +
 lib/dynamic_debug.c               | 137 +++++++++++++++++++++++++++---
 4 files changed, 157 insertions(+), 26 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h 
b/include/asm-generic/vmlinux.lds.h
index 3dc5824141cd..7100701fb68c 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -363,6 +363,9 @@
        __start___dyndbg_classes = .;                                   \
        KEEP(*(__dyndbg_classes))                                       \
        __stop___dyndbg_classes = .;                                    \
+       __start___dyndbg_class_refs = .;                                \
+       KEEP(*(__dyndbg_class_refs))                                    \
+       __stop___dyndbg_class_refs = .;                                 \
        __start___dyndbg = .;                                           \
        KEEP(*(__dyndbg))                                               \
        __stop___dyndbg = .;                                            \
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 1cdfd62fd2e4..dabbe1a9180c 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -81,8 +81,10 @@ enum ddebug_class_map_type {
 };
 
 struct ddebug_class_map {
-       struct module *mod;
-       const char *mod_name;   /* needed for builtins */
+       struct list_head link;
+       struct module *mod;                     /* NULL for builtins */
+       const char *mod_name;
+       struct ddebug_class_param *dc_parm;     /* controlling sysfs node */
        const char **class_names;
        const int length;
        const int base;         /* index of 1st .class_id, allows split/shared 
space */
@@ -99,8 +101,8 @@ struct ddebug_class_map {
  * @classes: class-names used to control class'd prdbgs
  */
 #define DYNDBG_CLASSMAP_DEFINE(_var, _maptype, _base, ...)             \
-       static const char *_var##_classnames[] = { __VA_ARGS__ };       \
-       static struct ddebug_class_map __aligned(8) __used              \
+       const char *_var##_classnames[] = { __VA_ARGS__ };              \
+       struct ddebug_class_map __aligned(8) __used                     \
                __section("__dyndbg_classes") _var = {                  \
                .mod = THIS_MODULE,                                     \
                .mod_name = KBUILD_MODNAME,                             \
@@ -108,24 +110,37 @@ struct ddebug_class_map {
                .map_type = _maptype,                                   \
                .length = ARRAY_SIZE(_var##_classnames),                \
                .class_names = _var##_classnames,                       \
-       }
+       };                                                              \
+       EXPORT_SYMBOL(_var)
 
-/*
- * refer to the classmap instantiated once, by the macro above.  This
- * distinguishes the multiple users of drm.debug from the single
- * definition, allowing them to specialize.  ATM its a pass-thru, but
- * it should help regularize the admittedly wierd sharing by identical
- * definitions.
+struct ddebug_class_user {
+       char *user_mod_name;
+       struct ddebug_class_map *map;
+};
+/**
+ * DYNDBG_CLASSMAP_USE - Use a classmap DEFINEd in another module.
+ * This lets dyndbg initialize the dependent module's prdbgs from the
+ * other module's controlling sysfs node.
  */
-#define DYNDBG_CLASSMAP_USE(_var, _maptype, _base, ...)                \
-       DYNDBG_CLASSMAP_DEFINE(_var, _maptype, _base, __VA_ARGS__)
+#define DYNDBG_CLASSMAP_USE(_var, ...)                                 \
+       DYNDBG_CLASSMAP_USE_(_var, __UNIQUE_ID(ddebug_class_user),      \
+                            __VA_ARGS__)
+#define DYNDBG_CLASSMAP_USE_(_var, _uname, ...)                                
\
+       extern struct ddebug_class_map _var[];                          \
+       static struct ddebug_class_user __used                          \
+       __section("__dyndbg_class_refs") _uname = {                     \
+               .user_mod_name = KBUILD_MODNAME,                        \
+               .map = _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_refs;
        unsigned int num_descs;
        unsigned int num_classes;
+       unsigned int num_class_refs;
 };
 
 struct ddebug_class_param {
diff --git a/kernel/module/main.c b/kernel/module/main.c
index d02d39c7174e..ee4f85a3b8f0 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2111,6 +2111,8 @@ static int find_module_sections(struct module *mod, 
struct load_info *info)
                                        sizeof(*info->dyndbg.descs), 
&info->dyndbg.num_descs);
        info->dyndbg.classes = section_objs(info, "__dyndbg_classes",
                                        sizeof(*info->dyndbg.classes), 
&info->dyndbg.num_classes);
+       info->dyndbg.class_refs = section_objs(info, "__dyndbg_class_refs",
+                                       sizeof(*info->dyndbg.class_refs), 
&info->dyndbg.num_class_refs);
 
        return 0;
 }
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 445f25ef2461..45b8414fa130 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_refs[];
+extern struct ddebug_class_user __stop___dyndbg_class_refs[];
 
 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_refs;
+       unsigned int num_ddebugs, num_classes, num_class_refs;
 };
 
 struct ddebug_query {
@@ -153,15 +156,23 @@ static struct ddebug_class_map 
*ddebug_find_valid_class(struct ddebug_table cons
                                                        __outvar int *class_id)
 {
        struct ddebug_class_map *map;
+       struct ddebug_class_user *cli;
        int i, idx;
 
-       for (map = dt->classes, i = 0; i < dt->num_classes; i++, map++) {
+       for (i = 0, map = dt->classes; i < dt->num_classes; i++, map++) {
                idx = match_string(map->class_names, map->length, class_string);
                if (idx >= 0) {
                        *class_id = idx + map->base;
                        return map;
                }
        }
+       for (i = 0, cli = dt->class_refs; i < dt->num_class_refs; i++, cli++) {
+               idx = match_string(cli->map->class_names, cli->map->length, 
class_string);
+               if (idx >= 0) {
+                       *class_id = idx + map->base;
+                       return map;
+               }
+       }
        *class_id = -ENOENT;
        return NULL;
 }
@@ -603,7 +614,7 @@ 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\n", *new_bits, *old_bits);
 
        for (bi = 0; bi < map->length; bi++) {
                if (test_bit(bi, new_bits) == test_bit(bi, old_bits))
@@ -1106,13 +1117,19 @@ 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 = iter->table->classes;
-       int i, nc = iter->table->num_classes;
+       struct ddebug_table *dt = iter->table;
+       struct ddebug_class_map *map;
+       struct ddebug_class_user *cli;
+       int i;
 
-       for (i = 0; i < nc; i++, map++)
+       for (i = 0, map = dt->classes; 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 = 0, cli = dt->class_refs; i < dt->num_class_refs; i++, cli++)
+               if (class_in_range(dp->class_id, cli->map))
+                       return cli->map->class_names[dp->class_id - map->base];
+
        return NULL;
 }
 
@@ -1193,6 +1210,54 @@ static const struct proc_ops proc_fops = {
        .proc_write = ddebug_proc_write
 };
 
+static void ddebug_match_attach_kparam(const struct kernel_param *kp,
+                                      struct ddebug_class_map *cm)
+{
+       struct ddebug_class_param *dcp;
+
+       if (kp->ops != &param_ops_dyndbg_classes)
+               return;
+       dcp = (struct ddebug_class_param *)kp->arg;
+
+       if (!strncmp(cm->mod_name, dcp->map->mod_name, strlen(cm->mod_name))) {
+               cm->dc_parm = dcp;
+               v2pr_info("controlling kp: %s.%s\n", cm->mod_name, kp->name);
+       } else
+               v2pr_info("not this: %s %s\n", cm->mod_name, kp->name);
+}
+
+static void ddebug_find_kparam(struct ddebug_class_map *cm)
+{
+       const struct kernel_param *kp;
+       int i;
+
+       if (cm->mod) {
+               v2pr_info("loaded class: module:%s base:%d len:%d ty:%d\n",
+                         cm->mod_name, cm->base, cm->length, cm->map_type);
+
+               for (i = 0, kp = cm->mod->kp; i < cm->mod->num_kp; i++, kp++)
+                       ddebug_match_attach_kparam(kp, cm);
+       } else {
+               v2pr_info("builtin class: module:%s base:%d len:%d ty:%d\n",
+                         cm->mod_name, cm->base, cm->length, cm->map_type);
+
+               for (kp = __start___param; kp < __stop___param; kp++)
+                       ddebug_match_attach_kparam(kp, cm);
+       }
+}
+
+static void ddebug_param_load_dependent_class(const struct ddebug_class_user 
*cli)
+{
+       unsigned long new_bits, old_bits = 0;
+
+       new_bits = *cli->map->dc_parm->bits;
+
+       vpr_info("%s needs %s, 0x%lx\n", cli->user_mod_name,
+                cli->map->mod_name, new_bits);
+
+       ddebug_apply_class_bitmap(cli->map->dc_parm, &new_bits, &old_bits, 
cli->user_mod_name);
+}
+
 static void ddebug_attach_module_classes(struct ddebug_table *dt, struct 
_ddebug_info *di)
 {
        struct ddebug_class_map *cm;
@@ -1203,20 +1268,60 @@ static void ddebug_attach_module_classes(struct 
ddebug_table *dt, struct _ddebug
         * the builtin/modular classmap vector/section.  Save the start
         * and length of the subrange at its edges.
         */
-       for (cm = di->classes, i = 0; i < di->num_classes; i++, cm++) {
+       for (i = 0, cm = di->classes; i < di->num_classes; i++, cm++) {
 
                if (!strcmp(cm->mod_name, dt->mod_name)) {
                        if (!nc) {
-                               v2pr_info("start subrange, class[%d]: module:%s 
base:%d len:%d ty:%d\n",
-                                         i, cm->mod_name, cm->base, 
cm->length, cm->map_type);
                                dt->classes = cm;
+                               v2pr_info("classes start: class[%d]: module:%s 
base:%d len:%d ty:%d\n",
+                                         i, cm->mod_name, cm->base, 
cm->length, cm->map_type);
                        }
+                       ddebug_find_kparam(cm);
                        nc++;
                }
        }
-       if (nc) {
-               dt->num_classes = nc;
+       dt->num_classes = nc;
+       if (nc)
                vpr_info("module:%s attached %d classes\n", dt->mod_name, nc);
+}
+
+static void ddebug_attach_client_module_classes(struct ddebug_table *dt, 
struct _ddebug_info *di)
+{
+       struct ddebug_class_user *cli;
+       int i;
+
+       for (i = 0, cli = di->class_refs; i < di->num_class_refs; i++, cli++) {
+
+               if (!cli) {
+                       v2pr_info("NO CLI\n");
+                       continue;
+               }
+               if (!cli->map) {
+                       v2pr_info("NO CLI map\n");
+                       continue;
+               }
+               if (!cli->user_mod_name) {
+                       v2pr_info("NO CLI name\n");
+                       continue;
+               }
+
+               if (!strcmp(cli->user_mod_name, dt->mod_name)) {
+
+                       v2pr_info("class_ref[%d] %s -> %s\n", i,
+                                 cli->user_mod_name, cli->map->mod_name);
+
+                       ddebug_param_load_dependent_class(cli);
+
+                       dt->class_refs = cli;
+                       /*
+                        * allow only 1 ref right now, see if that
+                        * works.  dont want to deal with vector,len
+                        * now, maybe inadequate anyway.
+                        */
+                       v2pr_info("break on %d/%d\n", i, di->num_class_refs);
+                       dt->num_class_refs = 1;
+                       break;
+               }
        }
 }
 
@@ -1229,7 +1334,8 @@ static int __ddebug_add_module(struct _ddebug_info *di, 
unsigned int base,
 {
        struct ddebug_table *dt;
 
-       v3pr_info("add-module: %s.%d sites\n", modname, di->num_descs);
+       v3pr_info("add-module: %s %d sites %d.%d\n", modname, di->num_descs,
+                 di->num_classes, di->num_class_refs);
        if (!di->num_descs) {
                v3pr_info(" skip %s\n", modname);
                return 0;
@@ -1252,13 +1358,16 @@ static int __ddebug_add_module(struct _ddebug_info *di, 
unsigned int base,
 
        INIT_LIST_HEAD(&dt->link);
 
-       if (di->classes && di->num_classes)
+       if (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 (di->num_class_refs)
+               ddebug_attach_client_module_classes(dt, di);
+
        vpr_info("%3u debug prints in module %s\n", di->num_descs, modname);
        return 0;
 }
@@ -1384,8 +1493,10 @@ static int __init dynamic_debug_init(void)
        struct _ddebug_info di = {
                .descs = __start___dyndbg,
                .classes = __start___dyndbg_classes,
+               .class_refs = __start___dyndbg_class_refs,
                .num_descs = __stop___dyndbg - __start___dyndbg,
                .num_classes = __stop___dyndbg_classes - 
__start___dyndbg_classes,
+               .num_class_refs = __stop___dyndbg_class_refs - 
__start___dyndbg_class_refs,
        };
 
        if (&__start___dyndbg == &__stop___dyndbg) {
-- 
2.38.1

Reply via email to