blob: 5afb234a31d6838e439db5c344eee1bce9e15b3a [file] [log] [blame]
/*
* Test soft page offline for process pages using madvise injector.
* Requires special injection support in the kernel.
*
* Copyright 2009 Intel Corporation
*
* tsoftinj is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; version
* 2.
*
* tinjpage is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should find a copy of v2 of the GNU General Public License somewhere
* on your Linux system; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Andi Kleen
*/
#define _GNU_SOURCE 1
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include "hugepage.h"
#define MADV_SOFT_OFFLINE 101
#define TMPDIR "./"
int PS;
int exitcode;
char empty[4096];
int corrupted;
void *checked_mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset)
{
void *p = mmap(addr, length, prot, flags, fd, offset);
if (p == (void *)-1L)
err("mmap");
return p;
}
unsigned meminfo(char *fmt)
{
int found = 0;
FILE *f = fopen("/proc/meminfo", "r");
if (!f) err("open /proc/meminfo");
char *line = NULL;
size_t linelen = 0;
unsigned val = 0;
while (getline(&line, &linelen, f) > 0) {
if (sscanf(line, fmt, &val) == 1) {
found = 1;
break;
}
}
free(line);
fclose(f);
if (!found) {
printf("cannot read HardwareCorruptedPages in meminfo\n");
exitcode = 1;
}
return val;
}
unsigned hardware_corrupted(void)
{
return (meminfo("HardwareCorrupted: %u") * 1024) / PS;
}
char *ndesc(char *buf, char *a, char *b)
{
snprintf(buf, 100, "%s %s", a, b);
return buf;
}
void offline(char *name, void *p)
{
char buf[100];
if (madvise(p, PS, MADV_SOFT_OFFLINE) < 0)
err(ndesc(buf, name, "offline"));
corrupted++;
}
void disk_backed(char *name, int flags)
{
char fn[100];
snprintf(fn, sizeof fn, TMPDIR "~test%u", getpid());
printf("private, diskbacked\n");
int fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, 0644);
if (fd < 0) err("open tmpfile");
write(fd, empty, sizeof empty);
char *p = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE,
MAP_PRIVATE|flags, fd, 0);
*(volatile int *)p = 1;
offline(ndesc(fn, "disk backed", name), p);
munmap(p, PS);
}
void anonymous(char *name, int flags)
{
char buf[100];
char *p = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|flags, 0, 0);
printf("anonymous\n");
*(volatile int *)p = 1;
offline(ndesc(buf, "anonymous", name), p);
*(volatile int *)p = 1;
munmap(p, PS);
}
void shm_hugepage(char *name, int flags)
{
int shmid = 0;
char buf[100];
char *p = alloc_shm_hugepage(&shmid, HPS);
if (!p)
errmsg("failed in alloc_shm_hugepage\n");
printf("shm hugepage\n");
*(volatile int *)p = 1;
offline(ndesc(buf, "shm hugepage", name), p);
*(volatile int *)p = 1;
free_shm_hugepage(shmid, p);
}
void anonymous_hugepage(char *name, int flags)
{
char buf[100];
char *p = alloc_anonymous_hugepage(HPS, 1);
printf("anonymous hugepage\n");
*(volatile int *)p = 1;
offline(ndesc(buf, "anonymous hugepage", name), p);
*(volatile int *)p = 1;
free_anonymous_hugepage(p, HPS);
}
void filebacked_hugepage(char *name, int flags)
{
int fd;
char path[100];
char fn[100];
snprintf(path, sizeof path, "%s/~test-hugepage%u",
hugetlbfsdir, getpid());
char *p = alloc_filebacked_hugepage(path, HPS, 0, &fd);
printf("file backed hugepage\n");
*(volatile int *)p = 1;
offline(ndesc(fn, "file backed hugepage", name), p);
*(volatile int *)p = 1;
free_filebacked_hugepage(p, HPS, fd, path);
}
void check(unsigned *count, char *name, unsigned expected)
{
unsigned count2 = hardware_corrupted();
unsigned diff = count2 - *count;
if (diff != expected) {
printf("%s: expected %d corrupted pages, got %u\n", name,
expected,
diff);
if (diff < expected)
exitcode = 1;
}
*count = count2;
corrupted = 0;
}
int main(void)
{
PS = getpagesize();
HPS = gethugepagesize();
unsigned count = hardware_corrupted();
if (!hugetlbfs_root(hugetlbfsdir))
err("hugetlbfs_root");
anonymous("anonymous", 0);
check(&count, "anonymous", 1);
anonymous("anonymous mlock", MAP_LOCKED);
check(&count, "anonymous mlock", 1);
disk_backed("disk backed", 0);
check(&count, "disk backed", 1);
disk_backed("disk backed mlock", MAP_LOCKED);
check(&count, "disk backed mlock", 1);
shm_hugepage("shm hugepage", 0);
check(&count, "shm hugepage", HPS / PS);
anonymous_hugepage("anonymous hugepage", 0);
check(&count, "anonymous hugepage", HPS / PS);
filebacked_hugepage("file backed hugepage", 0);
check(&count, "file backed hugepage", HPS / PS);
// add more test cases here
return exitcode;
}