Commit 7deabd67 authored by Jason Baron's avatar Jason Baron Committed by Luis Chamberlain

dyndbg: use the module notifier callbacks

Bring dynamic debug in line with other subsystems by using the module
notifier callbacks. This results in a net decrease in core module
code.

Additionally, Jim Cromie has a new dynamic debug classmap feature,
which requires that jump labels be initialized prior to dynamic debug.
Specifically, the new feature toggles a jump label from the existing
dynamic_debug_setup() function. However, this does not currently work
properly, because jump labels are initialized via the
'module_notify_list' notifier chain, which is invoked after the
current call to dynamic_debug_setup(). Thus, this patch ensures that
jump labels are initialized prior to dynamic debug by setting the
dynamic debug notifier priority to 0, while jump labels have the
higher priority of 1.

Tested by Jim using his new test case, and I've verfied the correct
printing via: # modprobe test_dynamic_debug dyndbg.

Link: https://lore.kernel.org/lkml/20230113193016.749791-21-jim.cromie@gmail.com/Reported-by: default avatarkernel test robot <lkp@intel.com>
Link: https://lore.kernel.org/oe-kbuild-all/202302190427.9iIK2NfJ-lkp@intel.com/Tested-by: default avatarJim Cromie <jim.cromie@gmail.com>
Reviewed-by: default avatarVincenzo Palazzo <vincenzopalazzodev@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
CC: Jim Cromie <jim.cromie@gmail.com>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJason Baron <jbaron@akamai.com>
Signed-off-by: default avatarLuis Chamberlain <mcgrof@kernel.org>
parent 85c37208
...@@ -130,9 +130,6 @@ struct ddebug_class_param { ...@@ -130,9 +130,6 @@ struct ddebug_class_param {
#if defined(CONFIG_DYNAMIC_DEBUG_CORE) #if defined(CONFIG_DYNAMIC_DEBUG_CORE)
int ddebug_add_module(struct _ddebug_info *dyndbg, const char *modname);
extern int ddebug_remove_module(const char *mod_name);
extern __printf(2, 3) extern __printf(2, 3)
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...); void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
...@@ -304,16 +301,6 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp); ...@@ -304,16 +301,6 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp);
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/printk.h> #include <linux/printk.h>
static inline int ddebug_add_module(struct _ddebug_info *dinfo, const char *modname)
{
return 0;
}
static inline int ddebug_remove_module(const char *mod)
{
return 0;
}
static inline int ddebug_dyndbg_module_param_cb(char *param, char *val, static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
const char *modname) const char *modname)
{ {
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/tracepoint-defs.h> #include <linux/tracepoint-defs.h>
#include <linux/srcu.h> #include <linux/srcu.h>
#include <linux/static_call_types.h> #include <linux/static_call_types.h>
#include <linux/dynamic_debug.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <asm/module.h> #include <asm/module.h>
...@@ -579,6 +580,9 @@ struct module { ...@@ -579,6 +580,9 @@ struct module {
struct error_injection_entry *ei_funcs; struct error_injection_entry *ei_funcs;
unsigned int num_ei_funcs; unsigned int num_ei_funcs;
#endif #endif
#ifdef CONFIG_DYNAMIC_DEBUG_CORE
struct _ddebug_info dyndbg_info;
#endif
} ____cacheline_aligned __randomize_layout; } ____cacheline_aligned __randomize_layout;
#ifndef MODULE_ARCH_INIT #ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {} #define MODULE_ARCH_INIT {}
......
...@@ -45,7 +45,6 @@ extern const struct kernel_symbol __stop___ksymtab_gpl[]; ...@@ -45,7 +45,6 @@ extern const struct kernel_symbol __stop___ksymtab_gpl[];
extern const s32 __start___kcrctab[]; extern const s32 __start___kcrctab[];
extern const s32 __start___kcrctab_gpl[]; extern const s32 __start___kcrctab_gpl[];
#include <linux/dynamic_debug.h>
struct load_info { struct load_info {
const char *name; const char *name;
/* pointer to module in temporary copy, freed at end of load_module() */ /* pointer to module in temporary copy, freed at end of load_module() */
...@@ -55,7 +54,6 @@ struct load_info { ...@@ -55,7 +54,6 @@ struct load_info {
Elf_Shdr *sechdrs; Elf_Shdr *sechdrs;
char *secstrings, *strtab; char *secstrings, *strtab;
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs; unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
struct _ddebug_info dyndbg;
bool sig_ok; bool sig_ok;
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
unsigned long mod_kallsyms_init_off; unsigned long mod_kallsyms_init_off;
......
...@@ -1216,9 +1216,6 @@ static void free_module(struct module *mod) ...@@ -1216,9 +1216,6 @@ static void free_module(struct module *mod)
mod->state = MODULE_STATE_UNFORMED; mod->state = MODULE_STATE_UNFORMED;
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
/* Remove dynamic debug info */
ddebug_remove_module(mod->name);
/* Arch-specific cleanup. */ /* Arch-specific cleanup. */
module_arch_cleanup(mod); module_arch_cleanup(mod);
...@@ -1619,19 +1616,6 @@ static void free_modinfo(struct module *mod) ...@@ -1619,19 +1616,6 @@ static void free_modinfo(struct module *mod)
} }
} }
static void dynamic_debug_setup(struct module *mod, struct _ddebug_info *dyndbg)
{
if (!dyndbg->num_descs)
return;
ddebug_add_module(dyndbg, mod->name);
}
static void dynamic_debug_remove(struct module *mod, struct _ddebug_info *dyndbg)
{
if (dyndbg->num_descs)
ddebug_remove_module(mod->name);
}
void * __weak module_alloc(unsigned long size) void * __weak module_alloc(unsigned long size)
{ {
return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
...@@ -2137,10 +2121,14 @@ static int find_module_sections(struct module *mod, struct load_info *info) ...@@ -2137,10 +2121,14 @@ static int find_module_sections(struct module *mod, struct load_info *info)
if (section_addr(info, "__obsparm")) if (section_addr(info, "__obsparm"))
pr_warn("%s: Ignoring obsolete parameters\n", mod->name); pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
info->dyndbg.descs = section_objs(info, "__dyndbg", #ifdef CONFIG_DYNAMIC_DEBUG_CORE
sizeof(*info->dyndbg.descs), &info->dyndbg.num_descs); mod->dyndbg_info.descs = section_objs(info, "__dyndbg",
info->dyndbg.classes = section_objs(info, "__dyndbg_classes", sizeof(*mod->dyndbg_info.descs),
sizeof(*info->dyndbg.classes), &info->dyndbg.num_classes); &mod->dyndbg_info.num_descs);
mod->dyndbg_info.classes = section_objs(info, "__dyndbg_classes",
sizeof(*mod->dyndbg_info.classes),
&mod->dyndbg_info.num_classes);
#endif
return 0; return 0;
} }
...@@ -2824,7 +2812,6 @@ static int load_module(struct load_info *info, const char __user *uargs, ...@@ -2824,7 +2812,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
} }
init_build_id(mod, info); init_build_id(mod, info);
dynamic_debug_setup(mod, &info->dyndbg);
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */ /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
ftrace_module_init(mod); ftrace_module_init(mod);
...@@ -2888,7 +2875,6 @@ static int load_module(struct load_info *info, const char __user *uargs, ...@@ -2888,7 +2875,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
ddebug_cleanup: ddebug_cleanup:
ftrace_release_mod(mod); ftrace_release_mod(mod);
dynamic_debug_remove(mod, &info->dyndbg);
synchronize_rcu(); synchronize_rcu();
kfree(mod->args); kfree(mod->args);
free_arch_cleanup: free_arch_cleanup:
......
...@@ -1223,7 +1223,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt, ...@@ -1223,7 +1223,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
* Allocate a new ddebug_table for the given module * Allocate a new ddebug_table for the given module
* and add it to the global list. * and add it to the global list.
*/ */
static int __ddebug_add_module(struct _ddebug_info *di, const char *modname) static int ddebug_add_module(struct _ddebug_info *di, const char *modname)
{ {
struct ddebug_table *dt; struct ddebug_table *dt;
...@@ -1262,11 +1262,6 @@ static int __ddebug_add_module(struct _ddebug_info *di, const char *modname) ...@@ -1262,11 +1262,6 @@ static int __ddebug_add_module(struct _ddebug_info *di, const char *modname)
return 0; return 0;
} }
int ddebug_add_module(struct _ddebug_info *di, const char *modname)
{
return __ddebug_add_module(di, modname);
}
/* helper for ddebug_dyndbg_(boot|module)_param_cb */ /* helper for ddebug_dyndbg_(boot|module)_param_cb */
static int ddebug_dyndbg_param_cb(char *param, char *val, static int ddebug_dyndbg_param_cb(char *param, char *val,
const char *modname, int on_err) const char *modname, int on_err)
...@@ -1313,11 +1308,13 @@ static void ddebug_table_free(struct ddebug_table *dt) ...@@ -1313,11 +1308,13 @@ static void ddebug_table_free(struct ddebug_table *dt)
kfree(dt); kfree(dt);
} }
#ifdef CONFIG_MODULES
/* /*
* Called in response to a module being unloaded. Removes * Called in response to a module being unloaded. Removes
* any ddebug_table's which point at the module. * any ddebug_table's which point at the module.
*/ */
int ddebug_remove_module(const char *mod_name) static int ddebug_remove_module(const char *mod_name)
{ {
struct ddebug_table *dt, *nextdt; struct ddebug_table *dt, *nextdt;
int ret = -ENOENT; int ret = -ENOENT;
...@@ -1336,6 +1333,33 @@ int ddebug_remove_module(const char *mod_name) ...@@ -1336,6 +1333,33 @@ int ddebug_remove_module(const char *mod_name)
return ret; return ret;
} }
static int ddebug_module_notify(struct notifier_block *self, unsigned long val,
void *data)
{
struct module *mod = data;
int ret = 0;
switch (val) {
case MODULE_STATE_COMING:
ret = ddebug_add_module(&mod->dyndbg_info, mod->name);
if (ret)
WARN(1, "Failed to allocate memory: dyndbg may not work properly.\n");
break;
case MODULE_STATE_GOING:
ddebug_remove_module(mod->name);
break;
}
return notifier_from_errno(ret);
}
static struct notifier_block ddebug_module_nb = {
.notifier_call = ddebug_module_notify,
.priority = 0, /* dynamic debug depends on jump label */
};
#endif /* CONFIG_MODULES */
static void ddebug_remove_all_tables(void) static void ddebug_remove_all_tables(void)
{ {
mutex_lock(&ddebug_lock); mutex_lock(&ddebug_lock);
...@@ -1387,6 +1411,14 @@ static int __init dynamic_debug_init(void) ...@@ -1387,6 +1411,14 @@ static int __init dynamic_debug_init(void)
.num_classes = __stop___dyndbg_classes - __start___dyndbg_classes, .num_classes = __stop___dyndbg_classes - __start___dyndbg_classes,
}; };
#ifdef CONFIG_MODULES
ret = register_module_notifier(&ddebug_module_nb);
if (ret) {
pr_warn("Failed to register dynamic debug module notifier\n");
return ret;
}
#endif /* CONFIG_MODULES */
if (&__start___dyndbg == &__stop___dyndbg) { if (&__start___dyndbg == &__stop___dyndbg) {
if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) { if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n"); pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n");
...@@ -1407,7 +1439,7 @@ static int __init dynamic_debug_init(void) ...@@ -1407,7 +1439,7 @@ static int __init dynamic_debug_init(void)
mod_ct++; mod_ct++;
di.num_descs = mod_sites; di.num_descs = mod_sites;
di.descs = iter_mod_start; di.descs = iter_mod_start;
ret = __ddebug_add_module(&di, modname); ret = ddebug_add_module(&di, modname);
if (ret) if (ret)
goto out_err; goto out_err;
...@@ -1418,7 +1450,7 @@ static int __init dynamic_debug_init(void) ...@@ -1418,7 +1450,7 @@ static int __init dynamic_debug_init(void)
} }
di.num_descs = mod_sites; di.num_descs = mod_sites;
di.descs = iter_mod_start; di.descs = iter_mod_start;
ret = __ddebug_add_module(&di, modname); ret = ddebug_add_module(&di, modname);
if (ret) if (ret)
goto out_err; goto out_err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment