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