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 |
