blob: 401d7c6a2d6b0c63f057f130ec44c063bbfd3928 [file] [log] [blame]
Garrett Cooper17fcc6f2010-12-08 00:51:08 -08001/*
2 * Test soft page offline for process pages using madvise injector.
3 * Requires special injection support in the kernel.
Garrett Cooper2c282152010-12-16 00:55:50 -08004 *
Garrett Cooper17fcc6f2010-12-08 00:51:08 -08005 * 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 Cooper2c282152010-12-16 00:55:50 -080018 * 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 Cooper17fcc6f2010-12-08 00:51:08 -080020 *
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) {
Garrett Cooper2c282152010-12-16 00:55:50 -080059 if (sscanf(line, fmt, &val) == 1) {
Garrett Cooper17fcc6f2010-12-08 00:51:08 -080060 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);
Garrett Cooper2c282152010-12-16 00:55:50 -0800100 char *p = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE,
Garrett Cooper17fcc6f2010-12-08 00:51:08 -0800101 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];
Garrett Cooper2c282152010-12-16 00:55:50 -0800110 char *p = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE,
Garrett Cooper17fcc6f2010-12-08 00:51:08 -0800111 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,
Garrett Cooper2c282152010-12-16 00:55:50 -0800166 diff);
Garrett Cooper17fcc6f2010-12-08 00:51:08 -0800167 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;
Garrett Cooper2c282152010-12-16 00:55:50 -0800199}