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
36 int PS;
37 int exitcode;
38 char empty[4096];
39 int corrupted;
40
checked_mmap(void * addr,size_t length,int prot,int flags,int fd,off_t offset)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
meminfo(char * fmt)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) {
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
hardware_corrupted(void)73 unsigned hardware_corrupted(void)
74 {
75 return (meminfo("HardwareCorrupted: %u") * 1024) / PS;
76 }
77
ndesc(char * buf,char * a,char * b)78 char *ndesc(char *buf, char *a, char *b)
79 {
80 snprintf(buf, 100, "%s %s", a, b);
81 return buf;
82 }
83
offline(char * name,void * p)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
disk_backed(char * name,int flags)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);
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
anonymous(char * name,int flags)107 void 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
shm_hugepage(char * name,int flags)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
anonymous_hugepage(char * name,int flags)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
filebacked_hugepage(char * name,int flags)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
check(unsigned * count,char * name,unsigned expected)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,
166 diff);
167 if (diff < expected)
168 exitcode = 1;
169 }
170 *count = count2;
171 corrupted = 0;
172 }
173
main(void)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;
199 }
200