Merge branch 'master' of git://git.kernel.org/pub/scm/utils/cpu/mce/mce-test
diff --git a/tsrc/hugepage.h b/tsrc/hugepage.h
new file mode 100644
index 0000000..d44e5ac
--- /dev/null
+++ b/tsrc/hugepage.h
@@ -0,0 +1,181 @@
+#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;
+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)
+{
+	int i, j;
+	for (i = 0; i < size; i++) {
+		if (addr == avoid)
+			continue;
+		for (j = 0; j < HPS; j++) {
+			*(addr + i * HPS + j) = (char)('a' + ((i + j) % 26));
+		}
+	}
+}
+
+/* return -1 if buffer content differs from the expected ones */
+int read_hugepage(char *addr, int size, char *avoid)
+{
+	int i, j;
+	int ret = 0;
+
+	for (i = 0; i < size; i++) {
+		if (addr == avoid)
+			continue;
+		for (j = 0; j < HPS; j++) {
+			if (*(addr + i * HPS + j) != (char)('a' + ((i + j) % 26))) {
+				printf("Mismatch at %d\n", i + j);
+				ret = -1;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+int hugetlbfs_root(char *dir)
+{
+	int found = 0;
+	FILE *f = fopen("/proc/mounts", "r");
+	if (!f) err("open /proc/mounts");
+	char *line = NULL;
+	size_t linelen = 0;
+	char dummy[100];
+	while (getline(&line, &linelen, f) > 0) {
+		if (sscanf(line, "none %s hugetlbfs %[^ ]",
+			   dir, dummy) >= 2) {
+			found = 1;
+			break;
+		}
+	}
+	free(line);
+	fclose(f);
+	if (!found)
+		printf("cannot find hugetlbfs directory in /proc/mounts\n");
+	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;
+	int shmid;
+	if ((shmid = shmget(*key, size,
+			    SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0) {
+		perror("shmget");
+		return NULL;
+	}
+	addr = shmat(shmid, (void *)0x0UL, 0);
+	if (addr == (char *)-1) {
+		perror("Shared memory attach failure");
+		shmctl(shmid, IPC_RMID, NULL);
+		return NULL;
+	}
+	*key = shmid;
+	return addr;
+}
+
+void *alloc_anonymous_hugepage(int size, int private)
+{
+	void *addr;
+	int mapflag = MAP_ANONYMOUS | 0x40000; /* MAP_HUGETLB */
+	if (private)
+		mapflag |= MAP_PRIVATE;
+	else
+		mapflag |= MAP_SHARED;
+	if ((addr = mmap(0, size,
+			 PROT_READ|PROT_WRITE, mapflag, -1, 0)) == MAP_FAILED) {
+		perror("mmap");
+		return NULL;
+	}
+	return addr;
+}
+
+void *alloc_filebacked_hugepage(char *filepath, int size, int private, int *fd)
+{
+	int mapflag = MAP_SHARED;
+	void *addr;
+	if (private)
+		mapflag = MAP_PRIVATE;
+	if ((*fd = open(filepath, O_CREAT | O_RDWR, 0777)) < 0) {
+		perror("open");
+		return NULL;
+	}
+	if ((addr = mmap(0, size,
+			 PROT_READ|PROT_WRITE, mapflag, *fd, 0)) == MAP_FAILED) {
+		perror("mmap");
+		unlink(filepath);
+		return NULL;
+	}
+	return addr;
+}
+
+int free_shm_hugepage(int key, void *addr)
+{
+	if (shmdt((const void *)addr) != 0) {
+		perror("Detach failure");
+		shmctl(key, IPC_RMID, NULL);
+		return -1;
+	}
+	shmctl(key, IPC_RMID, NULL);
+	return 0;
+}
+
+int free_anonymous_hugepage(void *addr, int size)
+{
+	int ret = 0;
+	if (munmap(addr, size)) {
+		perror("munmap");
+		ret = -1;
+	}
+	return ret;
+}
+
+int free_filebacked_hugepage(void *addr, int size, int fd, char *filepath)
+{
+	int ret = 0;
+	if (munmap(addr, size)) {
+		perror("munmap");
+		ret = -1;
+	}
+	if (close(fd)) {
+		perror("close");
+		ret = -1;
+	}
+	if (filepath) {
+		if (unlink(filepath)) {
+			perror("unlink");
+			ret = -1;
+		}
+	} else {
+		fprintf(stderr, "Filepath not specified.\n");
+		ret = -1;
+	}
+	return ret;
+}
diff --git a/tsrc/thugetlb.c b/tsrc/thugetlb.c
index b941e7e..28a1f10 100644
--- a/tsrc/thugetlb.c
+++ b/tsrc/thugetlb.c
@@ -2,6 +2,7 @@
  * Test program for memory error handling for hugepages
  * Author: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
  */
+#define _GNU_SOURCE 1
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h> 
@@ -16,6 +17,7 @@
 #include <sys/types.h>
 #include <sys/prctl.h>
 #include <sys/wait.h>
+#include "hugepage.h"
 
 #define FILE_BASE  "test"
 
@@ -36,6 +38,9 @@
 #define PR_MCE_KILL_DEFAULT 2
 #define PR_MCE_KILL_GET 34
 
+#define MADV_HWPOISON		100
+#define MADV_SOFT_OFFLINE	101
+
 int PS; /* Page size */
 int file_size; /* Memory allocation size (hugepage unit) */
 /* Error injection position (page offset from the first hugepage head) */
@@ -45,16 +50,14 @@
 
 #define DEB printf("DEBUG [%d:%s:%d]\n", getpid(), __FILE__, __LINE__);
 
-#define err(x) perror(x), exit(1)
-#define errmsg(x) fprintf(stderr, x), exit(1)
-
 static void usage(void)
 {
 	printf(
-"./thugetlb [-m memory] [-o offset] [-f file] [-xeSAaFpch] hugetlbfs_directory\n"
+"./thugetlb [-m memory] [-o offset] [-f file] [-xOeSAaFpch] hugetlbfs_directory\n"
 "            -m|--memory size(hugepage unit)    Size of hugetlbfs file\n"
 "            -o|--offset offset(page unit)      Position of error injection\n"
 "            -x|--inject                        Error injection switch\n"
+"            -O|--offline                       Soft offline switch\n"
 "            -e|--early-kill                    Set PR_MCE_KILL_EARLY\n"
 "            -S|--shm                           Use shmem with SHM_HUGETLB\n"
 "            -A|--anonymous                     Use MAP_ANONYMOUS\n"
@@ -87,45 +90,11 @@
 	return semop(sem_id, sembuffer, 1);
 }
 
-static int avoid_hpage(void *addr, int flag, char *avoid)
-{
-	return flag == 1 && addr == avoid;
-}
-
-static void write_bytes(char *addr, int flag, char *avoid)
-{
-	int i, j;
-	for (i = 0; i < file_size; i++) {
-		if (avoid_hpage(addr + i * HPAGE_SIZE, flag, avoid))
-			continue;
-		for (j = 0; j < HPAGE_SIZE; j++) {
-			*(addr + i * HPAGE_SIZE + j) = (char)('a' +
-							      ((i + j) % 26));
-		}
-	}
-}
-
-static void read_bytes(char *addr, int flag, char *avoid)
-{
-	int i, j;
-
-	for (i = 0; i < file_size; i++) {
-		if (avoid_hpage(addr + i * HPAGE_SIZE, flag, avoid))
-			continue;
-		for (j = 0; j < HPAGE_SIZE; j++) {
-			if (*(addr + i * HPAGE_SIZE + j) != (char)('a' +
-							   ((i + j) % 26))) {
-				printf("Mismatch at %u\n", i + j);
-				break;
-			}
-		}
-	}
-}
-
 static struct option opts[] = {
 	{ "memory"          , 1, NULL, 'm' },
 	{ "offset"          , 1, NULL, 'o' },
 	{ "inject"          , 0, NULL, 'x' },
+	{ "offline"         , 0, NULL, 'O' },
 	{ "early_kill"      , 0, NULL, 'e' },
 	{ "shm"             , 0, NULL, 'S' },
 	{ "anonymous"       , 0, NULL, 'A' },
@@ -144,10 +113,10 @@
 	int i;
 	int ret;
 	int fd = 0;
-	int shmid;
 	int semid;
 	int semaphore;
 	int inject = 0;
+	int madvise_code = MADV_HWPOISON;
 	int early_kill = 0;
 	int avoid_touch = 0;
 	int anonflag = 0;
@@ -162,6 +131,7 @@
 	struct sembuf sembuffer;
 
 	PS = getpagesize();
+	HPS = HPAGE_SIZE;
 	file_size = 1;
 	corrupt_page = -1;
 
@@ -171,7 +141,7 @@
 	}
 
 	while ((c = getopt_long(argc, argv,
-				"m:o:xeSAaFpcf:h", opts, NULL)) != -1) {
+				"m:o:xOeSAaFpcf:h", opts, NULL)) != -1) {
 		switch (c) {
 		case 'm':
 			file_size = strtol(optarg, NULL, 10);
@@ -182,6 +152,9 @@
 		case 'x':
 			inject = 1;
 			break;
+		case 'O':
+			madvise_code = MADV_SOFT_OFFLINE;
+			break;
 		case 'e':
 			early_kill = 1;
 			break;
@@ -232,38 +205,23 @@
 	}
 
 	if (shmflag) {
-		if ((shmid = shmget(shmkey, file_size * HPAGE_SIZE,
-				    SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0)
-			err("shmget");
-		addr = shmat(shmid, (void *)0x0UL, 0);
-		if (addr == (char *)-1) {
-			perror("Shared memory attach failure");
-			shmctl(shmid, IPC_RMID, NULL);
-			exit(2);
-		}
+		addr = alloc_shm_hugepage(&shmkey, file_size * HPAGE_SIZE);
+		if (!addr)
+			errmsg("Failed in alloc_shm_hugepage()");
 	} else if (anonflag) {
-		int mapflag = MAP_ANONYMOUS | 0x40000; /* MAP_HUGETLB */
-		if (privateflag)
-			mapflag |= MAP_PRIVATE;
-		else
-			mapflag |= MAP_SHARED;
-		if ((addr = mmap(0, file_size * HPAGE_SIZE,
-				 PROTECTION, mapflag, -1, 0)) == MAP_FAILED)
-			err("mmap");
+		addr = alloc_anonymous_hugepage(file_size * HPAGE_SIZE,
+						privateflag);
+		if (!addr)
+			errmsg("Failed in alloc_anonymous_hugepage()");
 	} else {
-		int mapflag = MAP_SHARED;
-		if (privateflag)
-			mapflag = MAP_PRIVATE;
-		if ((fd = open(filepath, O_CREAT | O_RDWR, 0777)) < 0)
-			err("Open failed");
-		if ((addr = mmap(0, file_size * HPAGE_SIZE,
-				 PROTECTION, mapflag, fd, 0)) == MAP_FAILED) {
-			unlink(filepath);
-			err("mmap");
-		}
+		addr = alloc_filebacked_hugepage(filepath,
+						 file_size * HPAGE_SIZE,
+						 privateflag, &fd);
+		if (!addr)
+			errmsg("Failed in alloc_filebacked_hugepage()");
 	}
 
-	if (corrupt_page != -1)
+	if (corrupt_page != -1 && avoid_touch)
 		expected_addr = (void *)(addr + corrupt_page / 512 * HPAGE_SIZE);
 
 	if (forkflag) {
@@ -283,8 +241,8 @@
 		}
 	}
 
-	write_bytes(addr, 0, 0);
-	read_bytes(addr, 0, 0);
+	write_hugepage(addr, file_size, 0);
+	read_hugepage(addr, file_size, 0);
 
 	if (early_kill)
 		prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY,
@@ -301,8 +259,8 @@
 		if (!pid) {
 			/* Semaphore is already held */
 			if (cowflag) {
-				write_bytes(addr, 0, expected_addr);
-				read_bytes(addr, 0, expected_addr);
+				write_hugepage(addr, 0, expected_addr);
+				read_hugepage(addr, 0, expected_addr);
 			}
 			if (put_semaphore(semid, &sembuffer))
 				err("put_semaphore");
@@ -323,7 +281,7 @@
 	}
 
 	if (inject && corrupt_page != -1) {
-		ret = madvise(addr + corrupt_page * PS, PS, 100);
+		ret = madvise(addr + corrupt_page * PS, PS, madvise_code);
 		if (ret) {
 			printf("madivise return %d :", ret);
 			perror("madvise");
@@ -336,27 +294,27 @@
 		goto cleanout;
 	}
 
-	write_bytes(addr, avoid_touch, expected_addr);
-	read_bytes(addr, avoid_touch, expected_addr);
+	if (madvise_code != MADV_SOFT_OFFLINE);
+		write_hugepage(addr, file_size, expected_addr);
+	read_hugepage(addr, file_size, expected_addr);
 
-	if (forkflag)
+	if (forkflag) {
 		if (wait(&i) == -1)
 			err("wait");
+		if (semctl(semid, 0, IPC_RMID) == -1)
+			err("semctl(IPC_RMID)");
+	}
 cleanout:
 	if (shmflag) {
-		if (shmdt((const void *)addr) != 0) {
-			err("Detach failure");
-			shmctl(shmid, IPC_RMID, NULL);
-			exit(EXIT_FAILURE);
-		}
-		shmctl(shmid, IPC_RMID, NULL);
+		if (free_shm_hugepage(shmkey, addr) == -1)
+			exit(2);
+	} else if (anonflag) {
+		if (free_anonymous_hugepage(addr, file_size * HPAGE_SIZE) == -1)
+			exit(2);
 	} else {
-		if (munmap(addr, file_size * HPAGE_SIZE))
-			err("munmap");
-		if (close(fd))
-			err("close");
-		if (!anonflag && unlink(filepath))
-			err("unlink");
+		if (free_filebacked_hugepage(addr, file_size * HPAGE_SIZE,
+					     fd, filepath) == -1)
+			exit(2);
 	}
 
 	return 0;
diff --git a/tsrc/tinjpage.c b/tsrc/tinjpage.c
index fd98a4f..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)
@@ -83,11 +87,40 @@
 	return p;
 }
 
+static int ilog2(int n)
+{
+	int r = 0;
+	n--;
+	while (n) {
+		n >>= 1;
+		r++;
+	}
+	return r;
+}
+
 int recovercount;
 sigjmp_buf recover_ctx;
 sigjmp_buf early_recover_ctx;
 void *expected_addr;
 
+/* Work around glibc not defining this yet */
+struct my_siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+	union {
+	struct {
+		void  *_addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_TRAPNO
+		int _trapno;	/* TRAP # which caused the signal */
+#endif
+		short _addr_lsb; /* LSB of the reported address */
+	} _sigfault;
+	} _sifields;
+};
+#undef si_addr_lsb
+#define si_addr_lsb _sifields._sigfault._addr_lsb
+
 void sighandler(int sig, siginfo_t *si, void *arg)
 {
 	if (si->si_addr != expected_addr) {
@@ -96,6 +129,17 @@
 		failure++;
 	}
 
+	int lsb = ((struct my_siginfo *)si)->si_addr_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);
 
 	if (--recovercount == 0) {
@@ -117,22 +161,79 @@
 	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++;
@@ -687,6 +788,55 @@
 	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;
@@ -703,6 +853,9 @@
 	{ 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 */
 	{}
@@ -717,20 +870,26 @@
 {
 	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)
@@ -739,6 +898,8 @@
 		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;
diff --git a/tsrc/tsoftinj.c b/tsrc/tsoftinj.c
index 02b0785..c2dfc6c 100644
--- a/tsrc/tsoftinj.c
+++ b/tsrc/tsoftinj.c
@@ -27,10 +27,10 @@
 #include <sys/fcntl.h>
 #include <stdlib.h>
 #include <errno.h>
+#include "hugepage.h"
 
 #define MADV_SOFT_OFFLINE 101
 
-#define err(x) perror(x), exit(1)
 #define TMPDIR "./"
 
 int PS;
@@ -116,15 +116,55 @@
 	munmap(p, PS);
 }
 
-void check(unsigned *count, char *name)
+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 != corrupted) {
+	if (diff != expected) {
 		printf("%s: expected %d corrupted pages, got %u\n", name,
-			corrupted, 
+			expected,
 			diff);	
-		if (diff < corrupted)
+		if (diff < expected)
 			exitcode = 1;
 	}
 	*count = count2;
@@ -134,17 +174,25 @@
 int main(void)
 {
 	PS = getpagesize();
+	HPS = gethugepagesize();
 
 	unsigned count = hardware_corrupted();
-	
-	anonymous("anonymous", 0);	
-	check(&count, "anonymous");
-	anonymous("anonymous mlock", MAP_LOCKED);	
-	check(&count, "anonymous mlock");
+	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");
+	check(&count, "disk backed", 1);
 	disk_backed("disk backed mlock", 0);
-	check(&count, "disk backed mlock");
+	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;
diff --git a/tsrc/utils.h b/tsrc/utils.h
new file mode 100644
index 0000000..8c8ab26
--- /dev/null
+++ b/tsrc/utils.h
@@ -0,0 +1 @@
+#define err(x) perror(x), exit(1)