aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-02-06 16:39:45 -0500
committerIngo Molnar <mingo@elte.hu>2008-02-06 16:39:45 -0500
commit971a52d66a3e87d4d2f5d3455e62680447cdb8e9 (patch)
treec55f87abe255ef85854ab36e7d081fd8e4d2aec1
parentf1fbabb312d657262322f4ce68b30a95f501945c (diff)
x86: delay CPA self-test and repeat it
delay the CPA self-test so that any impact (corruption) of user-space pagetables can be triggered. Repeat the test every 30 seconds. this would have prevented the bug fixed by 8cb2a7c1e95e472b5, at its source. Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/Kconfig.debug4
-rw-r--r--arch/x86/mm/pageattr-test.c65
2 files changed, 53 insertions, 16 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 2e1e3af28c3a..fa555148823d 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -220,9 +220,9 @@ config DEBUG_BOOT_PARAMS
220 This option will cause struct boot_params to be exported via debugfs. 220 This option will cause struct boot_params to be exported via debugfs.
221 221
222config CPA_DEBUG 222config CPA_DEBUG
223 bool "CPA self test code" 223 bool "CPA self-test code"
224 depends on DEBUG_KERNEL 224 depends on DEBUG_KERNEL
225 help 225 help
226 Do change_page_attr self tests at boot. 226 Do change_page_attr() self-tests every 30 seconds.
227 227
228endmenu 228endmenu
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c
index 398f3a578dde..ed8201600354 100644
--- a/arch/x86/mm/pageattr-test.c
+++ b/arch/x86/mm/pageattr-test.c
@@ -5,6 +5,7 @@
5 * and compares page tables forwards and afterwards. 5 * and compares page tables forwards and afterwards.
6 */ 6 */
7#include <linux/bootmem.h> 7#include <linux/bootmem.h>
8#include <linux/kthread.h>
8#include <linux/random.h> 9#include <linux/random.h>
9#include <linux/kernel.h> 10#include <linux/kernel.h>
10#include <linux/init.h> 11#include <linux/init.h>
@@ -14,8 +15,13 @@
14#include <asm/pgtable.h> 15#include <asm/pgtable.h>
15#include <asm/kdebug.h> 16#include <asm/kdebug.h>
16 17
18/*
19 * Only print the results of the first pass:
20 */
21static __read_mostly int print = 1;
22
17enum { 23enum {
18 NTEST = 4000, 24 NTEST = 400,
19#ifdef CONFIG_X86_64 25#ifdef CONFIG_X86_64
20 LPS = (1 << PMD_SHIFT), 26 LPS = (1 << PMD_SHIFT),
21#elif defined(CONFIG_X86_PAE) 27#elif defined(CONFIG_X86_PAE)
@@ -31,7 +37,7 @@ struct split_state {
31 long min_exec, max_exec; 37 long min_exec, max_exec;
32}; 38};
33 39
34static __init int print_split(struct split_state *s) 40static int print_split(struct split_state *s)
35{ 41{
36 long i, expected, missed = 0; 42 long i, expected, missed = 0;
37 int printed = 0; 43 int printed = 0;
@@ -82,10 +88,13 @@ static __init int print_split(struct split_state *s)
82 s->max_exec = addr; 88 s->max_exec = addr;
83 } 89 }
84 } 90 }
85 printk(KERN_INFO 91 if (print) {
86 "CPA mapping 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n", 92 printk(KERN_INFO
87 s->spg, s->lpg, s->gpg, s->exec, 93 " 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
88 s->min_exec != ~0UL ? s->min_exec : 0, s->max_exec, missed); 94 s->spg, s->lpg, s->gpg, s->exec,
95 s->min_exec != ~0UL ? s->min_exec : 0,
96 s->max_exec, missed);
97 }
89 98
90 expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed; 99 expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
91 if (expected != i) { 100 if (expected != i) {
@@ -96,11 +105,11 @@ static __init int print_split(struct split_state *s)
96 return err; 105 return err;
97} 106}
98 107
99static unsigned long __initdata addr[NTEST]; 108static unsigned long addr[NTEST];
100static unsigned int __initdata len[NTEST]; 109static unsigned int len[NTEST];
101 110
102/* Change the global bit on random pages in the direct mapping */ 111/* Change the global bit on random pages in the direct mapping */
103static __init int exercise_pageattr(void) 112static int pageattr_test(void)
104{ 113{
105 struct split_state sa, sb, sc; 114 struct split_state sa, sb, sc;
106 unsigned long *bm; 115 unsigned long *bm;
@@ -110,7 +119,8 @@ static __init int exercise_pageattr(void)
110 int i, k; 119 int i, k;
111 int err; 120 int err;
112 121
113 printk(KERN_INFO "CPA exercising pageattr\n"); 122 if (print)
123 printk(KERN_INFO "CPA self-test:\n");
114 124
115 bm = vmalloc((max_pfn_mapped + 7) / 8); 125 bm = vmalloc((max_pfn_mapped + 7) / 8);
116 if (!bm) { 126 if (!bm) {
@@ -186,7 +196,6 @@ static __init int exercise_pageattr(void)
186 196
187 failed += print_split(&sb); 197 failed += print_split(&sb);
188 198
189 printk(KERN_INFO "CPA reverting everything\n");
190 for (i = 0; i < NTEST; i++) { 199 for (i = 0; i < NTEST; i++) {
191 if (!addr[i]) 200 if (!addr[i])
192 continue; 201 continue;
@@ -214,12 +223,40 @@ static __init int exercise_pageattr(void)
214 failed += print_split(&sc); 223 failed += print_split(&sc);
215 224
216 if (failed) { 225 if (failed) {
217 printk(KERN_ERR "CPA selftests NOT PASSED. Please report.\n"); 226 printk(KERN_ERR "NOT PASSED. Please report.\n");
218 WARN_ON(1); 227 WARN_ON(1);
228 return -EINVAL;
219 } else { 229 } else {
220 printk(KERN_INFO "CPA selftests PASSED\n"); 230 if (print)
231 printk(KERN_INFO "ok.\n");
221 } 232 }
222 233
223 return 0; 234 return 0;
224} 235}
225module_init(exercise_pageattr); 236
237static int do_pageattr_test(void *__unused)
238{
239 while (!kthread_should_stop()) {
240 schedule_timeout_interruptible(HZ*30);
241 if (pageattr_test() < 0)
242 break;
243 if (print)
244 print--;
245 }
246 return 0;
247}
248
249static int start_pageattr_test(void)
250{
251 struct task_struct *p;
252
253 p = kthread_create(do_pageattr_test, NULL, "pageattr-test");
254 if (!IS_ERR(p))
255 wake_up_process(p);
256 else
257 WARN_ON(1);
258
259 return 0;
260}
261
262module_init(start_pageattr_test);