[LTP] [PATCH 09/13] testcases/kernel/mem: Move KSM bits to ksm tests

Cyril Hrubis
2024-12-18T18:48:00Z

Moves the ksm helpers into a ksm/ksm_test.h since these are not used by
any other but ksm tests.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
testcases/kernel/mem/include/mem.h | 5 -
testcases/kernel/mem/ksm/Makefile | 2 +-
testcases/kernel/mem/ksm/ksm01.c | 2 +-
testcases/kernel/mem/ksm/ksm02.c | 2 +-
testcases/kernel/mem/ksm/ksm03.c | 2 +-
testcases/kernel/mem/ksm/ksm04.c | 2 +-
testcases/kernel/mem/ksm/ksm05.c | 2 +-
testcases/kernel/mem/ksm/ksm06.c | 4 +-
testcases/kernel/mem/ksm/ksm07.c | 3 +-
testcases/kernel/mem/ksm/ksm_common.h | 3 +-
testcases/kernel/mem/ksm/ksm_test.h | 299 ++++++++++++++++++++++++++
testcases/kernel/mem/lib/mem.c | 287 ------------------------
12 files changed, 312 insertions(+), 301 deletions(-)
create mode 100644 testcases/kernel/mem/ksm/ksm_test.h

diff --git a/testcases/kernel/mem/include/mem.h b/testcases/kernel/mem/include/mem.h
index 5ebedc175..25389f34c 100644
--- a/testcases/kernel/mem/include/mem.h
+++ b/testcases/kernel/mem/include/mem.h
@@ -16,11 +16,6 @@

/* KSM */

-void create_same_memory(int size, int num, int unit);
-void test_ksm_merge_across_nodes(unsigned long nr_pages);
-void ksm_group_check(int run, int pg_shared, int pg_sharing, int pg_volatile,
- int pg_unshared, int sleep_msecs, int pages_to_scan);
-
/* HUGETLB */

#define PATH_SHMMAX "/proc/sys/kernel/shmmax"
diff --git a/testcases/kernel/mem/ksm/Makefile b/testcases/kernel/mem/ksm/Makefile
index 6aba73e61..2af02a274 100644
--- a/testcases/kernel/mem/ksm/Makefile
+++ b/testcases/kernel/mem/ksm/Makefile
@@ -7,5 +7,5 @@ LTPLIBS = numa
ksm06: LTPLDLIBS = -lltpnuma

include $(top_srcdir)/include/mk/testcases.mk
-include $(top_srcdir)/testcases/kernel/mem/include/libmem.mk
+include $(top_srcdir)/testcases/kernel/include/lib.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 e2d3d9e00..a22e4830f 100644
--- a/testcases/kernel/mem/ksm/ksm01.c
+++ b/testcases/kernel/mem/ksm/ksm01.c
@@ -56,7 +56,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include "mem.h"
+#include "tst_test.h"
#include "ksm_common.h"

static void verify_ksm(void)
diff --git a/testcases/kernel/mem/ksm/ksm02.c b/testcases/kernel/mem/ksm/ksm02.c
index a388e82ab..4d1306045 100644
--- a/testcases/kernel/mem/ksm/ksm02.c
+++ b/testcases/kernel/mem/ksm/ksm02.c
@@ -53,7 +53,7 @@
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
-#include "mem.h"
+#include "tst_test.h"
#include "ksm_common.h"

#ifdef HAVE_NUMA_V2
diff --git a/testcases/kernel/mem/ksm/ksm03.c b/testcases/kernel/mem/ksm/ksm03.c
index cff74700d..78844b30e 100644
--- a/testcases/kernel/mem/ksm/ksm03.c
+++ b/testcases/kernel/mem/ksm/ksm03.c
@@ -56,7 +56,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include "mem.h"
+#include "tst_test.h"
#include "ksm_common.h"

static void verify_ksm(void)
diff --git a/testcases/kernel/mem/ksm/ksm04.c b/testcases/kernel/mem/ksm/ksm04.c
index 31f3ff2eb..8465ee230 100644
--- a/testcases/kernel/mem/ksm/ksm04.c
+++ b/testcases/kernel/mem/ksm/ksm04.c
@@ -38,7 +38,7 @@
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
-#include "mem.h"
+#include "tst_test.h"
#include "ksm_common.h"

#ifdef HAVE_NUMA_V2
diff --git a/testcases/kernel/mem/ksm/ksm05.c b/testcases/kernel/mem/ksm/ksm05.c
index 1d9d9699a..025dffc09 100644
--- a/testcases/kernel/mem/ksm/ksm05.c
+++ b/testcases/kernel/mem/ksm/ksm05.c
@@ -39,7 +39,7 @@
#include <stdlib.h>
#include <errno.h>
#include "tst_test.h"
-#include "mem.h"
+#include "ksm_helper.h"

#ifdef HAVE_DECL_MADV_MERGEABLE

diff --git a/testcases/kernel/mem/ksm/ksm06.c b/testcases/kernel/mem/ksm/ksm06.c
index 80fdf1e47..09a54fd18 100644
--- a/testcases/kernel/mem/ksm/ksm06.c
+++ b/testcases/kernel/mem/ksm/ksm06.c
@@ -33,8 +33,10 @@
#include <unistd.h>
#include <limits.h>

-#include "mem.h"
+#include "tst_test.h"
#include "tst_numa.h"
+#include "ksm_helper.h"
+#include "ksm_test.h"

#ifdef HAVE_NUMA_V2
# include <numa.h>
diff --git a/testcases/kernel/mem/ksm/ksm07.c b/testcases/kernel/mem/ksm/ksm07.c
index 619bd7b55..24b393283 100644
--- a/testcases/kernel/mem/ksm/ksm07.c
+++ b/testcases/kernel/mem/ksm/ksm07.c
@@ -23,7 +23,8 @@
*/

#include <sys/wait.h>
-#include "mem.h"
+#include "tst_test.h"
+#include "ksm_helper.h"

/* This test allocates one page, fills the page with a's, captures the
* full_scan and pages_skipped counters. Then it makes sure at least 3
diff --git a/testcases/kernel/mem/ksm/ksm_common.h b/testcases/kernel/mem/ksm/ksm_common.h
index 43ea8f8c2..d677b224d 100644
--- a/testcases/kernel/mem/ksm/ksm_common.h
+++ b/testcases/kernel/mem/ksm/ksm_common.h
@@ -11,7 +11,9 @@
#define KSM_COMMON_H__

#include "tst_test.h"
+#include "ksm_helper.h"
#include "numa_helper.h"
+#include "ksm_test.h"

#define DEFAULT_MEMSIZE 128

@@ -67,5 +69,4 @@ static inline unsigned int get_a_numa_node(void)
abort();
}

-
#endif /* KSM_COMMON_H__ */
diff --git a/testcases/kernel/mem/ksm/ksm_test.h b/testcases/kernel/mem/ksm/ksm_test.h
new file mode 100644
index 000000000..ebce8197c
--- /dev/null
+++ b/testcases/kernel/mem/ksm/ksm_test.h
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) Linux Test Project, 2011-2021
+ * Copyright (c) Cyril Hrubis <chrubis@suse.cz> 2024
+ */
+#ifndef KSM_TEST_
+#define KSM_TEST_
+
+#include <sys/wait.h>
+
+static inline void check(char *path, long int value)
+{
+ char fullpath[BUFSIZ];
+ long actual_val;
+
+ snprintf(fullpath, BUFSIZ, PATH_KSM "%s", path);
+ SAFE_FILE_SCANF(fullpath, "%ld", &actual_val);
+
+ if (actual_val != value)
+ tst_res(TFAIL, "%s is not %ld but %ld.", path, value,
+ actual_val);
+ else
+ tst_res(TPASS, "%s is %ld.", path, actual_val);
+}
+
+static inline void final_group_check(int run, int pages_shared, int pages_sharing,
+ int pages_volatile, int pages_unshared,
+ int sleep_millisecs, int pages_to_scan)
+{
+ int ksm_run_orig;
+
+ tst_res(TINFO, "check!");
+ check("run", run);
+
+ /*
+ * Temporarily stop the KSM scan during the checks: during the
+ * KSM scan the rmap_items in the stale unstable tree of the
+ * old pass are removed from it and are later reinserted in
+ * the new unstable tree of the current pass. So if the checks
+ * run in the race window between removal and re-insertion, it
+ * can lead to unexpected false positives where page_volatile
+ * is elevated and page_unshared is recessed.
+ */
+ SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig);
+ SAFE_FILE_PRINTF(PATH_KSM "run", "0");
+
+ 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);
+
+ SAFE_FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig);
+}
+
+static inline void ksm_group_check(int run, int pages_shared, int pages_sharing,
+ int pages_volatile, int pages_unshared,
+ int sleep_millisecs, int pages_to_scan)
+{
+ if (run != 1) {
+ tst_res(TFAIL, "group_check run is not 1, %d.", run);
+ } else {
+ /* wait for ksm daemon to scan all mergeable pages. */
+ wait_ksmd_full_scan();
+ }
+
+ final_group_check(run, pages_shared, pages_sharing,
+ pages_volatile, pages_unshared,
+ sleep_millisecs, pages_to_scan);
+}
+
+static inline void verify(char **memory, char value, int proc,
+ int start, int end, int start2, int end2)
+{
+ int i, j;
+ void *s = NULL;
+
+ s = SAFE_MALLOC((end - start) * (end2 - start2));
+
+ tst_res(TINFO, "child %d verifies memory content.", proc);
+ memset(s, value, (end - start) * (end2 - start2));
+ if (memcmp(memory[start], s, (end - start) * (end2 - start2))
+ != 0)
+ for (j = start; j < end; j++)
+ for (i = start2; i < end2; i++)
+ if (memory[j][i] != value)
+ tst_res(TFAIL, "child %d has %c at "
+ "%d,%d,%d.",
+ proc, memory[j][i], proc,
+ j, i);
+ free(s);
+}
+
+struct ksm_merge_data {
+ char data;
+ unsigned int mergeable_size;
+};
+
+static inline void ksm_child_memset(int child_num, int size, int total_unit,
+ struct ksm_merge_data ksm_merge_data, char **memory)
+{
+ int i = 0, j;
+ int unit = size / total_unit;
+
+ tst_res(TINFO, "child %d continues...", child_num);
+
+ if (ksm_merge_data.mergeable_size == size * TST_MB) {
+ tst_res(TINFO, "child %d allocates %d TST_MB filled with '%c'",
+ child_num, size, ksm_merge_data.data);
+
+ } else {
+ tst_res(TINFO, "child %d allocates %d TST_MB filled with '%c'"
+ " except one page with 'e'",
+ child_num, size, ksm_merge_data.data);
+ }
+
+ for (j = 0; j < total_unit; j++) {
+ for (i = 0; (unsigned int)i < unit * TST_MB; i++)
+ memory[j][i] = ksm_merge_data.data;
+ }
+
+ /* if it contains unshared page, then set 'e' char
+ * at the end of the last page
+ */
+ if (ksm_merge_data.mergeable_size < size * TST_MB)
+ memory[j-1][i-1] = 'e';
+}
+
+static inline void create_ksm_child(int child_num, int size, int unit,
+ struct ksm_merge_data *ksm_merge_data)
+{
+ int j, total_unit;
+ char **memory;
+
+ /* The total units in all */
+ total_unit = size / unit;
+
+ /* Apply for the space for memory */
+ memory = SAFE_MALLOC(total_unit * sizeof(char *));
+ for (j = 0; j < total_unit; j++) {
+ memory[j] = SAFE_MMAP(NULL, unit * TST_MB, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+#ifdef HAVE_DECL_MADV_MERGEABLE
+ if (madvise(memory[j], unit * TST_MB, MADV_MERGEABLE) == -1)
+ tst_brk(TBROK|TERRNO, "madvise");
+#endif
+ }
+
+ tst_res(TINFO, "child %d stops.", child_num);
+ if (raise(SIGSTOP) == -1)
+ tst_brk(TBROK|TERRNO, "kill");
+ fflush(stdout);
+
+ for (j = 0; j < 4; j++) {
+
+ ksm_child_memset(child_num, size, total_unit,
+ ksm_merge_data[j], memory);
+
+ fflush(stdout);
+
+ tst_res(TINFO, "child %d stops.", child_num);
+ if (raise(SIGSTOP) == -1)
+ tst_brk(TBROK|TERRNO, "kill");
+
+ if (ksm_merge_data[j].mergeable_size < size * TST_MB) {
+ verify(memory, 'e', child_num, total_unit - 1,
+ total_unit, unit * TST_MB - 1, unit * TST_MB);
+ verify(memory, ksm_merge_data[j].data, child_num,
+ 0, total_unit, 0, unit * TST_MB - 1);
+ } else {
+ verify(memory, ksm_merge_data[j].data, child_num,
+ 0, total_unit, 0, unit * TST_MB);
+ }
+ }
+
+ tst_res(TINFO, "child %d finished.", child_num);
+}
+
+static inline void stop_ksm_children(int *child, int num)
+{
+ int k, status;
+
+ tst_res(TINFO, "wait for all children to stop.");
+ for (k = 0; k < num; k++) {
+ SAFE_WAITPID(child[k], &status, WUNTRACED);
+ if (!WIFSTOPPED(status))
+ tst_brk(TBROK, "child %d was not stopped", k);
+ }
+}
+
+static inline void resume_ksm_children(int *child, int num)
+{
+ int k;
+
+ tst_res(TINFO, "resume all children.");
+ for (k = 0; k < num; k++)
+ SAFE_KILL(child[k], SIGCONT);
+
+ fflush(stdout);
+}
+
+static inline void create_same_memory(int size, int num, int unit)
+{
+ int i, j, status, *child;
+ unsigned long ps, pages;
+ struct ksm_merge_data **ksm_data;
+
+ struct ksm_merge_data ksm_data0[] = {
+ {'c', size*TST_MB}, {'c', size*TST_MB}, {'d', size*TST_MB}, {'d', size*TST_MB},
+ };
+ struct ksm_merge_data ksm_data1[] = {
+ {'a', size*TST_MB}, {'b', size*TST_MB}, {'d', size*TST_MB}, {'d', size*TST_MB-1},
+ };
+ struct ksm_merge_data ksm_data2[] = {
+ {'a', size*TST_MB}, {'a', size*TST_MB}, {'d', size*TST_MB}, {'d', size*TST_MB},
+ };
+
+ ps = sysconf(_SC_PAGE_SIZE);
+ pages = TST_MB / ps;
+
+ ksm_data = malloc((num - 3) * sizeof(struct ksm_merge_data *));
+ /* Since from third child, the data is same with the first child's */
+ for (i = 0; i < num - 3; i++) {
+ ksm_data[i] = malloc(4 * sizeof(struct ksm_merge_data));
+ for (j = 0; j < 4; j++) {
+ ksm_data[i][j].data = ksm_data0[j].data;
+ ksm_data[i][j].mergeable_size =
+ ksm_data0[j].mergeable_size;
+ }
+ }
+
+ child = SAFE_MALLOC(num * sizeof(int));
+
+ for (i = 0; i < num; i++) {
+ fflush(stdout);
+ switch (child[i] = SAFE_FORK()) {
+ case 0:
+ if (i == 0) {
+ create_ksm_child(i, size, unit, ksm_data0);
+ exit(0);
+ } else if (i == 1) {
+ create_ksm_child(i, size, unit, ksm_data1);
+ exit(0);
+ } else if (i == 2) {
+ create_ksm_child(i, size, unit, ksm_data2);
+ exit(0);
+ } else {
+ create_ksm_child(i, size, unit, ksm_data[i-3]);
+ exit(0);
+ }
+ }
+ }
+
+ stop_ksm_children(child, num);
+
+ tst_res(TINFO, "KSM merging...");
+ if (access(PATH_KSM "max_page_sharing", F_OK) == 0) {
+ SAFE_FILE_PRINTF(PATH_KSM "run", "2");
+ SAFE_FILE_PRINTF(PATH_KSM "max_page_sharing", "%ld", size * pages * num);
+ }
+
+ SAFE_FILE_PRINTF(PATH_KSM "run", "1");
+ SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", size * pages * num);
+ SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0");
+
+ resume_ksm_children(child, num);
+ stop_ksm_children(child, num);
+ ksm_group_check(1, 2, size * num * pages - 2, 0, 0, 0, size * pages * num);
+
+ resume_ksm_children(child, num);
+ stop_ksm_children(child, num);
+ ksm_group_check(1, 3, size * num * pages - 3, 0, 0, 0, size * pages * num);
+
+ resume_ksm_children(child, num);
+ stop_ksm_children(child, num);
+ ksm_group_check(1, 1, size * num * pages - 1, 0, 0, 0, size * pages * num);
+
+ resume_ksm_children(child, num);
+ stop_ksm_children(child, num);
+ ksm_group_check(1, 1, size * num * pages - 2, 0, 1, 0, size * pages * num);
+
+ tst_res(TINFO, "KSM unmerging...");
+ SAFE_FILE_PRINTF(PATH_KSM "run", "2");
+
+ resume_ksm_children(child, num);
+ final_group_check(2, 0, 0, 0, 0, 0, size * pages * num);
+
+ tst_res(TINFO, "stop KSM.");
+ SAFE_FILE_PRINTF(PATH_KSM "run", "0");
+ final_group_check(0, 0, 0, 0, 0, 0, size * pages * num);
+
+ while (waitpid(-1, &status, 0) > 0)
+ if (WEXITSTATUS(status) != 0)
+ tst_res(TFAIL, "child exit status is %d",
+ WEXITSTATUS(status));
+}
+
+#endif /* KSM_TEST_ */
diff --git a/testcases/kernel/mem/lib/mem.c b/testcases/kernel/mem/lib/mem.c
index f3b844994..4e5c0b873 100644
--- a/testcases/kernel/mem/lib/mem.c
+++ b/testcases/kernel/mem/lib/mem.c
@@ -28,290 +28,3 @@

/* KSM */

-static void check(char *path, long int value)
-{
- char fullpath[BUFSIZ];
- long actual_val;
-
- snprintf(fullpath, BUFSIZ, PATH_KSM "%s", path);
- SAFE_FILE_SCANF(fullpath, "%ld", &actual_val);
-
- if (actual_val != value)
- tst_res(TFAIL, "%s is not %ld but %ld.", path, value,
- actual_val);
- else
- tst_res(TPASS, "%s is %ld.", path, actual_val);
-}
-
-static void final_group_check(int run, int pages_shared, int pages_sharing,
- int pages_volatile, int pages_unshared,
- int sleep_millisecs, int pages_to_scan)
-{
- int ksm_run_orig;
-
- tst_res(TINFO, "check!");
- check("run", run);
-
- /*
- * Temporarily stop the KSM scan during the checks: during the
- * KSM scan the rmap_items in the stale unstable tree of the
- * old pass are removed from it and are later reinserted in
- * the new unstable tree of the current pass. So if the checks
- * run in the race window between removal and re-insertion, it
- * can lead to unexpected false positives where page_volatile
- * is elevated and page_unshared is recessed.
- */
- SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig);
- SAFE_FILE_PRINTF(PATH_KSM "run", "0");
-
- 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);
-
- SAFE_FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig);
-}
-
-void ksm_group_check(int run, int pages_shared, int pages_sharing,
- int pages_volatile, int pages_unshared,
- int sleep_millisecs, int pages_to_scan)
-{
- if (run != 1) {
- tst_res(TFAIL, "group_check run is not 1, %d.", run);
- } else {
- /* wait for ksm daemon to scan all mergeable pages. */
- wait_ksmd_full_scan();
- }
-
- final_group_check(run, pages_shared, pages_sharing,
- pages_volatile, pages_unshared,
- sleep_millisecs, pages_to_scan);
-}
-
-static void verify(char **memory, char value, int proc,
- int start, int end, int start2, int end2)
-{
- int i, j;
- void *s = NULL;
-
- s = SAFE_MALLOC((end - start) * (end2 - start2));
-
- tst_res(TINFO, "child %d verifies memory content.", proc);
- memset(s, value, (end - start) * (end2 - start2));
- if (memcmp(memory[start], s, (end - start) * (end2 - start2))
- != 0)
- for (j = start; j < end; j++)
- for (i = start2; i < end2; i++)
- if (memory[j][i] != value)
- tst_res(TFAIL, "child %d has %c at "
- "%d,%d,%d.",
- proc, memory[j][i], proc,
- j, i);
- free(s);
-}
-
-struct ksm_merge_data {
- char data;
- unsigned int mergeable_size;
-};
-
-static void ksm_child_memset(int child_num, int size, int total_unit,
- struct ksm_merge_data ksm_merge_data, char **memory)
-{
- int i = 0, j;
- int unit = size / total_unit;
-
- tst_res(TINFO, "child %d continues...", child_num);
-
- if (ksm_merge_data.mergeable_size == size * MB) {
- tst_res(TINFO, "child %d allocates %d MB filled with '%c'",
- child_num, size, ksm_merge_data.data);
-
- } else {
- tst_res(TINFO, "child %d allocates %d MB filled with '%c'"
- " except one page with 'e'",
- child_num, size, ksm_merge_data.data);
- }
-
- for (j = 0; j < total_unit; j++) {
- for (i = 0; (unsigned int)i < unit * MB; i++)
- memory[j][i] = ksm_merge_data.data;
- }
-
- /* if it contains unshared page, then set 'e' char
- * at the end of the last page
- */
- if (ksm_merge_data.mergeable_size < size * MB)
- memory[j-1][i-1] = 'e';
-}
-
-static void create_ksm_child(int child_num, int size, int unit,
- struct ksm_merge_data *ksm_merge_data)
-{
- int j, total_unit;
- char **memory;
-
- /* The total units in all */
- total_unit = size / unit;
-
- /* Apply for the space for memory */
- memory = SAFE_MALLOC(total_unit * sizeof(char *));
- for (j = 0; j < total_unit; j++) {
- memory[j] = SAFE_MMAP(NULL, unit * MB, PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-#ifdef HAVE_DECL_MADV_MERGEABLE
- if (madvise(memory[j], unit * MB, MADV_MERGEABLE) == -1)
- tst_brk(TBROK|TERRNO, "madvise");
-#endif
- }
-
- tst_res(TINFO, "child %d stops.", child_num);
- if (raise(SIGSTOP) == -1)
- tst_brk(TBROK|TERRNO, "kill");
- fflush(stdout);
-
- for (j = 0; j < 4; j++) {
-
- ksm_child_memset(child_num, size, total_unit,
- ksm_merge_data[j], memory);
-
- fflush(stdout);
-
- tst_res(TINFO, "child %d stops.", child_num);
- if (raise(SIGSTOP) == -1)
- tst_brk(TBROK|TERRNO, "kill");
-
- if (ksm_merge_data[j].mergeable_size < size * MB) {
- verify(memory, 'e', child_num, total_unit - 1,
- total_unit, unit * MB - 1, unit * MB);
- verify(memory, ksm_merge_data[j].data, child_num,
- 0, total_unit, 0, unit * MB - 1);
- } else {
- verify(memory, ksm_merge_data[j].data, child_num,
- 0, total_unit, 0, unit * MB);
- }
- }
-
- tst_res(TINFO, "child %d finished.", child_num);
-}
-
-static void stop_ksm_children(int *child, int num)
-{
- int k, status;
-
- tst_res(TINFO, "wait for all children to stop.");
- for (k = 0; k < num; k++) {
- SAFE_WAITPID(child[k], &status, WUNTRACED);
- if (!WIFSTOPPED(status))
- tst_brk(TBROK, "child %d was not stopped", k);
- }
-}
-
-static void resume_ksm_children(int *child, int num)
-{
- int k;
-
- tst_res(TINFO, "resume all children.");
- for (k = 0; k < num; k++)
- SAFE_KILL(child[k], SIGCONT);
-
- fflush(stdout);
-}
-
-void create_same_memory(int size, int num, int unit)
-{
- int i, j, status, *child;
- unsigned long ps, pages;
- struct ksm_merge_data **ksm_data;
-
- struct ksm_merge_data ksm_data0[] = {
- {'c', size*MB}, {'c', size*MB}, {'d', size*MB}, {'d', size*MB},
- };
- struct ksm_merge_data ksm_data1[] = {
- {'a', size*MB}, {'b', size*MB}, {'d', size*MB}, {'d', size*MB-1},
- };
- struct ksm_merge_data ksm_data2[] = {
- {'a', size*MB}, {'a', size*MB}, {'d', size*MB}, {'d', size*MB},
- };
-
- ps = sysconf(_SC_PAGE_SIZE);
- pages = MB / ps;
-
- ksm_data = malloc((num - 3) * sizeof(struct ksm_merge_data *));
- /* Since from third child, the data is same with the first child's */
- for (i = 0; i < num - 3; i++) {
- ksm_data[i] = malloc(4 * sizeof(struct ksm_merge_data));
- for (j = 0; j < 4; j++) {
- ksm_data[i][j].data = ksm_data0[j].data;
- ksm_data[i][j].mergeable_size =
- ksm_data0[j].mergeable_size;
- }
- }
-
- child = SAFE_MALLOC(num * sizeof(int));
-
- for (i = 0; i < num; i++) {
- fflush(stdout);
- switch (child[i] = SAFE_FORK()) {
- case 0:
- if (i == 0) {
- create_ksm_child(i, size, unit, ksm_data0);
- exit(0);
- } else if (i == 1) {
- create_ksm_child(i, size, unit, ksm_data1);
- exit(0);
- } else if (i == 2) {
- create_ksm_child(i, size, unit, ksm_data2);
- exit(0);
- } else {
- create_ksm_child(i, size, unit, ksm_data[i-3]);
- exit(0);
- }
- }
- }
-
- stop_ksm_children(child, num);
-
- tst_res(TINFO, "KSM merging...");
- if (access(PATH_KSM "max_page_sharing", F_OK) == 0) {
- SAFE_FILE_PRINTF(PATH_KSM "run", "2");
- SAFE_FILE_PRINTF(PATH_KSM "max_page_sharing", "%ld", size * pages * num);
- }
-
- SAFE_FILE_PRINTF(PATH_KSM "run", "1");
- SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", size * pages * num);
- SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0");
-
- resume_ksm_children(child, num);
- stop_ksm_children(child, num);
- ksm_group_check(1, 2, size * num * pages - 2, 0, 0, 0, size * pages * num);
-
- resume_ksm_children(child, num);
- stop_ksm_children(child, num);
- ksm_group_check(1, 3, size * num * pages - 3, 0, 0, 0, size * pages * num);
-
- resume_ksm_children(child, num);
- stop_ksm_children(child, num);
- ksm_group_check(1, 1, size * num * pages - 1, 0, 0, 0, size * pages * num);
-
- resume_ksm_children(child, num);
- stop_ksm_children(child, num);
- ksm_group_check(1, 1, size * num * pages - 2, 0, 1, 0, size * pages * num);
-
- tst_res(TINFO, "KSM unmerging...");
- SAFE_FILE_PRINTF(PATH_KSM "run", "2");
-
- resume_ksm_children(child, num);
- final_group_check(2, 0, 0, 0, 0, 0, size * pages * num);
-
- tst_res(TINFO, "stop KSM.");
- SAFE_FILE_PRINTF(PATH_KSM "run", "0");
- final_group_check(0, 0, 0, 0, 0, 0, size * pages * num);
-
- while (waitpid(-1, &status, 0) > 0)
- if (WEXITSTATUS(status) != 0)
- tst_res(TFAIL, "child exit status is %d",
- WEXITSTATUS(status));
-}
--
2.45.2