1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2020 ARM Limited
15 #include "kselftest.h"
16 #include "mte_common_util.h"
20 #define PATH_KSM "/sys/kernel/mm/ksm/"
23 static size_t page_sz;
24 static unsigned long ksm_sysfs[5];
26 static unsigned long read_sysfs(char *str)
29 unsigned long val = 0;
33 ksft_print_msg("ERR: missing %s\n", str);
36 fscanf(f, "%lu", &val);
41 static void write_sysfs(char *str, unsigned long val)
47 ksft_print_msg("ERR: missing %s\n", str);
50 fprintf(f, "%lu", val);
54 static void mte_ksm_setup(void)
56 ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes");
57 write_sysfs(PATH_KSM "merge_across_nodes", 1);
58 ksm_sysfs[1] = read_sysfs(PATH_KSM "sleep_millisecs");
59 write_sysfs(PATH_KSM "sleep_millisecs", 0);
60 ksm_sysfs[2] = read_sysfs(PATH_KSM "run");
61 write_sysfs(PATH_KSM "run", 1);
62 ksm_sysfs[3] = read_sysfs(PATH_KSM "max_page_sharing");
63 write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3] + TEST_UNIT);
64 ksm_sysfs[4] = read_sysfs(PATH_KSM "pages_to_scan");
65 write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4] + TEST_UNIT);
68 static void mte_ksm_restore(void)
70 write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]);
71 write_sysfs(PATH_KSM "sleep_millisecs", ksm_sysfs[1]);
72 write_sysfs(PATH_KSM "run", ksm_sysfs[2]);
73 write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3]);
74 write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4]);
77 static void mte_ksm_scan(void)
79 int cur_count = read_sysfs(PATH_KSM "full_scans");
80 int scan_count = cur_count + 1;
81 int max_loop_count = MAX_LOOP;
83 while ((cur_count < scan_count) && max_loop_count) {
85 cur_count = read_sysfs(PATH_KSM "full_scans");
89 ksft_print_msg("INFO: pages_shared=%lu pages_sharing=%lu\n",
90 read_sysfs(PATH_KSM "pages_shared"),
91 read_sysfs(PATH_KSM "pages_sharing"));
95 static int check_madvise_options(int mem_type, int mode, int mapping)
101 if (access(PATH_KSM, F_OK) == -1) {
102 ksft_print_msg("ERR: Kernel KSM config not enabled\n");
106 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
107 ptr = mte_allocate_memory(TEST_UNIT * page_sz, mem_type, mapping, true);
108 if (check_allocated_memory(ptr, TEST_UNIT * page_sz, mem_type, false) != KSFT_PASS)
111 /* Insert same data in all the pages */
112 memset(ptr, 'A', TEST_UNIT * page_sz);
113 ret = madvise(ptr, TEST_UNIT * page_sz, MADV_MERGEABLE);
115 ksft_print_msg("ERR: madvise failed to set MADV_UNMERGEABLE\n");
119 /* Tagged pages should not merge */
120 if ((read_sysfs(PATH_KSM "pages_shared") < 1) ||
121 (read_sysfs(PATH_KSM "pages_sharing") < (TEST_UNIT - 1)))
124 mte_free_memory(ptr, TEST_UNIT * page_sz, mem_type, true);
128 int main(int argc, char *argv[])
132 err = mte_default_setup();
135 page_sz = getpagesize();
137 ksft_print_msg("ERR: Unable to get page size\n");
140 /* Register signal handlers */
141 mte_register_signal(SIGBUS, mte_default_handler);
142 mte_register_signal(SIGSEGV, mte_default_handler);
150 evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
151 "Check KSM mte page merge for private mapping, sync mode and mmap memory\n");
152 evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
153 "Check KSM mte page merge for private mapping, async mode and mmap memory\n");
154 evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
155 "Check KSM mte page merge for shared mapping, sync mode and mmap memory\n");
156 evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
157 "Check KSM mte page merge for shared mapping, async mode and mmap memory\n");
162 return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;