1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Test program for memory error handling for hugepages 3f08c3bdfSopenharmony_ci * Author: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci#define _GNU_SOURCE 1 6f08c3bdfSopenharmony_ci#include <stdlib.h> 7f08c3bdfSopenharmony_ci#include <stdio.h> 8f08c3bdfSopenharmony_ci#include <string.h> 9f08c3bdfSopenharmony_ci#include <fcntl.h> 10f08c3bdfSopenharmony_ci#include <signal.h> 11f08c3bdfSopenharmony_ci#include <unistd.h> 12f08c3bdfSopenharmony_ci#include <getopt.h> 13f08c3bdfSopenharmony_ci#include <sys/mman.h> 14f08c3bdfSopenharmony_ci#include <sys/ipc.h> 15f08c3bdfSopenharmony_ci#include <sys/shm.h> 16f08c3bdfSopenharmony_ci#include <sys/sem.h> 17f08c3bdfSopenharmony_ci#include <sys/types.h> 18f08c3bdfSopenharmony_ci#include <sys/prctl.h> 19f08c3bdfSopenharmony_ci#include <sys/wait.h> 20f08c3bdfSopenharmony_ci#include "hugepage.h" 21f08c3bdfSopenharmony_ci 22f08c3bdfSopenharmony_ci#define FILE_BASE "test" 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#define HPAGE_SIZE (2UL*1024*1024) 25f08c3bdfSopenharmony_ci#define BUF_SIZE 256 26f08c3bdfSopenharmony_ci#define PROTECTION (PROT_READ | PROT_WRITE) 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_ci#ifndef SHM_HUGETLB 29f08c3bdfSopenharmony_ci#define SHM_HUGETLB 04000 30f08c3bdfSopenharmony_ci#endif 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci/* Control early_kill/late_kill */ 33f08c3bdfSopenharmony_ci#define PR_MCE_KILL 33 34f08c3bdfSopenharmony_ci#define PR_MCE_KILL_CLEAR 0 35f08c3bdfSopenharmony_ci#define PR_MCE_KILL_SET 1 36f08c3bdfSopenharmony_ci#define PR_MCE_KILL_LATE 0 37f08c3bdfSopenharmony_ci#define PR_MCE_KILL_EARLY 1 38f08c3bdfSopenharmony_ci#define PR_MCE_KILL_DEFAULT 2 39f08c3bdfSopenharmony_ci#define PR_MCE_KILL_GET 34 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci#define MADV_HWPOISON 100 42f08c3bdfSopenharmony_ci#define MADV_SOFT_OFFLINE 101 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_ciint PS; /* Page size */ 45f08c3bdfSopenharmony_ciint file_size; /* Memory allocation size (hugepage unit) */ 46f08c3bdfSopenharmony_ci/* Error injection position (page offset from the first hugepage head) */ 47f08c3bdfSopenharmony_ciint corrupt_page; 48f08c3bdfSopenharmony_cichar filename[BUF_SIZE] = "/test"; 49f08c3bdfSopenharmony_cichar filepath[BUF_SIZE]; 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci#define DEB printf("DEBUG [%d:%s:%d]\n", getpid(), __FILE__, __LINE__); 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_cistatic void usage(void) 54f08c3bdfSopenharmony_ci{ 55f08c3bdfSopenharmony_ci printf( 56f08c3bdfSopenharmony_ci"./thugetlb [-m memory] [-o offset] [-f file] [-xOeSAaFpch] hugetlbfs_directory\n" 57f08c3bdfSopenharmony_ci" -m|--memory size(hugepage unit) Size of hugetlbfs file\n" 58f08c3bdfSopenharmony_ci" -o|--offset offset(page unit) Position of error injection\n" 59f08c3bdfSopenharmony_ci" -x|--inject Error injection switch\n" 60f08c3bdfSopenharmony_ci" -O|--offline Soft offline switch\n" 61f08c3bdfSopenharmony_ci" -e|--early-kill Set PR_MCE_KILL_EARLY\n" 62f08c3bdfSopenharmony_ci" -S|--shm Use shmem with SHM_HUGETLB\n" 63f08c3bdfSopenharmony_ci" -A|--anonymous Use MAP_ANONYMOUS\n" 64f08c3bdfSopenharmony_ci" -a|--avoid-touch Avoid touching error page\n" 65f08c3bdfSopenharmony_ci" -F|--fork\n" 66f08c3bdfSopenharmony_ci" -p|--private\n" 67f08c3bdfSopenharmony_ci" -c|--cow\n" 68f08c3bdfSopenharmony_ci" -f|--filename string\n" 69f08c3bdfSopenharmony_ci" -h|--help\n" 70f08c3bdfSopenharmony_ci"\n" 71f08c3bdfSopenharmony_ci ); 72f08c3bdfSopenharmony_ci} 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci/* 75f08c3bdfSopenharmony_ci * semaphore get/put wrapper 76f08c3bdfSopenharmony_ci */ 77f08c3bdfSopenharmony_ciint get_semaphore(int sem_id, struct sembuf *sembuffer) 78f08c3bdfSopenharmony_ci{ 79f08c3bdfSopenharmony_ci sembuffer->sem_num = 0; 80f08c3bdfSopenharmony_ci sembuffer->sem_op = -1; 81f08c3bdfSopenharmony_ci sembuffer->sem_flg = SEM_UNDO; 82f08c3bdfSopenharmony_ci return semop(sem_id, sembuffer, 1); 83f08c3bdfSopenharmony_ci} 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_ciint put_semaphore(int sem_id, struct sembuf *sembuffer) 86f08c3bdfSopenharmony_ci{ 87f08c3bdfSopenharmony_ci sembuffer->sem_num = 0; 88f08c3bdfSopenharmony_ci sembuffer->sem_op = 1; 89f08c3bdfSopenharmony_ci sembuffer->sem_flg = SEM_UNDO; 90f08c3bdfSopenharmony_ci return semop(sem_id, sembuffer, 1); 91f08c3bdfSopenharmony_ci} 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_cistatic struct option opts[] = { 94f08c3bdfSopenharmony_ci { "memory" , 1, NULL, 'm' }, 95f08c3bdfSopenharmony_ci { "offset" , 1, NULL, 'o' }, 96f08c3bdfSopenharmony_ci { "inject" , 0, NULL, 'x' }, 97f08c3bdfSopenharmony_ci { "offline" , 0, NULL, 'O' }, 98f08c3bdfSopenharmony_ci { "early_kill" , 0, NULL, 'e' }, 99f08c3bdfSopenharmony_ci { "shm" , 0, NULL, 'S' }, 100f08c3bdfSopenharmony_ci { "anonymous" , 0, NULL, 'A' }, 101f08c3bdfSopenharmony_ci { "avoid-touch" , 0, NULL, 'a' }, 102f08c3bdfSopenharmony_ci { "fork" , 0, NULL, 'F' }, 103f08c3bdfSopenharmony_ci { "private" , 0, NULL, 'p' }, 104f08c3bdfSopenharmony_ci { "cow" , 0, NULL, 'c' }, 105f08c3bdfSopenharmony_ci { "filename" , 1, NULL, 'f' }, 106f08c3bdfSopenharmony_ci { "help" , 0, NULL, 'h' }, 107f08c3bdfSopenharmony_ci { NULL , 0, NULL, 0 } 108f08c3bdfSopenharmony_ci}; 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 111f08c3bdfSopenharmony_ci{ 112f08c3bdfSopenharmony_ci void *addr; 113f08c3bdfSopenharmony_ci int i; 114f08c3bdfSopenharmony_ci int ret; 115f08c3bdfSopenharmony_ci int fd = 0; 116f08c3bdfSopenharmony_ci int semid; 117f08c3bdfSopenharmony_ci int semaphore; 118f08c3bdfSopenharmony_ci int inject = 0; 119f08c3bdfSopenharmony_ci int madvise_code = MADV_HWPOISON; 120f08c3bdfSopenharmony_ci int early_kill = 0; 121f08c3bdfSopenharmony_ci int avoid_touch = 0; 122f08c3bdfSopenharmony_ci int anonflag = 0; 123f08c3bdfSopenharmony_ci int shmflag = 0; 124f08c3bdfSopenharmony_ci int shmkey = 0; 125f08c3bdfSopenharmony_ci int forkflag = 0; 126f08c3bdfSopenharmony_ci int privateflag = 0; 127f08c3bdfSopenharmony_ci int cowflag = 0; 128f08c3bdfSopenharmony_ci char c; 129f08c3bdfSopenharmony_ci pid_t pid = 0; 130f08c3bdfSopenharmony_ci void *expected_addr = NULL; 131f08c3bdfSopenharmony_ci struct sembuf sembuffer; 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci PS = getpagesize(); 134f08c3bdfSopenharmony_ci HPS = HPAGE_SIZE; 135f08c3bdfSopenharmony_ci file_size = 1; 136f08c3bdfSopenharmony_ci corrupt_page = -1; 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_ci if (argc == 1) { 139f08c3bdfSopenharmony_ci usage(); 140f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 141f08c3bdfSopenharmony_ci } 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_ci while ((c = getopt_long(argc, argv, 144f08c3bdfSopenharmony_ci "m:o:xOeSAaFpcf:h", opts, NULL)) != -1) { 145f08c3bdfSopenharmony_ci switch (c) { 146f08c3bdfSopenharmony_ci case 'm': 147f08c3bdfSopenharmony_ci file_size = strtol(optarg, NULL, 10); 148f08c3bdfSopenharmony_ci break; 149f08c3bdfSopenharmony_ci case 'o': 150f08c3bdfSopenharmony_ci corrupt_page = strtol(optarg, NULL, 10); 151f08c3bdfSopenharmony_ci break; 152f08c3bdfSopenharmony_ci case 'x': 153f08c3bdfSopenharmony_ci inject = 1; 154f08c3bdfSopenharmony_ci break; 155f08c3bdfSopenharmony_ci case 'O': 156f08c3bdfSopenharmony_ci madvise_code = MADV_SOFT_OFFLINE; 157f08c3bdfSopenharmony_ci break; 158f08c3bdfSopenharmony_ci case 'e': 159f08c3bdfSopenharmony_ci early_kill = 1; 160f08c3bdfSopenharmony_ci break; 161f08c3bdfSopenharmony_ci case 'S': 162f08c3bdfSopenharmony_ci shmflag = 1; 163f08c3bdfSopenharmony_ci break; 164f08c3bdfSopenharmony_ci case 'A': 165f08c3bdfSopenharmony_ci anonflag = 1; 166f08c3bdfSopenharmony_ci break; 167f08c3bdfSopenharmony_ci case 'a': 168f08c3bdfSopenharmony_ci avoid_touch = 1; 169f08c3bdfSopenharmony_ci break; 170f08c3bdfSopenharmony_ci case 'F': 171f08c3bdfSopenharmony_ci forkflag = 1; 172f08c3bdfSopenharmony_ci break; 173f08c3bdfSopenharmony_ci case 'p': 174f08c3bdfSopenharmony_ci privateflag = 1; 175f08c3bdfSopenharmony_ci break; 176f08c3bdfSopenharmony_ci case 'c': 177f08c3bdfSopenharmony_ci cowflag = 1; 178f08c3bdfSopenharmony_ci break; 179f08c3bdfSopenharmony_ci case 'f': 180f08c3bdfSopenharmony_ci strcat(filename, optarg); 181f08c3bdfSopenharmony_ci shmkey = strtol(optarg, NULL, 10); 182f08c3bdfSopenharmony_ci break; 183f08c3bdfSopenharmony_ci case 'h': 184f08c3bdfSopenharmony_ci usage(); 185f08c3bdfSopenharmony_ci exit(EXIT_SUCCESS); 186f08c3bdfSopenharmony_ci default: 187f08c3bdfSopenharmony_ci usage(); 188f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 189f08c3bdfSopenharmony_ci } 190f08c3bdfSopenharmony_ci } 191f08c3bdfSopenharmony_ci 192f08c3bdfSopenharmony_ci if (inject && corrupt_page * PS > file_size * HPAGE_SIZE) 193f08c3bdfSopenharmony_ci errmsg("Target page is out of range.\n"); 194f08c3bdfSopenharmony_ci 195f08c3bdfSopenharmony_ci if (avoid_touch && corrupt_page == -1) 196f08c3bdfSopenharmony_ci errmsg("Avoid which page?\n"); 197f08c3bdfSopenharmony_ci 198f08c3bdfSopenharmony_ci /* Construct file name */ 199f08c3bdfSopenharmony_ci if (access(argv[argc - 1], F_OK) == -1) { 200f08c3bdfSopenharmony_ci usage(); 201f08c3bdfSopenharmony_ci exit(EXIT_FAILURE); 202f08c3bdfSopenharmony_ci } else { 203f08c3bdfSopenharmony_ci strcpy(filepath, argv[argc - 1]); 204f08c3bdfSopenharmony_ci strcat(filepath, filename); 205f08c3bdfSopenharmony_ci } 206f08c3bdfSopenharmony_ci 207f08c3bdfSopenharmony_ci if (shmflag) { 208f08c3bdfSopenharmony_ci addr = alloc_shm_hugepage(&shmkey, file_size * HPAGE_SIZE); 209f08c3bdfSopenharmony_ci if (!addr) 210f08c3bdfSopenharmony_ci errmsg("Failed in alloc_shm_hugepage()"); 211f08c3bdfSopenharmony_ci } else if (anonflag) { 212f08c3bdfSopenharmony_ci addr = alloc_anonymous_hugepage(file_size * HPAGE_SIZE, 213f08c3bdfSopenharmony_ci privateflag); 214f08c3bdfSopenharmony_ci if (!addr) 215f08c3bdfSopenharmony_ci errmsg("Failed in alloc_anonymous_hugepage()"); 216f08c3bdfSopenharmony_ci } else { 217f08c3bdfSopenharmony_ci addr = alloc_filebacked_hugepage(filepath, 218f08c3bdfSopenharmony_ci file_size * HPAGE_SIZE, 219f08c3bdfSopenharmony_ci privateflag, &fd); 220f08c3bdfSopenharmony_ci if (!addr) 221f08c3bdfSopenharmony_ci errmsg("Failed in alloc_filebacked_hugepage()"); 222f08c3bdfSopenharmony_ci } 223f08c3bdfSopenharmony_ci 224f08c3bdfSopenharmony_ci if (corrupt_page != -1 && avoid_touch) 225f08c3bdfSopenharmony_ci expected_addr = (void *)(addr + corrupt_page / 512 * HPAGE_SIZE); 226f08c3bdfSopenharmony_ci 227f08c3bdfSopenharmony_ci if (forkflag) { 228f08c3bdfSopenharmony_ci semid = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT); 229f08c3bdfSopenharmony_ci if (semid == -1) { 230f08c3bdfSopenharmony_ci perror("semget"); 231f08c3bdfSopenharmony_ci goto cleanout; 232f08c3bdfSopenharmony_ci } 233f08c3bdfSopenharmony_ci semaphore = semctl(semid, 0, SETVAL, 1); 234f08c3bdfSopenharmony_ci if (semaphore == -1) { 235f08c3bdfSopenharmony_ci perror("semctl"); 236f08c3bdfSopenharmony_ci goto cleanout; 237f08c3bdfSopenharmony_ci } 238f08c3bdfSopenharmony_ci if (get_semaphore(semid, &sembuffer)) { 239f08c3bdfSopenharmony_ci perror("get_semaphore"); 240f08c3bdfSopenharmony_ci goto cleanout; 241f08c3bdfSopenharmony_ci } 242f08c3bdfSopenharmony_ci } 243f08c3bdfSopenharmony_ci 244f08c3bdfSopenharmony_ci write_hugepage(addr, file_size, 0); 245f08c3bdfSopenharmony_ci read_hugepage(addr, file_size, 0); 246f08c3bdfSopenharmony_ci 247f08c3bdfSopenharmony_ci if (early_kill) 248f08c3bdfSopenharmony_ci prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 249f08c3bdfSopenharmony_ci NULL, NULL); 250f08c3bdfSopenharmony_ci 251f08c3bdfSopenharmony_ci /* 252f08c3bdfSopenharmony_ci * Intended order: 253f08c3bdfSopenharmony_ci * 1. Child COWs 254f08c3bdfSopenharmony_ci * 2. Parent madvise()s 255f08c3bdfSopenharmony_ci * 3. Child exit()s 256f08c3bdfSopenharmony_ci */ 257f08c3bdfSopenharmony_ci if (forkflag) { 258f08c3bdfSopenharmony_ci pid = fork(); 259f08c3bdfSopenharmony_ci if (!pid) { 260f08c3bdfSopenharmony_ci /* Semaphore is already held */ 261f08c3bdfSopenharmony_ci if (cowflag) { 262f08c3bdfSopenharmony_ci write_hugepage(addr, file_size, 0); 263f08c3bdfSopenharmony_ci read_hugepage(addr, file_size, 0); 264f08c3bdfSopenharmony_ci } 265f08c3bdfSopenharmony_ci if (put_semaphore(semid, &sembuffer)) 266f08c3bdfSopenharmony_ci err("put_semaphore"); 267f08c3bdfSopenharmony_ci usleep(1000); 268f08c3bdfSopenharmony_ci /* Wait for madvise() to be done */ 269f08c3bdfSopenharmony_ci if (get_semaphore(semid, &sembuffer)) 270f08c3bdfSopenharmony_ci err("put_semaphore"); 271f08c3bdfSopenharmony_ci if (put_semaphore(semid, &sembuffer)) 272f08c3bdfSopenharmony_ci err("put_semaphore"); 273f08c3bdfSopenharmony_ci return 0; 274f08c3bdfSopenharmony_ci } 275f08c3bdfSopenharmony_ci } 276f08c3bdfSopenharmony_ci 277f08c3bdfSopenharmony_ci /* Wait for COW */ 278f08c3bdfSopenharmony_ci if (forkflag && get_semaphore(semid, &sembuffer)) { 279f08c3bdfSopenharmony_ci perror("get_semaphore"); 280f08c3bdfSopenharmony_ci goto cleanout; 281f08c3bdfSopenharmony_ci } 282f08c3bdfSopenharmony_ci 283f08c3bdfSopenharmony_ci if (inject && corrupt_page != -1) { 284f08c3bdfSopenharmony_ci ret = madvise(addr + corrupt_page * PS, PS, madvise_code); 285f08c3bdfSopenharmony_ci if (ret) { 286f08c3bdfSopenharmony_ci printf("madivise return %d :", ret); 287f08c3bdfSopenharmony_ci perror("madvise"); 288f08c3bdfSopenharmony_ci goto cleanout; 289f08c3bdfSopenharmony_ci } 290f08c3bdfSopenharmony_ci } 291f08c3bdfSopenharmony_ci 292f08c3bdfSopenharmony_ci if (forkflag && put_semaphore(semid, &sembuffer)) { 293f08c3bdfSopenharmony_ci perror("put_semaphore"); 294f08c3bdfSopenharmony_ci goto cleanout; 295f08c3bdfSopenharmony_ci } 296f08c3bdfSopenharmony_ci 297f08c3bdfSopenharmony_ci if (madvise_code != MADV_SOFT_OFFLINE); 298f08c3bdfSopenharmony_ci write_hugepage(addr, file_size, expected_addr); 299f08c3bdfSopenharmony_ci read_hugepage(addr, file_size, expected_addr); 300f08c3bdfSopenharmony_ci 301f08c3bdfSopenharmony_ci if (forkflag) { 302f08c3bdfSopenharmony_ci if (wait(&i) == -1) 303f08c3bdfSopenharmony_ci err("wait"); 304f08c3bdfSopenharmony_ci if (semctl(semid, 0, IPC_RMID) == -1) 305f08c3bdfSopenharmony_ci err("semctl(IPC_RMID)"); 306f08c3bdfSopenharmony_ci } 307f08c3bdfSopenharmony_cicleanout: 308f08c3bdfSopenharmony_ci if (shmflag) { 309f08c3bdfSopenharmony_ci if (free_shm_hugepage(shmkey, addr) == -1) 310f08c3bdfSopenharmony_ci exit(2); 311f08c3bdfSopenharmony_ci } else if (anonflag) { 312f08c3bdfSopenharmony_ci if (free_anonymous_hugepage(addr, file_size * HPAGE_SIZE) == -1) 313f08c3bdfSopenharmony_ci exit(2); 314f08c3bdfSopenharmony_ci } else { 315f08c3bdfSopenharmony_ci if (free_filebacked_hugepage(addr, file_size * HPAGE_SIZE, 316f08c3bdfSopenharmony_ci fd, filepath) == -1) 317f08c3bdfSopenharmony_ci exit(2); 318f08c3bdfSopenharmony_ci } 319f08c3bdfSopenharmony_ci 320f08c3bdfSopenharmony_ci return 0; 321f08c3bdfSopenharmony_ci} 322