1/* 2 * Test soft page offline for process pages using madvise injector. 3 * Requires special injection support in the kernel. 4 * 5 * Copyright 2009 Intel Corporation 6 * 7 * tsoftinj is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public 9 * License as published by the Free Software Foundation; version 10 * 2. 11 * 12 * tinjpage is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should find a copy of v2 of the GNU General Public License somewhere 18 * on your Linux system; if not, write to the Free Software Foundation, 19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * Author: Andi Kleen 22 */ 23#define _GNU_SOURCE 1 24#include <sys/mman.h> 25#include <stdio.h> 26#include <unistd.h> 27#include <sys/fcntl.h> 28#include <stdlib.h> 29#include <errno.h> 30#include "hugepage.h" 31 32#define MADV_SOFT_OFFLINE 101 33 34#define TMPDIR "./" 35 36int PS; 37int exitcode; 38char empty[4096]; 39int corrupted; 40 41void *checked_mmap(void *addr, size_t length, int prot, int flags, 42 int fd, off_t offset) 43{ 44 void *p = mmap(addr, length, prot, flags, fd, offset); 45 if (p == (void *)-1L) 46 err("mmap"); 47 return p; 48} 49 50unsigned meminfo(char *fmt) 51{ 52 int found = 0; 53 FILE *f = fopen("/proc/meminfo", "r"); 54 if (!f) err("open /proc/meminfo"); 55 char *line = NULL; 56 size_t linelen = 0; 57 unsigned val = 0; 58 while (getline(&line, &linelen, f) > 0) { 59 if (sscanf(line, fmt, &val) == 1) { 60 found = 1; 61 break; 62 } 63 } 64 free(line); 65 fclose(f); 66 if (!found) { 67 printf("cannot read HardwareCorruptedPages in meminfo\n"); 68 exitcode = 1; 69 } 70 return val; 71} 72 73unsigned hardware_corrupted(void) 74{ 75 return (meminfo("HardwareCorrupted: %u") * 1024) / PS; 76} 77 78char *ndesc(char *buf, char *a, char *b) 79{ 80 snprintf(buf, 100, "%s %s", a, b); 81 return buf; 82} 83 84void offline(char *name, void *p) 85{ 86 char buf[100]; 87 if (madvise(p, PS, MADV_SOFT_OFFLINE) < 0) 88 err(ndesc(buf, name, "offline")); 89 corrupted++; 90} 91 92void disk_backed(char *name, int flags) 93{ 94 char fn[100]; 95 snprintf(fn, sizeof fn, TMPDIR "~test%u", getpid()); 96 printf("shared, diskbacked\n"); 97 int fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0644); 98 if (fd < 0) err("open tmpfile"); 99 write(fd, empty, sizeof empty); 100 char *p = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, 101 MAP_SHARED|flags, fd, 0); 102 *(volatile int *)p = 1; 103 offline(ndesc(fn, "disk backed", name), p); 104 munmap(p, PS); 105} 106 107void anonymous(char *name, int flags) 108{ 109 char buf[100]; 110 char *p = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, 111 MAP_PRIVATE|MAP_ANONYMOUS|flags, 0, 0); 112 printf("anonymous\n"); 113 *(volatile int *)p = 1; 114 offline(ndesc(buf, "anonymous", name), p); 115 *(volatile int *)p = 1; 116 munmap(p, PS); 117} 118 119void shm_hugepage(char *name, int flags) 120{ 121 int shmid = 0; 122 char buf[100]; 123 char *p = alloc_shm_hugepage(&shmid, HPS); 124 if (!p) 125 errmsg("failed in alloc_shm_hugepage\n"); 126 printf("shm hugepage\n"); 127 *(volatile int *)p = 1; 128 offline(ndesc(buf, "shm hugepage", name), p); 129 *(volatile int *)p = 1; 130 free_shm_hugepage(shmid, p); 131} 132 133void anonymous_hugepage(char *name, int flags) 134{ 135 char buf[100]; 136 char *p = alloc_anonymous_hugepage(HPS, 1); 137 printf("anonymous hugepage\n"); 138 *(volatile int *)p = 1; 139 offline(ndesc(buf, "anonymous hugepage", name), p); 140 *(volatile int *)p = 1; 141 free_anonymous_hugepage(p, HPS); 142} 143 144void filebacked_hugepage(char *name, int flags) 145{ 146 int fd; 147 char path[100]; 148 char fn[100]; 149 snprintf(path, sizeof path, "%s/~test-hugepage%u", 150 hugetlbfsdir, getpid()); 151 char *p = alloc_filebacked_hugepage(path, HPS, 0, &fd); 152 printf("file backed hugepage\n"); 153 *(volatile int *)p = 1; 154 offline(ndesc(fn, "file backed hugepage", name), p); 155 *(volatile int *)p = 1; 156 free_filebacked_hugepage(p, HPS, fd, path); 157} 158 159void check(unsigned *count, char *name, unsigned expected) 160{ 161 unsigned count2 = hardware_corrupted(); 162 unsigned diff = count2 - *count; 163 if (diff != expected) { 164 printf("%s: expected %d corrupted pages, got %u\n", name, 165 expected, 166 diff); 167 if (diff < expected) 168 exitcode = 1; 169 } 170 *count = count2; 171 corrupted = 0; 172} 173 174int main(void) 175{ 176 PS = getpagesize(); 177 HPS = gethugepagesize(); 178 179 unsigned count = hardware_corrupted(); 180 if (!hugetlbfs_root(hugetlbfsdir)) 181 err("hugetlbfs_root"); 182 anonymous("anonymous", 0); 183 check(&count, "anonymous", 1); 184 anonymous("anonymous mlock", MAP_LOCKED); 185 check(&count, "anonymous mlock", 1); 186 disk_backed("disk backed", 0); 187 check(&count, "disk backed", 1); 188 disk_backed("disk backed mlock", 0); 189 check(&count, "disk backed mlock", 1); 190 shm_hugepage("shm hugepage", 0); 191 check(&count, "shm hugepage", HPS / PS); 192 anonymous_hugepage("anonymous hugepage", 0); 193 check(&count, "anonymous hugepage", HPS / PS); 194 filebacked_hugepage("file backed hugepage", 0); 195 check(&count, "file backed hugepage", HPS / PS); 196 // add more test cases here 197 198 return exitcode; 199} 200