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