aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLi Zhong <zhong@linux.vnet.ibm.com>2012-03-29 16:11:17 -0400
committerIngo Molnar <mingo@kernel.org>2012-04-25 06:44:06 -0400
commit72b3fb24713755cf9740b403e95aa67ceedf3509 (patch)
treeff69fad7d2682e4f4fd857acbddef7a5335bef83
parent553222f3e81f18da31b2552e18dc519715198590 (diff)
x86/nmi: Fix page faults by nmiaction if kmemcheck is enabled
This patch tries to fix the problem of page fault exception caused by accessing nmiaction structure in nmi if kmemcheck is enabled. If kmemcheck is enabled, the memory allocated through slab are in pages that are marked non-present, so that some checks could be done in the page fault handling code ( e.g. whether the memory is read before written to ). As nmiaction is allocated in this way, so it resides in a non-present page. Then there is a page fault while the nmi code accessing the nmiaction structure, which would then cause a warning by WARN_ON_ONCE(in_nmi()) in kmemcheck_fault(), called by do_page_fault(). This significantly simplifies the code as well, as the whole dynamic allocation dance goes away. v2: as Peter suggested, changed the nmiaction to use static storage. v3: as Peter suggested, use macro to shorten the codes. Also keep the original usage of register_nmi_handler, so users of this call doesn't need change. Tested-by: Seiji Aguchi <seiji.aguchi@hds.com> Fixes: https://lkml.org/lkml/2012/3/2/356 Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com> [ simplified the wrappers ] Signed-off-by: Don Zickus <dzickus@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: thomas.mingarelli@hp.com Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Andrew Morton <akpm@linux-foundation.org> Link: http://lkml.kernel.org/r/1333051877-15755-4-git-send-email-dzickus@redhat.com [ tidied the patch a bit ] Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/nmi.h20
-rw-r--r--arch/x86/kernel/nmi.c65
2 files changed, 24 insertions, 61 deletions
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index 07162dfbff84..a1a836c8131c 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -37,8 +37,24 @@ enum {
37 37
38typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *); 38typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *);
39 39
40int register_nmi_handler(unsigned int, nmi_handler_t, unsigned long, 40struct nmiaction {
41 const char *); 41 struct list_head list;
42 nmi_handler_t handler;
43 unsigned int flags;
44 const char *name;
45};
46
47#define register_nmi_handler(t, fn, fg, n) \
48({ \
49 static struct nmiaction fn##_na = { \
50 .handler = (fn), \
51 .name = (n), \
52 .flags = (fg), \
53 }; \
54 __register_nmi_handler((t), &fn##_na); \
55})
56
57int __register_nmi_handler(unsigned int, struct nmiaction *);
42 58
43void unregister_nmi_handler(unsigned int, const char *); 59void unregister_nmi_handler(unsigned int, const char *);
44 60
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index ac9c1b76df96..585be4bd71a5 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -31,14 +31,6 @@
31#include <asm/nmi.h> 31#include <asm/nmi.h>
32#include <asm/x86_init.h> 32#include <asm/x86_init.h>
33 33
34#define NMI_MAX_NAMELEN 16
35struct nmiaction {
36 struct list_head list;
37 nmi_handler_t handler;
38 unsigned int flags;
39 char *name;
40};
41
42struct nmi_desc { 34struct nmi_desc {
43 spinlock_t lock; 35 spinlock_t lock;
44 struct list_head head; 36 struct list_head head;
@@ -115,11 +107,14 @@ static int notrace __kprobes nmi_handle(unsigned int type, struct pt_regs *regs,
115 return handled; 107 return handled;
116} 108}
117 109
118static int __setup_nmi(unsigned int type, struct nmiaction *action) 110int __register_nmi_handler(unsigned int type, struct nmiaction *action)
119{ 111{
120 struct nmi_desc *desc = nmi_to_desc(type); 112 struct nmi_desc *desc = nmi_to_desc(type);
121 unsigned long flags; 113 unsigned long flags;
122 114
115 if (!action->handler)
116 return -EINVAL;
117
123 spin_lock_irqsave(&desc->lock, flags); 118 spin_lock_irqsave(&desc->lock, flags);
124 119
125 /* 120 /*
@@ -143,8 +138,9 @@ static int __setup_nmi(unsigned int type, struct nmiaction *action)
143 spin_unlock_irqrestore(&desc->lock, flags); 138 spin_unlock_irqrestore(&desc->lock, flags);
144 return 0; 139 return 0;
145} 140}
141EXPORT_SYMBOL(__register_nmi_handler);
146 142
147static struct nmiaction *__free_nmi(unsigned int type, const char *name) 143void unregister_nmi_handler(unsigned int type, const char *name)
148{ 144{
149 struct nmi_desc *desc = nmi_to_desc(type); 145 struct nmi_desc *desc = nmi_to_desc(type);
150 struct nmiaction *n; 146 struct nmiaction *n;
@@ -167,56 +163,7 @@ static struct nmiaction *__free_nmi(unsigned int type, const char *name)
167 163
168 spin_unlock_irqrestore(&desc->lock, flags); 164 spin_unlock_irqrestore(&desc->lock, flags);
169 synchronize_rcu(); 165 synchronize_rcu();
170 return (n);
171} 166}
172
173int register_nmi_handler(unsigned int type, nmi_handler_t handler,
174 unsigned long nmiflags, const char *devname)
175{
176 struct nmiaction *action;
177 int retval = -ENOMEM;
178
179 if (!handler)
180 return -EINVAL;
181
182 action = kzalloc(sizeof(struct nmiaction), GFP_KERNEL);
183 if (!action)
184 goto fail_action;
185
186 action->handler = handler;
187 action->flags = nmiflags;
188 action->name = kstrndup(devname, NMI_MAX_NAMELEN, GFP_KERNEL);
189 if (!action->name)
190 goto fail_action_name;
191
192 retval = __setup_nmi(type, action);
193
194 if (retval)
195 goto fail_setup_nmi;
196
197 return retval;
198
199fail_setup_nmi:
200 kfree(action->name);
201fail_action_name:
202 kfree(action);
203fail_action:
204
205 return retval;
206}
207EXPORT_SYMBOL_GPL(register_nmi_handler);
208
209void unregister_nmi_handler(unsigned int type, const char *name)
210{
211 struct nmiaction *a;
212
213 a = __free_nmi(type, name);
214 if (a) {
215 kfree(a->name);
216 kfree(a);
217 }
218}
219
220EXPORT_SYMBOL_GPL(unregister_nmi_handler); 167EXPORT_SYMBOL_GPL(unregister_nmi_handler);
221 168
222static notrace __kprobes void 169static notrace __kprobes void