|
@@ -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
|