DRM has always had /sys/module/drm/parameters/debug (ie drm.debug). Without dyndbg, this is their only control point. One could presume they like it - in any case its a system/user interface, ie ABI.
With dyndbg enabled, drm calls DYNAMIC_DEBUG_CLASSMAP_PARAM() to create the drm.debug kparam, wired to our param-handler, which writes a "class FOO" query for each bit in the classmap. Since no new interface was ever contemplated, this is using >control. Since drm.debug is ABI, we should not allow class-less queries to alter our implementation of its settings. This patch provides that protection, *only* when theres a PARAM. This is the user, expressing their wish for easy control of their entire classmap. They also wish to trust its settings. Classes without a PARAM are unprotected, allowing admins their shortcuts. No such use-cases exist yet. Anyway, this patch does: 1. adds struct _ddebug_class_map.controlling_param 2. set it in ddebug_match_apply_kparam(), during modprobe/init, when options like drm.debug are handled. 3. ddebug_class_has_param() checks .controlling_param 4. ddebug_class_wants_protection() macro renames 3. 5. ddebug_change() calls 4 when needed. IE when applying a class-less query to a class'd pr_debug / drm_dbg_<T> Historical Summary: -v0 - before classmaps. no special case keywords -v1 - "class DEFAULT" is assumed if not mentioned. this protects classes from class-less queries -v2.pre-this-patch - protection macro'd to false -v2.with-this-patch - sysfs knob decides -v2.speculative - module decides wrt classmap protection seems unneeded now, TBD NOTE: protection is only against class-less queries, explicit "class FOO" adjustments are allowed (that is the mechanism). Signed-off-by: Jim Cromie <jim.cro...@gmail.com> --- v3 - new patch --- include/linux/dynamic_debug.h | 3 +- lib/dynamic_debug.c | 55 ++++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h index 2d87cca27544..d34a44ff961a 100644 --- a/include/linux/dynamic_debug.h +++ b/include/linux/dynamic_debug.h @@ -89,8 +89,9 @@ enum ddebug_class_map_type { * usually by stringifying the enum-vals. Modules with multiple * classmaps must arrange to share the 0..62 class_id space. */ - +struct _ddebug_class_param; struct _ddebug_class_map { + struct _ddebug_class_param *controlling_param; const struct module *mod; /* NULL for builtins */ const char *mod_name; const char **class_names; diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 54f462cf41b0..3eb4a8abeb33 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c @@ -198,16 +198,26 @@ ddebug_find_valid_class(struct _ddebug_info const *di, const char *query_class, } /* - * classmaps-v1 protected classes from changes by legacy commands - * (those selecting _DPRINTK_CLASS_DFLT by omission), v2 undoes that - * special treatment. State so explicitly. Later we could give - * modules the choice to protect their classes or to keep v2 behavior. + * classmaps-V1 protected classes from changes by legacy commands + * (those selecting _DPRINTK_CLASS_DFLT by omission). This had the + * downside that saying "class FOO" for every change can get tedious. + * + * V2 is smarter, it protects class-maps if the defining module also + * calls DYNAMIC_DEBUG_CLASSMAP_PARAM to create a sysfs parameter. + * Since they want the knob, we should assume they intend to use it + * (in preference to "class FOO +p" >control), and want to trust its + * settings. + * This gives protection when its useful, and not when its just tedious. */ -static inline bool ddebug_client_module_protects_classes(const struct ddebug_table *dt) +static inline bool ddebug_class_has_param(const struct _ddebug_class_map *map) { - return false; + return !!(map->controlling_param); } +/* re-framed as a policy choice */ +#define ddebug_class_wants_protection(map) \ + ddebug_class_has_param(map) + /* * Search the tables for _ddebug's which match the given `query' and * apply the `flags' and `mask' to them. Returns number of matching @@ -250,7 +260,7 @@ static int ddebug_change(const struct ddebug_query *query, struct flag_settings /* site.class != given class */ continue; /* legacy query, class'd site */ - else if (ddebug_client_module_protects_classes(dt)) + else if (ddebug_class_wants_protection(map)) continue; /* allow change on class'd pr_debug */ } @@ -650,6 +660,7 @@ 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, const unsigned long *new_bits, const unsigned long old_bits, @@ -1228,25 +1239,36 @@ static void ddebug_sync_classbits(const struct kernel_param *kp, const char *mod } } -static void ddebug_match_apply_kparam(const struct kernel_param *kp, - const struct _ddebug_class_map *map, - const char *mod_name) +static struct _ddebug_class_param * +ddebug_get_classmap_kparam(const struct kernel_param *kp, + const struct _ddebug_class_map *map) { struct _ddebug_class_param *dcp; if (kp->ops != ¶m_ops_dyndbg_classes) - return; + return false; dcp = (struct _ddebug_class_param *)kp->arg; - if (map == dcp->map) { + return (map == dcp->map) + ? dcp : (struct _ddebug_class_param *)NULL; +} + +static void ddebug_match_apply_kparam(const struct kernel_param *kp, + struct _ddebug_class_map *map, + const char *mod_name) +{ + struct _ddebug_class_param *dcp = ddebug_get_classmap_kparam(kp, map); + + if (dcp) { + map->controlling_param = dcp; v2pr_info(" kp:%s.%s =0x%lx", mod_name, kp->name, *dcp->bits); vpr_cm_info(map, " %s mapped to: ", mod_name); ddebug_sync_classbits(kp, mod_name); } } -static void ddebug_apply_params(const struct _ddebug_class_map *cm, const char *mod_name) +static void ddebug_apply_params(struct _ddebug_class_map *cm, const char *mod_name) { const struct kernel_param *kp; #if IS_ENABLED(CONFIG_MODULES) @@ -1266,6 +1288,13 @@ static void ddebug_apply_params(const struct _ddebug_class_map *cm, const char * } } +/* + * called from add_module, ie early. it can find controlling kparams, + * which can/does? enable protection of this classmap from class-less + * queries, on the grounds that the user created the kparam, means to + * use it, and expects it to reflect reality. We should oblige him, + * and protect those classmaps from classless "-p" changes. + */ static void ddebug_apply_class_maps(const struct _ddebug_info *di) { struct _ddebug_class_map *cm; -- 2.49.0