diff mbox series

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

Message ID 20241218184518.16190-10-chrubis@suse.cz
State Changes Requested
Headers show
Series Get rid of testcases/kernel/mem/lib library | expand

Commit Message

Cyril Hrubis Dec. 18, 2024, 6:45 p.m. UTC
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

Comments

Li Wang Dec. 19, 2024, 2:52 a.m. UTC | #1
On Thu, Dec 19, 2024 at 2:48 AM Cyril Hrubis <chrubis@suse.cz> wrote:

> 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 ++++++++++++++++++++++++++
>

We do have another tst_helper.h under testcases/kernel/include/,
maybe we can combine it with ksm_test.h together?



>  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
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
>
Li Wang Dec. 19, 2024, 2:55 a.m. UTC | #2
Li Wang <liwang@redhat.com> wrote:


>  testcases/kernel/mem/ksm/ksm_test.h   | 299 ++++++++++++++++++++++++++
>>
>
> We do have another tst_helper.h under testcases/kernel/include/,
> maybe we can combine it with ksm_test.h together?
>
Sorry for the typo: tst_helper.h ---> ksm_helper.h
Cyril Hrubis Dec. 19, 2024, 9:08 a.m. UTC | #3
Hi!
> We do have another tst_helper.h under testcases/kernel/include/,
> maybe we can combine it with ksm_test.h together?

The ksm_test.h are functions used only in ksm testcases, the
ksm_helper.h is used in more tests and I plan to make it an library in
top level libs/ later on.
Li Wang Dec. 19, 2024, 9:11 a.m. UTC | #4
On Thu, Dec 19, 2024 at 5:09 PM Cyril Hrubis <chrubis@suse.cz> wrote:

> Hi!
> > We do have another tst_helper.h under testcases/kernel/include/,
> > maybe we can combine it with ksm_test.h together?
>
> The ksm_test.h are functions used only in ksm testcases, the
> ksm_helper.h is used in more tests and I plan to make it an library in
> top level libs/ later on.
>

Sounds good. Thanks.
Petr Vorel Dec. 27, 2024, 11:15 a.m. UTC | #5
Hi Cyril,

> --- /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);

FYI there is an old warning (not relevant to this change), not sure if it's an
false positive or how to fix it:

mem.c: In function ‘write_cpusets’:
mem.c:555:52: warning: ‘/online’ directive output may be truncated writing 7 bytes into a region of size between 1 and 8192 [-Wformat-truncation=]
  555 |                         snprintf(path1, BUFSIZ, "%s/online", path);
      |                                                    ^~~~~~~ 

Kind regards,
Petr
Petr Vorel Dec. 27, 2024, 11:36 a.m. UTC | #6
Hi Cyril,

> new file mode 100644
> index 000000000..ebce8197c
> --- /dev/null
> +++ b/testcases/kernel/mem/ksm/ksm_test.h
...
> +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) {
This introduces new warnings, because the original code used MB which is long. 

#define MB                  (1UL<<20)

Now we use TST_MB, which is plain int.

In file included from ksm_common.h:16,
                 from ksm04.c:42:
ksm_test.h: In function ‘ksm_child_memset’:
ksm_test.h:108:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]
  108 |         if (ksm_merge_data.mergeable_size == size * TST_MB) {
      |                                           ^~
ksm_test.h:119:45: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]
  119 |                 for (i = 0; (unsigned int)i < unit * TST_MB; i++)
      |                                             ^
ksm_test.h:126:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]
  126 |         if (ksm_merge_data.mergeable_size < size * TST_MB)
      |                                           ^
ksm_test.h: In function ‘create_ksm_child’:
ksm_test.h:166:54: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]
  166 |                 if (ksm_merge_data[j].mergeable_size < size * TST_MB) {
      |                                                      ^
It would be nice to add cast before merge.

> +		tst_res(TINFO, "child %d allocates %d TST_MB filled with '%c'",

This should use MB (replace to whole file obviously should exclude strings):

		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 TST_MB filled with '%c'"

And here as well.
		tst_res(TINFO, "child %d allocates %d MB filled with '%c'"
> +				" except one page with 'e'",
> +				child_num, size, ksm_merge_data.data);
> +	}

Otherwise LGTM.

Kind regards,
Petr
Petr Vorel Dec. 27, 2024, 11:37 a.m. UTC | #7
Reviewed-by: Petr Vorel <pvorel@suse.cz>
Cyril Hrubis Feb. 10, 2025, 11:17 a.m. UTC | #8
Hi!
> > new file mode 100644
> > index 000000000..ebce8197c
> > --- /dev/null
> > +++ b/testcases/kernel/mem/ksm/ksm_test.h
> ...
> > +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) {
> This introduces new warnings, because the original code used MB which is long. 
> 
> #define MB                  (1UL<<20)
> 
> Now we use TST_MB, which is plain int.
> 
> In file included from ksm_common.h:16,
>                  from ksm04.c:42:
> ksm_test.h: In function ‘ksm_child_memset’:
> ksm_test.h:108:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]
>   108 |         if (ksm_merge_data.mergeable_size == size * TST_MB) {
>       |                                           ^~
> ksm_test.h:119:45: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]
>   119 |                 for (i = 0; (unsigned int)i < unit * TST_MB; i++)
>       |                                             ^
> ksm_test.h:126:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]
>   126 |         if (ksm_merge_data.mergeable_size < size * TST_MB)
>       |                                           ^
> ksm_test.h: In function ‘create_ksm_child’:
> ksm_test.h:166:54: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]
>   166 |                 if (ksm_merge_data[j].mergeable_size < size * TST_MB) {
>       |                                                      ^
> It would be nice to add cast before merge.

So the size is signed but it was implicitly casted to unsigned by the
TST_MB being unsigned. I guess that the best fix here is to make the
size and unit unsigned to begin with since these are numbers that should
not be negative at all.

> > +		tst_res(TINFO, "child %d allocates %d TST_MB filled with '%c'",
> 
> This should use MB (replace to whole file obviously should exclude strings):
> 
> 		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 TST_MB filled with '%c'"
> 
> And here as well.
> 		tst_res(TINFO, "child %d allocates %d MB filled with '%c'"
> > +				" except one page with 'e'",
> > +				child_num, size, ksm_merge_data.data);
> > +	}

Ah, sorry, that is a result from blindly doing sed s/...
diff mbox series

Patch

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));
-}