• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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