diff options
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 |