There are some general ksm operations could be used by other related
test cases. Put them into vm_util for common use.

This is a preparation patch for later use.

Signed-off-by: Wei Yang <[email protected]>
Suggested-by: David Hildenbrand <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Lorenzo Stoakes <[email protected]>
Cc: Rik van Riel <[email protected]>
Cc: Liam R. Howlett <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Cc: Harry Yoo <[email protected]>

---
v3:
  * rebase on latest mm-unstable
v2:
  * do check on file opening in init_global_file_handlers()
  * factor out ksm_merge() and ksm_unmerge() instead of partial of it
  * align the return value of helpers: 0 on success, -errno on error
v1: open/close fd in function itself instead of pass as parameter
---
 .../selftests/mm/ksm_functional_tests.c       | 134 +++---------------
 tools/testing/selftests/mm/vm_util.c          | 123 ++++++++++++++++
 tools/testing/selftests/mm/vm_util.h          |   7 +
 3 files changed, 153 insertions(+), 111 deletions(-)

diff --git a/tools/testing/selftests/mm/ksm_functional_tests.c 
b/tools/testing/selftests/mm/ksm_functional_tests.c
index d8bd1911dfc0..c9d72daa3138 100644
--- a/tools/testing/selftests/mm/ksm_functional_tests.c
+++ b/tools/testing/selftests/mm/ksm_functional_tests.c
@@ -38,11 +38,6 @@ enum ksm_merge_mode {
 };
 
 static int mem_fd;
-static int ksm_fd;
-static int ksm_full_scans_fd;
-static int proc_self_ksm_stat_fd;
-static int proc_self_ksm_merging_pages_fd;
-static int ksm_use_zero_pages_fd;
 static int pagemap_fd;
 static size_t pagesize;
 
@@ -73,88 +68,6 @@ static bool range_maps_duplicates(char *addr, unsigned long 
size)
        return false;
 }
 
-static long get_my_ksm_zero_pages(void)
-{
-       char buf[200];
-       char *substr_ksm_zero;
-       size_t value_pos;
-       ssize_t read_size;
-       unsigned long my_ksm_zero_pages;
-
-       if (!proc_self_ksm_stat_fd)
-               return 0;
-
-       read_size = pread(proc_self_ksm_stat_fd, buf, sizeof(buf) - 1, 0);
-       if (read_size < 0)
-               return -errno;
-
-       buf[read_size] = 0;
-
-       substr_ksm_zero = strstr(buf, "ksm_zero_pages");
-       if (!substr_ksm_zero)
-               return 0;
-
-       value_pos = strcspn(substr_ksm_zero, "0123456789");
-       my_ksm_zero_pages = strtol(substr_ksm_zero + value_pos, NULL, 10);
-
-       return my_ksm_zero_pages;
-}
-
-static long get_my_merging_pages(void)
-{
-       char buf[10];
-       ssize_t ret;
-
-       if (proc_self_ksm_merging_pages_fd < 0)
-               return proc_self_ksm_merging_pages_fd;
-
-       ret = pread(proc_self_ksm_merging_pages_fd, buf, sizeof(buf) - 1, 0);
-       if (ret <= 0)
-               return -errno;
-       buf[ret] = 0;
-
-       return strtol(buf, NULL, 10);
-}
-
-static long ksm_get_full_scans(void)
-{
-       char buf[10];
-       ssize_t ret;
-
-       ret = pread(ksm_full_scans_fd, buf, sizeof(buf) - 1, 0);
-       if (ret <= 0)
-               return -errno;
-       buf[ret] = 0;
-
-       return strtol(buf, NULL, 10);
-}
-
-static int ksm_merge(void)
-{
-       long start_scans, end_scans;
-
-       /* Wait for two full scans such that any possible merging happened. */
-       start_scans = ksm_get_full_scans();
-       if (start_scans < 0)
-               return start_scans;
-       if (write(ksm_fd, "1", 1) != 1)
-               return -errno;
-       do {
-               end_scans = ksm_get_full_scans();
-               if (end_scans < 0)
-                       return end_scans;
-       } while (end_scans < start_scans + 2);
-
-       return 0;
-}
-
-static int ksm_unmerge(void)
-{
-       if (write(ksm_fd, "2", 1) != 1)
-               return -errno;
-       return 0;
-}
-
 static char *__mmap_and_merge_range(char val, unsigned long size, int prot,
                                  enum ksm_merge_mode mode)
 {
@@ -163,12 +76,12 @@ static char *__mmap_and_merge_range(char val, unsigned 
long size, int prot,
        int ret;
 
        /* Stabilize accounting by disabling KSM completely. */
-       if (ksm_unmerge()) {
+       if (ksm_stop() < 0) {
                ksft_print_msg("Disabling (unmerging) KSM failed\n");
                return err_map;
        }
 
-       if (get_my_merging_pages() > 0) {
+       if (ksm_get_self_merging_pages() > 0) {
                ksft_print_msg("Still pages merged\n");
                return err_map;
        }
@@ -218,7 +131,7 @@ static char *__mmap_and_merge_range(char val, unsigned long 
size, int prot,
        }
 
        /* Run KSM to trigger merging and wait. */
-       if (ksm_merge()) {
+       if (ksm_start() < 0) {
                ksft_print_msg("Running KSM failed\n");
                goto unmap;
        }
@@ -227,7 +140,7 @@ static char *__mmap_and_merge_range(char val, unsigned long 
size, int prot,
         * Check if anything was merged at all. Ignore the zero page that is
         * accounted differently (depending on kernel support).
         */
-       if (val && !get_my_merging_pages()) {
+       if (val && !ksm_get_self_merging_pages()) {
                ksft_print_msg("No pages got merged\n");
                goto unmap;
        }
@@ -274,6 +187,7 @@ static void test_unmerge(void)
        ksft_test_result(!range_maps_duplicates(map, size),
                         "Pages were unmerged\n");
 unmap:
+       ksm_stop();
        munmap(map, size);
 }
 
@@ -286,15 +200,12 @@ static void test_unmerge_zero_pages(void)
 
        ksft_print_msg("[RUN] %s\n", __func__);
 
-       if (proc_self_ksm_stat_fd < 0) {
-               ksft_test_result_skip("open(\"/proc/self/ksm_stat\") failed\n");
-               return;
-       }
-       if (ksm_use_zero_pages_fd < 0) {
-               ksft_test_result_skip("open 
\"/sys/kernel/mm/ksm/use_zero_pages\" failed\n");
+       if (ksm_get_self_zero_pages() < 0) {
+               ksft_test_result_skip("accessing \"/proc/self/ksm_stat\" 
failed\n");
                return;
        }
-       if (write(ksm_use_zero_pages_fd, "1", 1) != 1) {
+
+       if (ksm_use_zero_pages() < 0) {
                ksft_test_result_skip("write 
\"/sys/kernel/mm/ksm/use_zero_pages\" failed\n");
                return;
        }
@@ -306,7 +217,7 @@ static void test_unmerge_zero_pages(void)
 
        /* Check if ksm_zero_pages is updated correctly after KSM merging */
        pages_expected = size / pagesize;
-       if (pages_expected != get_my_ksm_zero_pages()) {
+       if (pages_expected != ksm_get_self_zero_pages()) {
                ksft_test_result_fail("'ksm_zero_pages' updated after 
merging\n");
                goto unmap;
        }
@@ -319,7 +230,7 @@ static void test_unmerge_zero_pages(void)
 
        /* Check if ksm_zero_pages is updated correctly after unmerging */
        pages_expected /= 2;
-       if (pages_expected != get_my_ksm_zero_pages()) {
+       if (pages_expected != ksm_get_self_zero_pages()) {
                ksft_test_result_fail("'ksm_zero_pages' updated after 
unmerging\n");
                goto unmap;
        }
@@ -329,7 +240,7 @@ static void test_unmerge_zero_pages(void)
                *((unsigned int *)&map[offs]) = offs;
 
        /* Now we should have no zeropages remaining. */
-       if (get_my_ksm_zero_pages()) {
+       if (ksm_get_self_zero_pages()) {
                ksft_test_result_fail("'ksm_zero_pages' updated after write 
fault\n");
                goto unmap;
        }
@@ -338,6 +249,7 @@ static void test_unmerge_zero_pages(void)
        ksft_test_result(!range_maps_duplicates(map, size),
                        "KSM zero pages were unmerged\n");
 unmap:
+       ksm_stop();
        munmap(map, size);
 }
 
@@ -366,6 +278,7 @@ static void test_unmerge_discarded(void)
        ksft_test_result(!range_maps_duplicates(map, size),
                         "Pages were unmerged\n");
 unmap:
+       ksm_stop();
        munmap(map, size);
 }
 
@@ -452,6 +365,7 @@ static void test_unmerge_uffd_wp(void)
 close_uffd:
        close(uffd);
 unmap:
+       ksm_stop();
        munmap(map, size);
 }
 #endif
@@ -515,6 +429,7 @@ static int test_child_ksm(void)
        else if (map == MAP_MERGE_SKIP)
                return -3;
 
+       ksm_stop();
        munmap(map, size);
        return 0;
 }
@@ -644,6 +559,7 @@ static void test_prctl_unmerge(void)
        ksft_test_result(!range_maps_duplicates(map, size),
                         "Pages were unmerged\n");
 unmap:
+       ksm_stop();
        munmap(map, size);
 }
 
@@ -685,19 +601,15 @@ static void init_global_file_handles(void)
        mem_fd = open("/proc/self/mem", O_RDWR);
        if (mem_fd < 0)
                ksft_exit_fail_msg("opening /proc/self/mem failed\n");
-       ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR);
-       if (ksm_fd < 0)
-               ksft_exit_skip("open(\"/sys/kernel/mm/ksm/run\") failed\n");
-       ksm_full_scans_fd = open("/sys/kernel/mm/ksm/full_scans", O_RDONLY);
-       if (ksm_full_scans_fd < 0)
-               ksft_exit_skip("open(\"/sys/kernel/mm/ksm/full_scans\") 
failed\n");
+       if (ksm_stop() < 0)
+               ksft_exit_skip("accessing \"/sys/kernel/mm/ksm/run\") 
failed\n");
+       if (ksm_get_full_scans() < 0)
+               ksft_exit_skip("accessing \"/sys/kernel/mm/ksm/full_scans\") 
failed\n");
        pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
        if (pagemap_fd < 0)
                ksft_exit_skip("open(\"/proc/self/pagemap\") failed\n");
-       proc_self_ksm_stat_fd = open("/proc/self/ksm_stat", O_RDONLY);
-       proc_self_ksm_merging_pages_fd = open("/proc/self/ksm_merging_pages",
-                                               O_RDONLY);
-       ksm_use_zero_pages_fd = open("/sys/kernel/mm/ksm/use_zero_pages", 
O_RDWR);
+       if (ksm_get_self_merging_pages() < 0)
+               ksft_exit_skip("accessing \"/proc/self/ksm_merging_pages\") 
failed\n");
 }
 
 int main(int argc, char **argv)
diff --git a/tools/testing/selftests/mm/vm_util.c 
b/tools/testing/selftests/mm/vm_util.c
index 6a239aa413e2..ab7271ed5ff3 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -565,3 +565,126 @@ bool detect_huge_zeropage(void)
        close(fd);
        return enabled;
 }
+
+long ksm_get_self_zero_pages(void)
+{
+       int proc_self_ksm_stat_fd;
+       char buf[200];
+       char *substr_ksm_zero;
+       size_t value_pos;
+       ssize_t read_size;
+
+       proc_self_ksm_stat_fd = open("/proc/self/ksm_stat", O_RDONLY);
+       if (proc_self_ksm_stat_fd < 0)
+               return -errno;
+
+       read_size = pread(proc_self_ksm_stat_fd, buf, sizeof(buf) - 1, 0);
+       close(proc_self_ksm_stat_fd);
+       if (read_size < 0)
+               return -errno;
+
+       buf[read_size] = 0;
+
+       substr_ksm_zero = strstr(buf, "ksm_zero_pages");
+       if (!substr_ksm_zero)
+               return 0;
+
+       value_pos = strcspn(substr_ksm_zero, "0123456789");
+       return strtol(substr_ksm_zero + value_pos, NULL, 10);
+}
+
+long ksm_get_self_merging_pages(void)
+{
+       int proc_self_ksm_merging_pages_fd;
+       char buf[10];
+       ssize_t ret;
+
+       proc_self_ksm_merging_pages_fd = open("/proc/self/ksm_merging_pages",
+                                               O_RDONLY);
+       if (proc_self_ksm_merging_pages_fd < 0)
+               return -errno;
+
+       ret = pread(proc_self_ksm_merging_pages_fd, buf, sizeof(buf) - 1, 0);
+       close(proc_self_ksm_merging_pages_fd);
+       if (ret <= 0)
+               return -errno;
+       buf[ret] = 0;
+
+       return strtol(buf, NULL, 10);
+}
+
+long ksm_get_full_scans(void)
+{
+       int ksm_full_scans_fd;
+       char buf[10];
+       ssize_t ret;
+
+       ksm_full_scans_fd = open("/sys/kernel/mm/ksm/full_scans", O_RDONLY);
+       if (ksm_full_scans_fd < 0)
+               return -errno;
+
+       ret = pread(ksm_full_scans_fd, buf, sizeof(buf) - 1, 0);
+       close(ksm_full_scans_fd);
+       if (ret <= 0)
+               return -errno;
+       buf[ret] = 0;
+
+       return strtol(buf, NULL, 10);
+}
+
+int ksm_use_zero_pages(void)
+{
+       int ksm_use_zero_pages_fd;
+       ssize_t ret;
+
+       ksm_use_zero_pages_fd = open("/sys/kernel/mm/ksm/use_zero_pages", 
O_RDWR);
+       if (ksm_use_zero_pages_fd < 0)
+               return -errno;
+
+       ret = write(ksm_use_zero_pages_fd, "1", 1);
+       close(ksm_use_zero_pages_fd);
+       return ret == 1 ? 0 : -errno;
+}
+
+int ksm_start(void)
+{
+       int ksm_fd;
+       ssize_t ret;
+       long start_scans, end_scans;
+
+       ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR);
+       if (ksm_fd < 0)
+               return -errno;
+
+       /* Wait for two full scans such that any possible merging happened. */
+       start_scans = ksm_get_full_scans();
+       if (start_scans < 0) {
+               close(ksm_fd);
+               return start_scans;
+       }
+       ret = write(ksm_fd, "1", 1);
+       close(ksm_fd);
+       if (ret != 1)
+               return -errno;
+       do {
+               end_scans = ksm_get_full_scans();
+               if (end_scans < 0)
+                       return end_scans;
+       } while (end_scans < start_scans + 2);
+
+       return 0;
+}
+
+int ksm_stop(void)
+{
+       int ksm_fd;
+       ssize_t ret;
+
+       ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR);
+       if (ksm_fd < 0)
+               return -errno;
+
+       ret = write(ksm_fd, "2", 1);
+       close(ksm_fd);
+       return ret == 1 ? 0 : -errno;
+}
diff --git a/tools/testing/selftests/mm/vm_util.h 
b/tools/testing/selftests/mm/vm_util.h
index 1843ad48d32b..ba4d9fa44a7d 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -130,6 +130,13 @@ static inline void log_test_result(int result)
 void *sys_mremap(void *old_address, unsigned long old_size,
                 unsigned long new_size, int flags, void *new_address);
 
+long ksm_get_self_zero_pages(void);
+long ksm_get_self_merging_pages(void);
+long ksm_get_full_scans(void);
+int ksm_use_zero_pages(void);
+int ksm_start(void);
+int ksm_stop(void);
+
 /*
  * On ppc64 this will only work with radix 2M hugepage size
  */
-- 
2.34.1


Reply via email to