1f08c3bdfSopenharmony_ci/* 2f08c3bdfSopenharmony_ci * Test program for Linux poison memory error recovery. 3f08c3bdfSopenharmony_ci * This injects poison into various mapping cases and triggers the poison 4f08c3bdfSopenharmony_ci * handling. Requires special injection support in the kernel. 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Copyright 2009, 2010 Intel Corporation 7f08c3bdfSopenharmony_ci * 8f08c3bdfSopenharmony_ci * tinjpage 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 * tinjpage 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 23f08c3bdfSopenharmony_ci */ 24f08c3bdfSopenharmony_ci#define _GNU_SOURCE 1 25f08c3bdfSopenharmony_ci#include <stdio.h> 26f08c3bdfSopenharmony_ci#include <signal.h> 27f08c3bdfSopenharmony_ci#include <unistd.h> 28f08c3bdfSopenharmony_ci#include <sys/fcntl.h> 29f08c3bdfSopenharmony_ci#include <sys/wait.h> 30f08c3bdfSopenharmony_ci#include <sys/mman.h> 31f08c3bdfSopenharmony_ci#include <stdlib.h> 32f08c3bdfSopenharmony_ci#include <setjmp.h> 33f08c3bdfSopenharmony_ci#include <errno.h> 34f08c3bdfSopenharmony_ci#include <string.h> 35f08c3bdfSopenharmony_ci#include <time.h> 36f08c3bdfSopenharmony_ci#include <pthread.h> 37f08c3bdfSopenharmony_ci#include <sys/ipc.h> 38f08c3bdfSopenharmony_ci#include <sys/shm.h> 39f08c3bdfSopenharmony_ci#include <sys/sem.h> 40f08c3bdfSopenharmony_ci#include "utils.h" 41f08c3bdfSopenharmony_ci#include "hugepage.h" 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci#define MADV_POISON 100 44f08c3bdfSopenharmony_ci 45f08c3bdfSopenharmony_ci#define TMPDIR "./" 46f08c3bdfSopenharmony_ci#define PATHBUFLEN 100 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci#define Perror(x) failure++, perror(x) 49f08c3bdfSopenharmony_ci#define PAIR(x) x, sizeof(x)-1 50f08c3bdfSopenharmony_ci#define mb() asm volatile("" ::: "memory") 51f08c3bdfSopenharmony_ci#if defined(__i386__) || defined(__x86_64__) 52f08c3bdfSopenharmony_ci#define cpu_relax() asm volatile("rep ; nop" ::: "memory") 53f08c3bdfSopenharmony_ci#else 54f08c3bdfSopenharmony_ci#define cpu_relax() mb() 55f08c3bdfSopenharmony_ci#endif 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_citypedef unsigned long long u64; 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ciint PS; 60f08c3bdfSopenharmony_ciint failure; 61f08c3bdfSopenharmony_ciint unexpected; 62f08c3bdfSopenharmony_ciint early_kill; 63f08c3bdfSopenharmony_ciint test_hugepage; 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_civoid *checked_mmap(void *start, size_t length, int prot, int flags, 66f08c3bdfSopenharmony_ci int fd, off_t offset) 67f08c3bdfSopenharmony_ci{ 68f08c3bdfSopenharmony_ci void *map = mmap(start, length, prot, flags, fd, offset); 69f08c3bdfSopenharmony_ci if (map == (void*)-1L) 70f08c3bdfSopenharmony_ci err("mmap"); 71f08c3bdfSopenharmony_ci return map; 72f08c3bdfSopenharmony_ci} 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_civoid munmap_reserve(void *page, int size) 75f08c3bdfSopenharmony_ci{ 76f08c3bdfSopenharmony_ci if (munmap(page, size) < 0) 77f08c3bdfSopenharmony_ci err("munmap"); 78f08c3bdfSopenharmony_ci if (mmap(page, size, PROT_NONE, MAP_PRIVATE|MAP_FIXED, 0, 0) < 0) 79f08c3bdfSopenharmony_ci err("mmap2"); 80f08c3bdfSopenharmony_ci} 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_civoid *xmalloc(size_t s) 83f08c3bdfSopenharmony_ci{ 84f08c3bdfSopenharmony_ci void *p = malloc(s); 85f08c3bdfSopenharmony_ci if (!p) 86f08c3bdfSopenharmony_ci exit(ENOMEM); 87f08c3bdfSopenharmony_ci return p; 88f08c3bdfSopenharmony_ci} 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_cistatic int ilog2(int n) 91f08c3bdfSopenharmony_ci{ 92f08c3bdfSopenharmony_ci int r = 0; 93f08c3bdfSopenharmony_ci n--; 94f08c3bdfSopenharmony_ci while (n) { 95f08c3bdfSopenharmony_ci n >>= 1; 96f08c3bdfSopenharmony_ci r++; 97f08c3bdfSopenharmony_ci } 98f08c3bdfSopenharmony_ci return r; 99f08c3bdfSopenharmony_ci} 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ciint recovercount; 102f08c3bdfSopenharmony_cisigjmp_buf recover_ctx; 103f08c3bdfSopenharmony_cisigjmp_buf early_recover_ctx; 104f08c3bdfSopenharmony_civoid *expected_addr; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci/* Work around glibc not defining this yet */ 107f08c3bdfSopenharmony_cistruct my_siginfo { 108f08c3bdfSopenharmony_ci int si_signo; 109f08c3bdfSopenharmony_ci int si_errno; 110f08c3bdfSopenharmony_ci int si_code; 111f08c3bdfSopenharmony_ci union { 112f08c3bdfSopenharmony_ci struct { 113f08c3bdfSopenharmony_ci void *_addr; /* faulting insn/memory ref. */ 114f08c3bdfSopenharmony_ci#ifdef __ARCH_SI_TRAPNO 115f08c3bdfSopenharmony_ci int _trapno; /* TRAP # which caused the signal */ 116f08c3bdfSopenharmony_ci#endif 117f08c3bdfSopenharmony_ci short _addr_lsb; /* LSB of the reported address */ 118f08c3bdfSopenharmony_ci } _sigfault; 119f08c3bdfSopenharmony_ci } _sifields; 120f08c3bdfSopenharmony_ci}; 121f08c3bdfSopenharmony_ci#undef si_addr_lsb 122f08c3bdfSopenharmony_ci#define si_addr_lsb _sifields._sigfault._addr_lsb 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_civoid sighandler(int sig, siginfo_t *si, void *arg) 125f08c3bdfSopenharmony_ci{ 126f08c3bdfSopenharmony_ci if (si->si_addr != expected_addr) { 127f08c3bdfSopenharmony_ci printf("XXX: Unexpected address in signal %p (expected %p)\n", si->si_addr, 128f08c3bdfSopenharmony_ci expected_addr); 129f08c3bdfSopenharmony_ci failure++; 130f08c3bdfSopenharmony_ci } 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_ci int lsb = ((struct my_siginfo *)si)->si_addr_lsb; 133f08c3bdfSopenharmony_ci if (test_hugepage) { 134f08c3bdfSopenharmony_ci if (lsb != ilog2(HPS)) { 135f08c3bdfSopenharmony_ci printf("LATER: Unexpected addr lsb in siginfo %d\n", lsb); 136f08c3bdfSopenharmony_ci } 137f08c3bdfSopenharmony_ci } else { 138f08c3bdfSopenharmony_ci if (lsb != ilog2(sysconf(_SC_PAGE_SIZE))) { 139f08c3bdfSopenharmony_ci printf("LATER: Unexpected addr lsb in siginfo %d\n", lsb); 140f08c3bdfSopenharmony_ci } 141f08c3bdfSopenharmony_ci } 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_ci printf("\tsignal %d code %d addr %p\n", sig, si->si_code, si->si_addr); 144f08c3bdfSopenharmony_ci 145f08c3bdfSopenharmony_ci if (--recovercount == 0) { 146f08c3bdfSopenharmony_ci write(1, PAIR("I seem to be in a signal loop. bailing out.\n")); 147f08c3bdfSopenharmony_ci exit(1); 148f08c3bdfSopenharmony_ci } 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci if (si->si_code == 4) 151f08c3bdfSopenharmony_ci siglongjmp(recover_ctx, 1); 152f08c3bdfSopenharmony_ci else 153f08c3bdfSopenharmony_ci siglongjmp(early_recover_ctx, 1); 154f08c3bdfSopenharmony_ci} 155f08c3bdfSopenharmony_ci 156f08c3bdfSopenharmony_cienum rmode { 157f08c3bdfSopenharmony_ci MREAD = 0, 158f08c3bdfSopenharmony_ci MWRITE = 1, 159f08c3bdfSopenharmony_ci MREAD_OK = 2, 160f08c3bdfSopenharmony_ci MWRITE_OK = 3, 161f08c3bdfSopenharmony_ci MNOTHING = -1, 162f08c3bdfSopenharmony_ci}; 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_civoid inject_madvise(char *page) 165f08c3bdfSopenharmony_ci{ 166f08c3bdfSopenharmony_ci if (madvise(page, PS, MADV_POISON) != 0) { 167f08c3bdfSopenharmony_ci if (errno == EINVAL) { 168f08c3bdfSopenharmony_ci printf("Kernel doesn't support poison injection\n"); 169f08c3bdfSopenharmony_ci exit(0); 170f08c3bdfSopenharmony_ci } 171f08c3bdfSopenharmony_ci Perror("madvise"); 172f08c3bdfSopenharmony_ci } 173f08c3bdfSopenharmony_ci} 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_ciu64 page_to_pfn(char *page) 176f08c3bdfSopenharmony_ci{ 177f08c3bdfSopenharmony_ci static int pagemap_fd = -1; 178f08c3bdfSopenharmony_ci u64 pfn; 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_ci if (pagemap_fd < 0) { 181f08c3bdfSopenharmony_ci pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 182f08c3bdfSopenharmony_ci if (pagemap_fd < 0) 183f08c3bdfSopenharmony_ci err("/proc/self/pagemap not supported"); 184f08c3bdfSopenharmony_ci } 185f08c3bdfSopenharmony_ci 186f08c3bdfSopenharmony_ci if (pread(pagemap_fd, &pfn, sizeof(u64), 187f08c3bdfSopenharmony_ci ((u64)page / PS)*sizeof(u64)) != sizeof(u64)) 188f08c3bdfSopenharmony_ci err("Cannot read from pagemap"); 189f08c3bdfSopenharmony_ci 190f08c3bdfSopenharmony_ci pfn &= (1ULL<<56)-1; 191f08c3bdfSopenharmony_ci return pfn; 192f08c3bdfSopenharmony_ci} 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_ci/* 195f08c3bdfSopenharmony_ci * Inject Action Optional #MC 196f08c3bdfSopenharmony_ci * with mce-inject using the software injector. 197f08c3bdfSopenharmony_ci * 198f08c3bdfSopenharmony_ci * This tests the low level machine check handler too. 199f08c3bdfSopenharmony_ci * 200f08c3bdfSopenharmony_ci * Slightly racy with page migration because we don't mlock the page. 201f08c3bdfSopenharmony_ci */ 202f08c3bdfSopenharmony_civoid inject_mce_inject(char *page) 203f08c3bdfSopenharmony_ci{ 204f08c3bdfSopenharmony_ci u64 pfn = page_to_pfn(page); 205f08c3bdfSopenharmony_ci FILE *mce_inject; 206f08c3bdfSopenharmony_ci 207f08c3bdfSopenharmony_ci mce_inject = popen("mce-inject", "w"); 208f08c3bdfSopenharmony_ci if (!mce_inject) { 209f08c3bdfSopenharmony_ci fprintf(stderr, "Cannot open pipe to mce-inject: %s\n", 210f08c3bdfSopenharmony_ci strerror(errno)); 211f08c3bdfSopenharmony_ci exit(1); 212f08c3bdfSopenharmony_ci } 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_ci fprintf(mce_inject, 215f08c3bdfSopenharmony_ci "CPU 0 BANK 3 STATUS UNCORRECTED SRAO 0xc0\n" 216f08c3bdfSopenharmony_ci "MCGSTATUS RIPV MCIP\n" 217f08c3bdfSopenharmony_ci "ADDR %#llx\n" 218f08c3bdfSopenharmony_ci "MISC 0x8c\n" 219f08c3bdfSopenharmony_ci "RIP 0x73:0x1eadbabe\n", pfn); 220f08c3bdfSopenharmony_ci 221f08c3bdfSopenharmony_ci if (ferror(mce_inject) || fclose(mce_inject) < 0) { 222f08c3bdfSopenharmony_ci fprintf(stderr, "mce-inject failed: %s\n", strerror(errno)); 223f08c3bdfSopenharmony_ci exit(1); 224f08c3bdfSopenharmony_ci } 225f08c3bdfSopenharmony_ci} 226f08c3bdfSopenharmony_ci 227f08c3bdfSopenharmony_civoid (*inject)(char *page) = inject_madvise; 228f08c3bdfSopenharmony_ci 229f08c3bdfSopenharmony_civoid poison(char *msg, char *page, enum rmode mode) 230f08c3bdfSopenharmony_ci{ 231f08c3bdfSopenharmony_ci expected_addr = page; 232f08c3bdfSopenharmony_ci recovercount = 5; 233f08c3bdfSopenharmony_ci 234f08c3bdfSopenharmony_ci if (sigsetjmp(early_recover_ctx, 1) == 0) { 235f08c3bdfSopenharmony_ci inject(page); 236f08c3bdfSopenharmony_ci 237f08c3bdfSopenharmony_ci if (early_kill && (mode == MWRITE || mode == MREAD)) { 238f08c3bdfSopenharmony_ci printf("XXX: %s: process is not early killed\n", msg); 239f08c3bdfSopenharmony_ci failure++; 240f08c3bdfSopenharmony_ci } 241f08c3bdfSopenharmony_ci 242f08c3bdfSopenharmony_ci return; 243f08c3bdfSopenharmony_ci } 244f08c3bdfSopenharmony_ci 245f08c3bdfSopenharmony_ci if (early_kill) { 246f08c3bdfSopenharmony_ci if (mode == MREAD_OK || mode == MWRITE_OK) { 247f08c3bdfSopenharmony_ci printf("XXX: %s: killed\n", msg); 248f08c3bdfSopenharmony_ci failure++; 249f08c3bdfSopenharmony_ci } else 250f08c3bdfSopenharmony_ci printf("\trecovered\n"); 251f08c3bdfSopenharmony_ci } 252f08c3bdfSopenharmony_ci} 253f08c3bdfSopenharmony_ci 254f08c3bdfSopenharmony_civoid recover(char *msg, char *page, enum rmode mode) 255f08c3bdfSopenharmony_ci{ 256f08c3bdfSopenharmony_ci expected_addr = page; 257f08c3bdfSopenharmony_ci recovercount = 5; 258f08c3bdfSopenharmony_ci 259f08c3bdfSopenharmony_ci if (sigsetjmp(recover_ctx, 1) == 0) { 260f08c3bdfSopenharmony_ci switch (mode) { 261f08c3bdfSopenharmony_ci case MWRITE: 262f08c3bdfSopenharmony_ci printf("\twriting 2\n"); 263f08c3bdfSopenharmony_ci *page = 2; 264f08c3bdfSopenharmony_ci break; 265f08c3bdfSopenharmony_ci case MWRITE_OK: 266f08c3bdfSopenharmony_ci printf("\twriting 4\n"); 267f08c3bdfSopenharmony_ci *page = 4; 268f08c3bdfSopenharmony_ci return; 269f08c3bdfSopenharmony_ci case MREAD: 270f08c3bdfSopenharmony_ci printf("\treading %x\n", *(unsigned char *)page); 271f08c3bdfSopenharmony_ci break; 272f08c3bdfSopenharmony_ci case MREAD_OK: 273f08c3bdfSopenharmony_ci printf("\treading %x\n", *(unsigned char *)page); 274f08c3bdfSopenharmony_ci return; 275f08c3bdfSopenharmony_ci case MNOTHING: 276f08c3bdfSopenharmony_ci return; 277f08c3bdfSopenharmony_ci } 278f08c3bdfSopenharmony_ci /* signal or kill should have happened */ 279f08c3bdfSopenharmony_ci printf("XXX: %s: page not poisoned after injection\n", msg); 280f08c3bdfSopenharmony_ci failure++; 281f08c3bdfSopenharmony_ci return; 282f08c3bdfSopenharmony_ci } 283f08c3bdfSopenharmony_ci if (mode == MREAD_OK || mode == MWRITE_OK) { 284f08c3bdfSopenharmony_ci printf("XXX: %s: killed\n", msg); 285f08c3bdfSopenharmony_ci failure++; 286f08c3bdfSopenharmony_ci } else 287f08c3bdfSopenharmony_ci printf("\trecovered\n"); 288f08c3bdfSopenharmony_ci} 289f08c3bdfSopenharmony_ci 290f08c3bdfSopenharmony_civoid testmem(char *msg, char *page, enum rmode mode) 291f08c3bdfSopenharmony_ci{ 292f08c3bdfSopenharmony_ci printf("\t%s poisoning page %p\n", msg, page); 293f08c3bdfSopenharmony_ci poison(msg, page, mode); 294f08c3bdfSopenharmony_ci recover(msg, page, mode); 295f08c3bdfSopenharmony_ci} 296f08c3bdfSopenharmony_ci 297f08c3bdfSopenharmony_civoid expecterr(char *msg, int err) 298f08c3bdfSopenharmony_ci{ 299f08c3bdfSopenharmony_ci if (err) { 300f08c3bdfSopenharmony_ci printf("\texpected error %d on %s\n", errno, msg); 301f08c3bdfSopenharmony_ci } else { 302f08c3bdfSopenharmony_ci failure++; 303f08c3bdfSopenharmony_ci printf("XXX: unexpected no error on %s\n", msg); 304f08c3bdfSopenharmony_ci } 305f08c3bdfSopenharmony_ci} 306f08c3bdfSopenharmony_ci 307f08c3bdfSopenharmony_ci/* 308f08c3bdfSopenharmony_ci * Any optional error is really a deficiency in the kernel VFS error reporting 309f08c3bdfSopenharmony_ci * and should be eventually fixed and turned into a expecterr 310f08c3bdfSopenharmony_ci */ 311f08c3bdfSopenharmony_civoid optionalerr(char *msg, int err) 312f08c3bdfSopenharmony_ci{ 313f08c3bdfSopenharmony_ci if (err) { 314f08c3bdfSopenharmony_ci printf("\texpected optional error %d on %s\n", errno, msg); 315f08c3bdfSopenharmony_ci } else { 316f08c3bdfSopenharmony_ci unexpected++; 317f08c3bdfSopenharmony_ci printf("LATER: expected likely incorrect no error on %s\n", msg); 318f08c3bdfSopenharmony_ci } 319f08c3bdfSopenharmony_ci} 320f08c3bdfSopenharmony_ci 321f08c3bdfSopenharmony_cistatic int tmpcount; 322f08c3bdfSopenharmony_ciint tempfd(void) 323f08c3bdfSopenharmony_ci{ 324f08c3bdfSopenharmony_ci int fd; 325f08c3bdfSopenharmony_ci char buf[PATHBUFLEN]; 326f08c3bdfSopenharmony_ci snprintf(buf, sizeof buf, TMPDIR "~poison%d",tmpcount++); 327f08c3bdfSopenharmony_ci fd = open(buf, O_CREAT|O_RDWR, 0600); 328f08c3bdfSopenharmony_ci if (fd >= 0) 329f08c3bdfSopenharmony_ci unlink(buf); 330f08c3bdfSopenharmony_ci if (fd < 0) 331f08c3bdfSopenharmony_ci err("opening temporary file in " TMPDIR); 332f08c3bdfSopenharmony_ci return fd; 333f08c3bdfSopenharmony_ci} 334f08c3bdfSopenharmony_ci 335f08c3bdfSopenharmony_ciint playfile(char *buf) 336f08c3bdfSopenharmony_ci{ 337f08c3bdfSopenharmony_ci int fd; 338f08c3bdfSopenharmony_ci if (buf[0] == 0) 339f08c3bdfSopenharmony_ci snprintf(buf, PATHBUFLEN, TMPDIR "~poison%d", tmpcount++); 340f08c3bdfSopenharmony_ci fd = open(buf, O_CREAT|O_RDWR|O_TRUNC, 0600); 341f08c3bdfSopenharmony_ci if (fd < 0) 342f08c3bdfSopenharmony_ci err("opening temporary file in " TMPDIR); 343f08c3bdfSopenharmony_ci 344f08c3bdfSopenharmony_ci const int NPAGES = 5; 345f08c3bdfSopenharmony_ci char *tmp = xmalloc(PS * NPAGES); 346f08c3bdfSopenharmony_ci int i; 347f08c3bdfSopenharmony_ci for (i = 0; i < PS*NPAGES; i++) 348f08c3bdfSopenharmony_ci tmp[i] = i; 349f08c3bdfSopenharmony_ci write(fd, tmp, PS*NPAGES); 350f08c3bdfSopenharmony_ci 351f08c3bdfSopenharmony_ci lseek(fd, 0, SEEK_SET); 352f08c3bdfSopenharmony_ci return fd; 353f08c3bdfSopenharmony_ci} 354f08c3bdfSopenharmony_ci 355f08c3bdfSopenharmony_cistatic void dirty_anonymous(void) 356f08c3bdfSopenharmony_ci{ 357f08c3bdfSopenharmony_ci char *page; 358f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE, 0, 0); 359f08c3bdfSopenharmony_ci testmem("dirty", page, MWRITE); 360f08c3bdfSopenharmony_ci} 361f08c3bdfSopenharmony_ci 362f08c3bdfSopenharmony_cistatic void dirty_anonymous_unmap(void) 363f08c3bdfSopenharmony_ci{ 364f08c3bdfSopenharmony_ci char *page; 365f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE, 0, 0); 366f08c3bdfSopenharmony_ci testmem("dirty", page, MWRITE); 367f08c3bdfSopenharmony_ci munmap_reserve(page, PS); 368f08c3bdfSopenharmony_ci} 369f08c3bdfSopenharmony_ci 370f08c3bdfSopenharmony_cistatic void mlocked_anonymous(void) 371f08c3bdfSopenharmony_ci{ 372f08c3bdfSopenharmony_ci char *page; 373f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED, 0, 0); 374f08c3bdfSopenharmony_ci testmem("mlocked", page, MWRITE); 375f08c3bdfSopenharmony_ci} 376f08c3bdfSopenharmony_ci 377f08c3bdfSopenharmony_cistatic void do_file_clean(int flags, char *name) 378f08c3bdfSopenharmony_ci{ 379f08c3bdfSopenharmony_ci char *page; 380f08c3bdfSopenharmony_ci char fn[30]; 381f08c3bdfSopenharmony_ci snprintf(fn, 30, TMPDIR "~test%d", tmpcount++); 382f08c3bdfSopenharmony_ci int fd = open(fn, O_RDWR|O_TRUNC|O_CREAT); 383f08c3bdfSopenharmony_ci if (fd < 0) 384f08c3bdfSopenharmony_ci err("open temp file"); 385f08c3bdfSopenharmony_ci write(fd, fn, 4); 386f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_SHARED|flags, 387f08c3bdfSopenharmony_ci fd, 0); 388f08c3bdfSopenharmony_ci fsync(fd); 389f08c3bdfSopenharmony_ci close(fd); 390f08c3bdfSopenharmony_ci testmem(name, page, MREAD_OK); 391f08c3bdfSopenharmony_ci /* reread page from disk */ 392f08c3bdfSopenharmony_ci printf("\t reading %x\n", *(unsigned char *)page); 393f08c3bdfSopenharmony_ci testmem(name, page, MWRITE_OK); 394f08c3bdfSopenharmony_ci} 395f08c3bdfSopenharmony_ci 396f08c3bdfSopenharmony_cistatic void file_clean(void) 397f08c3bdfSopenharmony_ci{ 398f08c3bdfSopenharmony_ci do_file_clean(0, "file clean"); 399f08c3bdfSopenharmony_ci} 400f08c3bdfSopenharmony_ci 401f08c3bdfSopenharmony_cistatic void file_clean_mlocked(void) 402f08c3bdfSopenharmony_ci{ 403f08c3bdfSopenharmony_ci do_file_clean(MAP_LOCKED, "file clean mlocked"); 404f08c3bdfSopenharmony_ci} 405f08c3bdfSopenharmony_ci 406f08c3bdfSopenharmony_cistatic char *ndesc(char *buf, char *name, char *add) 407f08c3bdfSopenharmony_ci{ 408f08c3bdfSopenharmony_ci snprintf(buf, 100, "%s %s", name, add); 409f08c3bdfSopenharmony_ci return buf; 410f08c3bdfSopenharmony_ci} 411f08c3bdfSopenharmony_ci 412f08c3bdfSopenharmony_cistatic void do_file_dirty(int flags, char *name) 413f08c3bdfSopenharmony_ci{ 414f08c3bdfSopenharmony_ci char nbuf[100]; 415f08c3bdfSopenharmony_ci char *page; 416f08c3bdfSopenharmony_ci char fn[PATHBUFLEN]; 417f08c3bdfSopenharmony_ci fn[0] = 0; 418f08c3bdfSopenharmony_ci int fd = playfile(fn); 419f08c3bdfSopenharmony_ci 420f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ, 421f08c3bdfSopenharmony_ci MAP_SHARED|MAP_POPULATE|flags, fd, 0); 422f08c3bdfSopenharmony_ci testmem(ndesc(nbuf, name, "initial"), page, MREAD); 423f08c3bdfSopenharmony_ci expecterr("msync expect error", msync(page, PS, MS_SYNC) < 0); 424f08c3bdfSopenharmony_ci close(fd); 425f08c3bdfSopenharmony_ci munmap_reserve(page, PS); 426f08c3bdfSopenharmony_ci 427f08c3bdfSopenharmony_ci fd = open(fn, O_RDONLY); 428f08c3bdfSopenharmony_ci if (fd < 0) err("reopening temp file"); 429f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ, MAP_SHARED|MAP_POPULATE|flags, 430f08c3bdfSopenharmony_ci fd, 0); 431f08c3bdfSopenharmony_ci recover(ndesc(nbuf, name, "populated"), page, MREAD_OK); 432f08c3bdfSopenharmony_ci close(fd); 433f08c3bdfSopenharmony_ci munmap_reserve(page, PS); 434f08c3bdfSopenharmony_ci 435f08c3bdfSopenharmony_ci fd = open(fn, O_RDONLY); 436f08c3bdfSopenharmony_ci if (fd < 0) err("reopening temp file"); 437f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ, MAP_SHARED|flags, fd, 0); 438f08c3bdfSopenharmony_ci recover(ndesc(nbuf, name, "fault"), page, MREAD_OK); 439f08c3bdfSopenharmony_ci close(fd); 440f08c3bdfSopenharmony_ci munmap_reserve(page, PS); 441f08c3bdfSopenharmony_ci 442f08c3bdfSopenharmony_ci fd = open(fn, O_RDWR); 443f08c3bdfSopenharmony_ci char buf[128]; 444f08c3bdfSopenharmony_ci /* the earlier close has eaten the error */ 445f08c3bdfSopenharmony_ci optionalerr("explicit read after poison", read(fd, buf, sizeof buf) < 0); 446f08c3bdfSopenharmony_ci optionalerr("explicit write after poison", write(fd, "foobar", 6) < 0); 447f08c3bdfSopenharmony_ci optionalerr("fsync expect error", fsync(fd) < 0); 448f08c3bdfSopenharmony_ci close(fd); 449f08c3bdfSopenharmony_ci 450f08c3bdfSopenharmony_ci /* should unlink return an error here? */ 451f08c3bdfSopenharmony_ci if (unlink(fn) < 0) 452f08c3bdfSopenharmony_ci perror("unlink"); 453f08c3bdfSopenharmony_ci} 454f08c3bdfSopenharmony_ci 455f08c3bdfSopenharmony_cistatic void file_dirty(void) 456f08c3bdfSopenharmony_ci{ 457f08c3bdfSopenharmony_ci do_file_dirty(0, "file dirty"); 458f08c3bdfSopenharmony_ci} 459f08c3bdfSopenharmony_ci 460f08c3bdfSopenharmony_cistatic void file_dirty_mlocked(void) 461f08c3bdfSopenharmony_ci{ 462f08c3bdfSopenharmony_ci do_file_dirty(MAP_LOCKED, "file dirty mlocked"); 463f08c3bdfSopenharmony_ci} 464f08c3bdfSopenharmony_ci 465f08c3bdfSopenharmony_ci/* TBD */ 466f08c3bdfSopenharmony_cistatic void file_hole(void) 467f08c3bdfSopenharmony_ci{ 468f08c3bdfSopenharmony_ci int fd = tempfd(); 469f08c3bdfSopenharmony_ci char *page; 470f08c3bdfSopenharmony_ci 471f08c3bdfSopenharmony_ci ftruncate(fd, PS); 472f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 473f08c3bdfSopenharmony_ci *page = 1; 474f08c3bdfSopenharmony_ci testmem("hole file dirty", page, MREAD); 475f08c3bdfSopenharmony_ci /* hole error reporting doesn't work in kernel currently, so optional */ 476f08c3bdfSopenharmony_ci optionalerr("hole fsync expect error", fsync(fd) < 0); 477f08c3bdfSopenharmony_ci optionalerr("hole msync expect error", msync(page, PS, MS_SYNC) < 0); 478f08c3bdfSopenharmony_ci close(fd); 479f08c3bdfSopenharmony_ci} 480f08c3bdfSopenharmony_ci 481f08c3bdfSopenharmony_cistatic void nonlinear(void) 482f08c3bdfSopenharmony_ci{ 483f08c3bdfSopenharmony_ci int fd; 484f08c3bdfSopenharmony_ci const int NPAGES = 10; 485f08c3bdfSopenharmony_ci int i; 486f08c3bdfSopenharmony_ci char *page; 487f08c3bdfSopenharmony_ci char *tmp; 488f08c3bdfSopenharmony_ci 489f08c3bdfSopenharmony_ci fd = tempfd(); 490f08c3bdfSopenharmony_ci tmp = xmalloc(PS); 491f08c3bdfSopenharmony_ci for (i = 0; i < NPAGES; i++) { 492f08c3bdfSopenharmony_ci memset(tmp, i, PS); 493f08c3bdfSopenharmony_ci write(fd, tmp, PS); 494f08c3bdfSopenharmony_ci } 495f08c3bdfSopenharmony_ci free(tmp); 496f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS*NPAGES, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 497f08c3bdfSopenharmony_ci int k = NPAGES - 1; 498f08c3bdfSopenharmony_ci for (i = 0; i < NPAGES; i++, k--) { 499f08c3bdfSopenharmony_ci if (remap_file_pages(page + i*PS, PS, 0, k, 0)) 500f08c3bdfSopenharmony_ci perror("remap_file_pages"); 501f08c3bdfSopenharmony_ci } 502f08c3bdfSopenharmony_ci *page = 1; 503f08c3bdfSopenharmony_ci testmem("rfp file dirty", page, MREAD); 504f08c3bdfSopenharmony_ci expecterr("rfp fsync expect error", fsync(fd) < 0); 505f08c3bdfSopenharmony_ci optionalerr("rfp msync expect error", msync(page, PS, MS_SYNC) < 0); 506f08c3bdfSopenharmony_ci close(fd); 507f08c3bdfSopenharmony_ci} 508f08c3bdfSopenharmony_ci 509f08c3bdfSopenharmony_ci/* 510f08c3bdfSopenharmony_ci * These tests are currently too racy to be enabled. 511f08c3bdfSopenharmony_ci */ 512f08c3bdfSopenharmony_ci 513f08c3bdfSopenharmony_ci/* 514f08c3bdfSopenharmony_ci * This is quite timing dependent. The sniper might hit the page 515f08c3bdfSopenharmony_ci * before it is dirtied. If that happens tweak the delay 516f08c3bdfSopenharmony_ci * (should auto tune) 517f08c3bdfSopenharmony_ci */ 518f08c3bdfSopenharmony_cienum { 519f08c3bdfSopenharmony_ci DELAY_NS = 30, 520f08c3bdfSopenharmony_ci}; 521f08c3bdfSopenharmony_ci 522f08c3bdfSopenharmony_civolatile enum sstate { START, WAITING, SNIPE } sstate; 523f08c3bdfSopenharmony_ci 524f08c3bdfSopenharmony_civoid waitfor(enum sstate w, enum sstate s) 525f08c3bdfSopenharmony_ci{ 526f08c3bdfSopenharmony_ci sstate = w; 527f08c3bdfSopenharmony_ci mb(); 528f08c3bdfSopenharmony_ci while (sstate != s) 529f08c3bdfSopenharmony_ci cpu_relax(); 530f08c3bdfSopenharmony_ci} 531f08c3bdfSopenharmony_ci 532f08c3bdfSopenharmony_cistruct poison_arg { 533f08c3bdfSopenharmony_ci char *msg; 534f08c3bdfSopenharmony_ci char *page; 535f08c3bdfSopenharmony_ci enum rmode mode; 536f08c3bdfSopenharmony_ci}; 537f08c3bdfSopenharmony_ci 538f08c3bdfSopenharmony_civoid *sniper(void *p) 539f08c3bdfSopenharmony_ci{ 540f08c3bdfSopenharmony_ci struct poison_arg *arg = p; 541f08c3bdfSopenharmony_ci 542f08c3bdfSopenharmony_ci waitfor(START, WAITING); 543f08c3bdfSopenharmony_ci nanosleep(&((struct timespec) { .tv_nsec = DELAY_NS }), NULL); 544f08c3bdfSopenharmony_ci poison(arg->msg, arg->page, arg->mode); 545f08c3bdfSopenharmony_ci return NULL; 546f08c3bdfSopenharmony_ci} 547f08c3bdfSopenharmony_ci 548f08c3bdfSopenharmony_ciint setup_sniper(struct poison_arg *arg) 549f08c3bdfSopenharmony_ci{ 550f08c3bdfSopenharmony_ci if (sysconf(_SC_NPROCESSORS_ONLN) < 2) { 551f08c3bdfSopenharmony_ci printf("%s: Need at least two CPUs. Not tested\n", arg->msg); 552f08c3bdfSopenharmony_ci return -1; 553f08c3bdfSopenharmony_ci } 554f08c3bdfSopenharmony_ci sstate = START; 555f08c3bdfSopenharmony_ci mb(); 556f08c3bdfSopenharmony_ci pthread_t thr; 557f08c3bdfSopenharmony_ci if (pthread_create(&thr, NULL, sniper, arg) < 0) 558f08c3bdfSopenharmony_ci err("pthread_create"); 559f08c3bdfSopenharmony_ci pthread_detach(thr); 560f08c3bdfSopenharmony_ci return 0; 561f08c3bdfSopenharmony_ci} 562f08c3bdfSopenharmony_ci 563f08c3bdfSopenharmony_cistatic void under_io_dirty(void) 564f08c3bdfSopenharmony_ci{ 565f08c3bdfSopenharmony_ci struct poison_arg arg; 566f08c3bdfSopenharmony_ci int fd = tempfd(); 567f08c3bdfSopenharmony_ci char *page; 568f08c3bdfSopenharmony_ci 569f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, fd, 0); 570f08c3bdfSopenharmony_ci 571f08c3bdfSopenharmony_ci arg.page = page; 572f08c3bdfSopenharmony_ci arg.msg = "under io dirty"; 573f08c3bdfSopenharmony_ci arg.mode = MWRITE; 574f08c3bdfSopenharmony_ci if (setup_sniper(&arg) < 0) 575f08c3bdfSopenharmony_ci return; 576f08c3bdfSopenharmony_ci 577f08c3bdfSopenharmony_ci write(fd, "xyz", 3); 578f08c3bdfSopenharmony_ci waitfor(WAITING, WAITING); 579f08c3bdfSopenharmony_ci expecterr("write under io", fsync(fd) < 0); 580f08c3bdfSopenharmony_ci close(fd); 581f08c3bdfSopenharmony_ci} 582f08c3bdfSopenharmony_ci 583f08c3bdfSopenharmony_cistatic void under_io_clean(void) 584f08c3bdfSopenharmony_ci{ 585f08c3bdfSopenharmony_ci struct poison_arg arg; 586f08c3bdfSopenharmony_ci char fn[PATHBUFLEN]; 587f08c3bdfSopenharmony_ci int fd; 588f08c3bdfSopenharmony_ci char *page; 589f08c3bdfSopenharmony_ci char buf[10]; 590f08c3bdfSopenharmony_ci 591f08c3bdfSopenharmony_ci fd = playfile(fn); 592f08c3bdfSopenharmony_ci page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, fd, 0); 593f08c3bdfSopenharmony_ci madvise(page, PS, MADV_DONTNEED); 594f08c3bdfSopenharmony_ci 595f08c3bdfSopenharmony_ci arg.page = page; 596f08c3bdfSopenharmony_ci arg.msg = "under io clean"; 597f08c3bdfSopenharmony_ci arg.mode = MREAD_OK; 598f08c3bdfSopenharmony_ci if (setup_sniper(&arg) < 0) 599f08c3bdfSopenharmony_ci return; 600f08c3bdfSopenharmony_ci 601f08c3bdfSopenharmony_ci waitfor(WAITING, WAITING); 602f08c3bdfSopenharmony_ci // what is correct here? 603f08c3bdfSopenharmony_ci if (pread(fd, buf, 10, 0) != 0) 604f08c3bdfSopenharmony_ci perror("pread under io clean"); 605f08c3bdfSopenharmony_ci close(fd); 606f08c3bdfSopenharmony_ci} 607f08c3bdfSopenharmony_ci 608f08c3bdfSopenharmony_ci/* 609f08c3bdfSopenharmony_ci * semaphore get/put wrapper 610f08c3bdfSopenharmony_ci */ 611f08c3bdfSopenharmony_ciint get_semaphore(int sem_id, struct sembuf *sembuffer) 612f08c3bdfSopenharmony_ci{ 613f08c3bdfSopenharmony_ci sembuffer->sem_num = 0; 614f08c3bdfSopenharmony_ci sembuffer->sem_op = -1; 615f08c3bdfSopenharmony_ci sembuffer->sem_flg = SEM_UNDO; 616f08c3bdfSopenharmony_ci return semop(sem_id, sembuffer, 1); 617f08c3bdfSopenharmony_ci} 618f08c3bdfSopenharmony_ci 619f08c3bdfSopenharmony_ciint put_semaphore(int sem_id, struct sembuf *sembuffer) 620f08c3bdfSopenharmony_ci{ 621f08c3bdfSopenharmony_ci sembuffer->sem_num = 0; 622f08c3bdfSopenharmony_ci sembuffer->sem_op = 1; 623f08c3bdfSopenharmony_ci sembuffer->sem_flg = SEM_UNDO; 624f08c3bdfSopenharmony_ci return semop(sem_id, sembuffer, 1); 625f08c3bdfSopenharmony_ci} 626f08c3bdfSopenharmony_ci 627f08c3bdfSopenharmony_ci/* memory sharing mode */ 628f08c3bdfSopenharmony_cienum shared_mode { 629f08c3bdfSopenharmony_ci MMAP_SHARED = 0, 630f08c3bdfSopenharmony_ci IPV_SHARED = 1, 631f08c3bdfSopenharmony_ci}; 632f08c3bdfSopenharmony_ci 633f08c3bdfSopenharmony_ci/* 634f08c3bdfSopenharmony_ci * testcase for shared pages, where 635f08c3bdfSopenharmony_ci * if early_kill == 0, parent access the shared page hwpoisoned by child, and 636f08c3bdfSopenharmony_ci * if early_kill == 1, parent will be killed by SIGBUS from child. 637f08c3bdfSopenharmony_ci * This testcase checks whether if a shared page is hwpoisoned by one process, 638f08c3bdfSopenharmony_ci * another process sharing the page will be killed expectedly. 639f08c3bdfSopenharmony_ci */ 640f08c3bdfSopenharmony_cistatic void do_shared(int shared_mode) 641f08c3bdfSopenharmony_ci{ 642f08c3bdfSopenharmony_ci int shm_id = -1, sem_id = -1, semaphore; 643f08c3bdfSopenharmony_ci pid_t pid; 644f08c3bdfSopenharmony_ci char *shared_page = NULL; 645f08c3bdfSopenharmony_ci struct sembuf sembuffer; 646f08c3bdfSopenharmony_ci 647f08c3bdfSopenharmony_ci if (shared_mode == MMAP_SHARED) { 648f08c3bdfSopenharmony_ci shared_page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, 649f08c3bdfSopenharmony_ci MAP_SHARED|MAP_ANONYMOUS|MAP_POPULATE, 0, 0); 650f08c3bdfSopenharmony_ci } else if (shared_mode == IPV_SHARED) { 651f08c3bdfSopenharmony_ci shm_id = shmget(IPC_PRIVATE, PS, 0666|IPC_CREAT); 652f08c3bdfSopenharmony_ci if (shm_id == -1) 653f08c3bdfSopenharmony_ci err("shmget"); 654f08c3bdfSopenharmony_ci } else { 655f08c3bdfSopenharmony_ci printf("XXX: invalid shared_mode\n"); 656f08c3bdfSopenharmony_ci return; 657f08c3bdfSopenharmony_ci } 658f08c3bdfSopenharmony_ci 659f08c3bdfSopenharmony_ci if (early_kill) { 660f08c3bdfSopenharmony_ci sem_id = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT); 661f08c3bdfSopenharmony_ci if (sem_id == -1) { 662f08c3bdfSopenharmony_ci perror("semget"); 663f08c3bdfSopenharmony_ci goto cleanup; 664f08c3bdfSopenharmony_ci } 665f08c3bdfSopenharmony_ci semaphore = semctl(sem_id, 0, SETVAL, 1); 666f08c3bdfSopenharmony_ci if (semaphore == -1) { 667f08c3bdfSopenharmony_ci perror("semctl"); 668f08c3bdfSopenharmony_ci goto cleanup; 669f08c3bdfSopenharmony_ci } 670f08c3bdfSopenharmony_ci if (get_semaphore(sem_id, &sembuffer)) { 671f08c3bdfSopenharmony_ci perror("get_semaphore"); 672f08c3bdfSopenharmony_ci goto cleanup; 673f08c3bdfSopenharmony_ci } 674f08c3bdfSopenharmony_ci } 675f08c3bdfSopenharmony_ci 676f08c3bdfSopenharmony_ci pid = fork(); 677f08c3bdfSopenharmony_ci if (pid < 0) { 678f08c3bdfSopenharmony_ci perror("fork"); 679f08c3bdfSopenharmony_ci goto cleanup; 680f08c3bdfSopenharmony_ci } 681f08c3bdfSopenharmony_ci 682f08c3bdfSopenharmony_ci if (shared_mode == IPV_SHARED) { 683f08c3bdfSopenharmony_ci shared_page = shmat(shm_id, NULL, 0); 684f08c3bdfSopenharmony_ci if (shared_page == (char *)-1) { 685f08c3bdfSopenharmony_ci perror("shmat"); 686f08c3bdfSopenharmony_ci goto cleanup; 687f08c3bdfSopenharmony_ci } 688f08c3bdfSopenharmony_ci } 689f08c3bdfSopenharmony_ci 690f08c3bdfSopenharmony_ci memset(shared_page, 'a', 3); 691f08c3bdfSopenharmony_ci 692f08c3bdfSopenharmony_ci if (early_kill) { 693f08c3bdfSopenharmony_ci struct sigaction sa = { 694f08c3bdfSopenharmony_ci .sa_sigaction = sighandler, 695f08c3bdfSopenharmony_ci .sa_flags = SA_SIGINFO 696f08c3bdfSopenharmony_ci }; 697f08c3bdfSopenharmony_ci sigaction(SIGBUS, &sa, NULL); 698f08c3bdfSopenharmony_ci expected_addr = shared_page; 699f08c3bdfSopenharmony_ci } 700f08c3bdfSopenharmony_ci 701f08c3bdfSopenharmony_ci if (pid) { 702f08c3bdfSopenharmony_ci siginfo_t sig; 703f08c3bdfSopenharmony_ci 704f08c3bdfSopenharmony_ci if (early_kill && sigsetjmp(early_recover_ctx, 1) == 0) { 705f08c3bdfSopenharmony_ci if (put_semaphore(sem_id, &sembuffer)) 706f08c3bdfSopenharmony_ci err("get_semaphore"); 707f08c3bdfSopenharmony_ci /* waiting for SIGBUS from child */ 708f08c3bdfSopenharmony_ci sleep(10); 709f08c3bdfSopenharmony_ci printf("XXX timeout: child process does not send signal\n"); 710f08c3bdfSopenharmony_ci failure++; 711f08c3bdfSopenharmony_ci goto cleanup; 712f08c3bdfSopenharmony_ci } 713f08c3bdfSopenharmony_ci waitid(P_PID, pid, &sig, WEXITED); 714f08c3bdfSopenharmony_ci 715f08c3bdfSopenharmony_ci /* 716f08c3bdfSopenharmony_ci * check child termination status 717f08c3bdfSopenharmony_ci * late kill : child should exit 718f08c3bdfSopenharmony_ci * suicide version : child should be killed by signal 719f08c3bdfSopenharmony_ci * early kill : child should be killed by signal 720f08c3bdfSopenharmony_ci */ 721f08c3bdfSopenharmony_ci if (!early_kill) { 722f08c3bdfSopenharmony_ci struct sigaction sigact; 723f08c3bdfSopenharmony_ci sigaction(SIGBUS, NULL, &sigact); 724f08c3bdfSopenharmony_ci 725f08c3bdfSopenharmony_ci if (sigact.sa_handler == SIG_DFL) {/* suicide version */ 726f08c3bdfSopenharmony_ci if (sig.si_code != CLD_KILLED) 727f08c3bdfSopenharmony_ci goto child_error; 728f08c3bdfSopenharmony_ci } else { /* late kill */ 729f08c3bdfSopenharmony_ci if (sig.si_code != CLD_EXITED) 730f08c3bdfSopenharmony_ci goto child_error; 731f08c3bdfSopenharmony_ci } 732f08c3bdfSopenharmony_ci } else { /* early kill */ 733f08c3bdfSopenharmony_ci if (sig.si_code != CLD_EXITED) 734f08c3bdfSopenharmony_ci goto child_error; 735f08c3bdfSopenharmony_ci } 736f08c3bdfSopenharmony_ci 737f08c3bdfSopenharmony_ci if (!early_kill) 738f08c3bdfSopenharmony_ci recover("ipv shared page (parent)", 739f08c3bdfSopenharmony_ci shared_page, MWRITE); 740f08c3bdfSopenharmony_ci 741f08c3bdfSopenharmony_ci if (shared_mode == IPV_SHARED && shmdt(shared_page) == -1) { 742f08c3bdfSopenharmony_ci perror("shmdt"); 743f08c3bdfSopenharmony_ci goto cleanup; 744f08c3bdfSopenharmony_ci } 745f08c3bdfSopenharmony_ci } 746f08c3bdfSopenharmony_ci 747f08c3bdfSopenharmony_ci if (!pid) { 748f08c3bdfSopenharmony_ci failure = 0; 749f08c3bdfSopenharmony_ci 750f08c3bdfSopenharmony_ci if (early_kill) 751f08c3bdfSopenharmony_ci if (get_semaphore(sem_id, &sembuffer)) 752f08c3bdfSopenharmony_ci err("get_semaphore"); 753f08c3bdfSopenharmony_ci testmem("ipv shared page", shared_page, MWRITE); 754f08c3bdfSopenharmony_ci 755f08c3bdfSopenharmony_ci if (shared_mode == IPV_SHARED && shmdt(shared_page) == -1) 756f08c3bdfSopenharmony_ci err("shmdt"); 757f08c3bdfSopenharmony_ci 758f08c3bdfSopenharmony_ci fflush(stdout); 759f08c3bdfSopenharmony_ci _exit(failure); 760f08c3bdfSopenharmony_ci } 761f08c3bdfSopenharmony_ci 762f08c3bdfSopenharmony_cicleanup: 763f08c3bdfSopenharmony_ci if (shared_page) { 764f08c3bdfSopenharmony_ci if (shared_mode == IPV_SHARED) 765f08c3bdfSopenharmony_ci shmdt(shared_page); 766f08c3bdfSopenharmony_ci else 767f08c3bdfSopenharmony_ci munmap_reserve(shared_page, PS); 768f08c3bdfSopenharmony_ci } 769f08c3bdfSopenharmony_ci if (shm_id >= 0 && shmctl(shm_id, IPC_RMID, NULL) < 0) 770f08c3bdfSopenharmony_ci err("shmctl IPC_RMID"); 771f08c3bdfSopenharmony_ci if (sem_id >= 0 && semctl(sem_id, 0, IPC_RMID) < 0) 772f08c3bdfSopenharmony_ci err("semctl IPC_RMID"); 773f08c3bdfSopenharmony_ci return; 774f08c3bdfSopenharmony_ci 775f08c3bdfSopenharmony_cichild_error: 776f08c3bdfSopenharmony_ci printf("XXX child process was terminated unexpectedly\n"); 777f08c3bdfSopenharmony_ci failure++; 778f08c3bdfSopenharmony_ci goto cleanup; 779f08c3bdfSopenharmony_ci} 780f08c3bdfSopenharmony_ci 781f08c3bdfSopenharmony_cistatic void mmap_shared(void) 782f08c3bdfSopenharmony_ci{ 783f08c3bdfSopenharmony_ci do_shared(MMAP_SHARED); 784f08c3bdfSopenharmony_ci} 785f08c3bdfSopenharmony_ci 786f08c3bdfSopenharmony_cistatic void ipv_shared(void) 787f08c3bdfSopenharmony_ci{ 788f08c3bdfSopenharmony_ci do_shared(IPV_SHARED); 789f08c3bdfSopenharmony_ci} 790f08c3bdfSopenharmony_ci 791f08c3bdfSopenharmony_cistatic void anonymous_hugepage(void) 792f08c3bdfSopenharmony_ci{ 793f08c3bdfSopenharmony_ci char *page; 794f08c3bdfSopenharmony_ci /* Hugepage isn't supported. */ 795f08c3bdfSopenharmony_ci if (!HPS) 796f08c3bdfSopenharmony_ci return; 797f08c3bdfSopenharmony_ci test_hugepage = 1; 798f08c3bdfSopenharmony_ci page = alloc_anonymous_hugepage(HPS, 1); 799f08c3bdfSopenharmony_ci /* prefault */ 800f08c3bdfSopenharmony_ci page[0] = 'a'; 801f08c3bdfSopenharmony_ci testmem("anonymous hugepage", page, MWRITE); 802f08c3bdfSopenharmony_ci free_anonymous_hugepage(page, HPS); 803f08c3bdfSopenharmony_ci test_hugepage = 0; 804f08c3bdfSopenharmony_ci} 805f08c3bdfSopenharmony_ci 806f08c3bdfSopenharmony_cistatic void file_backed_hugepage(void) 807f08c3bdfSopenharmony_ci{ 808f08c3bdfSopenharmony_ci char *page; 809f08c3bdfSopenharmony_ci char buf[PATHBUFLEN]; 810f08c3bdfSopenharmony_ci int fd; 811f08c3bdfSopenharmony_ci /* Hugepage isn't supported. */ 812f08c3bdfSopenharmony_ci if (!HPS) 813f08c3bdfSopenharmony_ci return; 814f08c3bdfSopenharmony_ci test_hugepage = 1; 815f08c3bdfSopenharmony_ci snprintf(buf, PATHBUFLEN, "%s/test%d", hugetlbfsdir, tmpcount++); 816f08c3bdfSopenharmony_ci page = alloc_filebacked_hugepage(buf, HPS, 0, &fd); 817f08c3bdfSopenharmony_ci /* prefault */ 818f08c3bdfSopenharmony_ci page[0] = 'a'; 819f08c3bdfSopenharmony_ci testmem("file backed hugepage", page, MWRITE); 820f08c3bdfSopenharmony_ci free_filebacked_hugepage(page, HPS, fd, buf); 821f08c3bdfSopenharmony_ci test_hugepage = 0; 822f08c3bdfSopenharmony_ci} 823f08c3bdfSopenharmony_ci 824f08c3bdfSopenharmony_cistatic void shm_hugepage(void) 825f08c3bdfSopenharmony_ci{ 826f08c3bdfSopenharmony_ci char *page; 827f08c3bdfSopenharmony_ci /* Hugepage isn't supported. */ 828f08c3bdfSopenharmony_ci if (!HPS) 829f08c3bdfSopenharmony_ci return; 830f08c3bdfSopenharmony_ci test_hugepage = 1; 831f08c3bdfSopenharmony_ci page = alloc_shm_hugepage(&tmpcount, HPS); 832f08c3bdfSopenharmony_ci /* prefault */ 833f08c3bdfSopenharmony_ci page[0] = 'a'; 834f08c3bdfSopenharmony_ci testmem("shared memory hugepage", page, MWRITE); 835f08c3bdfSopenharmony_ci free_shm_hugepage(tmpcount, page); 836f08c3bdfSopenharmony_ci tmpcount++; 837f08c3bdfSopenharmony_ci test_hugepage = 0; 838f08c3bdfSopenharmony_ci} 839f08c3bdfSopenharmony_ci 840f08c3bdfSopenharmony_cistruct testcase { 841f08c3bdfSopenharmony_ci void (*f)(void); 842f08c3bdfSopenharmony_ci char *name; 843f08c3bdfSopenharmony_ci int survivable; 844f08c3bdfSopenharmony_ci} cases[] = { 845f08c3bdfSopenharmony_ci { dirty_anonymous, "dirty anonymous" }, 846f08c3bdfSopenharmony_ci { dirty_anonymous_unmap, "dirty anonymous unmap" }, 847f08c3bdfSopenharmony_ci { mlocked_anonymous, "mlocked anonymous" }, 848f08c3bdfSopenharmony_ci { file_clean, "file clean", 1 }, 849f08c3bdfSopenharmony_ci { file_dirty, "file dirty" }, 850f08c3bdfSopenharmony_ci { file_hole, "file hole" }, 851f08c3bdfSopenharmony_ci { file_clean_mlocked, "file clean mlocked", 1 }, 852f08c3bdfSopenharmony_ci { file_dirty_mlocked, "file dirty mlocked"}, 853f08c3bdfSopenharmony_ci { nonlinear, "nonlinear" }, 854f08c3bdfSopenharmony_ci { mmap_shared, "mmap shared" }, 855f08c3bdfSopenharmony_ci { ipv_shared, "ipv shared" }, 856f08c3bdfSopenharmony_ci { anonymous_hugepage, "anonymous hugepage" }, 857f08c3bdfSopenharmony_ci { file_backed_hugepage, "file backed hugepage" }, 858f08c3bdfSopenharmony_ci { shm_hugepage, "shared memory hugepage" }, 859f08c3bdfSopenharmony_ci {}, /* dummy 1 for sniper */ 860f08c3bdfSopenharmony_ci {}, /* dummy 2 for sniper */ 861f08c3bdfSopenharmony_ci {} 862f08c3bdfSopenharmony_ci}; 863f08c3bdfSopenharmony_ci 864f08c3bdfSopenharmony_cistruct testcase snipercases[] = { 865f08c3bdfSopenharmony_ci { under_io_dirty, "under io dirty" }, 866f08c3bdfSopenharmony_ci { under_io_clean, "under io clean" }, 867f08c3bdfSopenharmony_ci}; 868f08c3bdfSopenharmony_ci 869f08c3bdfSopenharmony_civoid usage(void) 870f08c3bdfSopenharmony_ci{ 871f08c3bdfSopenharmony_ci fprintf(stderr, "Usage: tinjpage [--sniper]\n" 872f08c3bdfSopenharmony_ci "Test hwpoison injection on pages in various states\n" 873f08c3bdfSopenharmony_ci "--mce-inject Use mce-inject for injection\n" 874f08c3bdfSopenharmony_ci "--sniper Enable racy sniper tests (likely broken)\n"); 875f08c3bdfSopenharmony_ci exit(1); 876f08c3bdfSopenharmony_ci} 877f08c3bdfSopenharmony_ci 878f08c3bdfSopenharmony_civoid handle_opts(char **av) 879f08c3bdfSopenharmony_ci{ 880f08c3bdfSopenharmony_ci while (*++av) { 881f08c3bdfSopenharmony_ci if (!strcmp(*av, "--sniper")) { 882f08c3bdfSopenharmony_ci struct testcase *t; 883f08c3bdfSopenharmony_ci for (t = cases; t->f; t++) 884f08c3bdfSopenharmony_ci ; 885f08c3bdfSopenharmony_ci *t++ = snipercases[0]; 886f08c3bdfSopenharmony_ci *t++ = snipercases[1]; 887f08c3bdfSopenharmony_ci } 888f08c3bdfSopenharmony_ci else if (!strcmp(*av, "--mce-inject")) { 889f08c3bdfSopenharmony_ci inject = inject_mce_inject; 890f08c3bdfSopenharmony_ci } else 891f08c3bdfSopenharmony_ci usage(); 892f08c3bdfSopenharmony_ci } 893f08c3bdfSopenharmony_ci} 894f08c3bdfSopenharmony_ci 895f08c3bdfSopenharmony_ciint main(int ac, char **av) 896f08c3bdfSopenharmony_ci{ 897f08c3bdfSopenharmony_ci if (av[1]) 898f08c3bdfSopenharmony_ci handle_opts(av); 899f08c3bdfSopenharmony_ci 900f08c3bdfSopenharmony_ci PS = getpagesize(); 901f08c3bdfSopenharmony_ci if (hugetlbfs_root(hugetlbfsdir)) 902f08c3bdfSopenharmony_ci HPS = gethugepagesize(); 903f08c3bdfSopenharmony_ci 904f08c3bdfSopenharmony_ci /* don't kill me at poison time, but possibly at page fault time */ 905f08c3bdfSopenharmony_ci early_kill = 0; 906f08c3bdfSopenharmony_ci system("sysctl -w vm.memory_failure_early_kill=0"); 907f08c3bdfSopenharmony_ci 908f08c3bdfSopenharmony_ci struct sigaction sa = { 909f08c3bdfSopenharmony_ci .sa_sigaction = sighandler, 910f08c3bdfSopenharmony_ci .sa_flags = SA_SIGINFO 911f08c3bdfSopenharmony_ci }; 912f08c3bdfSopenharmony_ci 913f08c3bdfSopenharmony_ci struct testcase *t; 914f08c3bdfSopenharmony_ci /* catch signals */ 915f08c3bdfSopenharmony_ci sigaction(SIGBUS, &sa, NULL); 916f08c3bdfSopenharmony_ci for (t = cases; t->f; t++) { 917f08c3bdfSopenharmony_ci printf("---- testing %s\n", t->name); 918f08c3bdfSopenharmony_ci t->f(); 919f08c3bdfSopenharmony_ci } 920f08c3bdfSopenharmony_ci 921f08c3bdfSopenharmony_ci /* suicide version */ 922f08c3bdfSopenharmony_ci for (t = cases; t->f; t++) { 923f08c3bdfSopenharmony_ci printf("---- testing %s in child\n", t->name); 924f08c3bdfSopenharmony_ci pid_t child = fork(); 925f08c3bdfSopenharmony_ci if (child == 0) { 926f08c3bdfSopenharmony_ci signal(SIGBUS, SIG_DFL); 927f08c3bdfSopenharmony_ci t->f(); 928f08c3bdfSopenharmony_ci if (t->survivable) 929f08c3bdfSopenharmony_ci _exit(2); 930f08c3bdfSopenharmony_ci write(1, t->name, strlen(t->name)); 931f08c3bdfSopenharmony_ci write(1, PAIR(" didn't kill itself?\n")); 932f08c3bdfSopenharmony_ci _exit(1); 933f08c3bdfSopenharmony_ci } else { 934f08c3bdfSopenharmony_ci siginfo_t sig; 935f08c3bdfSopenharmony_ci if (waitid(P_PID, child, &sig, WEXITED) < 0) 936f08c3bdfSopenharmony_ci perror("waitid"); 937f08c3bdfSopenharmony_ci else { 938f08c3bdfSopenharmony_ci if (t->survivable) { 939f08c3bdfSopenharmony_ci if (sig.si_code != CLD_EXITED) { 940f08c3bdfSopenharmony_ci printf("XXX: %s: child not survived\n", t->name); 941f08c3bdfSopenharmony_ci failure++; 942f08c3bdfSopenharmony_ci } 943f08c3bdfSopenharmony_ci } else { 944f08c3bdfSopenharmony_ci if (sig.si_code != CLD_KILLED || sig.si_status != SIGBUS) { 945f08c3bdfSopenharmony_ci printf("XXX: %s: child not killed by SIGBUS\n", t->name); 946f08c3bdfSopenharmony_ci failure++; 947f08c3bdfSopenharmony_ci } 948f08c3bdfSopenharmony_ci } 949f08c3bdfSopenharmony_ci } 950f08c3bdfSopenharmony_ci } 951f08c3bdfSopenharmony_ci } 952f08c3bdfSopenharmony_ci 953f08c3bdfSopenharmony_ci /* early kill version */ 954f08c3bdfSopenharmony_ci early_kill = 1; 955f08c3bdfSopenharmony_ci system("sysctl -w vm.memory_failure_early_kill=1"); 956f08c3bdfSopenharmony_ci 957f08c3bdfSopenharmony_ci sigaction(SIGBUS, &sa, NULL); 958f08c3bdfSopenharmony_ci for (t = cases; t->f; t++) { 959f08c3bdfSopenharmony_ci printf("---- testing %s (early kill)\n", t->name); 960f08c3bdfSopenharmony_ci t->f(); 961f08c3bdfSopenharmony_ci } 962f08c3bdfSopenharmony_ci 963f08c3bdfSopenharmony_ci if (failure > 0) { 964f08c3bdfSopenharmony_ci printf("FAILURE -- %d cases broken!\n", failure); 965f08c3bdfSopenharmony_ci return 1; 966f08c3bdfSopenharmony_ci } 967f08c3bdfSopenharmony_ci printf("SUCCESS\n"); 968f08c3bdfSopenharmony_ci return 0; 969f08c3bdfSopenharmony_ci} 970