diff options
Diffstat (limited to 'lib/bug.c')
-rw-r--r-- | lib/bug.c | 28 |
1 files changed, 20 insertions, 8 deletions
@@ -47,7 +47,7 @@ | |||
47 | #include <linux/sched.h> | 47 | #include <linux/sched.h> |
48 | #include <linux/rculist.h> | 48 | #include <linux/rculist.h> |
49 | 49 | ||
50 | extern const struct bug_entry __start___bug_table[], __stop___bug_table[]; | 50 | extern struct bug_entry __start___bug_table[], __stop___bug_table[]; |
51 | 51 | ||
52 | static inline unsigned long bug_addr(const struct bug_entry *bug) | 52 | static inline unsigned long bug_addr(const struct bug_entry *bug) |
53 | { | 53 | { |
@@ -62,10 +62,10 @@ static inline unsigned long bug_addr(const struct bug_entry *bug) | |||
62 | /* Updates are protected by module mutex */ | 62 | /* Updates are protected by module mutex */ |
63 | static LIST_HEAD(module_bug_list); | 63 | static LIST_HEAD(module_bug_list); |
64 | 64 | ||
65 | static const struct bug_entry *module_find_bug(unsigned long bugaddr) | 65 | static struct bug_entry *module_find_bug(unsigned long bugaddr) |
66 | { | 66 | { |
67 | struct module *mod; | 67 | struct module *mod; |
68 | const struct bug_entry *bug = NULL; | 68 | struct bug_entry *bug = NULL; |
69 | 69 | ||
70 | rcu_read_lock_sched(); | 70 | rcu_read_lock_sched(); |
71 | list_for_each_entry_rcu(mod, &module_bug_list, bug_list) { | 71 | list_for_each_entry_rcu(mod, &module_bug_list, bug_list) { |
@@ -122,15 +122,15 @@ void module_bug_cleanup(struct module *mod) | |||
122 | 122 | ||
123 | #else | 123 | #else |
124 | 124 | ||
125 | static inline const struct bug_entry *module_find_bug(unsigned long bugaddr) | 125 | static inline struct bug_entry *module_find_bug(unsigned long bugaddr) |
126 | { | 126 | { |
127 | return NULL; | 127 | return NULL; |
128 | } | 128 | } |
129 | #endif | 129 | #endif |
130 | 130 | ||
131 | const struct bug_entry *find_bug(unsigned long bugaddr) | 131 | struct bug_entry *find_bug(unsigned long bugaddr) |
132 | { | 132 | { |
133 | const struct bug_entry *bug; | 133 | struct bug_entry *bug; |
134 | 134 | ||
135 | for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) | 135 | for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) |
136 | if (bugaddr == bug_addr(bug)) | 136 | if (bugaddr == bug_addr(bug)) |
@@ -141,9 +141,9 @@ const struct bug_entry *find_bug(unsigned long bugaddr) | |||
141 | 141 | ||
142 | enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) | 142 | enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) |
143 | { | 143 | { |
144 | const struct bug_entry *bug; | 144 | struct bug_entry *bug; |
145 | const char *file; | 145 | const char *file; |
146 | unsigned line, warning; | 146 | unsigned line, warning, once, done; |
147 | 147 | ||
148 | if (!is_valid_bugaddr(bugaddr)) | 148 | if (!is_valid_bugaddr(bugaddr)) |
149 | return BUG_TRAP_TYPE_NONE; | 149 | return BUG_TRAP_TYPE_NONE; |
@@ -164,6 +164,18 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) | |||
164 | line = bug->line; | 164 | line = bug->line; |
165 | #endif | 165 | #endif |
166 | warning = (bug->flags & BUGFLAG_WARNING) != 0; | 166 | warning = (bug->flags & BUGFLAG_WARNING) != 0; |
167 | once = (bug->flags & BUGFLAG_ONCE) != 0; | ||
168 | done = (bug->flags & BUGFLAG_DONE) != 0; | ||
169 | |||
170 | if (warning && once) { | ||
171 | if (done) | ||
172 | return BUG_TRAP_TYPE_WARN; | ||
173 | |||
174 | /* | ||
175 | * Since this is the only store, concurrency is not an issue. | ||
176 | */ | ||
177 | bug->flags |= BUGFLAG_DONE; | ||
178 | } | ||
167 | } | 179 | } |
168 | 180 | ||
169 | if (warning) { | 181 | if (warning) { |