1/*
2 * Test program for Linux memory error recovery.
3 * Requires special injection support.
4 *
5 * This is a early primitive version of tinjpage.c,
6 * but simpler to debug in some cases.
7 */
8#define _GNU_SOURCE 1
9#include <sys/mman.h>
10#include <stdio.h>
11#include <signal.h>
12#include <unistd.h>
13#include <sys/fcntl.h>
14#include <stdlib.h>
15#include <setjmp.h>
16#include <errno.h>
17#include <string.h>
18
19#define MADV_POISON 100
20
21#define err(x) perror(x),exit(1)
22
23int count = 20;
24int failure = 0;
25int total_cases = 0;
26sigjmp_buf recover;
27int PS;
28
29void sighandler(int sig, siginfo_t *si, void *arg)
30{
31	printf("signal %d code %d addr %p\n", sig, si->si_code, si->si_addr);
32
33	if (--count == 0)
34		exit(1);
35
36	siglongjmp(recover, 1);
37}
38
39void testmem(char *msg, char *page, int write)
40{
41	printf("%s page %p\n", msg, page);
42	total_cases++;
43	if (sigsetjmp(recover,1) == 0) {
44		if (madvise(page, PS, MADV_POISON) != 0) {
45			failure++;
46			perror("madvise");
47		}
48		if (write)
49			*page = 2;
50		else
51			printf("%x\n", *(unsigned char *)page);
52	}
53	printf("recovered\n");
54}
55
56void expecterr(char *msg, int res)
57{
58	if (res == 0)
59		printf("no error on %s\n", msg);
60	else
61		perror(msg);
62}
63
64int tempfd(void)
65{
66	static int tmpcount;
67	int fd;
68	char buf[30];
69	snprintf(buf,30,"/tmp/test%d.XXXXXXXX",tmpcount++);
70	fd = mkstemp(buf);
71	if (fd >= 0)
72		unlink(buf);
73	return fd;
74}
75
76#define RANDOM_FILE "/etc/profile"
77
78int main(void)
79{
80	PS = getpagesize();
81	char *page;
82
83	struct sigaction sa = {
84		.sa_sigaction = sighandler,
85		.sa_flags = SA_SIGINFO
86	};
87	sigaction(SIGBUS, &sa, NULL);
88//	sigaction(SIGSEGV, &sa, NULL);
89
90 	page = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE, 0, 0);
91	testmem("dirty", page, 1);
92
93	page = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED, 0, 0);
94	testmem("mlocked", page, 1);
95
96	int fd = open(RANDOM_FILE, O_RDONLY);
97	if (fd < 0) err("open " RANDOM_FILE);
98	page = mmap(NULL, PS, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
99	if (page == (char *)-1) err("mmap");
100	close(fd);
101	testmem("clean file", page, 0);
102
103	fd = tempfd();
104	if (fd < 0) err("open testfile");
105	char *tmp = malloc(PS);
106	if (!tmp) err("no enough memory");
107	memset(tmp, 0xff, PS);
108	write(fd, tmp, PS);
109	free(tmp);
110	page = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
111	if (page == (char*)-1) err("mmap");
112	*page = 1;
113	testmem("file dirty", page, 0);
114	expecterr("msync expect error", msync(page, PS, MS_SYNC));
115	expecterr("fsync expect error", fsync(fd));
116	close(fd);
117
118	/* hole case still broken in the kernel -- doesn't report error */
119	fd = tempfd();
120	if (fd < 0) err("open testfile");
121	ftruncate(fd, PS);
122	page = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
123	if (page == (char*)-1) err("mmap");
124	*page = 1;
125	testmem("hole file dirty", page, 0);
126	expecterr("hole msync expect error", msync(page, PS, MS_SYNC));
127	expecterr("hole fsync expect error", fsync(fd));
128	close(fd);
129
130#if 0
131	const int NPAGES = 10;
132	int i;
133	fd = tempfd();
134	if (fd < 0) err("open rfp testfile");
135	tmp = malloc(PS);
136	if (!tmp) exit(ENOMEM);
137	for (i = 0; i < NPAGES; i++)  {
138		memset(tmp, i, PS);
139		write(fd, tmp, PS);
140	}
141	free(tmp);
142	page = mmap(NULL, PS*NPAGES, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
143	if (page == (char*)-1) err("mmap");
144	int k = NPAGES - 1;
145	for (i = 0; i < NPAGES; i++, k--) {
146		if (remap_file_pages(page + i*PS, PS, 0, k, 0))
147			perror("remap_file_pages");
148	}
149	*page = 1;
150	testmem("rfp file dirty", page, 0);
151	expecterr("rfp msync expect error", msync(page, PS, MS_SYNC));
152	expecterr("rfp fsync expect error", fsync(fd));
153	close(fd);
154#endif
155
156	if (failure > 0) {
157		printf("FAILURE -- %d of %d cases broken!\n", failure, total_cases);
158		return 1;
159	}
160	printf("SUCCESS\n");
161
162	return 0;
163}
164
165
166