Skip to content

Commit

Permalink
dyndbg: use the module notifier callbacks
Browse files Browse the repository at this point in the history
As part of Jim Cromie's new dynamic debug classmap feature, the new code
tries to toggle a jump label from dynamic_debug_setup(). However,
dynamic_debug_setup() is called before the 'module_notify_list' notifier
chain is invoked. And jump labels are initialized via the module notifier
chain. Note this is an issue for a new feature not yet merged and doesn't
affect any existing codepaths.

We could just move dynamic_debug_setup() earlier in load_module(). But
let's instead ensure the ordering via the 'priority' in the module list
notifier. This brings dynamic debug more in line with other subsystems and
pulls code out of the core module code.

Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
CC: Jim Cromie <jim.cromie@gmail.com>
Link: https://lore.kernel.org/lkml/20230113193016.749791-21-jim.cromie@gmail.com/
Signed-off-by: Jason Baron <jbaron@akamai.com>
  • Loading branch information
almostivan authored and jimc committed Feb 16, 2023
1 parent be9ba4a commit cf693cf
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 44 deletions.
13 changes: 0 additions & 13 deletions include/linux/dynamic_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,6 @@ struct ddebug_class_param {

#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)
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);

Expand Down Expand Up @@ -304,16 +301,6 @@ int param_get_dyndbg_classes(char *buffer, const struct kernel_param *kp);
#include <linux/errno.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,
const char *modname)
{
Expand Down
3 changes: 3 additions & 0 deletions include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,9 @@ struct module {
struct error_injection_entry *ei_funcs;
unsigned int num_ei_funcs;
#endif
#ifdef CONFIG_DYNAMIC_DEBUG_CORE
struct _ddebug_info dyndbg_info;
#endif
} ____cacheline_aligned __randomize_layout;
#ifndef MODULE_ARCH_INIT
#define MODULE_ARCH_INIT {}
Expand Down
1 change: 0 additions & 1 deletion kernel/module/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ struct load_info {
Elf_Shdr *sechdrs;
char *secstrings, *strtab;
unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs;
struct _ddebug_info dyndbg;
bool sig_ok;
#ifdef CONFIG_KALLSYMS
unsigned long mod_kallsyms_init_off;
Expand Down
30 changes: 8 additions & 22 deletions kernel/module/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1157,9 +1157,6 @@ static void free_module(struct module *mod)
mod->state = MODULE_STATE_UNFORMED;
mutex_unlock(&module_mutex);

/* Remove dynamic debug info */
ddebug_remove_module(mod->name);

/* Arch-specific cleanup. */
module_arch_cleanup(mod);

Expand Down Expand Up @@ -1591,19 +1588,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)
{
return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
Expand Down Expand Up @@ -2109,10 +2093,14 @@ static int find_module_sections(struct module *mod, struct load_info *info)
if (section_addr(info, "__obsparm"))
pr_warn("%s: Ignoring obsolete parameters\n", mod->name);

info->dyndbg.descs = section_objs(info, "__dyndbg",
sizeof(*info->dyndbg.descs), &info->dyndbg.num_descs);
info->dyndbg.classes = section_objs(info, "__dyndbg_classes",
sizeof(*info->dyndbg.classes), &info->dyndbg.num_classes);
#ifdef CONFIG_DYNAMIC_DEBUG_CORE
mod->dyndbg_info.descs = section_objs(info, "__dyndbg",
sizeof(*mod->dyndbg_info.descs),
&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;
}
Expand Down Expand Up @@ -2824,7 +2812,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
}

init_build_id(mod, info);
dynamic_debug_setup(mod, &info->dyndbg);

/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
ftrace_module_init(mod);
Expand Down Expand Up @@ -2888,7 +2875,6 @@ static int load_module(struct load_info *info, const char __user *uargs,

ddebug_cleanup:
ftrace_release_mod(mod);
dynamic_debug_remove(mod, &info->dyndbg);
synchronize_rcu();
kfree(mod->args);
free_arch_cleanup:
Expand Down
48 changes: 40 additions & 8 deletions lib/dynamic_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ static void ddebug_attach_module_classes(struct ddebug_table *dt,
* Allocate a new ddebug_table for the given module
* 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;

Expand Down Expand Up @@ -1262,11 +1262,6 @@ static int __ddebug_add_module(struct _ddebug_info *di, const char *modname)
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 */
static int ddebug_dyndbg_param_cb(char *param, char *val,
const char *modname, int on_err)
Expand Down Expand Up @@ -1336,6 +1331,35 @@ int ddebug_remove_module(const char *mod_name)
return ret;
}

#ifdef CONFIG_MODULES

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)
{
mutex_lock(&ddebug_lock);
Expand Down Expand Up @@ -1387,6 +1411,14 @@ static int __init dynamic_debug_init(void)
.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 (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) {
pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n");
Expand All @@ -1407,7 +1439,7 @@ static int __init dynamic_debug_init(void)
mod_ct++;
di.num_descs = mod_sites;
di.descs = iter_mod_start;
ret = __ddebug_add_module(&di, modname);
ret = ddebug_add_module(&di, modname);
if (ret)
goto out_err;

Expand All @@ -1418,7 +1450,7 @@ static int __init dynamic_debug_init(void)
}
di.num_descs = mod_sites;
di.descs = iter_mod_start;
ret = __ddebug_add_module(&di, modname);
ret = ddebug_add_module(&di, modname);
if (ret)
goto out_err;

Expand Down

0 comments on commit cf693cf

Please sign in to comment.