aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>2010-10-08 14:35:32 +0900
committerAndi Kleen <ak@linux.intel.com>2010-10-29 00:57:27 +0200
commitfacf6cc652a6d87d804ed2fada12620418408b3a (patch)
tree03dda0ec4515fdba10bf359690dd44626738ca10
parentc6a4c3d950385063db705e520bc9b6cda9587f57 (diff)
downloadmce-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.h21
-rw-r--r--tsrc/tinjpage.c173
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;