Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756635Ab0DITuz (ORCPT ); Fri, 9 Apr 2010 15:50:55 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36812 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756498Ab0DITuZ (ORCPT ); Fri, 9 Apr 2010 15:50:25 -0400 Date: Fri, 9 Apr 2010 15:49:48 -0400 From: Jason Baron To: linux-kernel@vger.kernel.org Cc: mingo@elte.hu, mathieu.desnoyers@polymtl.ca, hpa@zytor.com, tglx@linutronix.de, rostedt@goodmis.org, andi@firstfloor.org, roland@redhat.com, rth@redhat.com, mhiramat@redhat.com, fweisbec@gmail.com, avi@redhat.com Message-Id: <94f308cca88ca6c60014b49d2e70f848ef6f1f2c.1270839564.git.jbaron@redhat.com> In-Reply-To: References: Subject: [PATCH 5/9] jump label: add module support Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7029 Lines: 245 Add support for 'jump label' for modules. Signed-off-by: Jason Baron --- arch/x86/kernel/ptrace.c | 1 + include/linux/jump_label.h | 3 +- include/linux/module.h | 5 +- kernel/jump_label.c | 136 ++++++++++++++++++++++++++++++++++++++++++++ kernel/module.c | 7 ++ 5 files changed, 150 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 2d96aab..21854d2 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index 122d441..e0f968d 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h @@ -21,7 +21,8 @@ extern struct jump_entry __stop___jump_table[]; #define DEFINE_JUMP_LABEL(name) \ const char __jlstrtab_##name[] \ - __used __attribute__((section("__jump_strings"))) = #name; + __used __attribute__((section("__jump_strings"))) = #name; \ + EXPORT_SYMBOL_GPL(__jlstrtab_##name); extern void arch_jump_label_transform(struct jump_entry *entry, enum jump_label_type type); diff --git a/include/linux/module.h b/include/linux/module.h index dd618eb..6d7225e 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -339,7 +339,10 @@ struct module struct tracepoint *tracepoints; unsigned int num_tracepoints; #endif - +#ifdef __HAVE_ARCH_JUMP_LABEL + struct jump_entry *jump_entries; + unsigned int num_jump_entries; +#endif #ifdef CONFIG_TRACING const char **trace_bprintk_fmt_start; unsigned int num_trace_bprintk_fmt; diff --git a/kernel/jump_label.c b/kernel/jump_label.c index d5b7719..0714c20 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -30,6 +30,13 @@ struct jump_label_entry { const char *name; }; +struct jump_label_module_entry { + struct hlist_node hlist; + struct jump_entry *table; + int nr_entries; + struct module *mod; +}; + static void swap_jump_label_entries(struct jump_entry *previous, struct jump_entry *next) { struct jump_entry tmp; @@ -157,6 +164,17 @@ void jump_label_update(const char *name, enum jump_label_type type) arch_jump_label_transform(iter, type); iter++; } + /* eanble/disable jump labels in modules */ + hlist_for_each_entry(e_module, module_node, &(entry->modules), + hlist) { + count = e_module->nr_entries; + iter = e_module->table; + while (count--) { + if (kernel_text_address(iter->code)) + arch_jump_label_transform(iter, type); + iter++; + } + } } mutex_unlock(&jump_label_mutex); } @@ -173,4 +191,122 @@ static int init_jump_label(void) } early_initcall(init_jump_label); +#ifdef CONFIG_MODULES + +static struct jump_label_module_entry *add_jump_label_module_entry(struct jump_label_entry *entry, struct jump_entry *iter_begin, int count, struct module *mod) +{ + struct jump_label_module_entry *e; + + e = kmalloc(sizeof(struct jump_label_module_entry), GFP_KERNEL); + if (!e) + return ERR_PTR(-ENOMEM); + e->mod = mod; + e->nr_entries = count; + e->table = iter_begin; + hlist_add_head(&e->hlist, &entry->modules); + return e; +} + +static int add_jump_label_module(struct module *mod) +{ + struct jump_entry *iter, *iter_begin; + struct jump_label_entry *entry; + struct jump_label_module_entry *module_entry; + int count; + + /* if the module doesn't have jump label entries, just return */ + if (!mod->num_jump_entries) + return 0; + + sort_jump_label_entries(mod->jump_entries, + mod->jump_entries + mod->num_jump_entries); + iter = mod->jump_entries; + while (iter < mod->jump_entries + mod->num_jump_entries) { + entry = get_jump_label_entry(iter->name); + iter_begin = iter; + count = 0; + while ((iter < mod->jump_entries + mod->num_jump_entries) && + (strcmp(iter->name, iter_begin->name) == 0)) { + iter++; + count++; + } + if (!entry) { + entry = add_jump_label_entry(iter_begin->name, 0, NULL); + if (IS_ERR(entry)) + return PTR_ERR(entry); + } + module_entry = add_jump_label_module_entry(entry, iter_begin, + count, mod); + if (IS_ERR(module_entry)) + return PTR_ERR(module_entry); + } + return 0; +} + +static void remove_jump_label_module(struct module *mod) +{ + struct hlist_head *head; + struct hlist_node *node, *node_next, *module_node, *module_node_next; + struct jump_label_entry *e; + struct jump_label_module_entry *e_module; + int i; + + /* if the module doesn't have jump label entries, just return */ + if (!mod->num_jump_entries) + return; + + for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) { + head = &jump_label_table[i]; + hlist_for_each_entry_safe(e, node, node_next, head, hlist) { + hlist_for_each_entry_safe(e_module, module_node, + module_node_next, + &(e->modules), hlist) { + if (e_module->mod == mod) { + hlist_del(&e_module->hlist); + kfree(e_module); + } + } + if (hlist_empty(&e->modules) && (e->nr_entries == 0)) { + hlist_del(&e->hlist); + kfree(e); + } + } + } +} + +static int jump_label_module_notify(struct notifier_block *self, unsigned long val, void *data) +{ + struct module *mod = data; + int ret = 0; + + switch (val) { + case MODULE_STATE_COMING: + mutex_lock(&jump_label_mutex); + ret = add_jump_label_module(mod); + if (ret) + remove_jump_label_module(mod); + mutex_unlock(&jump_label_mutex); + break; + case MODULE_STATE_GOING: + mutex_lock(&jump_label_mutex); + remove_jump_label_module(mod); + mutex_unlock(&jump_label_mutex); + break; + } + return ret; +} + +struct notifier_block jump_label_module_nb = { + .notifier_call = jump_label_module_notify, + .priority = 0, +}; + +static int init_jump_label_module(void) +{ + return register_module_notifier(&jump_label_module_nb); +} +early_initcall(init_jump_label_module); + +#endif /* CONFIG_MODULES */ + #endif diff --git a/kernel/module.c b/kernel/module.c index c968d36..a8c34a2 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -55,6 +55,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -2249,6 +2250,12 @@ static noinline struct module *load_module(void __user *umod, sizeof(*mod->tracepoints), &mod->num_tracepoints); #endif +#ifdef __HAVE_ARCH_JUMP_LABEL + mod->jump_entries = section_objs(hdr, sechdrs, secstrings, + "__jump_table", + sizeof(*mod->jump_entries), + &mod->num_jump_entries); +#endif #ifdef CONFIG_EVENT_TRACING mod->trace_events = section_objs(hdr, sechdrs, secstrings, "_ftrace_events", -- 1.7.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/