diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2014-11-09 23:58:29 +0100 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2014-11-11 07:37:46 +0100 |
commit | 0286b5ea125e58b4797747f688949c05394412e8 (patch) | |
tree | def974e29b25f8a7a00da7b39f5b18bac93af98d /lib/bug.c | |
parent | module: Unlink module with RCU synchronizing instead of stop_machine (diff) | |
download | linux-0286b5ea125e58b4797747f688949c05394412e8.tar.xz linux-0286b5ea125e58b4797747f688949c05394412e8.zip |
lib/bug: Use RCU list ops for module_bug_list
Actually since module_bug_list should be used in BUG context,
we may not need this. But for someone who want to use this
from normal context, this makes module_bug_list an RCU list.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'lib/bug.c')
-rw-r--r-- | lib/bug.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/lib/bug.c b/lib/bug.c index d1d7c7878900..0c3bd9552b6f 100644 --- a/lib/bug.c +++ b/lib/bug.c @@ -64,16 +64,22 @@ static LIST_HEAD(module_bug_list); static const struct bug_entry *module_find_bug(unsigned long bugaddr) { struct module *mod; + const struct bug_entry *bug = NULL; - list_for_each_entry(mod, &module_bug_list, bug_list) { - const struct bug_entry *bug = mod->bug_table; + rcu_read_lock(); + list_for_each_entry_rcu(mod, &module_bug_list, bug_list) { unsigned i; + bug = mod->bug_table; for (i = 0; i < mod->num_bugs; ++i, ++bug) if (bugaddr == bug_addr(bug)) - return bug; + goto out; } - return NULL; + bug = NULL; +out: + rcu_read_unlock(); + + return bug; } void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, @@ -99,13 +105,15 @@ void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, * Strictly speaking this should have a spinlock to protect against * traversals, but since we only traverse on BUG()s, a spinlock * could potentially lead to deadlock and thus be counter-productive. + * Thus, this uses RCU to safely manipulate the bug list, since BUG + * must run in non-interruptive state. */ - list_add(&mod->bug_list, &module_bug_list); + list_add_rcu(&mod->bug_list, &module_bug_list); } void module_bug_cleanup(struct module *mod) { - list_del(&mod->bug_list); + list_del_rcu(&mod->bug_list); } #else |