Garrett Cooper | 17fcc6f | 2010-12-08 00:51:08 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Test soft page offline for process pages using madvise injector. |
| 3 | * Requires special injection support in the kernel. |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 4 | * |
Garrett Cooper | 17fcc6f | 2010-12-08 00:51:08 -0800 | [diff] [blame] | 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 |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 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 |
Garrett Cooper | 17fcc6f | 2010-12-08 00:51:08 -0800 | [diff] [blame] | 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 | |
| 36 | int PS; |
| 37 | int exitcode; |
| 38 | char empty[4096]; |
| 39 | int corrupted; |
| 40 | |
| 41 | void *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 | |
| 50 | unsigned 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) { |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 59 | if (sscanf(line, fmt, &val) == 1) { |
Garrett Cooper | 17fcc6f | 2010-12-08 00:51:08 -0800 | [diff] [blame] | 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 | |
| 73 | unsigned hardware_corrupted(void) |
| 74 | { |
| 75 | return (meminfo("HardwareCorrupted: %u") * 1024) / PS; |
| 76 | } |
| 77 | |
| 78 | char *ndesc(char *buf, char *a, char *b) |
| 79 | { |
| 80 | snprintf(buf, 100, "%s %s", a, b); |
| 81 | return buf; |
| 82 | } |
| 83 | |
| 84 | void 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 | |
| 92 | void 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); |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 100 | char *p = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, |
Garrett Cooper | 17fcc6f | 2010-12-08 00:51:08 -0800 | [diff] [blame] | 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 | |
| 107 | void anonymous(char *name, int flags) |
| 108 | { |
| 109 | char buf[100]; |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 110 | char *p = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE, |
Garrett Cooper | 17fcc6f | 2010-12-08 00:51:08 -0800 | [diff] [blame] | 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 | |
| 119 | void 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 | |
| 133 | void 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 | |
| 144 | void 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 | |
| 159 | void 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, |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 166 | diff); |
Garrett Cooper | 17fcc6f | 2010-12-08 00:51:08 -0800 | [diff] [blame] | 167 | if (diff < expected) |
| 168 | exitcode = 1; |
| 169 | } |
| 170 | *count = count2; |
| 171 | corrupted = 0; |
| 172 | } |
| 173 | |
| 174 | int 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; |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 199 | } |