/* * 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 #include #include #include #include #include #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("shared, 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_SHARED|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", 0); 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; }