1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Test program for Linux poison memory error recovery.
3f08c3bdfSopenharmony_ci * This program is extended from tinjpage with a multi-process model.
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci * This injects poison into various mapping cases and triggers the poison
6f08c3bdfSopenharmony_ci * handling.  Requires special injection support in the kernel.
7f08c3bdfSopenharmony_ci *
8f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or
9f08c3bdfSopenharmony_ci * modify it under the terms of the GNU General Public
10f08c3bdfSopenharmony_ci * License as published by the Free Software Foundation; version
11f08c3bdfSopenharmony_ci * 2.
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful,
14f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16f08c3bdfSopenharmony_ci * General Public License for more details.
17f08c3bdfSopenharmony_ci *
18f08c3bdfSopenharmony_ci * You should find a copy of v2 of the GNU General Public License somewhere
19f08c3bdfSopenharmony_ci * on your Linux system; if not, write to the Free Software Foundation,
20f08c3bdfSopenharmony_ci * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21f08c3bdfSopenharmony_ci *
22f08c3bdfSopenharmony_ci * Authors: Andi Kleen, Fengguang Wu, Haicheng Li
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci */
25f08c3bdfSopenharmony_ci#define _GNU_SOURCE 1
26f08c3bdfSopenharmony_ci#include <stdio.h>
27f08c3bdfSopenharmony_ci#include <signal.h>
28f08c3bdfSopenharmony_ci#include <stdlib.h>
29f08c3bdfSopenharmony_ci#include <setjmp.h>
30f08c3bdfSopenharmony_ci#include <errno.h>
31f08c3bdfSopenharmony_ci#include <string.h>
32f08c3bdfSopenharmony_ci#include <unistd.h>
33f08c3bdfSopenharmony_ci#include <stdarg.h>
34f08c3bdfSopenharmony_ci#include <getopt.h>
35f08c3bdfSopenharmony_ci#include <limits.h>
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci#include <sys/mman.h>
38f08c3bdfSopenharmony_ci#include <sys/fcntl.h>
39f08c3bdfSopenharmony_ci#include <sys/types.h>
40f08c3bdfSopenharmony_ci#include <sys/shm.h>
41f08c3bdfSopenharmony_ci#include <sys/sem.h>
42f08c3bdfSopenharmony_ci#include <sys/wait.h>
43f08c3bdfSopenharmony_ci#include <sys/stat.h>
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci#define MADV_POISON 100
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_ci#define PAGE_SIZE 4 * 1024
48f08c3bdfSopenharmony_ci#define SHM_SIZE 1		// in page_size.
49f08c3bdfSopenharmony_ci#define SHM_MODE 0600
50f08c3bdfSopenharmony_ci#define FILE_SIZE 1 * 1024 * 1024 * 1024
51f08c3bdfSopenharmony_ci#define LOG_BUFLEN 100
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci#define INSTANCE_NUM 10000
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci#define TEST_PASS 1
56f08c3bdfSopenharmony_ci#define TEST_FAIL 0
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_cistatic int PS = PAGE_SIZE;
59f08c3bdfSopenharmony_cistatic int instance = 0;	// index of the child process.
60f08c3bdfSopenharmony_cistatic int testid = 0;		// test index of the child process.
61f08c3bdfSopenharmony_cistatic int test_types = 0;	// totoal test types.
62f08c3bdfSopenharmony_cistatic int t_shm = -1;		// index of shm test case.
63f08c3bdfSopenharmony_cistatic int failure = 0;		// result of child process.
64f08c3bdfSopenharmony_cistatic int unexpected = 0;	// result of child process.
65f08c3bdfSopenharmony_cistatic int early_kill = 0;
66f08c3bdfSopenharmony_cistruct test {
67f08c3bdfSopenharmony_ci	int id;
68f08c3bdfSopenharmony_ci	int result;
69f08c3bdfSopenharmony_ci};
70f08c3bdfSopenharmony_cistruct shm {
71f08c3bdfSopenharmony_ci	int id;
72f08c3bdfSopenharmony_ci	int ready;
73f08c3bdfSopenharmony_ci	int done;
74f08c3bdfSopenharmony_ci};
75f08c3bdfSopenharmony_cistruct ipc {
76f08c3bdfSopenharmony_ci	struct test test[INSTANCE_NUM];
77f08c3bdfSopenharmony_ci	struct shm shm;
78f08c3bdfSopenharmony_ci};
79f08c3bdfSopenharmony_cistatic int ipc_entry;
80f08c3bdfSopenharmony_cistatic int *shmptr = NULL;
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_cistatic pid_t g_pid[INSTANCE_NUM] = { 0 };
83f08c3bdfSopenharmony_cistatic int shm_size = SHM_SIZE;
84f08c3bdfSopenharmony_cistatic int child_num = INSTANCE_NUM;
85f08c3bdfSopenharmony_cistatic int shm_child_num = 0;
86f08c3bdfSopenharmony_cistatic char log_file[PATH_MAX];
87f08c3bdfSopenharmony_cistatic FILE *log_fd = NULL;
88f08c3bdfSopenharmony_cistatic char result_file[PATH_MAX];
89f08c3bdfSopenharmony_cistatic FILE *result_fd = NULL;
90f08c3bdfSopenharmony_cistatic char tmp_dir[PATH_MAX] = { '\0' };
91f08c3bdfSopenharmony_cistatic int clean_env = 0;
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_cistatic int semid_ready = 0;
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_cistatic pid_t mypid;
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_ciunion semun {
98f08c3bdfSopenharmony_ci	int val;
99f08c3bdfSopenharmony_ci	struct semid_ds *buf;
100f08c3bdfSopenharmony_ci	unsigned short int *array;
101f08c3bdfSopenharmony_ci	struct semid_info *__buf;
102f08c3bdfSopenharmony_ci};
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_cienum rmode {
105f08c3bdfSopenharmony_ci	MREAD = 0,
106f08c3bdfSopenharmony_ci	MWRITE = 1,
107f08c3bdfSopenharmony_ci	MREAD_OK = 2,
108f08c3bdfSopenharmony_ci	MWRITE_OK = 3,
109f08c3bdfSopenharmony_ci	MNOTHING = -1,
110f08c3bdfSopenharmony_ci};
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_cistatic struct option opts[] = {
113f08c3bdfSopenharmony_ci	{"clean", 0, 0, 'C'},
114f08c3bdfSopenharmony_ci	{"help", 0, 0, 'h'},
115f08c3bdfSopenharmony_ci	{"instance", 0, 0, 'i'},
116f08c3bdfSopenharmony_ci	{"log", 0, 0, 'l'},
117f08c3bdfSopenharmony_ci	{"result", 0, 0, 'r'},
118f08c3bdfSopenharmony_ci	{"shmsize", 0, 0, 's'},
119f08c3bdfSopenharmony_ci	{"tmpdir", 0, 0, 't'},
120f08c3bdfSopenharmony_ci	{"", 0, 0, '\0'}
121f08c3bdfSopenharmony_ci};
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_cistatic void help(void)
124f08c3bdfSopenharmony_ci{
125f08c3bdfSopenharmony_ci	printf("Usage: page-poisoning [OPTION]...\n"
126f08c3bdfSopenharmony_ci	       "Stress test for Linux HWPOISON Page Recovery with multiple processes.\n"
127f08c3bdfSopenharmony_ci	       "\n"
128f08c3bdfSopenharmony_ci	       "Mandatory arguments to long options are mandatory for short options too.\n"
129f08c3bdfSopenharmony_ci	       "  -C, --clean                record log and result in clean files.\n"
130f08c3bdfSopenharmony_ci	       "  -h                         print this page\n"
131f08c3bdfSopenharmony_ci	       "  -i, --child_num=NUM        spawn NUM processes to do test (default NUM = %d)\n"
132f08c3bdfSopenharmony_ci	       "  -l, --log=LOG              record logs to file LOG.\n"
133f08c3bdfSopenharmony_ci	       "  -r, --result=RESULT        record test result to file RESULT.\n"
134f08c3bdfSopenharmony_ci	       "  -s, --shmsize=SIZE         each shared memory segment is SIZE-page based.\n"
135f08c3bdfSopenharmony_ci	       "  -t, --tmpdir=DIR           create temporary files in DIR.\n\n",
136f08c3bdfSopenharmony_ci	       INSTANCE_NUM);
137f08c3bdfSopenharmony_ci}
138f08c3bdfSopenharmony_ci
139f08c3bdfSopenharmony_cistatic void err(const char *fmt, ...);
140f08c3bdfSopenharmony_cistatic void mylog(const char *fmt, ...)
141f08c3bdfSopenharmony_ci{
142f08c3bdfSopenharmony_ci	char buf[LOG_BUFLEN] = { '\0' };
143f08c3bdfSopenharmony_ci	va_list args;
144f08c3bdfSopenharmony_ci	if (!log_fd)
145f08c3bdfSopenharmony_ci		err("no log file there\n");
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	va_start(args, fmt);
148f08c3bdfSopenharmony_ci	vsprintf(buf, fmt, args);
149f08c3bdfSopenharmony_ci	printf("[pid %d] %s", mypid, buf);
150f08c3bdfSopenharmony_ci	fprintf(log_fd, "[pid %d] %s", mypid, buf);
151f08c3bdfSopenharmony_ci	fflush(log_fd);
152f08c3bdfSopenharmony_ci	va_end(args);
153f08c3bdfSopenharmony_ci}
154f08c3bdfSopenharmony_ci
155f08c3bdfSopenharmony_cistatic void result(const char *fmt, ...)
156f08c3bdfSopenharmony_ci{
157f08c3bdfSopenharmony_ci	char buf[LOG_BUFLEN] = { '\0' };
158f08c3bdfSopenharmony_ci	va_list args;
159f08c3bdfSopenharmony_ci	if (!result_fd)
160f08c3bdfSopenharmony_ci		err("no result file there\n");
161f08c3bdfSopenharmony_ci
162f08c3bdfSopenharmony_ci	va_start(args, fmt);
163f08c3bdfSopenharmony_ci	vsprintf(buf, fmt, args);
164f08c3bdfSopenharmony_ci	fprintf(result_fd, "[pid %d] %s", mypid, buf);
165f08c3bdfSopenharmony_ci	fflush(result_fd);
166f08c3bdfSopenharmony_ci	if (log_fd)
167f08c3bdfSopenharmony_ci		mylog("%s", buf);
168f08c3bdfSopenharmony_ci	va_end(args);
169f08c3bdfSopenharmony_ci}
170f08c3bdfSopenharmony_ci
171f08c3bdfSopenharmony_cistatic void err(const char *fmt, ...)
172f08c3bdfSopenharmony_ci{
173f08c3bdfSopenharmony_ci	char buf[LOG_BUFLEN] = { '\0' };
174f08c3bdfSopenharmony_ci	va_list args;
175f08c3bdfSopenharmony_ci	va_start(args, fmt);
176f08c3bdfSopenharmony_ci
177f08c3bdfSopenharmony_ci	vsprintf(buf, fmt, args);
178f08c3bdfSopenharmony_ci	if (result_fd)
179f08c3bdfSopenharmony_ci		result("error: %s :%s\n", buf, strerror(errno));
180f08c3bdfSopenharmony_ci	else
181f08c3bdfSopenharmony_ci		perror(buf);
182f08c3bdfSopenharmony_ci	va_end(args);
183f08c3bdfSopenharmony_ci	exit(1);
184f08c3bdfSopenharmony_ci}
185f08c3bdfSopenharmony_ci
186f08c3bdfSopenharmony_cistatic void *checked_mmap(void *start, size_t length, int prot, int flags,
187f08c3bdfSopenharmony_ci		   int fd, off_t offset)
188f08c3bdfSopenharmony_ci{
189f08c3bdfSopenharmony_ci	void *map = mmap(start, length, prot, flags, fd, offset);
190f08c3bdfSopenharmony_ci	if (map == (void *)-1L)
191f08c3bdfSopenharmony_ci		err("mmap");
192f08c3bdfSopenharmony_ci	return map;
193f08c3bdfSopenharmony_ci}
194f08c3bdfSopenharmony_ci
195f08c3bdfSopenharmony_cistatic void munmap_reserve(void *page, int size)
196f08c3bdfSopenharmony_ci{
197f08c3bdfSopenharmony_ci	munmap(page, size);
198f08c3bdfSopenharmony_ci	mmap(page, size, PROT_NONE, MAP_PRIVATE | MAP_FIXED, 0, 0);
199f08c3bdfSopenharmony_ci}
200f08c3bdfSopenharmony_ci
201f08c3bdfSopenharmony_cistatic void *xmalloc(size_t s)
202f08c3bdfSopenharmony_ci{
203f08c3bdfSopenharmony_ci	void *p = malloc(s);
204f08c3bdfSopenharmony_ci	if (!p)
205f08c3bdfSopenharmony_ci		exit(ENOMEM);
206f08c3bdfSopenharmony_ci	return p;
207f08c3bdfSopenharmony_ci}
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_cistatic int recovercount;
210f08c3bdfSopenharmony_cistatic sigjmp_buf recover_ctx;
211f08c3bdfSopenharmony_cistatic sigjmp_buf early_recover_ctx;
212f08c3bdfSopenharmony_cistatic void *expected_addr;
213f08c3bdfSopenharmony_ci
214f08c3bdfSopenharmony_cistatic void sighandler(int sig, siginfo_t * si, void *arg)
215f08c3bdfSopenharmony_ci{
216f08c3bdfSopenharmony_ci	mylog("signal %d code %d addr %p\n", sig, si->si_code, si->si_addr);
217f08c3bdfSopenharmony_ci	if (si->si_addr != expected_addr) {
218f08c3bdfSopenharmony_ci		result("failed: Unexpected address in signal %p (expected %p)\n",
219f08c3bdfSopenharmony_ci		       si->si_addr, expected_addr);
220f08c3bdfSopenharmony_ci		failure++;
221f08c3bdfSopenharmony_ci	}
222f08c3bdfSopenharmony_ci
223f08c3bdfSopenharmony_ci	if (--recovercount == 0) {
224f08c3bdfSopenharmony_ci		result("failed: I seem to be in a signal loop. bailing out.\n");
225f08c3bdfSopenharmony_ci		exit(1);
226f08c3bdfSopenharmony_ci	}
227f08c3bdfSopenharmony_ci
228f08c3bdfSopenharmony_ci	if (si->si_code == 4)
229f08c3bdfSopenharmony_ci		siglongjmp(recover_ctx, 1);
230f08c3bdfSopenharmony_ci	else
231f08c3bdfSopenharmony_ci		siglongjmp(early_recover_ctx, 1);
232f08c3bdfSopenharmony_ci}
233f08c3bdfSopenharmony_ci
234f08c3bdfSopenharmony_cistatic void poison(char *msg, char *page, enum rmode mode)
235f08c3bdfSopenharmony_ci{
236f08c3bdfSopenharmony_ci	expected_addr = page;
237f08c3bdfSopenharmony_ci	recovercount = 5;
238f08c3bdfSopenharmony_ci
239f08c3bdfSopenharmony_ci	if (sigsetjmp(early_recover_ctx, 1) == 0) {
240f08c3bdfSopenharmony_ci		if (madvise(page, PS, MADV_POISON) != 0) {
241f08c3bdfSopenharmony_ci			if (errno == EINVAL) {
242f08c3bdfSopenharmony_ci				result("failed: Kernel doesn't support poison injection\n");
243f08c3bdfSopenharmony_ci				exit(0);
244f08c3bdfSopenharmony_ci			}
245f08c3bdfSopenharmony_ci			err("error: madvise: %s", strerror(errno));
246f08c3bdfSopenharmony_ci			return;
247f08c3bdfSopenharmony_ci		}
248f08c3bdfSopenharmony_ci
249f08c3bdfSopenharmony_ci		if (early_kill && (mode == MWRITE || mode == MREAD)) {
250f08c3bdfSopenharmony_ci			result("failed: %s: process is not early killed\n",
251f08c3bdfSopenharmony_ci			       msg);
252f08c3bdfSopenharmony_ci			failure++;
253f08c3bdfSopenharmony_ci		}
254f08c3bdfSopenharmony_ci
255f08c3bdfSopenharmony_ci		return;
256f08c3bdfSopenharmony_ci	}
257f08c3bdfSopenharmony_ci
258f08c3bdfSopenharmony_ci	if (early_kill) {
259f08c3bdfSopenharmony_ci		if (mode == MREAD_OK || mode == MWRITE_OK) {
260f08c3bdfSopenharmony_ci			result("failed: %s: killed\n", msg);
261f08c3bdfSopenharmony_ci			failure++;
262f08c3bdfSopenharmony_ci		} else
263f08c3bdfSopenharmony_ci			mylog("pass: recovered\n");
264f08c3bdfSopenharmony_ci	}
265f08c3bdfSopenharmony_ci}
266f08c3bdfSopenharmony_ci
267f08c3bdfSopenharmony_cistatic void recover(char *msg, char *page, enum rmode mode)
268f08c3bdfSopenharmony_ci{
269f08c3bdfSopenharmony_ci	expected_addr = page;
270f08c3bdfSopenharmony_ci	recovercount = 5;
271f08c3bdfSopenharmony_ci
272f08c3bdfSopenharmony_ci	if (sigsetjmp(recover_ctx, 1) == 0) {
273f08c3bdfSopenharmony_ci		switch (mode) {
274f08c3bdfSopenharmony_ci		case MWRITE:
275f08c3bdfSopenharmony_ci			mylog("writing 2\n");
276f08c3bdfSopenharmony_ci			*page = 2;
277f08c3bdfSopenharmony_ci			break;
278f08c3bdfSopenharmony_ci		case MWRITE_OK:
279f08c3bdfSopenharmony_ci			mylog("writing 4\n");
280f08c3bdfSopenharmony_ci			*page = 4;
281f08c3bdfSopenharmony_ci			return;
282f08c3bdfSopenharmony_ci		case MREAD:
283f08c3bdfSopenharmony_ci			mylog("reading %x\n", *(unsigned char *)page);
284f08c3bdfSopenharmony_ci			break;
285f08c3bdfSopenharmony_ci		case MREAD_OK:
286f08c3bdfSopenharmony_ci			mylog("reading %x\n", *(unsigned char *)page);
287f08c3bdfSopenharmony_ci			return;
288f08c3bdfSopenharmony_ci		case MNOTHING:
289f08c3bdfSopenharmony_ci			return;
290f08c3bdfSopenharmony_ci		}
291f08c3bdfSopenharmony_ci		/* signal or kill should have happened */
292f08c3bdfSopenharmony_ci		result("failed: %s: page is not poisoned after injection\n", msg);
293f08c3bdfSopenharmony_ci		failure++;
294f08c3bdfSopenharmony_ci		return;
295f08c3bdfSopenharmony_ci	}
296f08c3bdfSopenharmony_ci	if (mode == MREAD_OK || mode == MWRITE_OK) {
297f08c3bdfSopenharmony_ci		result("failed: %s: killed\n", msg);
298f08c3bdfSopenharmony_ci		failure++;
299f08c3bdfSopenharmony_ci	} else
300f08c3bdfSopenharmony_ci		mylog("pass: recovered\n");
301f08c3bdfSopenharmony_ci}
302f08c3bdfSopenharmony_ci
303f08c3bdfSopenharmony_cistatic void testmem(char *msg, char *page, enum rmode mode)
304f08c3bdfSopenharmony_ci{
305f08c3bdfSopenharmony_ci	mylog("%s poisoning page %p\n", msg, page);
306f08c3bdfSopenharmony_ci	poison(msg, page, mode);
307f08c3bdfSopenharmony_ci	recover(msg, page, mode);
308f08c3bdfSopenharmony_ci}
309f08c3bdfSopenharmony_ci
310f08c3bdfSopenharmony_cistatic void expecterr(char *msg, int err)
311f08c3bdfSopenharmony_ci{
312f08c3bdfSopenharmony_ci	if (err) {
313f08c3bdfSopenharmony_ci		mylog("pass: expected error %d on %s\n", errno, msg);
314f08c3bdfSopenharmony_ci	} else {
315f08c3bdfSopenharmony_ci		result("failed: unexpected no error on %s\n", msg);
316f08c3bdfSopenharmony_ci		failure++;
317f08c3bdfSopenharmony_ci	}
318f08c3bdfSopenharmony_ci}
319f08c3bdfSopenharmony_ci
320f08c3bdfSopenharmony_ci/*
321f08c3bdfSopenharmony_ci * Any optional error is really a deficiency in the kernel VFS error reporting
322f08c3bdfSopenharmony_ci * and should be eventually fixed and turned into a expecterr
323f08c3bdfSopenharmony_ci */
324f08c3bdfSopenharmony_cistatic void optionalerr(char *msg, int err)
325f08c3bdfSopenharmony_ci{
326f08c3bdfSopenharmony_ci	if (err) {
327f08c3bdfSopenharmony_ci		mylog("pass: expected error %d on %s\n", errno, msg);
328f08c3bdfSopenharmony_ci	} else {
329f08c3bdfSopenharmony_ci		mylog("LATER: expected likely incorrect no error on %s\n", msg);
330f08c3bdfSopenharmony_ci		unexpected++;
331f08c3bdfSopenharmony_ci	}
332f08c3bdfSopenharmony_ci}
333f08c3bdfSopenharmony_ci
334f08c3bdfSopenharmony_cistatic int playfile(char *buf)
335f08c3bdfSopenharmony_ci{
336f08c3bdfSopenharmony_ci	int fd;
337f08c3bdfSopenharmony_ci	if (buf[0] == 0)
338f08c3bdfSopenharmony_ci		snprintf(buf, PATH_MAX, "%s/dirty%d", tmp_dir, mypid);
339f08c3bdfSopenharmony_ci	fd = open(buf, O_CREAT | O_RDWR | O_TRUNC, 0600);
340f08c3bdfSopenharmony_ci	if (fd < 0)
341f08c3bdfSopenharmony_ci		err("opening temporary file: %s", buf);
342f08c3bdfSopenharmony_ci
343f08c3bdfSopenharmony_ci	const int NPAGES = 5;
344f08c3bdfSopenharmony_ci	char *tmp = xmalloc(PS * NPAGES);
345f08c3bdfSopenharmony_ci	int i;
346f08c3bdfSopenharmony_ci	for (i = 0; i < PS * NPAGES; i++)
347f08c3bdfSopenharmony_ci		tmp[i] = i;
348f08c3bdfSopenharmony_ci	write(fd, tmp, PS * NPAGES);
349f08c3bdfSopenharmony_ci
350f08c3bdfSopenharmony_ci	lseek(fd, 0, SEEK_SET);
351f08c3bdfSopenharmony_ci	free(tmp);
352f08c3bdfSopenharmony_ci	return fd;
353f08c3bdfSopenharmony_ci}
354f08c3bdfSopenharmony_ci
355f08c3bdfSopenharmony_cistatic void dirty_anonymous(void)
356f08c3bdfSopenharmony_ci{
357f08c3bdfSopenharmony_ci	struct ipc *ipc;
358f08c3bdfSopenharmony_ci	char *page;
359f08c3bdfSopenharmony_ci
360f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
361f08c3bdfSopenharmony_ci		err("shmat error\n");
362f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
363f08c3bdfSopenharmony_ci	page = checked_mmap(NULL, PS, PROT_READ | PROT_WRITE,
364f08c3bdfSopenharmony_ci			    MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, 0, 0);
365f08c3bdfSopenharmony_ci	testmem("dirty", page, MWRITE);
366f08c3bdfSopenharmony_ci	if (!failure)
367f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
368f08c3bdfSopenharmony_ci	shmdt(ipc);
369f08c3bdfSopenharmony_ci}
370f08c3bdfSopenharmony_ci
371f08c3bdfSopenharmony_cistatic void dirty_anonymous_unmap(void)
372f08c3bdfSopenharmony_ci{
373f08c3bdfSopenharmony_ci	struct ipc *ipc;
374f08c3bdfSopenharmony_ci	char *page;
375f08c3bdfSopenharmony_ci
376f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
377f08c3bdfSopenharmony_ci		err("shmat error\n");
378f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
379f08c3bdfSopenharmony_ci	page = checked_mmap(NULL, PS, PROT_READ | PROT_WRITE,
380f08c3bdfSopenharmony_ci			    MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, 0, 0);
381f08c3bdfSopenharmony_ci	testmem("dirty", page, MWRITE);
382f08c3bdfSopenharmony_ci	munmap_reserve(page, PS);
383f08c3bdfSopenharmony_ci	if (!failure)
384f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
385f08c3bdfSopenharmony_ci	shmdt(ipc);
386f08c3bdfSopenharmony_ci}
387f08c3bdfSopenharmony_ci
388f08c3bdfSopenharmony_cistatic void mlocked_anonymous(void)
389f08c3bdfSopenharmony_ci{
390f08c3bdfSopenharmony_ci	struct ipc *ipc;
391f08c3bdfSopenharmony_ci	char *page;
392f08c3bdfSopenharmony_ci
393f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
394f08c3bdfSopenharmony_ci		err("shmat error\n");
395f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
396f08c3bdfSopenharmony_ci	page = checked_mmap(NULL, PS, PROT_READ | PROT_WRITE,
397f08c3bdfSopenharmony_ci			    MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED, 0, 0);
398f08c3bdfSopenharmony_ci	testmem("mlocked", page, MWRITE);
399f08c3bdfSopenharmony_ci	if (!failure)
400f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
401f08c3bdfSopenharmony_ci	shmdt(ipc);
402f08c3bdfSopenharmony_ci}
403f08c3bdfSopenharmony_ci
404f08c3bdfSopenharmony_cistatic void do_file_clean(int flags, char *name)
405f08c3bdfSopenharmony_ci{
406f08c3bdfSopenharmony_ci	char *page;
407f08c3bdfSopenharmony_ci	char fn[PATH_MAX];
408f08c3bdfSopenharmony_ci	snprintf(fn, PATH_MAX, "%s/clean%d", tmp_dir, mypid);
409f08c3bdfSopenharmony_ci	int fd = open(fn, O_RDWR | O_TRUNC | O_CREAT, 0600);
410f08c3bdfSopenharmony_ci	if (fd < 0)
411f08c3bdfSopenharmony_ci		err("opening temporary file: %s", fn);
412f08c3bdfSopenharmony_ci	write(fd, fn, 4);
413f08c3bdfSopenharmony_ci	page = checked_mmap(NULL, PS, PROT_READ | PROT_WRITE, MAP_SHARED | flags,
414f08c3bdfSopenharmony_ci			    fd, 0);
415f08c3bdfSopenharmony_ci	fsync(fd);
416f08c3bdfSopenharmony_ci	close(fd);
417f08c3bdfSopenharmony_ci	testmem(name, page, MREAD_OK);
418f08c3bdfSopenharmony_ci	/* reread page from disk */
419f08c3bdfSopenharmony_ci	mylog("reading %x\n", *(unsigned char *)page);
420f08c3bdfSopenharmony_ci	testmem(name, page, MWRITE_OK);
421f08c3bdfSopenharmony_ci}
422f08c3bdfSopenharmony_ci
423f08c3bdfSopenharmony_cistatic void file_clean(void)
424f08c3bdfSopenharmony_ci{
425f08c3bdfSopenharmony_ci	struct ipc *ipc;
426f08c3bdfSopenharmony_ci
427f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
428f08c3bdfSopenharmony_ci		err("shmat error\n");
429f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
430f08c3bdfSopenharmony_ci	do_file_clean(0, "file clean");
431f08c3bdfSopenharmony_ci	if (!failure)
432f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
433f08c3bdfSopenharmony_ci	shmdt(ipc);
434f08c3bdfSopenharmony_ci}
435f08c3bdfSopenharmony_ci
436f08c3bdfSopenharmony_cistatic void file_clean_mlocked(void)
437f08c3bdfSopenharmony_ci{
438f08c3bdfSopenharmony_ci	struct ipc *ipc;
439f08c3bdfSopenharmony_ci
440f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
441f08c3bdfSopenharmony_ci		err("shmat error\n");
442f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
443f08c3bdfSopenharmony_ci	do_file_clean(MAP_LOCKED, "file clean mlocked");
444f08c3bdfSopenharmony_ci	if (!failure)
445f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
446f08c3bdfSopenharmony_ci	shmdt(ipc);
447f08c3bdfSopenharmony_ci}
448f08c3bdfSopenharmony_ci
449f08c3bdfSopenharmony_cistatic char *ndesc(char *buf, char *name, char *add)
450f08c3bdfSopenharmony_ci{
451f08c3bdfSopenharmony_ci	snprintf(buf, 100, "%s %s", name, add);
452f08c3bdfSopenharmony_ci	return buf;
453f08c3bdfSopenharmony_ci}
454f08c3bdfSopenharmony_ci
455f08c3bdfSopenharmony_cistatic void do_file_dirty(int flags, char *name)
456f08c3bdfSopenharmony_ci{
457f08c3bdfSopenharmony_ci	char nbuf[100];
458f08c3bdfSopenharmony_ci	char *page;
459f08c3bdfSopenharmony_ci	char fn[PATH_MAX];
460f08c3bdfSopenharmony_ci	fn[0] = 0;
461f08c3bdfSopenharmony_ci	int fd = playfile(fn);
462f08c3bdfSopenharmony_ci
463f08c3bdfSopenharmony_ci	page = checked_mmap(NULL, PS, PROT_READ,
464f08c3bdfSopenharmony_ci			    MAP_SHARED | MAP_POPULATE | flags, fd, 0);
465f08c3bdfSopenharmony_ci	testmem(ndesc(nbuf, name, "initial"), page, MREAD);
466f08c3bdfSopenharmony_ci	expecterr("msync expect error", msync(page, PS, MS_SYNC) < 0);
467f08c3bdfSopenharmony_ci	close(fd);
468f08c3bdfSopenharmony_ci	munmap_reserve(page, PS);
469f08c3bdfSopenharmony_ci
470f08c3bdfSopenharmony_ci	fd = open(fn, O_RDONLY);
471f08c3bdfSopenharmony_ci	if (fd < 0)
472f08c3bdfSopenharmony_ci		err("reopening temp file");
473f08c3bdfSopenharmony_ci	page = checked_mmap(NULL, PS, PROT_READ, MAP_SHARED | MAP_POPULATE | flags,
474f08c3bdfSopenharmony_ci			    fd, 0);
475f08c3bdfSopenharmony_ci	recover(ndesc(nbuf, name, "populated"), page, MREAD_OK);
476f08c3bdfSopenharmony_ci	close(fd);
477f08c3bdfSopenharmony_ci	munmap_reserve(page, PS);
478f08c3bdfSopenharmony_ci
479f08c3bdfSopenharmony_ci	fd = open(fn, O_RDONLY);
480f08c3bdfSopenharmony_ci	if (fd < 0)
481f08c3bdfSopenharmony_ci		err("reopening temp file");
482f08c3bdfSopenharmony_ci	page = checked_mmap(NULL, PS, PROT_READ, MAP_SHARED | flags, fd, 0);
483f08c3bdfSopenharmony_ci	recover(ndesc(nbuf, name, "fault"), page, MREAD_OK);
484f08c3bdfSopenharmony_ci	close(fd);
485f08c3bdfSopenharmony_ci	munmap_reserve(page, PS);
486f08c3bdfSopenharmony_ci
487f08c3bdfSopenharmony_ci	fd = open(fn, O_RDWR);
488f08c3bdfSopenharmony_ci	char buf[128];
489f08c3bdfSopenharmony_ci	/* the earlier close has eaten the error */
490f08c3bdfSopenharmony_ci	optionalerr("explicit read after poison", read(fd, buf, sizeof buf) < 0);
491f08c3bdfSopenharmony_ci	optionalerr("explicit write after poison", write(fd, "foobar", 6) < 0);
492f08c3bdfSopenharmony_ci	optionalerr("fsync expect error", fsync(fd) < 0);
493f08c3bdfSopenharmony_ci	close(fd);
494f08c3bdfSopenharmony_ci
495f08c3bdfSopenharmony_ci	/* should unlink return an error here? */
496f08c3bdfSopenharmony_ci	if (unlink(fn) < 0)
497f08c3bdfSopenharmony_ci		perror("unlink");
498f08c3bdfSopenharmony_ci}
499f08c3bdfSopenharmony_ci
500f08c3bdfSopenharmony_cistatic void file_dirty(void)
501f08c3bdfSopenharmony_ci{
502f08c3bdfSopenharmony_ci	struct ipc *ipc;
503f08c3bdfSopenharmony_ci
504f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
505f08c3bdfSopenharmony_ci		err("shmat error\n");
506f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
507f08c3bdfSopenharmony_ci	do_file_dirty(0, "file dirty");
508f08c3bdfSopenharmony_ci	if (!failure)
509f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
510f08c3bdfSopenharmony_ci	shmdt(ipc);
511f08c3bdfSopenharmony_ci}
512f08c3bdfSopenharmony_ci
513f08c3bdfSopenharmony_cistatic void file_dirty_mlocked(void)
514f08c3bdfSopenharmony_ci{
515f08c3bdfSopenharmony_ci	struct ipc *ipc;
516f08c3bdfSopenharmony_ci
517f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
518f08c3bdfSopenharmony_ci		err("shmat error\n");
519f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
520f08c3bdfSopenharmony_ci	do_file_dirty(MAP_LOCKED, "file dirty mlocked");
521f08c3bdfSopenharmony_ci	if (!failure)
522f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
523f08c3bdfSopenharmony_ci	shmdt(ipc);
524f08c3bdfSopenharmony_ci}
525f08c3bdfSopenharmony_ci
526f08c3bdfSopenharmony_cistatic void request_sem(int id, int num)
527f08c3bdfSopenharmony_ci{
528f08c3bdfSopenharmony_ci	struct sembuf sb;
529f08c3bdfSopenharmony_ci
530f08c3bdfSopenharmony_ci	sb.sem_num = num;
531f08c3bdfSopenharmony_ci	sb.sem_op = -1;
532f08c3bdfSopenharmony_ci	sb.sem_flg = 0;
533f08c3bdfSopenharmony_ci
534f08c3bdfSopenharmony_ci	semop(id, &sb, 1);
535f08c3bdfSopenharmony_ci}
536f08c3bdfSopenharmony_ci
537f08c3bdfSopenharmony_cistatic void waiton_sem(int id, int num)
538f08c3bdfSopenharmony_ci{
539f08c3bdfSopenharmony_ci	struct sembuf sb;
540f08c3bdfSopenharmony_ci
541f08c3bdfSopenharmony_ci	sb.sem_num = num;
542f08c3bdfSopenharmony_ci	sb.sem_flg = 0;
543f08c3bdfSopenharmony_ci
544f08c3bdfSopenharmony_ci	sb.sem_op = -1;
545f08c3bdfSopenharmony_ci	semop(id, &sb, 1);
546f08c3bdfSopenharmony_ci	sb.sem_op = 0;
547f08c3bdfSopenharmony_ci	semop(id, &sb, 1);
548f08c3bdfSopenharmony_ci}
549f08c3bdfSopenharmony_ci
550f08c3bdfSopenharmony_cistatic void release_sem(int id, int num)
551f08c3bdfSopenharmony_ci{
552f08c3bdfSopenharmony_ci	struct sembuf sb;
553f08c3bdfSopenharmony_ci
554f08c3bdfSopenharmony_ci	sb.sem_num = num;
555f08c3bdfSopenharmony_ci	sb.sem_op = 1;
556f08c3bdfSopenharmony_ci	sb.sem_flg = 0;
557f08c3bdfSopenharmony_ci
558f08c3bdfSopenharmony_ci	semop(id, &sb, 1);
559f08c3bdfSopenharmony_ci}
560f08c3bdfSopenharmony_ci
561f08c3bdfSopenharmony_cistatic void clean_anonymous(void)
562f08c3bdfSopenharmony_ci{
563f08c3bdfSopenharmony_ci	char *page;
564f08c3bdfSopenharmony_ci	page = checked_mmap(NULL, PS, PROT_READ | PROT_WRITE,
565f08c3bdfSopenharmony_ci			    MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
566f08c3bdfSopenharmony_ci	testmem("clean", page, MWRITE_OK);
567f08c3bdfSopenharmony_ci}
568f08c3bdfSopenharmony_ci
569f08c3bdfSopenharmony_cistatic void anon_clean(void)
570f08c3bdfSopenharmony_ci{
571f08c3bdfSopenharmony_ci	struct ipc *ipc;
572f08c3bdfSopenharmony_ci
573f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
574f08c3bdfSopenharmony_ci		err("shmat error\n");
575f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
576f08c3bdfSopenharmony_ci	clean_anonymous();
577f08c3bdfSopenharmony_ci	if (!failure)
578f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
579f08c3bdfSopenharmony_ci	shmdt(ipc);
580f08c3bdfSopenharmony_ci}
581f08c3bdfSopenharmony_ci
582f08c3bdfSopenharmony_ci/* TBD
583f08c3bdfSopenharmony_cistatic void survival(void)
584f08c3bdfSopenharmony_ci{
585f08c3bdfSopenharmony_ci	struct ipc *ipc;
586f08c3bdfSopenharmony_ci	char page;
587f08c3bdfSopenharmony_ci
588f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
589f08c3bdfSopenharmony_ci		err("shmat error\n");
590f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
591f08c3bdfSopenharmony_ci	testmem("survial", &page, MNOTHING);
592f08c3bdfSopenharmony_ci	if (!failure)
593f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
594f08c3bdfSopenharmony_ci	shmdt(ipc);
595f08c3bdfSopenharmony_ci}
596f08c3bdfSopenharmony_ci*/
597f08c3bdfSopenharmony_ci
598f08c3bdfSopenharmony_cistatic void shm_test(void)
599f08c3bdfSopenharmony_ci{
600f08c3bdfSopenharmony_ci	struct ipc *ipc;
601f08c3bdfSopenharmony_ci
602f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
603f08c3bdfSopenharmony_ci		err("shmat error\n");
604f08c3bdfSopenharmony_ci	ipc->test[instance].id = testid;
605f08c3bdfSopenharmony_ci
606f08c3bdfSopenharmony_ci	request_sem(semid_ready, 0);
607f08c3bdfSopenharmony_ci	if (!ipc->shm.ready) {
608f08c3bdfSopenharmony_ci		if ((ipc->shm.id = shmget(IPC_PRIVATE, shm_size * PS,
609f08c3bdfSopenharmony_ci					  SHM_MODE)) < 0)
610f08c3bdfSopenharmony_ci			err("shmget error\n");
611f08c3bdfSopenharmony_ci		ipc->shm.ready = 1;
612f08c3bdfSopenharmony_ci	}
613f08c3bdfSopenharmony_ci	if ((shmptr = shmat(ipc->shm.id, 0, 0)) == (void *)-1) {
614f08c3bdfSopenharmony_ci		err("shmat error\n");
615f08c3bdfSopenharmony_ci	} else
616f08c3bdfSopenharmony_ci		*shmptr = mypid;
617f08c3bdfSopenharmony_ci	release_sem(semid_ready, 0);
618f08c3bdfSopenharmony_ci
619f08c3bdfSopenharmony_ci	waiton_sem(semid_ready, 1);
620f08c3bdfSopenharmony_ci
621f08c3bdfSopenharmony_ci	request_sem(semid_ready, 0);
622f08c3bdfSopenharmony_ci	if (!ipc->shm.done) {
623f08c3bdfSopenharmony_ci		ipc->shm.done = 1;
624f08c3bdfSopenharmony_ci		testmem("shm dirty", (char *)shmptr, MWRITE);
625f08c3bdfSopenharmony_ci	} else
626f08c3bdfSopenharmony_ci		recover("shm dirty", (char *)shmptr, MREAD);
627f08c3bdfSopenharmony_ci	release_sem(semid_ready, 0);
628f08c3bdfSopenharmony_ci
629f08c3bdfSopenharmony_ci	if (!failure)
630f08c3bdfSopenharmony_ci		ipc->test[instance].result = TEST_PASS;
631f08c3bdfSopenharmony_ci	shmdt(shmptr);
632f08c3bdfSopenharmony_ci	shmdt(ipc);
633f08c3bdfSopenharmony_ci}
634f08c3bdfSopenharmony_ci
635f08c3bdfSopenharmony_cistatic void setup_ipc(void)
636f08c3bdfSopenharmony_ci{
637f08c3bdfSopenharmony_ci	int size;
638f08c3bdfSopenharmony_ci	union semun sunion;
639f08c3bdfSopenharmony_ci	struct ipc *ipc;
640f08c3bdfSopenharmony_ci
641f08c3bdfSopenharmony_ci	size = sizeof(struct ipc);
642f08c3bdfSopenharmony_ci
643f08c3bdfSopenharmony_ci	if ((ipc_entry = shmget(IPC_PRIVATE, size, SHM_MODE)) < 0)
644f08c3bdfSopenharmony_ci		err("shmget error\n");
645f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
646f08c3bdfSopenharmony_ci		err("shmat error\n");
647f08c3bdfSopenharmony_ci	memset(ipc, 0, sizeof(struct ipc));
648f08c3bdfSopenharmony_ci	ipc->shm.id = -1;
649f08c3bdfSopenharmony_ci	shmdt(ipc);
650f08c3bdfSopenharmony_ci
651f08c3bdfSopenharmony_ci	semid_ready = semget(IPC_PRIVATE, 2, SHM_R | SHM_W);
652f08c3bdfSopenharmony_ci	sunion.val = 1;
653f08c3bdfSopenharmony_ci	semctl(semid_ready, 0, SETVAL, sunion);
654f08c3bdfSopenharmony_ci	if (t_shm != -1) {
655f08c3bdfSopenharmony_ci		if (((child_num - 1) % test_types) >= t_shm)
656f08c3bdfSopenharmony_ci			shm_child_num = (child_num - 1) / test_types + 1;
657f08c3bdfSopenharmony_ci		else
658f08c3bdfSopenharmony_ci			shm_child_num = (child_num - 1) / test_types;
659f08c3bdfSopenharmony_ci	}
660f08c3bdfSopenharmony_ci	if (shm_child_num) {
661f08c3bdfSopenharmony_ci		sunion.val = shm_child_num;
662f08c3bdfSopenharmony_ci		semctl(semid_ready, 1, SETVAL, sunion);
663f08c3bdfSopenharmony_ci		mylog("there are %d shm_child\n", shm_child_num);
664f08c3bdfSopenharmony_ci	}
665f08c3bdfSopenharmony_ci}
666f08c3bdfSopenharmony_ci
667f08c3bdfSopenharmony_cistatic void free_ipc(void)
668f08c3bdfSopenharmony_ci{
669f08c3bdfSopenharmony_ci	struct ipc *ipc;
670f08c3bdfSopenharmony_ci
671f08c3bdfSopenharmony_ci	semctl(semid_ready, 0, IPC_RMID);
672f08c3bdfSopenharmony_ci	if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
673f08c3bdfSopenharmony_ci		err("shmat error\n");
674f08c3bdfSopenharmony_ci	if (ipc->shm.id != -1)
675f08c3bdfSopenharmony_ci		shmctl(ipc->shm.id, IPC_RMID, 0);
676f08c3bdfSopenharmony_ci	shmdt(ipc);
677f08c3bdfSopenharmony_ci	shmctl(ipc_entry, IPC_RMID, 0);
678f08c3bdfSopenharmony_ci}
679f08c3bdfSopenharmony_ci
680f08c3bdfSopenharmony_cistatic void cleanup(void)
681f08c3bdfSopenharmony_ci{
682f08c3bdfSopenharmony_ci	int i;
683f08c3bdfSopenharmony_ci	for (i = 0; i < instance; i++)
684f08c3bdfSopenharmony_ci		kill(g_pid[i], 9);	//kill the suviving child.
685f08c3bdfSopenharmony_ci	free_ipc();
686f08c3bdfSopenharmony_ci}
687f08c3bdfSopenharmony_ci
688f08c3bdfSopenharmony_cistruct testcase {
689f08c3bdfSopenharmony_ci	void (*f) (void);
690f08c3bdfSopenharmony_ci	char *name;
691f08c3bdfSopenharmony_ci	int survivable;
692f08c3bdfSopenharmony_ci} cases[] = {
693f08c3bdfSopenharmony_ci	{
694f08c3bdfSopenharmony_ci	shm_test, "shared memory test", 0}, {
695f08c3bdfSopenharmony_ci	anon_clean, "anonymous clean", 1}, {
696f08c3bdfSopenharmony_ci	dirty_anonymous, "anonymous dirty", 0}, {
697f08c3bdfSopenharmony_ci	dirty_anonymous_unmap, "anonymous dirty unmap", 0}, {
698f08c3bdfSopenharmony_ci	mlocked_anonymous, "anonymous dirty mlocked", 0}, {
699f08c3bdfSopenharmony_ci	file_clean, "file clean", 1}, {
700f08c3bdfSopenharmony_ci	file_dirty, "file dirty", 0}, {
701f08c3bdfSopenharmony_ci	file_clean_mlocked, "file clean mlocked", 1}, {
702f08c3bdfSopenharmony_ci	file_dirty_mlocked, "file dirty mlocked", 0},
703f08c3bdfSopenharmony_ci//      { survival, "survival", 0 },
704f08c3bdfSopenharmony_ci	{
705f08c3bdfSopenharmony_ci	NULL, NULL, 0}
706f08c3bdfSopenharmony_ci};
707f08c3bdfSopenharmony_ci
708f08c3bdfSopenharmony_cistatic int run_test(int children)
709f08c3bdfSopenharmony_ci{
710f08c3bdfSopenharmony_ci	pid_t pid = -1;
711f08c3bdfSopenharmony_ci	int i = 0, rc = 0;
712f08c3bdfSopenharmony_ci	siginfo_t sig;
713f08c3bdfSopenharmony_ci	struct ipc *ipc;
714f08c3bdfSopenharmony_ci
715f08c3bdfSopenharmony_ci	for (i = 0; i < children; i++) {
716f08c3bdfSopenharmony_ci		pid = fork();
717f08c3bdfSopenharmony_ci		if (pid < 0) {
718f08c3bdfSopenharmony_ci			err("fork %d\n", i);
719f08c3bdfSopenharmony_ci			break;
720f08c3bdfSopenharmony_ci		} else if (pid == 0) {
721f08c3bdfSopenharmony_ci			int j = instance % test_types;
722f08c3bdfSopenharmony_ci			mypid = getpid();
723f08c3bdfSopenharmony_ci			testid = j;
724f08c3bdfSopenharmony_ci			cases[j].f();
725f08c3bdfSopenharmony_ci			exit(0);
726f08c3bdfSopenharmony_ci		} else {
727f08c3bdfSopenharmony_ci			g_pid[i] = pid;
728f08c3bdfSopenharmony_ci			++instance;
729f08c3bdfSopenharmony_ci			fflush(stdout);
730f08c3bdfSopenharmony_ci		}
731f08c3bdfSopenharmony_ci	}
732f08c3bdfSopenharmony_ci
733f08c3bdfSopenharmony_ci	mylog("have spawned %d processes\n", instance);
734f08c3bdfSopenharmony_ci	if (instance) {
735f08c3bdfSopenharmony_ci		if ((ipc = shmat(ipc_entry, 0, 0)) == (void *)-1)
736f08c3bdfSopenharmony_ci			err("shmat error\n");
737f08c3bdfSopenharmony_ci
738f08c3bdfSopenharmony_ci		for (i = 0; i < instance; i++) {
739f08c3bdfSopenharmony_ci			int t = ipc->test[i].id;
740f08c3bdfSopenharmony_ci
741f08c3bdfSopenharmony_ci			mylog("wait for Pid %d\n", g_pid[i]);
742f08c3bdfSopenharmony_ci			waitid(P_PID, g_pid[i], &sig, WEXITED);
743f08c3bdfSopenharmony_ci			if (ipc->test[i].result == TEST_PASS)
744f08c3bdfSopenharmony_ci				result("Ins %d: Pid %d: pass - %s\n", i,
745f08c3bdfSopenharmony_ci				      g_pid[i], cases[t].name);
746f08c3bdfSopenharmony_ci			else {
747f08c3bdfSopenharmony_ci				result("Ins %d: Pid %d: failed - %s\n", i,
748f08c3bdfSopenharmony_ci				       g_pid[i], cases[t].name);
749f08c3bdfSopenharmony_ci				failure++;
750f08c3bdfSopenharmony_ci			}
751f08c3bdfSopenharmony_ci		}
752f08c3bdfSopenharmony_ci		shmdt(ipc);
753f08c3bdfSopenharmony_ci	}
754f08c3bdfSopenharmony_ci
755f08c3bdfSopenharmony_ci	if (!failure)
756f08c3bdfSopenharmony_ci		result("\t!!! Page Poisoning Test got PASS. !!!\n\n");
757f08c3bdfSopenharmony_ci	else {
758f08c3bdfSopenharmony_ci		result("\t!!! Page Poisoning Test is FAILED (%d failures found). !!!\n\n",
759f08c3bdfSopenharmony_ci		         failure);
760f08c3bdfSopenharmony_ci		rc = 1;
761f08c3bdfSopenharmony_ci	}
762f08c3bdfSopenharmony_ci
763f08c3bdfSopenharmony_ci	return rc;
764f08c3bdfSopenharmony_ci}
765f08c3bdfSopenharmony_ci
766f08c3bdfSopenharmony_cistatic void setup_log(void)
767f08c3bdfSopenharmony_ci{
768f08c3bdfSopenharmony_ci	int rc = 0;
769f08c3bdfSopenharmony_ci	if (clean_env)
770f08c3bdfSopenharmony_ci		log_fd = fopen(log_file, "w");
771f08c3bdfSopenharmony_ci	else
772f08c3bdfSopenharmony_ci		log_fd = fopen(log_file, "a");
773f08c3bdfSopenharmony_ci	if (!log_fd)
774f08c3bdfSopenharmony_ci		err("cannot open log file: %s\n", log_file);
775f08c3bdfSopenharmony_ci
776f08c3bdfSopenharmony_ci	if (clean_env)
777f08c3bdfSopenharmony_ci		result_fd = fopen(result_file, "w");
778f08c3bdfSopenharmony_ci	else
779f08c3bdfSopenharmony_ci		result_fd = fopen(result_file, "a");
780f08c3bdfSopenharmony_ci	if (!result_fd)
781f08c3bdfSopenharmony_ci		err("cannot open log file: %s\n", result_file);
782f08c3bdfSopenharmony_ci
783f08c3bdfSopenharmony_ci	if (tmp_dir[0] != '\0') {
784f08c3bdfSopenharmony_ci		rc = mkdir(tmp_dir, 0777);
785f08c3bdfSopenharmony_ci		if (rc && errno != EEXIST)
786f08c3bdfSopenharmony_ci			err("cannot create tmp dir: %s: %s\n", tmp_dir,
787f08c3bdfSopenharmony_ci			    strerror(errno));
788f08c3bdfSopenharmony_ci	}
789f08c3bdfSopenharmony_ci}
790f08c3bdfSopenharmony_ci
791f08c3bdfSopenharmony_cistatic void free_log(void)
792f08c3bdfSopenharmony_ci{
793f08c3bdfSopenharmony_ci	fclose(log_fd);
794f08c3bdfSopenharmony_ci	fclose(result_fd);
795f08c3bdfSopenharmony_ci}
796f08c3bdfSopenharmony_ci
797f08c3bdfSopenharmony_cistatic void main_sighandler(int sig, siginfo_t * si, void *arg)
798f08c3bdfSopenharmony_ci{
799f08c3bdfSopenharmony_ci	mylog("receive signal to get terminated\n");
800f08c3bdfSopenharmony_ci	cleanup();
801f08c3bdfSopenharmony_ci	exit(1);
802f08c3bdfSopenharmony_ci}
803f08c3bdfSopenharmony_ci
804f08c3bdfSopenharmony_cistatic void setup_sig(void)
805f08c3bdfSopenharmony_ci{
806f08c3bdfSopenharmony_ci	struct sigaction sa = {
807f08c3bdfSopenharmony_ci		.sa_sigaction = main_sighandler,
808f08c3bdfSopenharmony_ci		.sa_flags = SA_SIGINFO
809f08c3bdfSopenharmony_ci	};
810f08c3bdfSopenharmony_ci	struct sigaction sa_bus = {
811f08c3bdfSopenharmony_ci		.sa_sigaction = sighandler,
812f08c3bdfSopenharmony_ci		.sa_flags = SA_SIGINFO
813f08c3bdfSopenharmony_ci	};
814f08c3bdfSopenharmony_ci
815f08c3bdfSopenharmony_ci	sigaction(SIGINT, &sa, NULL);
816f08c3bdfSopenharmony_ci	sigaction(SIGKILL, &sa, NULL);
817f08c3bdfSopenharmony_ci	sigaction(SIGTERM, &sa, NULL);
818f08c3bdfSopenharmony_ci	sigaction(SIGBUS, &sa_bus, NULL);
819f08c3bdfSopenharmony_ci}
820f08c3bdfSopenharmony_ci
821f08c3bdfSopenharmony_cistatic void setup_test(void)
822f08c3bdfSopenharmony_ci{
823f08c3bdfSopenharmony_ci	struct testcase *t;
824f08c3bdfSopenharmony_ci	/* catch signals */
825f08c3bdfSopenharmony_ci	for (t = cases; t->f; t++)
826f08c3bdfSopenharmony_ci		if (t->f == shm_test)
827f08c3bdfSopenharmony_ci			t_shm = (t - cases);
828f08c3bdfSopenharmony_ci	test_types = t - cases;
829f08c3bdfSopenharmony_ci}
830f08c3bdfSopenharmony_ci
831f08c3bdfSopenharmony_ciint main(int argc, char **argv)
832f08c3bdfSopenharmony_ci{
833f08c3bdfSopenharmony_ci	int rc = 0, c, opt_index;
834f08c3bdfSopenharmony_ci
835f08c3bdfSopenharmony_ci	snprintf(log_file, sizeof(log_file), "page-poisoning.log");
836f08c3bdfSopenharmony_ci	snprintf(result_file, sizeof(result_file), "page-poisoning.result");
837f08c3bdfSopenharmony_ci	snprintf(tmp_dir, sizeof(tmp_dir), "./tmp");
838f08c3bdfSopenharmony_ci	while (1) {
839f08c3bdfSopenharmony_ci		c = getopt_long(argc, argv, "Chi:l:r:s:t:", opts, &opt_index);
840f08c3bdfSopenharmony_ci		if (c == -1)
841f08c3bdfSopenharmony_ci			break;
842f08c3bdfSopenharmony_ci		switch (c) {
843f08c3bdfSopenharmony_ci		case 'C':
844f08c3bdfSopenharmony_ci			clean_env = 1;
845f08c3bdfSopenharmony_ci			break;
846f08c3bdfSopenharmony_ci		case 'h':
847f08c3bdfSopenharmony_ci			help();
848f08c3bdfSopenharmony_ci			return 0;
849f08c3bdfSopenharmony_ci		case 'i':
850f08c3bdfSopenharmony_ci			child_num = strtol(optarg, NULL, 0);
851f08c3bdfSopenharmony_ci			if (child_num > INSTANCE_NUM)
852f08c3bdfSopenharmony_ci				child_num = INSTANCE_NUM;
853f08c3bdfSopenharmony_ci			break;
854f08c3bdfSopenharmony_ci		case 'l':
855f08c3bdfSopenharmony_ci			snprintf(log_file, sizeof(log_file), "%s", optarg);
856f08c3bdfSopenharmony_ci			break;
857f08c3bdfSopenharmony_ci		case 'r':
858f08c3bdfSopenharmony_ci			snprintf(result_file, sizeof(result_file), "%s",
859f08c3bdfSopenharmony_ci				 optarg);
860f08c3bdfSopenharmony_ci			break;
861f08c3bdfSopenharmony_ci		case 's':
862f08c3bdfSopenharmony_ci			shm_size = strtol(optarg, NULL, 0);
863f08c3bdfSopenharmony_ci			if (shm_size < SHM_SIZE)
864f08c3bdfSopenharmony_ci				shm_size = SHM_SIZE;
865f08c3bdfSopenharmony_ci			break;
866f08c3bdfSopenharmony_ci		case 't':
867f08c3bdfSopenharmony_ci			snprintf(tmp_dir, sizeof(tmp_dir), "%s", optarg);
868f08c3bdfSopenharmony_ci			break;
869f08c3bdfSopenharmony_ci		default:
870f08c3bdfSopenharmony_ci			help();
871f08c3bdfSopenharmony_ci			return 0;
872f08c3bdfSopenharmony_ci		}
873f08c3bdfSopenharmony_ci	}
874f08c3bdfSopenharmony_ci
875f08c3bdfSopenharmony_ci	if (!early_kill)
876f08c3bdfSopenharmony_ci		system("sysctl -w vm.memory_failure_early_kill=0");
877f08c3bdfSopenharmony_ci	mypid = getpid();
878f08c3bdfSopenharmony_ci	setup_log();
879f08c3bdfSopenharmony_ci	setup_test();
880f08c3bdfSopenharmony_ci	if (!child_num) {
881f08c3bdfSopenharmony_ci		mylog("end without test executed since child_num = 0\n");
882f08c3bdfSopenharmony_ci		return rc;
883f08c3bdfSopenharmony_ci	}
884f08c3bdfSopenharmony_ci
885f08c3bdfSopenharmony_ci	mylog("start page-poisoning test\n");
886f08c3bdfSopenharmony_ci	PS = getpagesize();
887f08c3bdfSopenharmony_ci	setup_ipc();
888f08c3bdfSopenharmony_ci	setup_sig();
889f08c3bdfSopenharmony_ci	rc = run_test(child_num);
890f08c3bdfSopenharmony_ci	free_ipc();
891f08c3bdfSopenharmony_ci	mylog("page-poisoning test done!\n");
892f08c3bdfSopenharmony_ci	free_log();
893f08c3bdfSopenharmony_ci
894f08c3bdfSopenharmony_ci	return rc;
895f08c3bdfSopenharmony_ci}
896