aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-12 23:42:54 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-12 23:42:54 -0500
commit099469502f62fbe0d7e4f0b83a2f22538367f734 (patch)
tree5229c3818b2e6e09d35026d49314047121130536 /tools
parent7c17d86a8502c2e30c2eea777ed1b830aa3b447b (diff)
parent35f1526845a9d804206883e19bd257d3dcef758f (diff)
Merge branch 'akpm' (aka "Andrew's patch-bomb, take two")
Andrew explains: - various misc stuff - Most of the rest of MM: memcg, threaded hugepages, others. - cpumask - kexec - kdump - some direct-io performance tweaking - radix-tree optimisations - new selftests code A note on this: often people will develop a new userspace-visible feature and will develop userspace code to exercise/test that feature. Then they merge the patch and the selftest code dies. Sometimes we paste it into the changelog. Sometimes the code gets thrown into Documentation/(!). This saddens me. So this patch creates a bare-bones framework which will henceforth allow me to ask people to include their test apps in the kernel tree so we can keep them alive. Then when people enhance or fix the feature, I can ask them to update the test app too. The infrastruture is terribly trivial at present - let's see how it evolves. - checkpoint/restart feature work. A note on this: this is a project by various mad Russians to perform c/r mainly from userspace, with various oddball helper code added into the kernel where the need is demonstrated. So rather than some large central lump of code, what we have is little bits and pieces popping up in various places which either expose something new or which permit something which is normally kernel-private to be modified. The overall project is an ongoing thing. I've judged that the size and scope of the thing means that we're more likely to be successful with it if we integrate the support into mainline piecemeal rather than allowing it all to develop out-of-tree. However I'm less confident than the developers that it will all eventually work! So what I'm asking them to do is to wrap each piece of new code inside CONFIG_CHECKPOINT_RESTORE. So if it all eventually comes to tears and the project as a whole fails, it should be a simple matter to go through and delete all trace of it. This lot pretty much wraps up the -rc1 merge for me. * akpm: (96 commits) unlzo: fix input buffer free ramoops: update parameters only after successful init ramoops: fix use of rounddown_pow_of_two() c/r: prctl: add PR_SET_MM codes to set up mm_struct entries c/r: procfs: add start_data, end_data, start_brk members to /proc/$pid/stat v4 c/r: introduce CHECKPOINT_RESTORE symbol selftests: new x86 breakpoints selftest selftests: new very basic kernel selftests directory radix_tree: take radix_tree_path off stack radix_tree: remove radix_tree_indirect_to_ptr() dio: optimize cache misses in the submission path vfs: cache request_queue in struct block_device fs/direct-io.c: calculate fs_count correctly in get_more_blocks() drivers/parport/parport_pc.c: fix warnings panic: don't print redundant backtraces on oops sysctl: add the kernel.ns_last_pid control kdump: add udev events for memory online/offline include/linux/crash_dump.h needs elf.h kdump: fix crash_kexec()/smp_send_stop() race in panic() kdump: crashk_res init check for /sys/kernel/kexec_crash_size ...
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/Makefile11
-rw-r--r--tools/testing/selftests/breakpoints/Makefile20
-rw-r--r--tools/testing/selftests/breakpoints/breakpoint_test.c394
-rw-r--r--tools/testing/selftests/run_tests8
4 files changed, 433 insertions, 0 deletions
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
new file mode 100644
index 000000000000..4ec84018cc13
--- /dev/null
+++ b/tools/testing/selftests/Makefile
@@ -0,0 +1,11 @@
1TARGETS = breakpoints
2
3all:
4 for TARGET in $(TARGETS); do \
5 make -C $$TARGET; \
6 done;
7
8clean:
9 for TARGET in $(TARGETS); do \
10 make -C $$TARGET clean; \
11 done;
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile
new file mode 100644
index 000000000000..f362722cdce7
--- /dev/null
+++ b/tools/testing/selftests/breakpoints/Makefile
@@ -0,0 +1,20 @@
1# Taken from perf makefile
2uname_M := $(shell uname -m 2>/dev/null || echo not)
3ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
4ifeq ($(ARCH),i386)
5 ARCH := x86
6endif
7ifeq ($(ARCH),x86_64)
8 ARCH := x86
9endif
10
11
12all:
13ifeq ($(ARCH),x86)
14 gcc breakpoint_test.c -o run_test
15else
16 echo "Not an x86 target, can't build breakpoints selftests"
17endif
18
19clean:
20 rm -fr run_test
diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c
new file mode 100644
index 000000000000..a0743f3b2b57
--- /dev/null
+++ b/tools/testing/selftests/breakpoints/breakpoint_test.c
@@ -0,0 +1,394 @@
1/*
2 * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
3 *
4 * Licensed under the terms of the GNU GPL License version 2
5 *
6 * Selftests for breakpoints (and more generally the do_debug() path) in x86.
7 */
8
9
10#include <sys/ptrace.h>
11#include <unistd.h>
12#include <stddef.h>
13#include <sys/user.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <signal.h>
17#include <sys/types.h>
18#include <sys/wait.h>
19
20
21/* Breakpoint access modes */
22enum {
23 BP_X = 1,
24 BP_RW = 2,
25 BP_W = 4,
26};
27
28static pid_t child_pid;
29
30/*
31 * Ensures the child and parent are always "talking" about
32 * the same test sequence. (ie: that we haven't forgotten
33 * to call check_trapped() somewhere).
34 */
35static int nr_tests;
36
37static void set_breakpoint_addr(void *addr, int n)
38{
39 int ret;
40
41 ret = ptrace(PTRACE_POKEUSER, child_pid,
42 offsetof(struct user, u_debugreg[n]), addr);
43 if (ret) {
44 perror("Can't set breakpoint addr\n");
45 exit(-1);
46 }
47}
48
49static void toggle_breakpoint(int n, int type, int len,
50 int local, int global, int set)
51{
52 int ret;
53
54 int xtype, xlen;
55 unsigned long vdr7, dr7;
56
57 switch (type) {
58 case BP_X:
59 xtype = 0;
60 break;
61 case BP_W:
62 xtype = 1;
63 break;
64 case BP_RW:
65 xtype = 3;
66 break;
67 }
68
69 switch (len) {
70 case 1:
71 xlen = 0;
72 break;
73 case 2:
74 xlen = 4;
75 break;
76 case 4:
77 xlen = 0xc;
78 break;
79 case 8:
80 xlen = 8;
81 break;
82 }
83
84 dr7 = ptrace(PTRACE_PEEKUSER, child_pid,
85 offsetof(struct user, u_debugreg[7]), 0);
86
87 vdr7 = (xlen | xtype) << 16;
88 vdr7 <<= 4 * n;
89
90 if (local) {
91 vdr7 |= 1 << (2 * n);
92 vdr7 |= 1 << 8;
93 }
94 if (global) {
95 vdr7 |= 2 << (2 * n);
96 vdr7 |= 1 << 9;
97 }
98
99 if (set)
100 dr7 |= vdr7;
101 else
102 dr7 &= ~vdr7;
103
104 ret = ptrace(PTRACE_POKEUSER, child_pid,
105 offsetof(struct user, u_debugreg[7]), dr7);
106 if (ret) {
107 perror("Can't set dr7");
108 exit(-1);
109 }
110}
111
112/* Dummy variables to test read/write accesses */
113static unsigned long long dummy_var[4];
114
115/* Dummy functions to test execution accesses */
116static void dummy_func(void) { }
117static void dummy_func1(void) { }
118static void dummy_func2(void) { }
119static void dummy_func3(void) { }
120
121static void (*dummy_funcs[])(void) = {
122 dummy_func,
123 dummy_func1,
124 dummy_func2,
125 dummy_func3,
126};
127
128static int trapped;
129
130static void check_trapped(void)
131{
132 /*
133 * If we haven't trapped, wake up the parent
134 * so that it notices the failure.
135 */
136 if (!trapped)
137 kill(getpid(), SIGUSR1);
138 trapped = 0;
139
140 nr_tests++;
141}
142
143static void write_var(int len)
144{
145 char *pcval; short *psval; int *pival; long long *plval;
146 int i;
147
148 for (i = 0; i < 4; i++) {
149 switch (len) {
150 case 1:
151 pcval = (char *)&dummy_var[i];
152 *pcval = 0xff;
153 break;
154 case 2:
155 psval = (short *)&dummy_var[i];
156 *psval = 0xffff;
157 break;
158 case 4:
159 pival = (int *)&dummy_var[i];
160 *pival = 0xffffffff;
161 break;
162 case 8:
163 plval = (long long *)&dummy_var[i];
164 *plval = 0xffffffffffffffffLL;
165 break;
166 }
167 check_trapped();
168 }
169}
170
171static void read_var(int len)
172{
173 char cval; short sval; int ival; long long lval;
174 int i;
175
176 for (i = 0; i < 4; i++) {
177 switch (len) {
178 case 1:
179 cval = *(char *)&dummy_var[i];
180 break;
181 case 2:
182 sval = *(short *)&dummy_var[i];
183 break;
184 case 4:
185 ival = *(int *)&dummy_var[i];
186 break;
187 case 8:
188 lval = *(long long *)&dummy_var[i];
189 break;
190 }
191 check_trapped();
192 }
193}
194
195/*
196 * Do the r/w/x accesses to trigger the breakpoints. And run
197 * the usual traps.
198 */
199static void trigger_tests(void)
200{
201 int len, local, global, i;
202 char val;
203 int ret;
204
205 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
206 if (ret) {
207 perror("Can't be traced?\n");
208 return;
209 }
210
211 /* Wake up father so that it sets up the first test */
212 kill(getpid(), SIGUSR1);
213
214 /* Test instruction breakpoints */
215 for (local = 0; local < 2; local++) {
216 for (global = 0; global < 2; global++) {
217 if (!local && !global)
218 continue;
219
220 for (i = 0; i < 4; i++) {
221 dummy_funcs[i]();
222 check_trapped();
223 }
224 }
225 }
226
227 /* Test write watchpoints */
228 for (len = 1; len <= sizeof(long); len <<= 1) {
229 for (local = 0; local < 2; local++) {
230 for (global = 0; global < 2; global++) {
231 if (!local && !global)
232 continue;
233 write_var(len);
234 }
235 }
236 }
237
238 /* Test read/write watchpoints (on read accesses) */
239 for (len = 1; len <= sizeof(long); len <<= 1) {
240 for (local = 0; local < 2; local++) {
241 for (global = 0; global < 2; global++) {
242 if (!local && !global)
243 continue;
244 read_var(len);
245 }
246 }
247 }
248
249 /* Icebp trap */
250 asm(".byte 0xf1\n");
251 check_trapped();
252
253 /* Int 3 trap */
254 asm("int $3\n");
255 check_trapped();
256
257 kill(getpid(), SIGUSR1);
258}
259
260static void check_success(const char *msg)
261{
262 const char *msg2;
263 int child_nr_tests;
264 int status;
265
266 /* Wait for the child to SIGTRAP */
267 wait(&status);
268
269 msg2 = "Failed";
270
271 if (WSTOPSIG(status) == SIGTRAP) {
272 child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid,
273 &nr_tests, 0);
274 if (child_nr_tests == nr_tests)
275 msg2 = "Ok";
276 if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) {
277 perror("Can't poke\n");
278 exit(-1);
279 }
280 }
281
282 nr_tests++;
283
284 printf("%s [%s]\n", msg, msg2);
285}
286
287static void launch_instruction_breakpoints(char *buf, int local, int global)
288{
289 int i;
290
291 for (i = 0; i < 4; i++) {
292 set_breakpoint_addr(dummy_funcs[i], i);
293 toggle_breakpoint(i, BP_X, 1, local, global, 1);
294 ptrace(PTRACE_CONT, child_pid, NULL, 0);
295 sprintf(buf, "Test breakpoint %d with local: %d global: %d",
296 i, local, global);
297 check_success(buf);
298 toggle_breakpoint(i, BP_X, 1, local, global, 0);
299 }
300}
301
302static void launch_watchpoints(char *buf, int mode, int len,
303 int local, int global)
304{
305 const char *mode_str;
306 int i;
307
308 if (mode == BP_W)
309 mode_str = "write";
310 else
311 mode_str = "read";
312
313 for (i = 0; i < 4; i++) {
314 set_breakpoint_addr(&dummy_var[i], i);
315 toggle_breakpoint(i, mode, len, local, global, 1);
316 ptrace(PTRACE_CONT, child_pid, NULL, 0);
317 sprintf(buf, "Test %s watchpoint %d with len: %d local: "
318 "%d global: %d", mode_str, i, len, local, global);
319 check_success(buf);
320 toggle_breakpoint(i, mode, len, local, global, 0);
321 }
322}
323
324/* Set the breakpoints and check the child successfully trigger them */
325static void launch_tests(void)
326{
327 char buf[1024];
328 int len, local, global, i;
329
330 /* Instruction breakpoints */
331 for (local = 0; local < 2; local++) {
332 for (global = 0; global < 2; global++) {
333 if (!local && !global)
334 continue;
335 launch_instruction_breakpoints(buf, local, global);
336 }
337 }
338
339 /* Write watchpoint */
340 for (len = 1; len <= sizeof(long); len <<= 1) {
341 for (local = 0; local < 2; local++) {
342 for (global = 0; global < 2; global++) {
343 if (!local && !global)
344 continue;
345 launch_watchpoints(buf, BP_W, len,
346 local, global);
347 }
348 }
349 }
350
351 /* Read-Write watchpoint */
352 for (len = 1; len <= sizeof(long); len <<= 1) {
353 for (local = 0; local < 2; local++) {
354 for (global = 0; global < 2; global++) {
355 if (!local && !global)
356 continue;
357 launch_watchpoints(buf, BP_RW, len,
358 local, global);
359 }
360 }
361 }
362
363 /* Icebp traps */
364 ptrace(PTRACE_CONT, child_pid, NULL, 0);
365 check_success("Test icebp");
366
367 /* Int 3 traps */
368 ptrace(PTRACE_CONT, child_pid, NULL, 0);
369 check_success("Test int 3 trap");
370
371 ptrace(PTRACE_CONT, child_pid, NULL, 0);
372}
373
374int main(int argc, char **argv)
375{
376 pid_t pid;
377 int ret;
378
379 pid = fork();
380 if (!pid) {
381 trigger_tests();
382 return 0;
383 }
384
385 child_pid = pid;
386
387 wait(NULL);
388
389 launch_tests();
390
391 wait(NULL);
392
393 return 0;
394}
diff --git a/tools/testing/selftests/run_tests b/tools/testing/selftests/run_tests
new file mode 100644
index 000000000000..320718a4e6bf
--- /dev/null
+++ b/tools/testing/selftests/run_tests
@@ -0,0 +1,8 @@
1#!/bin/bash
2
3TARGETS=breakpoints
4
5for TARGET in $TARGETS
6do
7 $TARGET/run_test
8done