All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH] rework code for oom and ksm tests
       [not found] <488834807.56177.1295424703727.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com>
@ 2011-01-19  8:11 ` CAI Qian
  2011-01-19  9:05   ` Garrett Cooper
  0 siblings, 1 reply; 2+ messages in thread
From: CAI Qian @ 2011-01-19  8:11 UTC (permalink / raw)
  To: ltp-list

[-- Attachment #1: Type: text/plain, Size: 51008 bytes --]

Mainly to reduce code duplication. Also, to add an option for ksm01 to
use a different memory allocation unit size to take advantage of THP.
In addition, adjust ksm01 according the latest upstream development
effort,
http://marc.info/?l=linux-mm&m=129473104716901&w=2
http://marc.info/?l=linux-mm&m=129442718808733&w=2

Signed-off-by: CAI Qian <caiqian@redhat.com>
---
 testcases/kernel/mem/include/mem.h |   50 +++
 testcases/kernel/mem/ksm/Makefile  |   23 ++-
 testcases/kernel/mem/ksm/ksm01.c   |  461 +------------------------
 testcases/kernel/mem/lib/Makefile  |   25 ++
 testcases/kernel/mem/lib/mem.c     |  651 ++++++++++++++++++++++++++++++++++++
 testcases/kernel/mem/oom/Makefile  |    6 +-
 testcases/kernel/mem/oom/oom01.c   |    5 +-
 testcases/kernel/mem/oom/oom02.c   |    4 +-
 testcases/kernel/mem/oom/oom03.c   |    5 +-
 testcases/kernel/mem/oom/oom04.c   |  256 +-------------
 10 files changed, 786 insertions(+), 700 deletions(-)
 create mode 100644 testcases/kernel/mem/include/mem.h
 create mode 100644 testcases/kernel/mem/lib/Makefile
 create mode 100644 testcases/kernel/mem/lib/mem.c

diff --git a/testcases/kernel/mem/include/mem.h b/testcases/kernel/mem/include/mem.h
new file mode 100644
index 0000000..778d403
--- /dev/null
+++ b/testcases/kernel/mem/include/mem.h
@@ -0,0 +1,50 @@
+#ifndef _MEM_H
+#define _MEM_H
+#include "test.h"
+#include "usctest.h"
+
+#define LENGTH			(3UL<<30)
+#define SYSFS_OVER		"/proc/sys/vm/overcommit_memory"
+#define OVERCOMMIT		1
+#define NORMAL			2
+#define MLOCK			3
+#define KSM			4
+#define CPATH			"/dev/cpuset"
+#define CPATH_NEW		CPATH "/1"
+#define MAXNODES		512
+#define MEMCG_PATH		"/dev/cgroup"
+#define MEMCG_PATH_NEW		MEMCG_PATH "/1"
+#define TESTMEM			(1UL<<30)
+#define MB			(1UL<<20)
+#define PATH_SYS_SYSTEM		"/sys/devices/system"
+#define PATH_KSM		"/sys/kernel/mm/ksm/"
+
+char overcommit[BUFSIZ];
+int opt_num, opt_size, opt_unit;
+char *opt_numstr, *opt_sizestr, *opt_unitstr;
+/* memory pointer to identify per process, MB unit, and byte like
+   memory[process No.][MB unit No.][byte No.]. */
+char ***memory;
+
+void oom(int testcase, int mempolicy, int lite);
+void testoom(int mempolicy, int lite, int numa);
+long count_numa(void);
+int path_exist(const char *path, ...);
+int alloc_mem(long int length, int testcase);
+void test_alloc(int testcase, int lite);
+void gather_cpus(char *cpus);
+void umount_mem(char *path, char *path_new);
+void mount_mem(char *name, char *fs, char *options, char *path, char *path_new);
+void cleanup(void);
+void setup(void);
+void ksm_usage(void);
+void check(char *path, long int value);
+void verify(char value, int proc, int start, int end, int start2, int end2);
+void group_check(int run, int pages_shared, int pages_sharing,
+		int pages_volatile, int pages_unshared, int sleep_millisecs,
+		int pages_to_scan);
+void create_same_memory(int size, int num, int unit);
+void check_ksm_options(int *size, int *num, int *unit);
+void write_cpusets(void);
+void write_memcg(void);
+#endif
diff --git a/testcases/kernel/mem/ksm/Makefile b/testcases/kernel/mem/ksm/Makefile
index 3634570..81509bf 100644
--- a/testcases/kernel/mem/ksm/Makefile
+++ b/testcases/kernel/mem/ksm/Makefile
@@ -18,5 +18,26 @@
 
 top_srcdir              ?= ../../../..
 
+include $(top_srcdir)/include/mk/env_pre.mk
+
+LDLIBS			+= $(NUMA_LIBS) -lmem
+LIBDIR			:= ../lib
+LIB			:= $(LIBDIR)/libmem.a
+FILTER_OUT_DIRS		:= $(LIBDIR)
+LDFLAGS			+= -L$(LIBDIR)
+
+$(LIBDIR):
+	mkdir -p "$@"
+
+$(LIB): $(LIBDIR)
+	$(MAKE) -C $^ -f "$(abs_srcdir)/$^/Makefile" all
+
+MAKE_DEPS		:= $(LIB)
+
+trunk-clean:: | lib-clean
+
+lib-clean:: $(LIBDIR)
+	$(MAKE) -C $^ -f "$(abs_srcdir)/$^/Makefile" clean
+
+include $(top_srcdir)/include/mk/generic_trunk_target.mk
 include $(top_srcdir)/include/mk/testcases.mk
-include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/mem/ksm/ksm01.c b/testcases/kernel/mem/ksm/ksm01.c
index 09f71d7..e1c7d7f 100644
--- a/testcases/kernel/mem/ksm/ksm01.c
+++ b/testcases/kernel/mem/ksm/ksm01.c
@@ -1,5 +1,5 @@
 /*
- * functional testing for Kernel Samepage Merging (KSM)
+ * Kernel Samepage Merging (KSM)
  *
  * Basic tests were to start several programs with same and different
  * memory contents and ensure only to merge the ones with the same
@@ -69,471 +69,46 @@
 #include <errno.h>
 #include "test.h"
 #include "usctest.h"
-
-#define _PATH_KSM	"/sys/kernel/mm/ksm/"
-#define MB		(1024 * 1024)
+#include "../include/mem.h"
 
 char *TCID = "ksm01";
 int TST_TOTAL = 1;
-static int opt_num, opt_size;
-static char *opt_numstr, *opt_sizestr;
-/* memory pointer to identify per process, MB, and byte like
-   memory[process No.][MB No.][byte No.]. */
-static char ***memory;
-static option_t options[] = {
-	{ "n:", &opt_num,	&opt_numstr},
-	{ "s:", &opt_size,	&opt_sizestr},
-	{ NULL, NULL,		NULL}
+
+option_t ksm_options[] = {
+        { "n:", &opt_num,       &opt_numstr},
+        { "s:", &opt_size,      &opt_sizestr},
+        { "u:", &opt_unit,      &opt_unitstr},
+        { NULL, NULL,           NULL}
 };
-static void setup(void);
-static void ksmtest(void);
-static void usage(void);
-static void check(char *path, char *path2, long int value);
-static void verify(char value, int proc, int start, int end, int start2,
-		int end2);
-static void group_check(int run, int pages_shared, int pages_sharing,
-			int pages_volatile, int pages_unshared,
-			int sleep_millisecs, int pages_to_scan);
 
 int main(int argc, char *argv[])
 {
 	int lc;
 	char *msg;
+	int size = 128, num = 3, unit = 1;
 
-	msg = parse_opts(argc, argv, options, usage);
-	if (msg != (char *)NULL)
-		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+	msg = parse_opts(argc, argv, ksm_options, ksm_usage);
+	if (msg != NULL)
+		tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
 	setup();
 	for (lc = 0; TEST_LOOPING(lc); lc++) {
 		Tst_count = 0;
-		ksmtest();
+		check_ksm_options(&size, &num, &unit);
+		create_same_memory(size, num, unit);
 	}
+	cleanup();
 	tst_exit();
 }
 
-void ksmtest(void)
-{
-	char buf[BUFSIZ], buf2[BUFSIZ];
-	int i, j, status, k, fd, *child;
-	int size = 128, num = 3;
-
-	if (opt_size) {
-		size = atoi(opt_sizestr);
-		if (size < 1)
-			tst_brkm(TBROK, NULL,
-				"size cannot be less than 1.");
-	}
-	if (opt_num) {
-		num = atoi(opt_numstr);
-		if (num < 3)
-			tst_brkm(TBROK, NULL,
-				"process number cannot be less 3.");
-	}
-	child = malloc(num);
-	if (child == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "malloc");
-
-	memory = malloc(num * sizeof(**memory));
-	if (memory == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "malloc");
-
-	switch (child[0] = fork()) {
-	case -1:
-		tst_brkm(TBROK|TERRNO, NULL, "fork");
-	case 0:
-		tst_resm(TINFO, "child 0 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-
-		tst_resm(TINFO, "child 0 continues...");
-
-		/* Avoid TransparentHugePage allocation which can't ksm at the
-		   moment. */
-		tst_resm(TINFO, "child 0 allocates %d MB filled with 'c'.",
-			size);
-		memory[0] = malloc(size * sizeof(*memory));
-		if (memory[0] == NULL)
-			tst_brkm(TBROK|TERRNO, NULL, "malloc");
-		for (j = 0; j < size; j++) {
-			memory[0][j] = mmap(NULL, MB, PROT_READ|PROT_WRITE,
-					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-			if (memory[0][j] == MAP_FAILED)
-				tst_brkm(TBROK|TERRNO, NULL, "mmap");
-			if (madvise(memory[0][j], MB, MADV_MERGEABLE) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "madvise");
-			for (i = 0; i < MB; i++)
-				memory[0][j][i] = 'c';
-		}
-		tst_resm(TINFO, "child 0 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-
-		tst_resm(TINFO, "child 0 continues...");
-		verify('c', 0, 0, size, 0, MB);
-		tst_resm(TINFO, "child 0 changes memory content to 'd'.");
-		for (j = 0; j < size; j++) {
-			for (i = 0; i < MB; i++)
-				memory[0][j][i] = 'd';
-		}
-		/* Unmerge. */
-		tst_resm(TINFO, "child 0 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-
-		tst_resm(TINFO, "child 0 continues...");
-		verify('d', 0, 0, size, 0, MB);
-		/* Stop. */
-		tst_resm(TINFO, "child 0 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 0 continues...");
-		exit(0);
-	}
-	switch (child[1] = fork()) {
-	case -1:
-		tst_brkm(TBROK|TERRNO, NULL, "fork");
-	case 0:
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		tst_resm(TINFO, "child 1 allocates %d MB filled with 'a'.",
-			size);
-		memory[1] = malloc(size * sizeof(*memory));
-		if (memory[1] == NULL)
-			tst_brkm(TBROK|TERRNO, NULL, "malloc");
-		for (j = 0; j < size; j++) {
-			memory[1][j] = mmap(NULL, MB, PROT_READ|PROT_WRITE,
-					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-			if (memory[1][j] == MAP_FAILED)
-				tst_brkm(TBROK|TERRNO, NULL, "mmap");
-			if (madvise(memory[1][j], MB, MADV_MERGEABLE) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "madvise");
-			for (i = 0; i < MB; i++)
-				memory[1][j][i] = 'a';
-		}
-
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		verify('a', 1, 0, size, 0, MB);
-		tst_resm(TINFO, "child 1 changes memory content to 'b'.");
-		for (j = 0; j < size; j++) {
-			for (i = 0; i < MB; i++)
-				memory[1][j][i] = 'b';
-		}
-
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		verify('b', 1, 0, size, 0, MB);
-		tst_resm(TINFO, "child 1 changes memory content to 'd'");
-		for (j = 0; j < size; j++) {
-			for (i = 0; i < MB; i++)
-				memory[1][j][i] = 'd';
-		}
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-
-		tst_resm(TINFO, "child 1 continues...");
-		verify('d', 1, 0, size, 0, MB);
-		tst_resm(TINFO, "child 1 changes one page to 'e'.");
-		memory[1][size - 1][MB - 1] = 'e';
-
-		/* Unmerge. */
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		verify('e', 1, size - 1, size, MB - 1, MB);
-		verify('d', 1, 0, size - 1, 0, MB - 1);
-
-		/* Stop. */
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		exit(0);
-	}
-	for (k = 2; k < num; k++) {
-		switch (child[k] = fork()) {
-		case -1:
-			tst_brkm(TBROK|TERRNO, NULL, "fork");
-		case 0:
-			tst_resm(TINFO, "child %d stops.", k);
-			if (raise(SIGSTOP) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "kill");
-			tst_resm(TINFO, "child %d continues...", k);
-			tst_resm(TINFO, "child %d allocates %d "
-				"MB filled with 'a'.", k, size);
-			memory[k] = malloc(size * sizeof(*memory));
-			if (memory[k] == NULL)
-				tst_brkm(TBROK|TERRNO, NULL, "malloc");
-			for (j = 0; j < size; j++) {
-				memory[k][j] = mmap(NULL, MB,
-						PROT_READ|PROT_WRITE,
-						MAP_ANONYMOUS
-						|MAP_PRIVATE, -1, 0);
-				if (memory[k][j] == MAP_FAILED)
-					tst_brkm(TBROK|TERRNO, NULL,
-						"mmap");
-				if (madvise(memory[k][j], MB,
-						MADV_MERGEABLE) == -1)
-					tst_brkm(TBROK|TERRNO, NULL,
-						"madvise");
-				for (i = 0; i < MB; i++)
-					memory[k][j][i] = 'a';
-			}
-			tst_resm(TINFO, "child %d stops.", k);
-			if (raise(SIGSTOP) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "kill");
-			tst_resm(TINFO, "child %d continues...", k);
-			tst_resm(TINFO, "child %d changes memory content to "
-				"'d'", k);
-			for (j = 0; j < size; j++) {
-				for (i = 0; i < MB; i++)
-					memory[k][j][i] = 'd';
-		        }
-			/* Unmerge. */
-			tst_resm(TINFO, "child %d stops.", k);
-			if (raise(SIGSTOP) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "kill");
-			tst_resm(TINFO, "child %d continues...", k);
-
-			/* Stop. */
-			tst_resm(TINFO, "child %d stops.", k);
-			if (raise(SIGSTOP) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "kill");
-			tst_resm(TINFO, "child %d continues...", k);
-			exit(0);
-		}
-	}
-	tst_resm(TINFO, "KSM merging...");
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "run");
-	fd = open(buf, O_WRONLY);
-	if (fd == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "open");
-	if (write(fd, "1", 1) != 1)
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	close(fd);
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "pages_to_scan");
-	snprintf(buf2, BUFSIZ, "%d", size * 256 * num);
-	fd = open(buf, O_WRONLY);
-	if (fd == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "open");
-	if (write(fd, buf2, strlen(buf2)) != strlen(buf2))
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	close(fd);
-
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "sleep_millisecs");
-	fd = open(buf, O_WRONLY);
-	if (fd == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "open");
-	if (write(fd, "0", 1) != 1)
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	close(fd);
-
-	tst_resm(TINFO, "wait for all children to stop.");
-	for (k = 0; k < num; k++) {
-		if (waitpid(child[k], &status, WUNTRACED) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-		if (!WIFSTOPPED(status))
-			tst_brkm(TBROK, NULL, "child %d was not stopped.",
-				k);
-	}
-	tst_resm(TINFO, "resume all children.");
-	for (k = 0; k < num; k++) {
-		if (kill(child[k], SIGCONT) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill child[%d]", k);
-	}
-	group_check(1, 2, size * num * 256 - 2, 0, 0, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for child 1 to stop.");
-	if (waitpid(child[1], &status, WUNTRACED) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-	if (!WIFSTOPPED(status))
-		tst_brkm(TBROK, NULL, "child 1 was not stopped.");
-
-	/* Child 1 changes all pages to 'b'. */
-	tst_resm(TINFO, "resume child 1.");
-	if (kill(child[1], SIGCONT) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "kill");
-	group_check(1, 3, size * num * 256 - 3, 0, 0, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for child 1 to stop.");
-	if (waitpid(child[1], &status, WUNTRACED) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-	if (!WIFSTOPPED(status))
-		tst_brkm(TBROK, NULL, "child 1 was not stopped.");
-
-	/* All children change pages to 'd'. */
-	tst_resm(TINFO, "resume all children.");
-	for (k = 0; k < num; k++) {
-		if (kill(child[k], SIGCONT) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill child[%d]", k);
-	}
-	group_check(1, 1, size * num * 256 - 1, 0, 0, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for all children to stop.");
-	for (k = 0; k < num; k++) {
-		if (waitpid(child[k], &status, WUNTRACED) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-		if (!WIFSTOPPED(status))
-			tst_brkm(TBROK, NULL, "child %d was not stopped.",
-				k);
-	}
-	/* Child 1 changes pages to 'e'. */
-	tst_resm(TINFO, "resume child 1.");
-	if (kill(child[1], SIGCONT) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "kill");
-	group_check(1, 1, size * num * 256 - 2, 0, 1, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for child 1 to stop.");
-	if (waitpid(child[1], &status, WUNTRACED) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-	if (!WIFSTOPPED(status))
-		tst_brkm(TBROK, NULL, "child 1 was not stopped.");
-
-	tst_resm(TINFO, "resume all children.");
-	for (k = 0; k < num; k++) {
-		if (kill(child[k], SIGCONT) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill child[%d]", k);
-	}
-	tst_resm(TINFO, "KSM unmerging...");
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "run");
-	fd = open(buf, O_WRONLY);
-	if (fd == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "open");
-	if (write(fd, "2", 1) != 1)
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	group_check(2, 0, 0, 0, 0, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for all children to stop.");
-	for (k = 0; k < num; k++) {
-		if (waitpid(child[k], &status, WUNTRACED) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-		if (!WIFSTOPPED(status))
-			tst_brkm(TBROK, NULL, "child %d was not stopped.",
-				k);
-	}
-	tst_resm(TINFO, "resume all children.");
-	for (k = 0; k < num; k++) {
-		if (kill(child[k], SIGCONT) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill child[%d]", k);
-	}
-	tst_resm(TINFO, "stop KSM.");
-	if (lseek(fd, 0, SEEK_SET) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "lseek");
-	if (write(fd, "0", 1) != 1)
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	close(fd);
-	group_check(0, 0, 0, 0, 0, 0, size * 256 * num);
-	while (waitpid(-1, &status, WUNTRACED | WCONTINUED) > 0)
-		if (WEXITSTATUS(status) != 0)
-			tst_resm(TFAIL, "child exit status is %d",
-				WEXITSTATUS(status));
-}
-
 void setup(void)
 {
-	char buf[BUFSIZ];
-	struct stat new;
+	tst_require_root(NULL);
 
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "run");
-	if (stat(buf, &new) == -1) {
-		if (errno == ENOENT)
-			tst_brkm(TCONF, NULL, "no KSM.");
-		else
-			tst_brkm(TBROK, NULL, "stat");
-	}
-	/*
-	 * setup a default signal hander and a
-	 * temporary working directory.
-	 */
 	tst_sig(FORK, DEF_HANDLER, NULL);
 	TEST_PAUSE;
 }
 
-void usage(void)
+void cleanup(void)
 {
-	printf("  -n      Number of processes\n");
-	printf("  -s      Memory allocation size in MB\n");
+	TEST_CLEANUP;
 }
-
-/* There is currently a bug will cause the test failure - *
- http://marc.info/?l=linux-mm&m=128928530308526&w=2 .  Since it has
- still been discussed upstream, the interface here was added some
- flexiblity with path2, so it is possible to make changes here depends
- on the future implementation in kernel. For example, to verify
- (pages_sharing + pages_volatile) instead of a single item. */
-void check(char *path, char *path2, long int value)
-{
-	FILE *fp;
-	char buf[BUFSIZ], buf2[BUFSIZ];
-
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, path);
-	fp = fopen(buf, "r");
-	if (fp == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "fopen");
-	if (fgets(buf, BUFSIZ, fp) == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "fgets");
-	fclose(fp);
-
-	tst_resm(TINFO, "%s is %ld.", path, atol(buf));
-	if (path2 != NULL) {
-		snprintf(buf2, BUFSIZ, "%s%s", _PATH_KSM, path2);
-		fp = fopen(buf2, "r");
-		if (fp == NULL)
-			tst_brkm(TBROK|TERRNO, NULL, "fopen");
-		if (fgets(buf2, BUFSIZ, fp) == NULL)
-			tst_brkm(TBROK|TERRNO, NULL, "fgets");
-		fclose(fp);
-
-		tst_resm(TINFO, "%s is %ld.", path2, atol(buf2));
-		if (atol(buf) + atol(buf2) != value)
-			tst_resm(TFAIL, "%s + %s is not %ld.", path, path2,
-				value);
-	} else
-		if (atol(buf) != value)
-			tst_resm(TFAIL, "%s is not %ld.", path, value);
-}
-
-void verify(char value, int proc, int start, int end, int start2, int end2)
-{
-	int i, j;
-	void *s = NULL;
-
-	s = malloc((end - start) * (end2 - start2));
-	if (s == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "malloc");
-
-	tst_resm(TINFO, "child %d verifies memory content.", proc);
-	memset(s, value, (end - start) * (end2 - start2));
-	if (memcmp(memory[proc][start], s, (end - start) * (end2 - start2)) != 0)
-		for (j = start; j < end; j++)
-			for (i = start2; i < end2; i++)
-				if (memory[proc][j][i] != value)
-					tst_resm(TFAIL, "child %d has %c at "
-						"%d,%d,%d.",
-						proc, memory[proc][j][i], proc,
-						j, i);
-	free(s);
-}
-
-void group_check(int run, int pages_shared, int pages_sharing,
-		int pages_volatile, int pages_unshared,
-		int sleep_millisecs, int pages_to_scan)
-{
-        /* 5 seconds for ksm to scan pages. */
-	sleep(5);
-	tst_resm(TINFO, "check!");
-	check("run", NULL, run);
-	check("pages_shared", NULL, pages_shared);
-	check("pages_sharing", NULL, pages_sharing);
-	check("pages_volatile", NULL, pages_volatile);
-	check("pages_unshared", NULL, pages_unshared);
-	check("sleep_millisecs", NULL, sleep_millisecs);
-	check("pages_to_scan", NULL, pages_to_scan);
-}
\ No newline at end of file
diff --git a/testcases/kernel/mem/lib/Makefile b/testcases/kernel/mem/lib/Makefile
new file mode 100644
index 0000000..dd978a7
--- /dev/null
+++ b/testcases/kernel/mem/lib/Makefile
@@ -0,0 +1,25 @@
+#
+#  Copyright (C) 2010  Red Hat, Inc.
+#
+#  This program 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; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program 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 have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+top_srcdir              ?= ../../../..
+
+include $(top_srcdir)/include/mk/env_pre.mk
+
+LIB			:= libmem.a
+
+include $(top_srcdir)/include/mk/lib.mk
diff --git a/testcases/kernel/mem/lib/mem.c b/testcases/kernel/mem/lib/mem.c
new file mode 100644
index 0000000..297eedd
--- /dev/null
+++ b/testcases/kernel/mem/lib/mem.c
@@ -0,0 +1,651 @@
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "test.h"
+#include "usctest.h"
+#include "../include/mem.h"
+#include "config.h"
+#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
+	&& HAVE_MPOL_CONSTANTS
+#include <numaif.h>
+#endif
+
+void oom(int testcase, int mempolicy, int lite)
+{
+	pid_t pid;
+	int status;
+#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
+	&& HAVE_MPOL_CONSTANTS
+	unsigned long nmask = 2;
+#endif
+
+	switch(pid = fork()) {
+	case -1:
+		tst_brkm(TBROK|TERRNO, cleanup, "fork");
+	case 0:
+#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
+	&& HAVE_MPOL_CONSTANTS
+		if (mempolicy)
+			if (set_mempolicy(MPOL_BIND, &nmask, MAXNODES) == -1)
+				tst_brkm(TBROK|TERRNO, cleanup,
+					"set_mempolicy");
+#endif
+		test_alloc(testcase, lite);
+		exit(0);
+	default:
+		break;
+	}
+	tst_resm(TINFO, "expected victim is %d.", pid);
+	if (waitpid(-1, &status, 0) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+
+	if (testcase == OVERCOMMIT) {
+		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+			tst_resm(TFAIL, "the victim unexpectedly failed: %d",
+				status);
+	} else {
+		if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL)
+			tst_resm(TFAIL, "the victim unexpectedly failed: %d",
+				status);
+	}
+}
+
+void write_memcg(void)
+{
+	int fd;
+	char buf[BUFSIZ], mem[BUFSIZ];
+
+	fd = open(MEMCG_PATH_NEW "/memory.limit_in_bytes", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	sprintf(mem, "%ld", TESTMEM);
+	if (write(fd, mem, strlen(mem)) != strlen(mem))
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);
+
+	fd = open(MEMCG_PATH_NEW "/tasks", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	snprintf(buf, BUFSIZ, "%d", getpid());
+	if (write(fd, buf, strlen(buf)) != strlen(buf))
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);	
+}
+
+void write_cpusets(void)
+{
+	char cpus[BUFSIZ] = "";
+	char buf[BUFSIZ] = "";
+	int fd;
+
+	gather_cpus(cpus);
+	tst_resm(TINFO, "CPU list for 2nd node is %s.", cpus);
+
+	fd = open(CPATH_NEW "/mems", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	if (write(fd, "1", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);
+
+	fd = open(CPATH_NEW "/cpus", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	if (write(fd, cpus, strlen(cpus)) != strlen(cpus))
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);
+
+	fd = open(CPATH_NEW "/tasks", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	snprintf(buf, BUFSIZ, "%d", getpid());
+	if (write(fd, buf, strlen(buf)) != strlen(buf))
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);
+}
+
+void testoom(int mempolicy, int lite, int numa)
+{
+	if (numa && !mempolicy)
+		write_cpusets();
+
+	tst_resm(TINFO, "start normal OOM testing.");
+	oom(NORMAL, mempolicy, lite);
+
+	tst_resm(TINFO, "start OOM testing for mlocked pages.");
+	oom(MLOCK, mempolicy, lite);
+
+	tst_resm(TINFO, "start OOM testing for KSM pages.");
+	oom(KSM, mempolicy, lite);
+}
+
+long count_numa(void)
+{
+	int nnodes = 0;
+
+	while(path_exist(PATH_SYS_SYSTEM "/node/node%d", nnodes))
+		nnodes++;
+
+	return nnodes;
+}
+
+int path_exist(const char *path, ...)
+{
+	va_list ap;
+	char pathbuf[PATH_MAX];
+
+	va_start(ap, path);
+	vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
+	va_end(ap);
+
+	return access(pathbuf, F_OK) == 0;
+}
+
+void gather_cpus(char *cpus)
+{
+	int ncpus = 0;
+	int i;
+	char buf[BUFSIZ];
+
+	while(path_exist(PATH_SYS_SYSTEM "/cpu/cpu%d", ncpus))
+		ncpus++;
+
+	for (i = 0; i < ncpus; i++)
+		if (path_exist(PATH_SYS_SYSTEM "/node/node1/cpu%d", i)) {
+			sprintf(buf, "%d,", i);
+			strcat(cpus, buf);
+		}
+	/* Remove the trailing comma. */
+	cpus[strlen(cpus) - 1] = '\0';
+}
+
+int alloc_mem(long int length, int testcase)
+{
+	void *s;
+
+	tst_resm(TINFO, "allocating %ld bytes.", length);
+	s = mmap(NULL, length, PROT_READ|PROT_WRITE,
+		MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+	if (s == MAP_FAILED) {
+		if (testcase == OVERCOMMIT && errno == ENOMEM)
+			return 1;
+		else
+			tst_brkm(TBROK|TERRNO, cleanup, "mmap");
+	}
+	if (testcase == MLOCK && mlock(s, length) == -1)
+		tst_brkm(TINFO|TERRNO, cleanup, "mlock");
+	if (testcase == KSM
+		&& madvise(s, length, MADV_MERGEABLE) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "madvise");
+	memset(s, '\a', length);
+
+	return 0;
+}
+
+void test_alloc(int testcase, int lite)
+{
+	if (lite)
+		alloc_mem(TESTMEM + MB, testcase);
+	else
+		while(1)
+			if (alloc_mem(LENGTH, testcase))
+				return;
+}
+
+void umount_mem(char *path, char *path_new)
+{
+	FILE *fp;
+	int fd;
+	char s_new[BUFSIZ], s[BUFSIZ], value[BUFSIZ];
+
+	/* Move all processes in task to its parent node. */
+	sprintf(s, "%s/tasks", path);
+	fd = open(s, O_WRONLY);
+	if (fd == -1)
+		tst_resm(TWARN|TERRNO, "open %s", s);
+
+	snprintf(s_new, BUFSIZ, "%s/tasks", path_new);
+	fp = fopen(s_new, "r");
+	if (fp == NULL)
+		tst_resm(TWARN|TERRNO, "fopen %s", s_new);
+	if ((fd != -1) && (fp != NULL)) {
+		while (fgets(value, BUFSIZ, fp) != NULL)
+			if (write(fd, value, strlen(value) - 1)
+				!= strlen(value) - 1)
+				tst_resm(TWARN|TERRNO, "write %s", s);
+	}
+	if (fd != -1)
+		close(fd);
+	if (fp != NULL)
+		fclose(fp);
+	if (rmdir(path_new) == -1)
+		tst_resm(TWARN|TERRNO, "rmdir %s", path_new);
+	if (umount(path) == -1)
+		tst_resm(TWARN|TERRNO, "umount %s", path);
+	if (rmdir(path) == -1)
+		tst_resm(TWARN|TERRNO, "rmdir %s", path);
+}
+
+void mount_mem(char *name, char *fs, char *options, char *path, char *path_new)
+{
+	if (mkdir(path, 0777) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "mkdir %s", path);
+	if (mount(name, path, fs, 0, options) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "mount %s", path);
+	if (mkdir(path_new, 0777) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "mkdir %s", path_new);
+}
+
+void ksm_usage(void)
+{
+	printf("  -n      Number of processes\n");
+	printf("  -s      Memory allocation size in MB\n");
+	printf("  -u      Memory allocation unit in MB\n");
+}
+
+void check(char *path, long int value)
+{
+	FILE *fp;
+	char buf[BUFSIZ];
+
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, path);
+	fp = fopen(buf, "r");
+	if (fp == NULL)
+		tst_brkm(TBROK|TERRNO, tst_exit, "fopen");
+	if (fgets(buf, BUFSIZ, fp) == NULL)
+		tst_brkm(TBROK|TERRNO, tst_exit, "fgets");
+	fclose(fp);
+
+	tst_resm(TINFO, "%s is %ld.", path, atol(buf));
+	if (atol(buf) != value)
+		tst_resm(TFAIL, "%s is not %ld.", path, value);
+}
+
+void verify(char value, int proc, int start, int end, int start2, int end2)
+{
+	int i, j;
+	void *s = NULL;
+
+	s = malloc((end - start) * (end2 - start2));
+	if (s == NULL)
+		tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
+
+	tst_resm(TINFO, "child %d verifies memory content.", proc);
+	memset(s, value, (end - start) * (end2 - start2));
+	if (memcmp(memory[proc][start], s, (end - start) * (end2 - start2))
+		!= 0)
+		for (j = start; j < end; j++)
+			for (i = start2; i < end2; i++)
+				if (memory[proc][j][i] != value)
+					tst_resm(TFAIL, "child %d has %c at "
+						"%d,%d,%d.",
+						proc, memory[proc][j][i], proc,
+						j, i);
+	free(s);
+}
+
+void group_check(int run, int pages_shared, int pages_sharing,
+		int pages_volatile, int pages_unshared,
+		int sleep_millisecs, int pages_to_scan)
+{
+        /* 5 seconds for ksm to scan pages. */
+	sleep(5);
+	tst_resm(TINFO, "check!");
+	check("run", run);
+	check("pages_shared", pages_shared);
+	check("pages_sharing", pages_sharing);
+	check("pages_volatile", pages_volatile);
+	check("pages_unshared", pages_unshared);
+	check("sleep_millisecs", sleep_millisecs);
+	check("pages_to_scan", pages_to_scan);
+}
+
+void create_same_memory(int size, int num, int unit)
+{
+	char buf[BUFSIZ], buf2[BUFSIZ];
+	int i, j, k;
+	int status, fd;
+	int *child;
+
+	child = malloc(num);
+	if (child == NULL)
+		tst_brkm(TBROK|TERRNO, cleanup, "malloc");
+
+	memory = malloc(num * sizeof(**memory));
+	if (memory == NULL)
+		tst_brkm(TBROK|TERRNO, cleanup, "malloc");
+
+	/* Don't call cleanup in those children. Instead, do a cleanup from the
+	   parent after fetched children's status.*/
+	switch (child[0] = fork()) {
+	case -1:
+		tst_brkm(TBROK|TERRNO, cleanup, "fork");
+	case 0:
+		tst_resm(TINFO, "child 0 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+
+		tst_resm(TINFO, "child 0 continues...");
+		tst_resm(TINFO, "child 0 allocates %d MB filled with 'c'.",
+			size);
+		memory[0] = malloc(size / unit * sizeof(*memory));
+		if (memory[0] == NULL)
+			tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
+		for (j = 0; j * unit < size; j++) {
+			memory[0][j] = mmap(NULL, unit * MB,
+					PROT_READ|PROT_WRITE,
+					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+			if (memory[0][j] == MAP_FAILED)
+				tst_brkm(TBROK|TERRNO, tst_exit, "mmap");
+			if (madvise(memory[0][j], unit * MB, MADV_MERGEABLE)
+				== -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "madvise");
+			for (i = 0; i < unit * MB; i++)
+				memory[0][j][i] = 'c';
+		}
+		tst_resm(TINFO, "child 0 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+
+		tst_resm(TINFO, "child 0 continues...");
+		verify('c', 0, 0, size / unit, 0, unit * MB);
+		tst_resm(TINFO, "child 0 changes memory content to 'd'.");
+		for (j = 0; j < size / unit; j++) {
+			for (i = 0; i < unit * MB; i++)
+				memory[0][j][i] = 'd';
+		}
+		/* Unmerge. */
+		tst_resm(TINFO, "child 0 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+
+		tst_resm(TINFO, "child 0 continues...");
+		verify('d', 0, 0, size / unit, 0, unit * MB);
+		/* Stop. */
+		tst_resm(TINFO, "child 0 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 0 continues...");
+		exit(0);
+	}
+	switch (child[1] = fork()) {
+	case -1:
+		tst_brkm(TBROK|TERRNO, cleanup, "fork");
+	case 0:
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		tst_resm(TINFO, "child 1 allocates %d MB filled with 'a'.",
+			size);
+		memory[1] = malloc(size / unit * sizeof(*memory));
+		if (memory[1] == NULL)
+			tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
+		for (j = 0; j < size / unit; j++) {
+			memory[1][j] = mmap(NULL, unit * MB,
+					PROT_READ|PROT_WRITE,
+					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+			if (memory[1][j] == MAP_FAILED)
+				tst_brkm(TBROK|TERRNO, tst_exit, "mmap");
+			if (madvise(memory[1][j], unit * MB, MADV_MERGEABLE)
+				== -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "madvise");
+			for (i = 0; i < unit * MB; i++)
+				memory[1][j][i] = 'a';
+		}
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		verify('a', 1, 0, size / unit, 0, unit * MB);
+		tst_resm(TINFO, "child 1 changes memory content to 'b'.");
+		for (j = 0; j < size / unit; j++) {
+			for (i = 0; i < unit * MB; i++)
+				memory[1][j][i] = 'b';
+		}
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		verify('b', 1, 0, size / unit, 0, unit * MB);
+		tst_resm(TINFO, "child 1 changes memory content to 'd'");
+		for (j = 0; j < size / unit; j++) {
+			for (i = 0; i < unit * MB; i++)
+				memory[1][j][i] = 'd';
+		}
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+
+		tst_resm(TINFO, "child 1 continues...");
+		verify('d', 1, 0, size / unit, 0, unit * MB);
+		tst_resm(TINFO, "child 1 changes one page to 'e'.");
+		memory[1][size / unit - 1][unit * MB - 1] = 'e';
+
+		/* Unmerge. */
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		verify('e', 1, size / unit - 1, size / unit,
+			unit * MB - 1, unit * MB);
+		verify('d', 1, 0, size / unit - 1, 0, unit * MB - 1);
+
+		/* Stop. */
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		exit(0);
+	}
+	for (k = 2; k < num; k++) {
+		switch (child[k] = fork()) {
+		case -1:
+			tst_brkm(TBROK|TERRNO, cleanup, "fork");
+		case 0:
+			tst_resm(TINFO, "child %d stops.", k);
+			if (raise(SIGSTOP) == -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+			tst_resm(TINFO, "child %d continues...", k);
+			tst_resm(TINFO, "child %d allocates %d "
+				"MB filled with 'a'.", k, size);
+			memory[k] = malloc(size / unit * sizeof(*memory));
+			if (memory[k] == NULL)
+				tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
+			for (j = 0; j < size / unit; j++) {
+				memory[k][j] = mmap(NULL, unit * MB,
+						PROT_READ|PROT_WRITE,
+						MAP_ANONYMOUS
+						|MAP_PRIVATE, -1, 0);
+				if (memory[k][j] == MAP_FAILED)
+					tst_brkm(TBROK|TERRNO, cleanup,
+						"mmap");
+				if (madvise(memory[k][j], unit * MB,
+						MADV_MERGEABLE) == -1)
+					tst_brkm(TBROK|TERRNO, cleanup,
+						"madvise");
+				for (i = 0; i < unit * MB; i++)
+					memory[k][j][i] = 'a';
+			}
+			tst_resm(TINFO, "child %d stops.", k);
+			if (raise(SIGSTOP) == -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+			tst_resm(TINFO, "child %d continues...", k);
+			tst_resm(TINFO, "child %d changes memory content to "
+				"'d'", k);
+			for (j = 0; j < size / unit; j++) {
+				for (i = 0; i < unit * MB; i++)
+					memory[k][j][i] = 'd';
+		        }
+			/* Unmerge. */
+			tst_resm(TINFO, "child %d stops.", k);
+			if (raise(SIGSTOP) == -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+			tst_resm(TINFO, "child %d continues...", k);
+
+			/* Stop. */
+			tst_resm(TINFO, "child %d stops.", k);
+			if (raise(SIGSTOP) == -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+			tst_resm(TINFO, "child %d continues...", k);
+			exit(0);
+		}
+	}
+	tst_resm(TINFO, "KSM merging...");
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "run");
+	fd = open(buf, O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open");
+	if (write(fd, "1", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	close(fd);
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "pages_to_scan");
+	snprintf(buf2, BUFSIZ, "%d", size * 256 * num);
+	fd = open(buf, O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open");
+	if (write(fd, buf2, strlen(buf2)) != strlen(buf2))
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	close(fd);
+
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "sleep_millisecs");
+	fd = open(buf, O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open");
+	if (write(fd, "0", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	close(fd);
+
+	tst_resm(TINFO, "wait for all children to stop.");
+	for (k = 0; k < num; k++) {
+		if (waitpid(child[k], &status, WUNTRACED) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+		if (!WIFSTOPPED(status))
+			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
+				k);
+	}
+	tst_resm(TINFO, "resume all children.");
+	for (k = 0; k < num; k++) {
+		if (kill(child[k], SIGCONT) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
+	}
+	group_check(1, 2, size * num * 256 - 2, 0, 0, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for child 1 to stop.");
+	if (waitpid(child[1], &status, WUNTRACED) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+	if (!WIFSTOPPED(status))
+		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");
+
+	/* Child 1 changes all pages to 'b'. */
+	tst_resm(TINFO, "resume child 1.");
+	if (kill(child[1], SIGCONT) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "kill");
+	group_check(1, 3, size * num * 256 - 3, 0, 0, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for child 1 to stop.");
+	if (waitpid(child[1], &status, WUNTRACED) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+	if (!WIFSTOPPED(status))
+		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");
+
+	/* All children change pages to 'd'. */
+	tst_resm(TINFO, "resume all children.");
+	for (k = 0; k < num; k++) {
+		if (kill(child[k], SIGCONT) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
+	}
+	group_check(1, 1, size * num * 256 - 1, 0, 0, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for all children to stop.");
+	for (k = 0; k < num; k++) {
+		if (waitpid(child[k], &status, WUNTRACED) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+		if (!WIFSTOPPED(status))
+			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
+				k);
+	}
+	/* Child 1 changes pages to 'e'. */
+	tst_resm(TINFO, "resume child 1.");
+	if (kill(child[1], SIGCONT) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "kill");
+	group_check(1, 1, size * num * 256 - 2, 0, 1, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for child 1 to stop.");
+	if (waitpid(child[1], &status, WUNTRACED) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+	if (!WIFSTOPPED(status))
+		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");
+
+	tst_resm(TINFO, "resume all children.");
+	for (k = 0; k < num; k++) {
+		if (kill(child[k], SIGCONT) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
+	}
+	tst_resm(TINFO, "KSM unmerging...");
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "run");
+	fd = open(buf, O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open");
+	if (write(fd, "2", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	group_check(2, 0, 0, 0, 0, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for all children to stop.");
+	for (k = 0; k < num; k++) {
+		if (waitpid(child[k], &status, WUNTRACED) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+		if (!WIFSTOPPED(status))
+			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
+				k);
+	}
+	tst_resm(TINFO, "resume all children.");
+	for (k = 0; k < num; k++) {
+		if (kill(child[k], SIGCONT) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
+	}
+	tst_resm(TINFO, "stop KSM.");
+	if (lseek(fd, 0, SEEK_SET) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "lseek");
+	if (write(fd, "0", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	close(fd);
+	group_check(0, 0, 0, 0, 0, 0, size * 256 * num);
+	while (waitpid(-1, &status, WUNTRACED | WCONTINUED) > 0)
+		if (WEXITSTATUS(status) != 0)
+			tst_resm(TFAIL, "child exit status is %d",
+				WEXITSTATUS(status));
+}
+
+void check_ksm_options(int *size, int *num, int *unit)
+{
+	if (opt_size) {
+		*size = atoi(opt_sizestr);
+		if (*size < 1)
+			tst_brkm(TBROK, cleanup,
+				"size cannot be less than 1.");
+	}
+	if (opt_unit) {
+		*unit = atoi(opt_unitstr);
+		if (*unit > *size)
+			tst_brkm(TBROK, cleanup,
+				"unit cannot be greater than size.");
+		if (*size % *unit != 0)
+			tst_brkm(TBROK, cleanup,
+				"the remainder of division of size by unit is "
+				"not zero.");
+	}
+	if (opt_num) {
+		*num = atoi(opt_numstr);
+		if (*num < 3)
+			tst_brkm(TBROK, cleanup,
+				"process number cannot be less 3.");
+	}
+}
diff --git a/testcases/kernel/mem/oom/Makefile b/testcases/kernel/mem/oom/Makefile
index 01c0546..81509bf 100644
--- a/testcases/kernel/mem/oom/Makefile
+++ b/testcases/kernel/mem/oom/Makefile
@@ -20,9 +20,9 @@ top_srcdir              ?= ../../../..
 
 include $(top_srcdir)/include/mk/env_pre.mk
 
-LDLIBS			+= $(NUMA_LIBS) -loom
-LIBDIR			:= lib
-LIB			:= $(LIBDIR)/liboom.a
+LDLIBS			+= $(NUMA_LIBS) -lmem
+LIBDIR			:= ../lib
+LIB			:= $(LIBDIR)/libmem.a
 FILTER_OUT_DIRS		:= $(LIBDIR)
 LDFLAGS			+= -L$(LIBDIR)
 
diff --git a/testcases/kernel/mem/oom/oom01.c b/testcases/kernel/mem/oom/oom01.c
index c670d90..b6c9d83 100644
--- a/testcases/kernel/mem/oom/oom01.c
+++ b/testcases/kernel/mem/oom/oom01.c
@@ -38,13 +38,10 @@
 #include <unistd.h>
 #include "test.h"
 #include "usctest.h"
-#include "lib/oom.h"
+#include "../include/mem.h"
 
 char *TCID = "oom01";
 int TST_TOTAL = 1;
-extern int Tst_count;
-
-static void setup(void);
 
 int main(int argc, char *argv[])
 {
diff --git a/testcases/kernel/mem/oom/oom02.c b/testcases/kernel/mem/oom/oom02.c
index 68ed1ef..04c6507 100644
--- a/testcases/kernel/mem/oom/oom02.c
+++ b/testcases/kernel/mem/oom/oom02.c
@@ -42,9 +42,7 @@ int TST_TOTAL = 1;
 #include <fcntl.h>
 #include <stdio.h>
 #include <errno.h>
-#include "lib/oom.h"
-
-static void setup(void);
+#include "../include/mem.h"
 
 int main(int argc, char *argv[])
 {
diff --git a/testcases/kernel/mem/oom/oom03.c b/testcases/kernel/mem/oom/oom03.c
index dd09467..da01d3e 100644
--- a/testcases/kernel/mem/oom/oom03.c
+++ b/testcases/kernel/mem/oom/oom03.c
@@ -35,13 +35,10 @@
 #include <errno.h>
 #include "test.h"
 #include "usctest.h"
-#include "lib/oom.h"
+#include "../include/mem.h"
 
 char *TCID = "oom03";
 int TST_TOTAL = 1;
-extern int Tst_count;
-
-static void setup(void);
 
 int main(int argc, char *argv[])
 {
diff --git a/testcases/kernel/mem/oom/oom04.c b/testcases/kernel/mem/oom/oom04.c
index 1dff85e..8eb5c04 100644
--- a/testcases/kernel/mem/oom/oom04.c
+++ b/testcases/kernel/mem/oom/oom04.c
@@ -34,55 +34,15 @@
 
 char *TCID = "oom04";
 int TST_TOTAL = 1;
-extern int Tst_count;
 
 #if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
 	&& HAVE_MPOL_CONSTANTS
-#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/mount.h>
-#include <numaif.h>
 #include <fcntl.h>
 #include <stdio.h>
-#include <unistd.h>
 #include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-#include <stdarg.h>
-
-#define MAXNODES		512
-#define CPATH			"/dev/cpuset"
-#define CPATH_NEW		CPATH "/1"
-#define MEMCG_PATH		"/dev/cgroup"
-#define MEMCG_PATH_NEW		MEMCG_PATH "/1"
-#define _PATH_SYS_SYSTEM	"/sys/devices/system"
-#define LENGTH			(3UL<<30)
-#define TESTMEM			(1UL<<30)
-#define MB			(1UL<<20)
-#define NORMAL			1
-#define MLOCK			2
-#define KSM			3
-#define SYSFS_OVER		"/proc/sys/vm/overcommit_memory"
-
-static char overcommit[BUFSIZ];
-
-static void setup(void);
-static void cleanup(void) LTP_ATTRIBUTE_NORETURN;
-static void oom(int testcase, int mempolicy, int lite);
-static long count_numa(void);
-static int path_exist(const char *path, ...);
-static void testoom(int mempolicy, int lite);
-static void alloc_mem(long int length, int testcase);
-static void test_alloc(int testcase, int lite);
-static void gather_cpus(char *cpus);
-static void umount_mem(char *path, char *path_new);
-static void mount_mem(char *name, char *fs, char *options, char *path,
-		char *path_new);
+#include "../include/mem.h"
 
 int main(int argc, char *argv[])
 {
@@ -113,9 +73,7 @@ int main(int argc, char *argv[])
 			tst_brkm(TBROK|TERRNO, cleanup, "write");
 		close(fd);
 
-		snprintf(buf, BUFSIZ, "%s/memory.limit_in_bytes",
-			MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/memory.limit_in_bytes", O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		sprintf(mem, "%ld", TESTMEM);
@@ -123,8 +81,7 @@ int main(int argc, char *argv[])
 			tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
 		close(fd);
 
-		snprintf(buf, BUFSIZ, "%s/tasks", MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/tasks", O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		snprintf(buf, BUFSIZ, "%d", getpid());
@@ -135,9 +92,8 @@ int main(int argc, char *argv[])
 		tst_resm(TINFO, "process mempolicy.");
 		testoom(1, 0, 1);
 
-		snprintf(buf, BUFSIZ, "%s/memory.memsw.limit_in_bytes",
-			MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/memory.memsw.limit_in_bytes",
+			O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		if (write(fd, mem, strlen(mem)) != strlen(mem))
@@ -146,9 +102,8 @@ int main(int argc, char *argv[])
 		testoom(1, 1, 1);
 
 		tst_resm(TINFO, "process cpuset.");
-		snprintf(buf, BUFSIZ, "%s/memory.memsw.limit_in_bytes",
-			MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/memory.memsw.limit_in_bytes",
+			O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		sprintf(mem, "%ld", TESTMEM);
@@ -157,9 +112,8 @@ int main(int argc, char *argv[])
 		close(fd);
 		testoom(0, 0, 1);
 
-		snprintf(buf, BUFSIZ, "%s/memory.memsw.limit_in_bytes",
-			MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/memory.memsw.limit_in_bytes",
+			O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		if (write(fd, mem, strlen(mem)) != strlen(mem))
@@ -168,52 +122,6 @@ int main(int argc, char *argv[])
 		testoom(0, 1, 1);
 	}
 	cleanup();
-	tst_exit();
-}
-
-void testoom(int mempolicy, int lite)
-{
-	int fd;
-	char buf[BUFSIZ] = "";
-	char cpus[BUFSIZ] = "";
-
-	if (!mempolicy) {
-		gather_cpus(cpus);
-		tst_resm(TINFO, "CPU list for 2nd node is %s.", cpus);
-
-		snprintf(buf, BUFSIZ, "%s/cpuset.mems", CPATH_NEW);
-		fd = open(buf, O_WRONLY);
-		if (fd == -1)
-			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
-		if (write(fd, "1", 1) != 1)
-			tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
-		close(fd);
-
-		snprintf(buf, BUFSIZ, "%s/cpuset.cpus", CPATH_NEW);
-		fd = open(buf, O_WRONLY);
-		if (fd == -1)
-			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
-		if (write(fd, cpus, strlen(cpus)) != strlen(cpus))
-			tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
-		close(fd);
-
-		snprintf(buf, BUFSIZ, "%s/tasks", CPATH_NEW);
-		fd = open(buf, O_WRONLY);
-		if (fd == -1)
-			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
-		snprintf(buf, BUFSIZ, "%d", getpid());
-		if (write(fd, buf, strlen(buf)) != strlen(buf))
-			tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
-		close(fd);
-	}
-	tst_resm(TINFO, "start normal OOM testing.");
-	oom(NORMAL, mempolicy, lite);
-
-	tst_resm(TINFO, "start OOM testing for mlocked pages.");
-	oom(MLOCK, mempolicy, lite);
-
-	tst_resm(TINFO, "start OOM testing for KSM pages.");
-	oom(KSM, mempolicy, lite);
 }
 
 void setup(void)
@@ -236,50 +144,6 @@ void setup(void)
 	mount_mem("memcg", "cgroup", "memory", MEMCG_PATH, MEMCG_PATH_NEW);
 }
 
-void umount_mem(char *path, char *path_new)
-{
-	FILE *fp;
-	int fd;
-	char s_new[BUFSIZ], s[BUFSIZ], value[BUFSIZ];
-
-	/* Move all processes in task to its parent node. */
-	snprintf(s, BUFSIZ, "%s/tasks", path);
-	fd = open(s, O_WRONLY);
-	if (fd == -1)
-		tst_resm(TWARN|TERRNO, "open %s", s);
-	snprintf(s_new, BUFSIZ, "%s/tasks", path_new);
-
-	fp = fopen(s_new, "r");
-	if (fp == NULL)
-		tst_resm(TWARN|TERRNO, "fopen %s", s_new);
-	if ((fd != -1) && (fp != NULL)) {
-		while (fgets(value, BUFSIZ, fp) != NULL)
-			if (write(fd, value, strlen(value) - 1)
-				!= strlen(value) - 1)
-				tst_resm(TWARN|TERRNO, "write %s", s);
-	}
-	if (fd != -1)
-		close(fd);
-	if (fp != NULL)
-		fclose(fp);
-	if (rmdir(path_new) == -1)
-		tst_resm(TWARN|TERRNO, "rmdir %s", path_new);
-	if (umount(path) == -1)
-		tst_resm(TWARN|TERRNO, "umount %s", path);
-	if (rmdir(path) == -1)
-		tst_resm(TWARN|TERRNO, "rmdir %s", path);
-}
-
-void mount_mem(char *name, char *fs, char *options, char *path, char *path_new)
-{
-	if (mkdir(path, 0777) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "mkdir %s", path);
-	if (mount(name, path, fs, 0, options) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "mount %s", path);
-	if (mkdir(path_new, 0777) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "mkdir %s", path_new);
-}
-
 void cleanup(void)
 {
 	int fd;
@@ -295,105 +159,13 @@ void cleanup(void)
 	umount_mem(MEMCG_PATH, MEMCG_PATH_NEW);
 
 	TEST_CLEANUP;
-}
-
-void oom(int testcase, int mempolicy, int lite)
-{
-	pid_t pid;
-	int status;
-	unsigned long nmask = 2;
-
-	switch(pid = fork()) {
-	case -1:
-		tst_brkm(TBROK|TERRNO, cleanup, "fork");
-	case 0:
-		if (mempolicy)
-			if (set_mempolicy(MPOL_BIND, &nmask, MAXNODES) == -1)
-				tst_brkm(TBROK|TERRNO, cleanup,
-					"set_mempolicy");
-
-		test_alloc(testcase, lite);
-		exit(0);
-	default:
-		break;
-	}
-	tst_resm(TINFO, "expected victim is %d.", pid);
-	if (waitpid(-1, &status, 0) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
-
-	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL)
-		tst_resm(TFAIL, "the victim unexpectedly failed: %d", status);
-}
-
-long count_numa(void)
-{
-	int nnodes = 0;
-
-	while(path_exist(_PATH_SYS_SYSTEM "/node/node%d", nnodes))
-		nnodes++;
-
-	return nnodes;
-}
-
-int path_exist(const char *path, ...)
-{
-	va_list ap;
-	char pathbuf[PATH_MAX];
-
-	va_start(ap, path);
-	vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
-	va_end(ap);
-
-	return access(pathbuf, F_OK) == 0;
-}
-
-void gather_cpus(char *cpus)
-{
-	int ncpus = 0;
-	int i;
-	char buf[BUFSIZ];
-
-	while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d", ncpus))
-		ncpus++;
-
-	for (i = 0; i < ncpus; i++)
-		if (path_exist(_PATH_SYS_SYSTEM "/node/node1/cpu%d", i)) {
-			sprintf(buf, "%d,", i);
-			strcat(cpus, buf);
-		}
-	/* Remove the trailing comma. */
-	cpus[strlen(cpus) - 1] = '\0';
-}
-
-void alloc_mem(long int length, int testcase)
-{
-	void *s;
-
-	tst_resm(TINFO, "allocating %ld bytes.", length);
-	s = mmap(NULL, length, PROT_READ|PROT_WRITE,
-		MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-	if (s == MAP_FAILED) {
-			tst_brkm(TBROK|TERRNO, cleanup, "mmap");
-	}
-	if (testcase == MLOCK && mlock(s, length) == -1)
-		tst_brkm(TINFO|TERRNO, cleanup, "mlock");
-	if (testcase == KSM
-		&& madvise(s, length, MADV_MERGEABLE) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "madvise");
-	memset(s, '\a', length);
-}
-
-void test_alloc(int testcase, int lite)
-{
-	if (lite)
-		alloc_mem(TESTMEM + MB, testcase);
-	else
-		while(1)
-			alloc_mem(LENGTH, testcase);
+	tst_exit();
 }
 
 #else /* no NUMA */
-int main(void) {
-	tst_brkm(TCONF, NULL, "no NUMA development packages installed.");
+int main(void)
+{
+	tst_resm(TCONF, "no NUMA development packages installed.");
+	tst_exit();
 }
 #endif
-- 
1.7.3.2

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-rework-code-for-oom-and-ksm-tests.patch --]
[-- Type: text/x-patch; name=0001-rework-code-for-oom-and-ksm-tests.patch, Size: 51207 bytes --]

From 08f55c67028dde19addc41c49a95fdf37af3300e Mon Sep 17 00:00:00 2001
From: CAI Qian <caiqian@redhat.com>
Date: Wed, 19 Jan 2011 15:48:41 +0800
Subject: [PATCH] rework code for oom and ksm tests

Mainly to reduce code duplication. Also, to add an option for ksm01 to
use a different memory allocation unit size to take advantage of THP.
In addition, adjust ksm01 according the latest upstream development
effort,
http://marc.info/?l=linux-mm&m=129473104716901&w=2
http://marc.info/?l=linux-mm&m=129442718808733&w=2

Signed-off-by: CAI Qian <caiqian@redhat.com>
---
 testcases/kernel/mem/include/mem.h |   50 +++
 testcases/kernel/mem/ksm/Makefile  |   23 ++-
 testcases/kernel/mem/ksm/ksm01.c   |  461 +------------------------
 testcases/kernel/mem/lib/Makefile  |   25 ++
 testcases/kernel/mem/lib/mem.c     |  651 ++++++++++++++++++++++++++++++++++++
 testcases/kernel/mem/oom/Makefile  |    6 +-
 testcases/kernel/mem/oom/oom01.c   |    5 +-
 testcases/kernel/mem/oom/oom02.c   |    4 +-
 testcases/kernel/mem/oom/oom03.c   |    5 +-
 testcases/kernel/mem/oom/oom04.c   |  256 +-------------
 10 files changed, 786 insertions(+), 700 deletions(-)
 create mode 100644 testcases/kernel/mem/include/mem.h
 create mode 100644 testcases/kernel/mem/lib/Makefile
 create mode 100644 testcases/kernel/mem/lib/mem.c

diff --git a/testcases/kernel/mem/include/mem.h b/testcases/kernel/mem/include/mem.h
new file mode 100644
index 0000000..778d403
--- /dev/null
+++ b/testcases/kernel/mem/include/mem.h
@@ -0,0 +1,50 @@
+#ifndef _MEM_H
+#define _MEM_H
+#include "test.h"
+#include "usctest.h"
+
+#define LENGTH			(3UL<<30)
+#define SYSFS_OVER		"/proc/sys/vm/overcommit_memory"
+#define OVERCOMMIT		1
+#define NORMAL			2
+#define MLOCK			3
+#define KSM			4
+#define CPATH			"/dev/cpuset"
+#define CPATH_NEW		CPATH "/1"
+#define MAXNODES		512
+#define MEMCG_PATH		"/dev/cgroup"
+#define MEMCG_PATH_NEW		MEMCG_PATH "/1"
+#define TESTMEM			(1UL<<30)
+#define MB			(1UL<<20)
+#define PATH_SYS_SYSTEM		"/sys/devices/system"
+#define PATH_KSM		"/sys/kernel/mm/ksm/"
+
+char overcommit[BUFSIZ];
+int opt_num, opt_size, opt_unit;
+char *opt_numstr, *opt_sizestr, *opt_unitstr;
+/* memory pointer to identify per process, MB unit, and byte like
+   memory[process No.][MB unit No.][byte No.]. */
+char ***memory;
+
+void oom(int testcase, int mempolicy, int lite);
+void testoom(int mempolicy, int lite, int numa);
+long count_numa(void);
+int path_exist(const char *path, ...);
+int alloc_mem(long int length, int testcase);
+void test_alloc(int testcase, int lite);
+void gather_cpus(char *cpus);
+void umount_mem(char *path, char *path_new);
+void mount_mem(char *name, char *fs, char *options, char *path, char *path_new);
+void cleanup(void);
+void setup(void);
+void ksm_usage(void);
+void check(char *path, long int value);
+void verify(char value, int proc, int start, int end, int start2, int end2);
+void group_check(int run, int pages_shared, int pages_sharing,
+		int pages_volatile, int pages_unshared, int sleep_millisecs,
+		int pages_to_scan);
+void create_same_memory(int size, int num, int unit);
+void check_ksm_options(int *size, int *num, int *unit);
+void write_cpusets(void);
+void write_memcg(void);
+#endif
diff --git a/testcases/kernel/mem/ksm/Makefile b/testcases/kernel/mem/ksm/Makefile
index 3634570..81509bf 100644
--- a/testcases/kernel/mem/ksm/Makefile
+++ b/testcases/kernel/mem/ksm/Makefile
@@ -18,5 +18,26 @@
 
 top_srcdir              ?= ../../../..
 
+include $(top_srcdir)/include/mk/env_pre.mk
+
+LDLIBS			+= $(NUMA_LIBS) -lmem
+LIBDIR			:= ../lib
+LIB			:= $(LIBDIR)/libmem.a
+FILTER_OUT_DIRS		:= $(LIBDIR)
+LDFLAGS			+= -L$(LIBDIR)
+
+$(LIBDIR):
+	mkdir -p "$@"
+
+$(LIB): $(LIBDIR)
+	$(MAKE) -C $^ -f "$(abs_srcdir)/$^/Makefile" all
+
+MAKE_DEPS		:= $(LIB)
+
+trunk-clean:: | lib-clean
+
+lib-clean:: $(LIBDIR)
+	$(MAKE) -C $^ -f "$(abs_srcdir)/$^/Makefile" clean
+
+include $(top_srcdir)/include/mk/generic_trunk_target.mk
 include $(top_srcdir)/include/mk/testcases.mk
-include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/mem/ksm/ksm01.c b/testcases/kernel/mem/ksm/ksm01.c
index 09f71d7..e1c7d7f 100644
--- a/testcases/kernel/mem/ksm/ksm01.c
+++ b/testcases/kernel/mem/ksm/ksm01.c
@@ -1,5 +1,5 @@
 /*
- * functional testing for Kernel Samepage Merging (KSM)
+ * Kernel Samepage Merging (KSM)
  *
  * Basic tests were to start several programs with same and different
  * memory contents and ensure only to merge the ones with the same
@@ -69,471 +69,46 @@
 #include <errno.h>
 #include "test.h"
 #include "usctest.h"
-
-#define _PATH_KSM	"/sys/kernel/mm/ksm/"
-#define MB		(1024 * 1024)
+#include "../include/mem.h"
 
 char *TCID = "ksm01";
 int TST_TOTAL = 1;
-static int opt_num, opt_size;
-static char *opt_numstr, *opt_sizestr;
-/* memory pointer to identify per process, MB, and byte like
-   memory[process No.][MB No.][byte No.]. */
-static char ***memory;
-static option_t options[] = {
-	{ "n:", &opt_num,	&opt_numstr},
-	{ "s:", &opt_size,	&opt_sizestr},
-	{ NULL, NULL,		NULL}
+
+option_t ksm_options[] = {
+        { "n:", &opt_num,       &opt_numstr},
+        { "s:", &opt_size,      &opt_sizestr},
+        { "u:", &opt_unit,      &opt_unitstr},
+        { NULL, NULL,           NULL}
 };
-static void setup(void);
-static void ksmtest(void);
-static void usage(void);
-static void check(char *path, char *path2, long int value);
-static void verify(char value, int proc, int start, int end, int start2,
-		int end2);
-static void group_check(int run, int pages_shared, int pages_sharing,
-			int pages_volatile, int pages_unshared,
-			int sleep_millisecs, int pages_to_scan);
 
 int main(int argc, char *argv[])
 {
 	int lc;
 	char *msg;
+	int size = 128, num = 3, unit = 1;
 
-	msg = parse_opts(argc, argv, options, usage);
-	if (msg != (char *)NULL)
-		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+	msg = parse_opts(argc, argv, ksm_options, ksm_usage);
+	if (msg != NULL)
+		tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
 	setup();
 	for (lc = 0; TEST_LOOPING(lc); lc++) {
 		Tst_count = 0;
-		ksmtest();
+		check_ksm_options(&size, &num, &unit);
+		create_same_memory(size, num, unit);
 	}
+	cleanup();
 	tst_exit();
 }
 
-void ksmtest(void)
-{
-	char buf[BUFSIZ], buf2[BUFSIZ];
-	int i, j, status, k, fd, *child;
-	int size = 128, num = 3;
-
-	if (opt_size) {
-		size = atoi(opt_sizestr);
-		if (size < 1)
-			tst_brkm(TBROK, NULL,
-				"size cannot be less than 1.");
-	}
-	if (opt_num) {
-		num = atoi(opt_numstr);
-		if (num < 3)
-			tst_brkm(TBROK, NULL,
-				"process number cannot be less 3.");
-	}
-	child = malloc(num);
-	if (child == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "malloc");
-
-	memory = malloc(num * sizeof(**memory));
-	if (memory == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "malloc");
-
-	switch (child[0] = fork()) {
-	case -1:
-		tst_brkm(TBROK|TERRNO, NULL, "fork");
-	case 0:
-		tst_resm(TINFO, "child 0 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-
-		tst_resm(TINFO, "child 0 continues...");
-
-		/* Avoid TransparentHugePage allocation which can't ksm at the
-		   moment. */
-		tst_resm(TINFO, "child 0 allocates %d MB filled with 'c'.",
-			size);
-		memory[0] = malloc(size * sizeof(*memory));
-		if (memory[0] == NULL)
-			tst_brkm(TBROK|TERRNO, NULL, "malloc");
-		for (j = 0; j < size; j++) {
-			memory[0][j] = mmap(NULL, MB, PROT_READ|PROT_WRITE,
-					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-			if (memory[0][j] == MAP_FAILED)
-				tst_brkm(TBROK|TERRNO, NULL, "mmap");
-			if (madvise(memory[0][j], MB, MADV_MERGEABLE) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "madvise");
-			for (i = 0; i < MB; i++)
-				memory[0][j][i] = 'c';
-		}
-		tst_resm(TINFO, "child 0 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-
-		tst_resm(TINFO, "child 0 continues...");
-		verify('c', 0, 0, size, 0, MB);
-		tst_resm(TINFO, "child 0 changes memory content to 'd'.");
-		for (j = 0; j < size; j++) {
-			for (i = 0; i < MB; i++)
-				memory[0][j][i] = 'd';
-		}
-		/* Unmerge. */
-		tst_resm(TINFO, "child 0 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-
-		tst_resm(TINFO, "child 0 continues...");
-		verify('d', 0, 0, size, 0, MB);
-		/* Stop. */
-		tst_resm(TINFO, "child 0 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 0 continues...");
-		exit(0);
-	}
-	switch (child[1] = fork()) {
-	case -1:
-		tst_brkm(TBROK|TERRNO, NULL, "fork");
-	case 0:
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		tst_resm(TINFO, "child 1 allocates %d MB filled with 'a'.",
-			size);
-		memory[1] = malloc(size * sizeof(*memory));
-		if (memory[1] == NULL)
-			tst_brkm(TBROK|TERRNO, NULL, "malloc");
-		for (j = 0; j < size; j++) {
-			memory[1][j] = mmap(NULL, MB, PROT_READ|PROT_WRITE,
-					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-			if (memory[1][j] == MAP_FAILED)
-				tst_brkm(TBROK|TERRNO, NULL, "mmap");
-			if (madvise(memory[1][j], MB, MADV_MERGEABLE) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "madvise");
-			for (i = 0; i < MB; i++)
-				memory[1][j][i] = 'a';
-		}
-
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		verify('a', 1, 0, size, 0, MB);
-		tst_resm(TINFO, "child 1 changes memory content to 'b'.");
-		for (j = 0; j < size; j++) {
-			for (i = 0; i < MB; i++)
-				memory[1][j][i] = 'b';
-		}
-
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		verify('b', 1, 0, size, 0, MB);
-		tst_resm(TINFO, "child 1 changes memory content to 'd'");
-		for (j = 0; j < size; j++) {
-			for (i = 0; i < MB; i++)
-				memory[1][j][i] = 'd';
-		}
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-
-		tst_resm(TINFO, "child 1 continues...");
-		verify('d', 1, 0, size, 0, MB);
-		tst_resm(TINFO, "child 1 changes one page to 'e'.");
-		memory[1][size - 1][MB - 1] = 'e';
-
-		/* Unmerge. */
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		verify('e', 1, size - 1, size, MB - 1, MB);
-		verify('d', 1, 0, size - 1, 0, MB - 1);
-
-		/* Stop. */
-		tst_resm(TINFO, "child 1 stops.");
-		if (raise(SIGSTOP) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill");
-		tst_resm(TINFO, "child 1 continues...");
-		exit(0);
-	}
-	for (k = 2; k < num; k++) {
-		switch (child[k] = fork()) {
-		case -1:
-			tst_brkm(TBROK|TERRNO, NULL, "fork");
-		case 0:
-			tst_resm(TINFO, "child %d stops.", k);
-			if (raise(SIGSTOP) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "kill");
-			tst_resm(TINFO, "child %d continues...", k);
-			tst_resm(TINFO, "child %d allocates %d "
-				"MB filled with 'a'.", k, size);
-			memory[k] = malloc(size * sizeof(*memory));
-			if (memory[k] == NULL)
-				tst_brkm(TBROK|TERRNO, NULL, "malloc");
-			for (j = 0; j < size; j++) {
-				memory[k][j] = mmap(NULL, MB,
-						PROT_READ|PROT_WRITE,
-						MAP_ANONYMOUS
-						|MAP_PRIVATE, -1, 0);
-				if (memory[k][j] == MAP_FAILED)
-					tst_brkm(TBROK|TERRNO, NULL,
-						"mmap");
-				if (madvise(memory[k][j], MB,
-						MADV_MERGEABLE) == -1)
-					tst_brkm(TBROK|TERRNO, NULL,
-						"madvise");
-				for (i = 0; i < MB; i++)
-					memory[k][j][i] = 'a';
-			}
-			tst_resm(TINFO, "child %d stops.", k);
-			if (raise(SIGSTOP) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "kill");
-			tst_resm(TINFO, "child %d continues...", k);
-			tst_resm(TINFO, "child %d changes memory content to "
-				"'d'", k);
-			for (j = 0; j < size; j++) {
-				for (i = 0; i < MB; i++)
-					memory[k][j][i] = 'd';
-		        }
-			/* Unmerge. */
-			tst_resm(TINFO, "child %d stops.", k);
-			if (raise(SIGSTOP) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "kill");
-			tst_resm(TINFO, "child %d continues...", k);
-
-			/* Stop. */
-			tst_resm(TINFO, "child %d stops.", k);
-			if (raise(SIGSTOP) == -1)
-				tst_brkm(TBROK|TERRNO, NULL, "kill");
-			tst_resm(TINFO, "child %d continues...", k);
-			exit(0);
-		}
-	}
-	tst_resm(TINFO, "KSM merging...");
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "run");
-	fd = open(buf, O_WRONLY);
-	if (fd == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "open");
-	if (write(fd, "1", 1) != 1)
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	close(fd);
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "pages_to_scan");
-	snprintf(buf2, BUFSIZ, "%d", size * 256 * num);
-	fd = open(buf, O_WRONLY);
-	if (fd == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "open");
-	if (write(fd, buf2, strlen(buf2)) != strlen(buf2))
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	close(fd);
-
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "sleep_millisecs");
-	fd = open(buf, O_WRONLY);
-	if (fd == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "open");
-	if (write(fd, "0", 1) != 1)
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	close(fd);
-
-	tst_resm(TINFO, "wait for all children to stop.");
-	for (k = 0; k < num; k++) {
-		if (waitpid(child[k], &status, WUNTRACED) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-		if (!WIFSTOPPED(status))
-			tst_brkm(TBROK, NULL, "child %d was not stopped.",
-				k);
-	}
-	tst_resm(TINFO, "resume all children.");
-	for (k = 0; k < num; k++) {
-		if (kill(child[k], SIGCONT) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill child[%d]", k);
-	}
-	group_check(1, 2, size * num * 256 - 2, 0, 0, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for child 1 to stop.");
-	if (waitpid(child[1], &status, WUNTRACED) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-	if (!WIFSTOPPED(status))
-		tst_brkm(TBROK, NULL, "child 1 was not stopped.");
-
-	/* Child 1 changes all pages to 'b'. */
-	tst_resm(TINFO, "resume child 1.");
-	if (kill(child[1], SIGCONT) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "kill");
-	group_check(1, 3, size * num * 256 - 3, 0, 0, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for child 1 to stop.");
-	if (waitpid(child[1], &status, WUNTRACED) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-	if (!WIFSTOPPED(status))
-		tst_brkm(TBROK, NULL, "child 1 was not stopped.");
-
-	/* All children change pages to 'd'. */
-	tst_resm(TINFO, "resume all children.");
-	for (k = 0; k < num; k++) {
-		if (kill(child[k], SIGCONT) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill child[%d]", k);
-	}
-	group_check(1, 1, size * num * 256 - 1, 0, 0, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for all children to stop.");
-	for (k = 0; k < num; k++) {
-		if (waitpid(child[k], &status, WUNTRACED) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-		if (!WIFSTOPPED(status))
-			tst_brkm(TBROK, NULL, "child %d was not stopped.",
-				k);
-	}
-	/* Child 1 changes pages to 'e'. */
-	tst_resm(TINFO, "resume child 1.");
-	if (kill(child[1], SIGCONT) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "kill");
-	group_check(1, 1, size * num * 256 - 2, 0, 1, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for child 1 to stop.");
-	if (waitpid(child[1], &status, WUNTRACED) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-	if (!WIFSTOPPED(status))
-		tst_brkm(TBROK, NULL, "child 1 was not stopped.");
-
-	tst_resm(TINFO, "resume all children.");
-	for (k = 0; k < num; k++) {
-		if (kill(child[k], SIGCONT) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill child[%d]", k);
-	}
-	tst_resm(TINFO, "KSM unmerging...");
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "run");
-	fd = open(buf, O_WRONLY);
-	if (fd == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "open");
-	if (write(fd, "2", 1) != 1)
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	group_check(2, 0, 0, 0, 0, 0, size * 256 * num);
-
-	tst_resm(TINFO, "wait for all children to stop.");
-	for (k = 0; k < num; k++) {
-		if (waitpid(child[k], &status, WUNTRACED) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "waitpid");
-		if (!WIFSTOPPED(status))
-			tst_brkm(TBROK, NULL, "child %d was not stopped.",
-				k);
-	}
-	tst_resm(TINFO, "resume all children.");
-	for (k = 0; k < num; k++) {
-		if (kill(child[k], SIGCONT) == -1)
-			tst_brkm(TBROK|TERRNO, NULL, "kill child[%d]", k);
-	}
-	tst_resm(TINFO, "stop KSM.");
-	if (lseek(fd, 0, SEEK_SET) == -1)
-		tst_brkm(TBROK|TERRNO, NULL, "lseek");
-	if (write(fd, "0", 1) != 1)
-		tst_brkm(TBROK|TERRNO, NULL, "write");
-	close(fd);
-	group_check(0, 0, 0, 0, 0, 0, size * 256 * num);
-	while (waitpid(-1, &status, WUNTRACED | WCONTINUED) > 0)
-		if (WEXITSTATUS(status) != 0)
-			tst_resm(TFAIL, "child exit status is %d",
-				WEXITSTATUS(status));
-}
-
 void setup(void)
 {
-	char buf[BUFSIZ];
-	struct stat new;
+	tst_require_root(NULL);
 
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, "run");
-	if (stat(buf, &new) == -1) {
-		if (errno == ENOENT)
-			tst_brkm(TCONF, NULL, "no KSM.");
-		else
-			tst_brkm(TBROK, NULL, "stat");
-	}
-	/*
-	 * setup a default signal hander and a
-	 * temporary working directory.
-	 */
 	tst_sig(FORK, DEF_HANDLER, NULL);
 	TEST_PAUSE;
 }
 
-void usage(void)
+void cleanup(void)
 {
-	printf("  -n      Number of processes\n");
-	printf("  -s      Memory allocation size in MB\n");
+	TEST_CLEANUP;
 }
-
-/* There is currently a bug will cause the test failure - *
- http://marc.info/?l=linux-mm&m=128928530308526&w=2 .  Since it has
- still been discussed upstream, the interface here was added some
- flexiblity with path2, so it is possible to make changes here depends
- on the future implementation in kernel. For example, to verify
- (pages_sharing + pages_volatile) instead of a single item. */
-void check(char *path, char *path2, long int value)
-{
-	FILE *fp;
-	char buf[BUFSIZ], buf2[BUFSIZ];
-
-	snprintf(buf, BUFSIZ, "%s%s", _PATH_KSM, path);
-	fp = fopen(buf, "r");
-	if (fp == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "fopen");
-	if (fgets(buf, BUFSIZ, fp) == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "fgets");
-	fclose(fp);
-
-	tst_resm(TINFO, "%s is %ld.", path, atol(buf));
-	if (path2 != NULL) {
-		snprintf(buf2, BUFSIZ, "%s%s", _PATH_KSM, path2);
-		fp = fopen(buf2, "r");
-		if (fp == NULL)
-			tst_brkm(TBROK|TERRNO, NULL, "fopen");
-		if (fgets(buf2, BUFSIZ, fp) == NULL)
-			tst_brkm(TBROK|TERRNO, NULL, "fgets");
-		fclose(fp);
-
-		tst_resm(TINFO, "%s is %ld.", path2, atol(buf2));
-		if (atol(buf) + atol(buf2) != value)
-			tst_resm(TFAIL, "%s + %s is not %ld.", path, path2,
-				value);
-	} else
-		if (atol(buf) != value)
-			tst_resm(TFAIL, "%s is not %ld.", path, value);
-}
-
-void verify(char value, int proc, int start, int end, int start2, int end2)
-{
-	int i, j;
-	void *s = NULL;
-
-	s = malloc((end - start) * (end2 - start2));
-	if (s == NULL)
-		tst_brkm(TBROK|TERRNO, NULL, "malloc");
-
-	tst_resm(TINFO, "child %d verifies memory content.", proc);
-	memset(s, value, (end - start) * (end2 - start2));
-	if (memcmp(memory[proc][start], s, (end - start) * (end2 - start2)) != 0)
-		for (j = start; j < end; j++)
-			for (i = start2; i < end2; i++)
-				if (memory[proc][j][i] != value)
-					tst_resm(TFAIL, "child %d has %c at "
-						"%d,%d,%d.",
-						proc, memory[proc][j][i], proc,
-						j, i);
-	free(s);
-}
-
-void group_check(int run, int pages_shared, int pages_sharing,
-		int pages_volatile, int pages_unshared,
-		int sleep_millisecs, int pages_to_scan)
-{
-        /* 5 seconds for ksm to scan pages. */
-	sleep(5);
-	tst_resm(TINFO, "check!");
-	check("run", NULL, run);
-	check("pages_shared", NULL, pages_shared);
-	check("pages_sharing", NULL, pages_sharing);
-	check("pages_volatile", NULL, pages_volatile);
-	check("pages_unshared", NULL, pages_unshared);
-	check("sleep_millisecs", NULL, sleep_millisecs);
-	check("pages_to_scan", NULL, pages_to_scan);
-}
\ No newline at end of file
diff --git a/testcases/kernel/mem/lib/Makefile b/testcases/kernel/mem/lib/Makefile
new file mode 100644
index 0000000..dd978a7
--- /dev/null
+++ b/testcases/kernel/mem/lib/Makefile
@@ -0,0 +1,25 @@
+#
+#  Copyright (C) 2010  Red Hat, Inc.
+#
+#  This program 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; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program 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 have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+top_srcdir              ?= ../../../..
+
+include $(top_srcdir)/include/mk/env_pre.mk
+
+LIB			:= libmem.a
+
+include $(top_srcdir)/include/mk/lib.mk
diff --git a/testcases/kernel/mem/lib/mem.c b/testcases/kernel/mem/lib/mem.c
new file mode 100644
index 0000000..297eedd
--- /dev/null
+++ b/testcases/kernel/mem/lib/mem.c
@@ -0,0 +1,651 @@
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "test.h"
+#include "usctest.h"
+#include "../include/mem.h"
+#include "config.h"
+#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
+	&& HAVE_MPOL_CONSTANTS
+#include <numaif.h>
+#endif
+
+void oom(int testcase, int mempolicy, int lite)
+{
+	pid_t pid;
+	int status;
+#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
+	&& HAVE_MPOL_CONSTANTS
+	unsigned long nmask = 2;
+#endif
+
+	switch(pid = fork()) {
+	case -1:
+		tst_brkm(TBROK|TERRNO, cleanup, "fork");
+	case 0:
+#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
+	&& HAVE_MPOL_CONSTANTS
+		if (mempolicy)
+			if (set_mempolicy(MPOL_BIND, &nmask, MAXNODES) == -1)
+				tst_brkm(TBROK|TERRNO, cleanup,
+					"set_mempolicy");
+#endif
+		test_alloc(testcase, lite);
+		exit(0);
+	default:
+		break;
+	}
+	tst_resm(TINFO, "expected victim is %d.", pid);
+	if (waitpid(-1, &status, 0) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+
+	if (testcase == OVERCOMMIT) {
+		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+			tst_resm(TFAIL, "the victim unexpectedly failed: %d",
+				status);
+	} else {
+		if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL)
+			tst_resm(TFAIL, "the victim unexpectedly failed: %d",
+				status);
+	}
+}
+
+void write_memcg(void)
+{
+	int fd;
+	char buf[BUFSIZ], mem[BUFSIZ];
+
+	fd = open(MEMCG_PATH_NEW "/memory.limit_in_bytes", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	sprintf(mem, "%ld", TESTMEM);
+	if (write(fd, mem, strlen(mem)) != strlen(mem))
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);
+
+	fd = open(MEMCG_PATH_NEW "/tasks", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	snprintf(buf, BUFSIZ, "%d", getpid());
+	if (write(fd, buf, strlen(buf)) != strlen(buf))
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);	
+}
+
+void write_cpusets(void)
+{
+	char cpus[BUFSIZ] = "";
+	char buf[BUFSIZ] = "";
+	int fd;
+
+	gather_cpus(cpus);
+	tst_resm(TINFO, "CPU list for 2nd node is %s.", cpus);
+
+	fd = open(CPATH_NEW "/mems", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	if (write(fd, "1", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);
+
+	fd = open(CPATH_NEW "/cpus", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	if (write(fd, cpus, strlen(cpus)) != strlen(cpus))
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);
+
+	fd = open(CPATH_NEW "/tasks", O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
+	snprintf(buf, BUFSIZ, "%d", getpid());
+	if (write(fd, buf, strlen(buf)) != strlen(buf))
+		tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
+	close(fd);
+}
+
+void testoom(int mempolicy, int lite, int numa)
+{
+	if (numa && !mempolicy)
+		write_cpusets();
+
+	tst_resm(TINFO, "start normal OOM testing.");
+	oom(NORMAL, mempolicy, lite);
+
+	tst_resm(TINFO, "start OOM testing for mlocked pages.");
+	oom(MLOCK, mempolicy, lite);
+
+	tst_resm(TINFO, "start OOM testing for KSM pages.");
+	oom(KSM, mempolicy, lite);
+}
+
+long count_numa(void)
+{
+	int nnodes = 0;
+
+	while(path_exist(PATH_SYS_SYSTEM "/node/node%d", nnodes))
+		nnodes++;
+
+	return nnodes;
+}
+
+int path_exist(const char *path, ...)
+{
+	va_list ap;
+	char pathbuf[PATH_MAX];
+
+	va_start(ap, path);
+	vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
+	va_end(ap);
+
+	return access(pathbuf, F_OK) == 0;
+}
+
+void gather_cpus(char *cpus)
+{
+	int ncpus = 0;
+	int i;
+	char buf[BUFSIZ];
+
+	while(path_exist(PATH_SYS_SYSTEM "/cpu/cpu%d", ncpus))
+		ncpus++;
+
+	for (i = 0; i < ncpus; i++)
+		if (path_exist(PATH_SYS_SYSTEM "/node/node1/cpu%d", i)) {
+			sprintf(buf, "%d,", i);
+			strcat(cpus, buf);
+		}
+	/* Remove the trailing comma. */
+	cpus[strlen(cpus) - 1] = '\0';
+}
+
+int alloc_mem(long int length, int testcase)
+{
+	void *s;
+
+	tst_resm(TINFO, "allocating %ld bytes.", length);
+	s = mmap(NULL, length, PROT_READ|PROT_WRITE,
+		MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+	if (s == MAP_FAILED) {
+		if (testcase == OVERCOMMIT && errno == ENOMEM)
+			return 1;
+		else
+			tst_brkm(TBROK|TERRNO, cleanup, "mmap");
+	}
+	if (testcase == MLOCK && mlock(s, length) == -1)
+		tst_brkm(TINFO|TERRNO, cleanup, "mlock");
+	if (testcase == KSM
+		&& madvise(s, length, MADV_MERGEABLE) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "madvise");
+	memset(s, '\a', length);
+
+	return 0;
+}
+
+void test_alloc(int testcase, int lite)
+{
+	if (lite)
+		alloc_mem(TESTMEM + MB, testcase);
+	else
+		while(1)
+			if (alloc_mem(LENGTH, testcase))
+				return;
+}
+
+void umount_mem(char *path, char *path_new)
+{
+	FILE *fp;
+	int fd;
+	char s_new[BUFSIZ], s[BUFSIZ], value[BUFSIZ];
+
+	/* Move all processes in task to its parent node. */
+	sprintf(s, "%s/tasks", path);
+	fd = open(s, O_WRONLY);
+	if (fd == -1)
+		tst_resm(TWARN|TERRNO, "open %s", s);
+
+	snprintf(s_new, BUFSIZ, "%s/tasks", path_new);
+	fp = fopen(s_new, "r");
+	if (fp == NULL)
+		tst_resm(TWARN|TERRNO, "fopen %s", s_new);
+	if ((fd != -1) && (fp != NULL)) {
+		while (fgets(value, BUFSIZ, fp) != NULL)
+			if (write(fd, value, strlen(value) - 1)
+				!= strlen(value) - 1)
+				tst_resm(TWARN|TERRNO, "write %s", s);
+	}
+	if (fd != -1)
+		close(fd);
+	if (fp != NULL)
+		fclose(fp);
+	if (rmdir(path_new) == -1)
+		tst_resm(TWARN|TERRNO, "rmdir %s", path_new);
+	if (umount(path) == -1)
+		tst_resm(TWARN|TERRNO, "umount %s", path);
+	if (rmdir(path) == -1)
+		tst_resm(TWARN|TERRNO, "rmdir %s", path);
+}
+
+void mount_mem(char *name, char *fs, char *options, char *path, char *path_new)
+{
+	if (mkdir(path, 0777) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "mkdir %s", path);
+	if (mount(name, path, fs, 0, options) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "mount %s", path);
+	if (mkdir(path_new, 0777) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "mkdir %s", path_new);
+}
+
+void ksm_usage(void)
+{
+	printf("  -n      Number of processes\n");
+	printf("  -s      Memory allocation size in MB\n");
+	printf("  -u      Memory allocation unit in MB\n");
+}
+
+void check(char *path, long int value)
+{
+	FILE *fp;
+	char buf[BUFSIZ];
+
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, path);
+	fp = fopen(buf, "r");
+	if (fp == NULL)
+		tst_brkm(TBROK|TERRNO, tst_exit, "fopen");
+	if (fgets(buf, BUFSIZ, fp) == NULL)
+		tst_brkm(TBROK|TERRNO, tst_exit, "fgets");
+	fclose(fp);
+
+	tst_resm(TINFO, "%s is %ld.", path, atol(buf));
+	if (atol(buf) != value)
+		tst_resm(TFAIL, "%s is not %ld.", path, value);
+}
+
+void verify(char value, int proc, int start, int end, int start2, int end2)
+{
+	int i, j;
+	void *s = NULL;
+
+	s = malloc((end - start) * (end2 - start2));
+	if (s == NULL)
+		tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
+
+	tst_resm(TINFO, "child %d verifies memory content.", proc);
+	memset(s, value, (end - start) * (end2 - start2));
+	if (memcmp(memory[proc][start], s, (end - start) * (end2 - start2))
+		!= 0)
+		for (j = start; j < end; j++)
+			for (i = start2; i < end2; i++)
+				if (memory[proc][j][i] != value)
+					tst_resm(TFAIL, "child %d has %c at "
+						"%d,%d,%d.",
+						proc, memory[proc][j][i], proc,
+						j, i);
+	free(s);
+}
+
+void group_check(int run, int pages_shared, int pages_sharing,
+		int pages_volatile, int pages_unshared,
+		int sleep_millisecs, int pages_to_scan)
+{
+        /* 5 seconds for ksm to scan pages. */
+	sleep(5);
+	tst_resm(TINFO, "check!");
+	check("run", run);
+	check("pages_shared", pages_shared);
+	check("pages_sharing", pages_sharing);
+	check("pages_volatile", pages_volatile);
+	check("pages_unshared", pages_unshared);
+	check("sleep_millisecs", sleep_millisecs);
+	check("pages_to_scan", pages_to_scan);
+}
+
+void create_same_memory(int size, int num, int unit)
+{
+	char buf[BUFSIZ], buf2[BUFSIZ];
+	int i, j, k;
+	int status, fd;
+	int *child;
+
+	child = malloc(num);
+	if (child == NULL)
+		tst_brkm(TBROK|TERRNO, cleanup, "malloc");
+
+	memory = malloc(num * sizeof(**memory));
+	if (memory == NULL)
+		tst_brkm(TBROK|TERRNO, cleanup, "malloc");
+
+	/* Don't call cleanup in those children. Instead, do a cleanup from the
+	   parent after fetched children's status.*/
+	switch (child[0] = fork()) {
+	case -1:
+		tst_brkm(TBROK|TERRNO, cleanup, "fork");
+	case 0:
+		tst_resm(TINFO, "child 0 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+
+		tst_resm(TINFO, "child 0 continues...");
+		tst_resm(TINFO, "child 0 allocates %d MB filled with 'c'.",
+			size);
+		memory[0] = malloc(size / unit * sizeof(*memory));
+		if (memory[0] == NULL)
+			tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
+		for (j = 0; j * unit < size; j++) {
+			memory[0][j] = mmap(NULL, unit * MB,
+					PROT_READ|PROT_WRITE,
+					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+			if (memory[0][j] == MAP_FAILED)
+				tst_brkm(TBROK|TERRNO, tst_exit, "mmap");
+			if (madvise(memory[0][j], unit * MB, MADV_MERGEABLE)
+				== -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "madvise");
+			for (i = 0; i < unit * MB; i++)
+				memory[0][j][i] = 'c';
+		}
+		tst_resm(TINFO, "child 0 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+
+		tst_resm(TINFO, "child 0 continues...");
+		verify('c', 0, 0, size / unit, 0, unit * MB);
+		tst_resm(TINFO, "child 0 changes memory content to 'd'.");
+		for (j = 0; j < size / unit; j++) {
+			for (i = 0; i < unit * MB; i++)
+				memory[0][j][i] = 'd';
+		}
+		/* Unmerge. */
+		tst_resm(TINFO, "child 0 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+
+		tst_resm(TINFO, "child 0 continues...");
+		verify('d', 0, 0, size / unit, 0, unit * MB);
+		/* Stop. */
+		tst_resm(TINFO, "child 0 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 0 continues...");
+		exit(0);
+	}
+	switch (child[1] = fork()) {
+	case -1:
+		tst_brkm(TBROK|TERRNO, cleanup, "fork");
+	case 0:
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		tst_resm(TINFO, "child 1 allocates %d MB filled with 'a'.",
+			size);
+		memory[1] = malloc(size / unit * sizeof(*memory));
+		if (memory[1] == NULL)
+			tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
+		for (j = 0; j < size / unit; j++) {
+			memory[1][j] = mmap(NULL, unit * MB,
+					PROT_READ|PROT_WRITE,
+					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+			if (memory[1][j] == MAP_FAILED)
+				tst_brkm(TBROK|TERRNO, tst_exit, "mmap");
+			if (madvise(memory[1][j], unit * MB, MADV_MERGEABLE)
+				== -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "madvise");
+			for (i = 0; i < unit * MB; i++)
+				memory[1][j][i] = 'a';
+		}
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		verify('a', 1, 0, size / unit, 0, unit * MB);
+		tst_resm(TINFO, "child 1 changes memory content to 'b'.");
+		for (j = 0; j < size / unit; j++) {
+			for (i = 0; i < unit * MB; i++)
+				memory[1][j][i] = 'b';
+		}
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		verify('b', 1, 0, size / unit, 0, unit * MB);
+		tst_resm(TINFO, "child 1 changes memory content to 'd'");
+		for (j = 0; j < size / unit; j++) {
+			for (i = 0; i < unit * MB; i++)
+				memory[1][j][i] = 'd';
+		}
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+
+		tst_resm(TINFO, "child 1 continues...");
+		verify('d', 1, 0, size / unit, 0, unit * MB);
+		tst_resm(TINFO, "child 1 changes one page to 'e'.");
+		memory[1][size / unit - 1][unit * MB - 1] = 'e';
+
+		/* Unmerge. */
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		verify('e', 1, size / unit - 1, size / unit,
+			unit * MB - 1, unit * MB);
+		verify('d', 1, 0, size / unit - 1, 0, unit * MB - 1);
+
+		/* Stop. */
+		tst_resm(TINFO, "child 1 stops.");
+		if (raise(SIGSTOP) == -1)
+			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+		tst_resm(TINFO, "child 1 continues...");
+		exit(0);
+	}
+	for (k = 2; k < num; k++) {
+		switch (child[k] = fork()) {
+		case -1:
+			tst_brkm(TBROK|TERRNO, cleanup, "fork");
+		case 0:
+			tst_resm(TINFO, "child %d stops.", k);
+			if (raise(SIGSTOP) == -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+			tst_resm(TINFO, "child %d continues...", k);
+			tst_resm(TINFO, "child %d allocates %d "
+				"MB filled with 'a'.", k, size);
+			memory[k] = malloc(size / unit * sizeof(*memory));
+			if (memory[k] == NULL)
+				tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
+			for (j = 0; j < size / unit; j++) {
+				memory[k][j] = mmap(NULL, unit * MB,
+						PROT_READ|PROT_WRITE,
+						MAP_ANONYMOUS
+						|MAP_PRIVATE, -1, 0);
+				if (memory[k][j] == MAP_FAILED)
+					tst_brkm(TBROK|TERRNO, cleanup,
+						"mmap");
+				if (madvise(memory[k][j], unit * MB,
+						MADV_MERGEABLE) == -1)
+					tst_brkm(TBROK|TERRNO, cleanup,
+						"madvise");
+				for (i = 0; i < unit * MB; i++)
+					memory[k][j][i] = 'a';
+			}
+			tst_resm(TINFO, "child %d stops.", k);
+			if (raise(SIGSTOP) == -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+			tst_resm(TINFO, "child %d continues...", k);
+			tst_resm(TINFO, "child %d changes memory content to "
+				"'d'", k);
+			for (j = 0; j < size / unit; j++) {
+				for (i = 0; i < unit * MB; i++)
+					memory[k][j][i] = 'd';
+		        }
+			/* Unmerge. */
+			tst_resm(TINFO, "child %d stops.", k);
+			if (raise(SIGSTOP) == -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+			tst_resm(TINFO, "child %d continues...", k);
+
+			/* Stop. */
+			tst_resm(TINFO, "child %d stops.", k);
+			if (raise(SIGSTOP) == -1)
+				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
+			tst_resm(TINFO, "child %d continues...", k);
+			exit(0);
+		}
+	}
+	tst_resm(TINFO, "KSM merging...");
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "run");
+	fd = open(buf, O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open");
+	if (write(fd, "1", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	close(fd);
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "pages_to_scan");
+	snprintf(buf2, BUFSIZ, "%d", size * 256 * num);
+	fd = open(buf, O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open");
+	if (write(fd, buf2, strlen(buf2)) != strlen(buf2))
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	close(fd);
+
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "sleep_millisecs");
+	fd = open(buf, O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open");
+	if (write(fd, "0", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	close(fd);
+
+	tst_resm(TINFO, "wait for all children to stop.");
+	for (k = 0; k < num; k++) {
+		if (waitpid(child[k], &status, WUNTRACED) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+		if (!WIFSTOPPED(status))
+			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
+				k);
+	}
+	tst_resm(TINFO, "resume all children.");
+	for (k = 0; k < num; k++) {
+		if (kill(child[k], SIGCONT) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
+	}
+	group_check(1, 2, size * num * 256 - 2, 0, 0, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for child 1 to stop.");
+	if (waitpid(child[1], &status, WUNTRACED) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+	if (!WIFSTOPPED(status))
+		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");
+
+	/* Child 1 changes all pages to 'b'. */
+	tst_resm(TINFO, "resume child 1.");
+	if (kill(child[1], SIGCONT) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "kill");
+	group_check(1, 3, size * num * 256 - 3, 0, 0, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for child 1 to stop.");
+	if (waitpid(child[1], &status, WUNTRACED) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+	if (!WIFSTOPPED(status))
+		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");
+
+	/* All children change pages to 'd'. */
+	tst_resm(TINFO, "resume all children.");
+	for (k = 0; k < num; k++) {
+		if (kill(child[k], SIGCONT) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
+	}
+	group_check(1, 1, size * num * 256 - 1, 0, 0, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for all children to stop.");
+	for (k = 0; k < num; k++) {
+		if (waitpid(child[k], &status, WUNTRACED) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+		if (!WIFSTOPPED(status))
+			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
+				k);
+	}
+	/* Child 1 changes pages to 'e'. */
+	tst_resm(TINFO, "resume child 1.");
+	if (kill(child[1], SIGCONT) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "kill");
+	group_check(1, 1, size * num * 256 - 2, 0, 1, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for child 1 to stop.");
+	if (waitpid(child[1], &status, WUNTRACED) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+	if (!WIFSTOPPED(status))
+		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");
+
+	tst_resm(TINFO, "resume all children.");
+	for (k = 0; k < num; k++) {
+		if (kill(child[k], SIGCONT) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
+	}
+	tst_resm(TINFO, "KSM unmerging...");
+	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "run");
+	fd = open(buf, O_WRONLY);
+	if (fd == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "open");
+	if (write(fd, "2", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	group_check(2, 0, 0, 0, 0, 0, size * 256 * num);
+
+	tst_resm(TINFO, "wait for all children to stop.");
+	for (k = 0; k < num; k++) {
+		if (waitpid(child[k], &status, WUNTRACED) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+		if (!WIFSTOPPED(status))
+			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
+				k);
+	}
+	tst_resm(TINFO, "resume all children.");
+	for (k = 0; k < num; k++) {
+		if (kill(child[k], SIGCONT) == -1)
+			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
+	}
+	tst_resm(TINFO, "stop KSM.");
+	if (lseek(fd, 0, SEEK_SET) == -1)
+		tst_brkm(TBROK|TERRNO, cleanup, "lseek");
+	if (write(fd, "0", 1) != 1)
+		tst_brkm(TBROK|TERRNO, cleanup, "write");
+	close(fd);
+	group_check(0, 0, 0, 0, 0, 0, size * 256 * num);
+	while (waitpid(-1, &status, WUNTRACED | WCONTINUED) > 0)
+		if (WEXITSTATUS(status) != 0)
+			tst_resm(TFAIL, "child exit status is %d",
+				WEXITSTATUS(status));
+}
+
+void check_ksm_options(int *size, int *num, int *unit)
+{
+	if (opt_size) {
+		*size = atoi(opt_sizestr);
+		if (*size < 1)
+			tst_brkm(TBROK, cleanup,
+				"size cannot be less than 1.");
+	}
+	if (opt_unit) {
+		*unit = atoi(opt_unitstr);
+		if (*unit > *size)
+			tst_brkm(TBROK, cleanup,
+				"unit cannot be greater than size.");
+		if (*size % *unit != 0)
+			tst_brkm(TBROK, cleanup,
+				"the remainder of division of size by unit is "
+				"not zero.");
+	}
+	if (opt_num) {
+		*num = atoi(opt_numstr);
+		if (*num < 3)
+			tst_brkm(TBROK, cleanup,
+				"process number cannot be less 3.");
+	}
+}
diff --git a/testcases/kernel/mem/oom/Makefile b/testcases/kernel/mem/oom/Makefile
index 01c0546..81509bf 100644
--- a/testcases/kernel/mem/oom/Makefile
+++ b/testcases/kernel/mem/oom/Makefile
@@ -20,9 +20,9 @@ top_srcdir              ?= ../../../..
 
 include $(top_srcdir)/include/mk/env_pre.mk
 
-LDLIBS			+= $(NUMA_LIBS) -loom
-LIBDIR			:= lib
-LIB			:= $(LIBDIR)/liboom.a
+LDLIBS			+= $(NUMA_LIBS) -lmem
+LIBDIR			:= ../lib
+LIB			:= $(LIBDIR)/libmem.a
 FILTER_OUT_DIRS		:= $(LIBDIR)
 LDFLAGS			+= -L$(LIBDIR)
 
diff --git a/testcases/kernel/mem/oom/oom01.c b/testcases/kernel/mem/oom/oom01.c
index c670d90..b6c9d83 100644
--- a/testcases/kernel/mem/oom/oom01.c
+++ b/testcases/kernel/mem/oom/oom01.c
@@ -38,13 +38,10 @@
 #include <unistd.h>
 #include "test.h"
 #include "usctest.h"
-#include "lib/oom.h"
+#include "../include/mem.h"
 
 char *TCID = "oom01";
 int TST_TOTAL = 1;
-extern int Tst_count;
-
-static void setup(void);
 
 int main(int argc, char *argv[])
 {
diff --git a/testcases/kernel/mem/oom/oom02.c b/testcases/kernel/mem/oom/oom02.c
index 68ed1ef..04c6507 100644
--- a/testcases/kernel/mem/oom/oom02.c
+++ b/testcases/kernel/mem/oom/oom02.c
@@ -42,9 +42,7 @@ int TST_TOTAL = 1;
 #include <fcntl.h>
 #include <stdio.h>
 #include <errno.h>
-#include "lib/oom.h"
-
-static void setup(void);
+#include "../include/mem.h"
 
 int main(int argc, char *argv[])
 {
diff --git a/testcases/kernel/mem/oom/oom03.c b/testcases/kernel/mem/oom/oom03.c
index dd09467..da01d3e 100644
--- a/testcases/kernel/mem/oom/oom03.c
+++ b/testcases/kernel/mem/oom/oom03.c
@@ -35,13 +35,10 @@
 #include <errno.h>
 #include "test.h"
 #include "usctest.h"
-#include "lib/oom.h"
+#include "../include/mem.h"
 
 char *TCID = "oom03";
 int TST_TOTAL = 1;
-extern int Tst_count;
-
-static void setup(void);
 
 int main(int argc, char *argv[])
 {
diff --git a/testcases/kernel/mem/oom/oom04.c b/testcases/kernel/mem/oom/oom04.c
index 1dff85e..8eb5c04 100644
--- a/testcases/kernel/mem/oom/oom04.c
+++ b/testcases/kernel/mem/oom/oom04.c
@@ -34,55 +34,15 @@
 
 char *TCID = "oom04";
 int TST_TOTAL = 1;
-extern int Tst_count;
 
 #if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
 	&& HAVE_MPOL_CONSTANTS
-#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/mount.h>
-#include <numaif.h>
 #include <fcntl.h>
 #include <stdio.h>
-#include <unistd.h>
 #include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-#include <stdarg.h>
-
-#define MAXNODES		512
-#define CPATH			"/dev/cpuset"
-#define CPATH_NEW		CPATH "/1"
-#define MEMCG_PATH		"/dev/cgroup"
-#define MEMCG_PATH_NEW		MEMCG_PATH "/1"
-#define _PATH_SYS_SYSTEM	"/sys/devices/system"
-#define LENGTH			(3UL<<30)
-#define TESTMEM			(1UL<<30)
-#define MB			(1UL<<20)
-#define NORMAL			1
-#define MLOCK			2
-#define KSM			3
-#define SYSFS_OVER		"/proc/sys/vm/overcommit_memory"
-
-static char overcommit[BUFSIZ];
-
-static void setup(void);
-static void cleanup(void) LTP_ATTRIBUTE_NORETURN;
-static void oom(int testcase, int mempolicy, int lite);
-static long count_numa(void);
-static int path_exist(const char *path, ...);
-static void testoom(int mempolicy, int lite);
-static void alloc_mem(long int length, int testcase);
-static void test_alloc(int testcase, int lite);
-static void gather_cpus(char *cpus);
-static void umount_mem(char *path, char *path_new);
-static void mount_mem(char *name, char *fs, char *options, char *path,
-		char *path_new);
+#include "../include/mem.h"
 
 int main(int argc, char *argv[])
 {
@@ -113,9 +73,7 @@ int main(int argc, char *argv[])
 			tst_brkm(TBROK|TERRNO, cleanup, "write");
 		close(fd);
 
-		snprintf(buf, BUFSIZ, "%s/memory.limit_in_bytes",
-			MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/memory.limit_in_bytes", O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		sprintf(mem, "%ld", TESTMEM);
@@ -123,8 +81,7 @@ int main(int argc, char *argv[])
 			tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
 		close(fd);
 
-		snprintf(buf, BUFSIZ, "%s/tasks", MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/tasks", O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		snprintf(buf, BUFSIZ, "%d", getpid());
@@ -135,9 +92,8 @@ int main(int argc, char *argv[])
 		tst_resm(TINFO, "process mempolicy.");
 		testoom(1, 0, 1);
 
-		snprintf(buf, BUFSIZ, "%s/memory.memsw.limit_in_bytes",
-			MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/memory.memsw.limit_in_bytes",
+			O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		if (write(fd, mem, strlen(mem)) != strlen(mem))
@@ -146,9 +102,8 @@ int main(int argc, char *argv[])
 		testoom(1, 1, 1);
 
 		tst_resm(TINFO, "process cpuset.");
-		snprintf(buf, BUFSIZ, "%s/memory.memsw.limit_in_bytes",
-			MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/memory.memsw.limit_in_bytes",
+			O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		sprintf(mem, "%ld", TESTMEM);
@@ -157,9 +112,8 @@ int main(int argc, char *argv[])
 		close(fd);
 		testoom(0, 0, 1);
 
-		snprintf(buf, BUFSIZ, "%s/memory.memsw.limit_in_bytes",
-			MEMCG_PATH_NEW);
-		fd = open(buf, O_WRONLY);
+		fd = open(MEMCG_PATH_NEW "/memory.memsw.limit_in_bytes",
+			O_WRONLY);
 		if (fd == -1)
 			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
 		if (write(fd, mem, strlen(mem)) != strlen(mem))
@@ -168,52 +122,6 @@ int main(int argc, char *argv[])
 		testoom(0, 1, 1);
 	}
 	cleanup();
-	tst_exit();
-}
-
-void testoom(int mempolicy, int lite)
-{
-	int fd;
-	char buf[BUFSIZ] = "";
-	char cpus[BUFSIZ] = "";
-
-	if (!mempolicy) {
-		gather_cpus(cpus);
-		tst_resm(TINFO, "CPU list for 2nd node is %s.", cpus);
-
-		snprintf(buf, BUFSIZ, "%s/cpuset.mems", CPATH_NEW);
-		fd = open(buf, O_WRONLY);
-		if (fd == -1)
-			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
-		if (write(fd, "1", 1) != 1)
-			tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
-		close(fd);
-
-		snprintf(buf, BUFSIZ, "%s/cpuset.cpus", CPATH_NEW);
-		fd = open(buf, O_WRONLY);
-		if (fd == -1)
-			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
-		if (write(fd, cpus, strlen(cpus)) != strlen(cpus))
-			tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
-		close(fd);
-
-		snprintf(buf, BUFSIZ, "%s/tasks", CPATH_NEW);
-		fd = open(buf, O_WRONLY);
-		if (fd == -1)
-			tst_brkm(TBROK|TERRNO, cleanup, "open %s", buf);
-		snprintf(buf, BUFSIZ, "%d", getpid());
-		if (write(fd, buf, strlen(buf)) != strlen(buf))
-			tst_brkm(TBROK|TERRNO, cleanup, "write %s", buf);
-		close(fd);
-	}
-	tst_resm(TINFO, "start normal OOM testing.");
-	oom(NORMAL, mempolicy, lite);
-
-	tst_resm(TINFO, "start OOM testing for mlocked pages.");
-	oom(MLOCK, mempolicy, lite);
-
-	tst_resm(TINFO, "start OOM testing for KSM pages.");
-	oom(KSM, mempolicy, lite);
 }
 
 void setup(void)
@@ -236,50 +144,6 @@ void setup(void)
 	mount_mem("memcg", "cgroup", "memory", MEMCG_PATH, MEMCG_PATH_NEW);
 }
 
-void umount_mem(char *path, char *path_new)
-{
-	FILE *fp;
-	int fd;
-	char s_new[BUFSIZ], s[BUFSIZ], value[BUFSIZ];
-
-	/* Move all processes in task to its parent node. */
-	snprintf(s, BUFSIZ, "%s/tasks", path);
-	fd = open(s, O_WRONLY);
-	if (fd == -1)
-		tst_resm(TWARN|TERRNO, "open %s", s);
-	snprintf(s_new, BUFSIZ, "%s/tasks", path_new);
-
-	fp = fopen(s_new, "r");
-	if (fp == NULL)
-		tst_resm(TWARN|TERRNO, "fopen %s", s_new);
-	if ((fd != -1) && (fp != NULL)) {
-		while (fgets(value, BUFSIZ, fp) != NULL)
-			if (write(fd, value, strlen(value) - 1)
-				!= strlen(value) - 1)
-				tst_resm(TWARN|TERRNO, "write %s", s);
-	}
-	if (fd != -1)
-		close(fd);
-	if (fp != NULL)
-		fclose(fp);
-	if (rmdir(path_new) == -1)
-		tst_resm(TWARN|TERRNO, "rmdir %s", path_new);
-	if (umount(path) == -1)
-		tst_resm(TWARN|TERRNO, "umount %s", path);
-	if (rmdir(path) == -1)
-		tst_resm(TWARN|TERRNO, "rmdir %s", path);
-}
-
-void mount_mem(char *name, char *fs, char *options, char *path, char *path_new)
-{
-	if (mkdir(path, 0777) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "mkdir %s", path);
-	if (mount(name, path, fs, 0, options) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "mount %s", path);
-	if (mkdir(path_new, 0777) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "mkdir %s", path_new);
-}
-
 void cleanup(void)
 {
 	int fd;
@@ -295,105 +159,13 @@ void cleanup(void)
 	umount_mem(MEMCG_PATH, MEMCG_PATH_NEW);
 
 	TEST_CLEANUP;
-}
-
-void oom(int testcase, int mempolicy, int lite)
-{
-	pid_t pid;
-	int status;
-	unsigned long nmask = 2;
-
-	switch(pid = fork()) {
-	case -1:
-		tst_brkm(TBROK|TERRNO, cleanup, "fork");
-	case 0:
-		if (mempolicy)
-			if (set_mempolicy(MPOL_BIND, &nmask, MAXNODES) == -1)
-				tst_brkm(TBROK|TERRNO, cleanup,
-					"set_mempolicy");
-
-		test_alloc(testcase, lite);
-		exit(0);
-	default:
-		break;
-	}
-	tst_resm(TINFO, "expected victim is %d.", pid);
-	if (waitpid(-1, &status, 0) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
-
-	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL)
-		tst_resm(TFAIL, "the victim unexpectedly failed: %d", status);
-}
-
-long count_numa(void)
-{
-	int nnodes = 0;
-
-	while(path_exist(_PATH_SYS_SYSTEM "/node/node%d", nnodes))
-		nnodes++;
-
-	return nnodes;
-}
-
-int path_exist(const char *path, ...)
-{
-	va_list ap;
-	char pathbuf[PATH_MAX];
-
-	va_start(ap, path);
-	vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
-	va_end(ap);
-
-	return access(pathbuf, F_OK) == 0;
-}
-
-void gather_cpus(char *cpus)
-{
-	int ncpus = 0;
-	int i;
-	char buf[BUFSIZ];
-
-	while(path_exist(_PATH_SYS_SYSTEM "/cpu/cpu%d", ncpus))
-		ncpus++;
-
-	for (i = 0; i < ncpus; i++)
-		if (path_exist(_PATH_SYS_SYSTEM "/node/node1/cpu%d", i)) {
-			sprintf(buf, "%d,", i);
-			strcat(cpus, buf);
-		}
-	/* Remove the trailing comma. */
-	cpus[strlen(cpus) - 1] = '\0';
-}
-
-void alloc_mem(long int length, int testcase)
-{
-	void *s;
-
-	tst_resm(TINFO, "allocating %ld bytes.", length);
-	s = mmap(NULL, length, PROT_READ|PROT_WRITE,
-		MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-	if (s == MAP_FAILED) {
-			tst_brkm(TBROK|TERRNO, cleanup, "mmap");
-	}
-	if (testcase == MLOCK && mlock(s, length) == -1)
-		tst_brkm(TINFO|TERRNO, cleanup, "mlock");
-	if (testcase == KSM
-		&& madvise(s, length, MADV_MERGEABLE) == -1)
-		tst_brkm(TBROK|TERRNO, cleanup, "madvise");
-	memset(s, '\a', length);
-}
-
-void test_alloc(int testcase, int lite)
-{
-	if (lite)
-		alloc_mem(TESTMEM + MB, testcase);
-	else
-		while(1)
-			alloc_mem(LENGTH, testcase);
+	tst_exit();
 }
 
 #else /* no NUMA */
-int main(void) {
-	tst_brkm(TCONF, NULL, "no NUMA development packages installed.");
+int main(void)
+{
+	tst_resm(TCONF, "no NUMA development packages installed.");
+	tst_exit();
 }
 #endif
-- 
1.7.3.2


[-- Attachment #3: Type: text/plain, Size: 372 bytes --]

------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl

[-- Attachment #4: Type: text/plain, Size: 155 bytes --]

_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [LTP] [PATCH] rework code for oom and ksm tests
  2011-01-19  8:11 ` [LTP] [PATCH] rework code for oom and ksm tests CAI Qian
@ 2011-01-19  9:05   ` Garrett Cooper
  0 siblings, 0 replies; 2+ messages in thread
From: Garrett Cooper @ 2011-01-19  9:05 UTC (permalink / raw)
  To: CAI Qian; +Cc: ltp-list

On Wed, Jan 19, 2011 at 12:11 AM, CAI Qian <caiqian@redhat.com> wrote:
> Mainly to reduce code duplication. Also, to add an option for ksm01 to
> use a different memory allocation unit size to take advantage of THP.
> In addition, adjust ksm01 according the latest upstream development
> effort,
> http://marc.info/?l=linux-mm&m=129473104716901&w=2
> http://marc.info/?l=linux-mm&m=129442718808733&w=2

Commit pending.
Thanks,
-Garrett

------------------------------------------------------------------------------
Protect Your Site and Customers from Malware Attacks
Learn about various malware tactics and how to avoid them. Understand 
malware threats, the impact they can have on your business, and how you 
can protect your company and customers by using code signing.
http://p.sf.net/sfu/oracle-sfdevnl
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2011-01-19  9:05 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <488834807.56177.1295424703727.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com>
2011-01-19  8:11 ` [LTP] [PATCH] rework code for oom and ksm tests CAI Qian
2011-01-19  9:05   ` Garrett Cooper

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.