diff options
author | Andi Kleen <ak@linux.intel.com> | 2009-12-14 14:47:35 +0100 |
---|---|---|
committer | Andi Kleen <ak@linux.intel.com> | 2009-12-14 14:47:35 +0100 |
commit | 7ecd1b6daa8b40d866a7b98edc750988db210f8d (patch) | |
tree | d32c44819d5b7e236f083b4d8465da508495d9ce | |
parent | 3d35af8b3ea31539ce1c21664c54c024dd00a301 (diff) | |
download | mce-test-7ecd1b6daa8b40d866a7b98edc750988db210f8d.tar.gz |
Random soft offline test cases
Signed-off-by: Andi Kleen <ak@linux.intel.com>
-rw-r--r-- | tsrc/Makefile | 2 | ||||
-rwxr-xr-x | tsrc/random_offline | 71 | ||||
-rw-r--r-- | tsrc/tsoft.c | 29 | ||||
-rw-r--r-- | tsrc/tsoftinj.c | 129 |
4 files changed, 230 insertions, 1 deletions
diff --git a/tsrc/Makefile b/tsrc/Makefile index 5f384d5..17da18d 100644 --- a/tsrc/Makefile +++ b/tsrc/Makefile @@ -5,7 +5,7 @@ CFLAGS += -I ${LSRC}/arch/x86/kernel/cpu/mcheck/ -g -Wall KFLAGS := -I ./kinclude -EXE := tinjpage tinjpage-working tkillpoison tprctl +EXE := tinjpage tinjpage-working tkillpoison tprctl tsoft tsoftinj EXEKERNEL := tring ttable OBJ := $(addsuffix .o,${EXE}) diff --git a/tsrc/random_offline b/tsrc/random_offline new file mode 100755 index 0000000..3386abc --- /dev/null +++ b/tsrc/random_offline @@ -0,0 +1,71 @@ +#!/bin/bash +# randomly soft offline pages + +# fixme: uses time seed, non reproducible + +#mount -t debugfs none /debug + +THRESH=${1:-1000} + +end_of_memory() { + for i in /sys/firmware/memmap/* ; do + case "$(< $i/type)" in + "System RAM") ;; + *) continue ;; + esac + + k=$(< $i/end) + k=${k/0x/} + k=$(echo $k | tr a-z A-Z) + + echo "ibase=16; $k/1000" | bc + done | sort -n | tail -n1 +} + +E=$(end_of_memory) + +echo "soft offlining pages upto $E" + +unpoison() { + if [ ! -f offlined ] ; then + return + fi + + echo unpoisioning + while read i ; do + #echo -n , + #echo "u $i" + echo $i | sed 's/000$//' > /debug/hwpoison/unpoison-pfn \ + || echo "unpoisioning $i failed: $?" + done < offlined + echo done + echo +} + +trap unpoison 0 + +(( k = 0 )) +rm -f offlined +while true ; do + T=$( + R=$RANDOM + X=$(echo "obase=16; ($R%$E)*4096" | bc) + echo 0x$X + ) + #echo "p $T" + if echo 2>/dev/null $T >/sys/devices/system/memory/soft_offline_page ; then + echo $T >> offlined + else + #echo offlining $T failed $? + true + fi + #echo -n . + + (( k++ )) + if [ $k -gt $THRESH ] ; then + unpoison + (( k = 0 )) + rm offlined + fi +done + diff --git a/tsrc/tsoft.c b/tsrc/tsoft.c new file mode 100644 index 0000000..4fbaa15 --- /dev/null +++ b/tsrc/tsoft.c @@ -0,0 +1,29 @@ +/* Simplest soft offline testcase */ +#include <stdlib.h> +#include <sys/mman.h> +#include <stdio.h> +#include <unistd.h> + +#define err(x) perror(x), exit(1) + +#define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */ + +int PS; + +int main(void) +{ + PS = getpagesize(); + char *map = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, 0, 0); + + if (map == (char *)-1L) + err("mmap"); + + *map = 1; + + if (madvise(map, PS, MADV_SOFT_OFFLINE) < 0) + perror("madvise SOFT_OFFLINE"); + + *map = 2; + + return 0; +} diff --git a/tsrc/tsoftinj.c b/tsrc/tsoftinj.c new file mode 100644 index 0000000..e48c912 --- /dev/null +++ b/tsrc/tsoftinj.c @@ -0,0 +1,129 @@ +/* Test soft page offline for process pages using madvise injector */ +#define _GNU_SOURCE 1 +#include <sys/mman.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/fcntl.h> +#include <stdlib.h> +#include <errno.h> + +#define MADV_SOFT_OFFLINE 101 + +#define err(x) perror(x), exit(1) + +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, "t%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 check(unsigned *count, char *name) +{ + unsigned count2 = hardware_corrupted(); + unsigned diff = count2 - *count; + if (diff != corrupted) { + printf("%s: expected %d corrupted pages, got %u\n", name, + corrupted, + diff); + if (diff < corrupted) + exitcode = 1; + } + *count = count2; + corrupted = 0; +} + +int main(void) +{ + PS = getpagesize(); + + unsigned count = hardware_corrupted(); + + anonymous("anonymous", 0); + check(&count, "anonymous"); + anonymous("anonymous mlock", MAP_LOCKED); + check(&count, "anonymous mlock"); + disk_backed("disk backed", 0); + check(&count, "disk backed"); + disk_backed("disk backed mlock", 0); + check(&count, "disk backed mlock"); + // add more test cases here + + return exitcode; +} |