* Called in response to a module being unloaded. Removes * any ddebug_table's which point at the module. */int ddebug_remove_module(const char *mod_name){ struct ddebug_table *dt, *nextdt; int ret = -ENOENT; v2pr_info("removing module \"%s\"\n", mod_name); mutex_lock(&ddebug_lock); list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) { if (dt->mod_name == mod_name) { ddebug_table_free(dt); ret = 0; break; } } mutex_unlock(&ddebug_lock); return ret;} static void ddebug_remove_all_tables(void){ mutex_lock(&ddebug_lock); while (!list_empty(&ddebug_tables)) { struct ddebug_table *dt = list_entry(ddebug_tables.next, struct ddebug_table, link); ddebug_table_free(dt); } mutex_unlock(&ddebug_lock);} static __initdata int ddebug_init_success; static int __init dynamic_debug_init_control(void){ struct proc_dir_entry *procfs_dir; struct dentry *debugfs_dir; if (!ddebug_init_success) return -ENODEV; /* Create the control file in debugfs if it is enabled */ if (debugfs_initialized()) { debugfs_dir = debugfs_create_dir("dynamic_debug", NULL); debugfs_create_file("control", 0644, debugfs_dir, NULL, &ddebug_proc_fops); } /* Also create the control file in procfs */ procfs_dir = proc_mkdir("dynamic_debug", NULL); if (procfs_dir) proc_create("control", 0644, procfs_dir, &proc_fops); return 0;} static int __init dynamic_debug_init(void){ struct _ddebug *iter, *iter_start; const char *modname = NULL; char *cmdline; int ret = 0; int n = 0, entries = 0, modct = 0; if (&__start___dyndbg == &__stop___dyndbg) { if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) { pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n"); return 1; } pr_info("Ignore empty _ddebug table in a CONFIG_DYNAMIC_DEBUG_CORE build\n"); ddebug_init_success = 1; return 0; } iter = __start___dyndbg; modname = iter->modname; iter_start = iter; for (; iter < __stop___dyndbg; iter++) { entries++; if (strcmp(modname, iter->modname)) { modct++; ret = ddebug_add_module(iter_start, n, modname); if (ret) goto out_err; n = 0; modname = iter->modname; iter_start = iter; } n++; } ret = ddebug_add_module(iter_start, n, modname); if (ret) goto out_err; ddebug_init_success = 1; vpr_info("%d modules, %d entries and %d bytes in ddebug tables, %d bytes in __dyndbg section\n", modct, entries, (int)(modct * sizeof(struct ddebug_table)), (int)(entries * sizeof(struct _ddebug))); /* apply ddebug_query boot param, dont unload tables on err */ if (ddebug_setup_string[0] != '\0') { pr_warn("ddebug_query param name is deprecated, change it to dyndbg\n"); ret = ddebug_exec_queries(ddebug_setup_string, NULL); if (ret < 0) pr_warn("Invalid ddebug boot param %s\n", ddebug_setup_string); else pr_info("%d changes by ddebug_query\n", ret); } /* now that ddebug tables are loaded, process all boot args * again to find and activate queries given in dyndbg params. * While this has already been done for known boot params, it * ignored the unknown ones (dyndbg in particular). Reusing * parse_args avoids ad-hoc parsing. This will also attempt * to activate queries for not-yet-loaded modules, which is * slightly noisy if verbose, but harmless. */ cmdline = kstrdup(saved_command_line, GFP_KERNEL); parse_args("dyndbg params", cmdline, NULL, 0, 0, 0, NULL, &ddebug_dyndbg_boot_param_cb); kfree(cmdline); return 0; out_err: ddebug_remove_all_tables(); return 0;}/* Allow early initialization for boot messages via boot param */early_initcall(dynamic_debug_init); /* Debugfs setup must be done later */fs_initcall(dynamic_debug_init_control);Lines 1001–1134 of 1134. Previous lines
* Called in response to a module being unloaded. Removes * any ddebug_table's which point at the module. */ int ddebug_remove_module(const char *mod_name) { struct ddebug_table *dt, *nextdt; int ret = -ENOENT; v2pr_info("removing module \"%s\"\n", mod_name); mutex_lock(&ddebug_lock); list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) { if (dt->mod_name == mod_name) { ddebug_table_free(dt); ret = 0; break; } } mutex_unlock(&ddebug_lock); return ret; } static void ddebug_remove_all_tables(void) { mutex_lock(&ddebug_lock); while (!list_empty(&ddebug_tables)) { struct ddebug_table *dt = list_entry(ddebug_tables.next, struct ddebug_table, link); ddebug_table_free(dt); } mutex_unlock(&ddebug_lock); } static __initdata int ddebug_init_success; static int __init dynamic_debug_init_control(void) { struct proc_dir_entry *procfs_dir; struct dentry *debugfs_dir; if (!ddebug_init_success) return -ENODEV; /* Create the control file in debugfs if it is enabled */ if (debugfs_initialized()) { debugfs_dir = debugfs_create_dir("dynamic_debug", NULL); debugfs_create_file("control", 0644, debugfs_dir, NULL, &ddebug_proc_fops); } /* Also create the control file in procfs */ procfs_dir = proc_mkdir("dynamic_debug", NULL); if (procfs_dir) proc_create("control", 0644, procfs_dir, &proc_fops); return 0; } static int __init dynamic_debug_init(void) { struct _ddebug *iter, *iter_start; const char *modname = NULL; char *cmdline; int ret = 0; int n = 0, entries = 0, modct = 0; if (&__start___dyndbg == &__stop___dyndbg) { if (IS_ENABLED(CONFIG_DYNAMIC_DEBUG)) { pr_warn("_ddebug table is empty in a CONFIG_DYNAMIC_DEBUG build\n"); return 1; } pr_info("Ignore empty _ddebug table in a CONFIG_DYNAMIC_DEBUG_CORE build\n"); ddebug_init_success = 1; return 0; } iter = __start___dyndbg; modname = iter->modname; iter_start = iter; for (; iter < __stop___dyndbg; iter++) { entries++; if (strcmp(modname, iter->modname)) { modct++; ret = ddebug_add_module(iter_start, n, modname); if (ret) goto out_err; n = 0; modname = iter->modname; iter_start = iter; } n++; } ret = ddebug_add_module(iter_start, n, modname); if (ret) goto out_err; ddebug_init_success = 1; vpr_info("%d modules, %d entries and %d bytes in ddebug tables, %d bytes in __dyndbg section\n", modct, entries, (int)(modct * sizeof(struct ddebug_table)), (int)(entries * sizeof(struct _ddebug))); /* apply ddebug_query boot param, dont unload tables on err */ if (ddebug_setup_string[0] != '\0') { pr_warn("ddebug_query param name is deprecated, change it to dyndbg\n"); ret = ddebug_exec_queries(ddebug_setup_string, NULL); if (ret < 0) pr_warn("Invalid ddebug boot param %s\n", ddebug_setup_string); else pr_info("%d changes by ddebug_query\n", ret); } /* now that ddebug tables are loaded, process all boot args * again to find and activate queries given in dyndbg params. * While this has already been done for known boot params, it * ignored the unknown ones (dyndbg in particular). Reusing * parse_args avoids ad-hoc parsing. This will also attempt * to activate queries for not-yet-loaded modules, which is * slightly noisy if verbose, but harmless. */ cmdline = kstrdup(saved_command_line, GFP_KERNEL); parse_args("dyndbg params", cmdline, NULL, 0, 0, 0, NULL, &ddebug_dyndbg_boot_param_cb); kfree(cmdline); return 0; out_err: ddebug_remove_all_tables(); return 0; } /* Allow early initialization for boot messages via boot param */ early_initcall(dynamic_debug_init); /* Debugfs setup must be done later */ fs_initcall(dynamic_debug_init_control);