diff options
author | Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> | 2010-10-08 14:35:32 +0900 |
---|---|---|
committer | Andi Kleen <ak@linux.intel.com> | 2010-10-29 00:57:27 +0200 |
commit | facf6cc652a6d87d804ed2fada12620418408b3a (patch) | |
tree | 03dda0ec4515fdba10bf359690dd44626738ca10 | |
parent | c6a4c3d950385063db705e520bc9b6cda9587f57 (diff) | |
download | mce-test-facf6cc652a6d87d804ed2fada12620418408b3a.tar.gz |
tinjpage: add hugepage testcases
si_addr_lsb check in sighandler() is also extended to hugepage shift.
Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
-rw-r--r-- | tsrc/hugepage.h | 21 | ||||
-rw-r--r-- | tsrc/tinjpage.c | 173 |
2 files changed, 170 insertions, 24 deletions
diff --git a/tsrc/hugepage.h b/tsrc/hugepage.h index c2ff779..d44e5ac 100644 --- a/tsrc/hugepage.h +++ b/tsrc/hugepage.h @@ -1,12 +1,16 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <dirent.h> #include <sys/mman.h> #include <sys/ipc.h> #include <sys/shm.h> int HPS; -#define err(x) perror(x), exit(1) +char hugetlbfsdir[256]; +#ifndef UTILS +#include "utils.h" +#endif #define errmsg(x) fprintf(stderr, x), exit(1) void write_hugepage(char *addr, int size, char *avoid) @@ -63,6 +67,21 @@ int hugetlbfs_root(char *dir) return found; } +/* Assume there is only one types of hugepage size for now. */ +int gethugepagesize(void) +{ + int hpagesize = 0; + struct dirent *dent; + DIR *dir; + dir = opendir("/sys/kernel/mm/hugepages"); + if (!dir) err("open /sys/kernel/mm/hugepages"); + while ((dent = readdir(dir)) != NULL) + if (sscanf(dent->d_name, "hugepages-%dkB", &hpagesize) >= 1) + break; + closedir(dir); + return hpagesize * 1024; +} + void *alloc_shm_hugepage(int *key, int size) { void *addr; diff --git a/tsrc/tinjpage.c b/tsrc/tinjpage.c index 1042c13..bee38af 100644 --- a/tsrc/tinjpage.c +++ b/tsrc/tinjpage.c @@ -3,7 +3,7 @@ * This injects poison into various mapping cases and triggers the poison * handling. Requires special injection support in the kernel. * - * Copyright 2009 Intel Corporation + * Copyright 2009, 2010 Intel Corporation * * tinjpage is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -37,13 +37,14 @@ #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> +#include "utils.h" +#include "hugepage.h" #define MADV_POISON 100 #define TMPDIR "./" #define PATHBUFLEN 100 -#define err(x) perror(x),exit(1) #define Perror(x) failure++, perror(x) #define PAIR(x) x, sizeof(x)-1 #define mb() asm volatile("" ::: "memory") @@ -53,10 +54,13 @@ #define cpu_relax() mb() #endif +typedef unsigned long long u64; + int PS; int failure; int unexpected; int early_kill; +int test_hugepage; void *checked_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) @@ -126,8 +130,14 @@ void sighandler(int sig, siginfo_t *si, void *arg) } int lsb = ((struct my_siginfo *)si)->si_addr_lsb; - if (lsb != ilog2(sysconf(_SC_PAGE_SIZE))) { - printf("LATER: Unexpected addr lsb in siginfo %d\n", lsb); + if (test_hugepage) { + if (lsb != ilog2(HPS)) { + printf("LATER: Unexpected addr lsb in siginfo %d\n", lsb); + } + } else { + if (lsb != ilog2(sysconf(_SC_PAGE_SIZE))) { + printf("LATER: Unexpected addr lsb in siginfo %d\n", lsb); + } } printf("\tsignal %d code %d addr %p\n", sig, si->si_code, si->si_addr); @@ -151,22 +161,79 @@ enum rmode { MNOTHING = -1, }; +void inject_madvise(char *page) +{ + if (madvise(page, PS, MADV_POISON) != 0) { + if (errno == EINVAL) { + printf("Kernel doesn't support poison injection\n"); + exit(0); + } + Perror("madvise"); + } +} + +u64 page_to_pfn(char *page) +{ + static int pagemap_fd = -1; + u64 pfn; + + if (pagemap_fd < 0) { + pagemap_fd = open("/proc/self/pagemap", O_RDONLY); + if (pagemap_fd < 0) + err("/proc/self/pagemap not supported"); + } + + if (pread(pagemap_fd, &pfn, sizeof(u64), + ((u64)page / PS)*sizeof(u64)) != sizeof(u64)) + err("Cannot read from pagemap"); + + pfn &= (1ULL<<56)-1; + return pfn; +} + +/* + * Inject Action Optional #MC + * with mce-inject using the software injector. + * + * This tests the low level machine check handler too. + * + * Slightly racy with page migration because we don't mlock the page. + */ +void inject_mce_inject(char *page) +{ + u64 pfn = page_to_pfn(page); + FILE *mce_inject; + + mce_inject = popen("mce-inject", "w"); + if (!mce_inject) { + fprintf(stderr, "Cannot open pipe to mce-inject: %s\n", + strerror(errno)); + exit(1); + } + + fprintf(mce_inject, + "CPU 0 BANK 3 STATUS UNCORRECTED SRAO 0xc0\n" + "MCGSTATUS RIPV MCIP\n" + "ADDR %#llx\n" + "MISC 0x8c\n" + "RIP 0x73:0x1eadbabe\n", pfn); + + if (ferror(mce_inject) || fclose(mce_inject) < 0) { + fprintf(stderr, "mce-inject failed: %s\n", strerror(errno)); + exit(1); + } +} + +void (*inject)(char *page) = inject_madvise; + void poison(char *msg, char *page, enum rmode mode) { expected_addr = page; recovercount = 5; if (sigsetjmp(early_recover_ctx, 1) == 0) { - - if (madvise(page, PS, MADV_POISON) != 0) { - if (errno == EINVAL) { - printf("Kernel doesn't support poison injection\n"); - exit(0); - } - Perror("madvise"); - return; - } - + inject(page); + if (early_kill && (mode == MWRITE || mode == MREAD)) { printf("XXX: %s: process is not early killed\n", msg); failure++; @@ -721,6 +788,55 @@ static void ipv_shared(void) do_shared(IPV_SHARED); } +static void anonymous_hugepage(void) +{ + char *page; + /* Hugepage isn't supported. */ + if (!HPS) + return; + test_hugepage = 1; + page = alloc_anonymous_hugepage(HPS, 1); + /* prefault */ + page[0] = 'a'; + testmem("anonymous hugepage", page, MWRITE); + free_anonymous_hugepage(page, HPS); + test_hugepage = 0; +} + +static void file_backed_hugepage(void) +{ + char *page; + char buf[PATHBUFLEN]; + int fd; + /* Hugepage isn't supported. */ + if (!HPS) + return; + test_hugepage = 1; + snprintf(buf, PATHBUFLEN, "%s/test%d", hugetlbfsdir, tmpcount++); + page = alloc_filebacked_hugepage(buf, HPS, 0, &fd); + /* prefault */ + page[0] = 'a'; + testmem("file backed hugepage", page, MWRITE); + free_filebacked_hugepage(page, HPS, fd, buf); + test_hugepage = 0; +} + +static void shm_hugepage(void) +{ + char *page; + /* Hugepage isn't supported. */ + if (!HPS) + return; + test_hugepage = 1; + page = alloc_shm_hugepage(&tmpcount, HPS); + /* prefault */ + page[0] = 'a'; + testmem("shared memory hugepage", page, MWRITE); + free_shm_hugepage(tmpcount, page); + tmpcount++; + test_hugepage = 0; +} + struct testcase { void (*f)(void); char *name; @@ -737,6 +853,9 @@ struct testcase { { nonlinear, "nonlinear" }, { mmap_shared, "mmap shared" }, { ipv_shared, "ipv shared" }, + { anonymous_hugepage, "anonymous hugepage" }, + { file_backed_hugepage, "file backed hugepage" }, + { shm_hugepage, "shared memory hugepage" }, {}, /* dummy 1 for sniper */ {}, /* dummy 2 for sniper */ {} @@ -751,20 +870,26 @@ void usage(void) { fprintf(stderr, "Usage: tinjpage [--sniper]\n" "Test hwpoison injection on pages in various states\n" - "--sniper: Enable racy sniper tests (likely broken)\n"); + "--mce-inject Use mce-inject for injection\n" + "--sniper Enable racy sniper tests (likely broken)\n"); exit(1); } void handle_opts(char **av) { - if (!strcmp(av[1], "--sniper")) { - struct testcase *t; - for (t = cases; t->f; t++) - ; - *t++ = snipercases[0]; - *t++ = snipercases[1]; - } else - usage(); + while (*++av) { + if (!strcmp(*av, "--sniper")) { + struct testcase *t; + for (t = cases; t->f; t++) + ; + *t++ = snipercases[0]; + *t++ = snipercases[1]; + } + else if (!strcmp(*av, "--mce-inject")) { + inject = inject_mce_inject; + } else + usage(); + } } int main(int ac, char **av) @@ -773,6 +898,8 @@ int main(int ac, char **av) handle_opts(av); PS = getpagesize(); + if (hugetlbfs_root(hugetlbfsdir)) + HPS = gethugepagesize(); /* don't kill me at poison time, but possibly at page fault time */ early_kill = 0; |