diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2014-11-09 17:58:29 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2014-11-11 01:37:46 -0500 |
commit | 0286b5ea125e58b4797747f688949c05394412e8 (patch) | |
tree | def974e29b25f8a7a00da7b39f5b18bac93af98d /lib/bug.c | |
parent | 461e34aed0550fee706a9a28fb453830b5079ea0 (diff) |
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
@@ -64,16 +64,22 @@ static LIST_HEAD(module_bug_list); | |||
64 | static const struct bug_entry *module_find_bug(unsigned long bugaddr) | 64 | static const struct bug_entry *module_find_bug(unsigned long bugaddr) |
65 | { | 65 | { |
66 | struct module *mod; | 66 | struct module *mod; |
67 | const struct bug_entry *bug = NULL; | ||
67 | 68 | ||
68 | list_for_each_entry(mod, &module_bug_list, bug_list) { | 69 | rcu_read_lock(); |
69 | const struct bug_entry *bug = mod->bug_table; | 70 | list_for_each_entry_rcu(mod, &module_bug_list, bug_list) { |
70 | unsigned i; | 71 | unsigned i; |
71 | 72 | ||
73 | bug = mod->bug_table; | ||
72 | for (i = 0; i < mod->num_bugs; ++i, ++bug) | 74 | for (i = 0; i < mod->num_bugs; ++i, ++bug) |
73 | if (bugaddr == bug_addr(bug)) | 75 | if (bugaddr == bug_addr(bug)) |
74 | return bug; | 76 | goto out; |
75 | } | 77 | } |
76 | return NULL; | 78 | bug = NULL; |
79 | out: | ||
80 | rcu_read_unlock(); | ||
81 | |||
82 | return bug; | ||
77 | } | 83 | } |
78 | 84 | ||
79 | void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, | 85 | 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, | |||
99 | * Strictly speaking this should have a spinlock to protect against | 105 | * Strictly speaking this should have a spinlock to protect against |
100 | * traversals, but since we only traverse on BUG()s, a spinlock | 106 | * traversals, but since we only traverse on BUG()s, a spinlock |
101 | * could potentially lead to deadlock and thus be counter-productive. | 107 | * could potentially lead to deadlock and thus be counter-productive. |
108 | * Thus, this uses RCU to safely manipulate the bug list, since BUG | ||
109 | * must run in non-interruptive state. | ||
102 | */ | 110 | */ |
103 | list_add(&mod->bug_list, &module_bug_list); | 111 | list_add_rcu(&mod->bug_list, &module_bug_list); |
104 | } | 112 | } |
105 | 113 | ||
106 | void module_bug_cleanup(struct module *mod) | 114 | void module_bug_cleanup(struct module *mod) |
107 | { | 115 | { |
108 | list_del(&mod->bug_list); | 116 | list_del_rcu(&mod->bug_list); |
109 | } | 117 | } |
110 | 118 | ||
111 | #else | 119 | #else |