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