1f981d8faSAmit Daniel Kachhap // SPDX-License-Identifier: GPL-2.0
2f981d8faSAmit Daniel Kachhap // Copyright (C) 2020 ARM Limited
3f981d8faSAmit Daniel Kachhap
4f981d8faSAmit Daniel Kachhap #define _GNU_SOURCE
5f981d8faSAmit Daniel Kachhap
6f981d8faSAmit Daniel Kachhap #include <errno.h>
7f981d8faSAmit Daniel Kachhap #include <fcntl.h>
8f981d8faSAmit Daniel Kachhap #include <signal.h>
9f981d8faSAmit Daniel Kachhap #include <stdio.h>
10f981d8faSAmit Daniel Kachhap #include <stdlib.h>
11f981d8faSAmit Daniel Kachhap #include <string.h>
12f981d8faSAmit Daniel Kachhap #include <ucontext.h>
13f981d8faSAmit Daniel Kachhap #include <sys/mman.h>
14f981d8faSAmit Daniel Kachhap
15f981d8faSAmit Daniel Kachhap #include "kselftest.h"
16f981d8faSAmit Daniel Kachhap #include "mte_common_util.h"
17f981d8faSAmit Daniel Kachhap #include "mte_def.h"
18f981d8faSAmit Daniel Kachhap
19f981d8faSAmit Daniel Kachhap #define TEST_UNIT 10
20f981d8faSAmit Daniel Kachhap #define PATH_KSM "/sys/kernel/mm/ksm/"
21f981d8faSAmit Daniel Kachhap #define MAX_LOOP 4
22f981d8faSAmit Daniel Kachhap
23f981d8faSAmit Daniel Kachhap static size_t page_sz;
24f981d8faSAmit Daniel Kachhap static unsigned long ksm_sysfs[5];
25f981d8faSAmit Daniel Kachhap
read_sysfs(char * str)26f981d8faSAmit Daniel Kachhap static unsigned long read_sysfs(char *str)
27f981d8faSAmit Daniel Kachhap {
28f981d8faSAmit Daniel Kachhap FILE *f;
29f981d8faSAmit Daniel Kachhap unsigned long val = 0;
30f981d8faSAmit Daniel Kachhap
31f981d8faSAmit Daniel Kachhap f = fopen(str, "r");
32f981d8faSAmit Daniel Kachhap if (!f) {
33f981d8faSAmit Daniel Kachhap ksft_print_msg("ERR: missing %s\n", str);
34f981d8faSAmit Daniel Kachhap return 0;
35f981d8faSAmit Daniel Kachhap }
36*31c88729SAndre Przywara if (fscanf(f, "%lu", &val) != 1) {
37*31c88729SAndre Przywara ksft_print_msg("ERR: parsing %s\n", str);
38*31c88729SAndre Przywara val = 0;
39*31c88729SAndre Przywara }
40f981d8faSAmit Daniel Kachhap fclose(f);
41f981d8faSAmit Daniel Kachhap return val;
42f981d8faSAmit Daniel Kachhap }
43f981d8faSAmit Daniel Kachhap
write_sysfs(char * str,unsigned long val)44f981d8faSAmit Daniel Kachhap static void write_sysfs(char *str, unsigned long val)
45f981d8faSAmit Daniel Kachhap {
46f981d8faSAmit Daniel Kachhap FILE *f;
47f981d8faSAmit Daniel Kachhap
48f981d8faSAmit Daniel Kachhap f = fopen(str, "w");
49f981d8faSAmit Daniel Kachhap if (!f) {
50f981d8faSAmit Daniel Kachhap ksft_print_msg("ERR: missing %s\n", str);
51f981d8faSAmit Daniel Kachhap return;
52f981d8faSAmit Daniel Kachhap }
53f981d8faSAmit Daniel Kachhap fprintf(f, "%lu", val);
54f981d8faSAmit Daniel Kachhap fclose(f);
55f981d8faSAmit Daniel Kachhap }
56f981d8faSAmit Daniel Kachhap
mte_ksm_setup(void)57f981d8faSAmit Daniel Kachhap static void mte_ksm_setup(void)
58f981d8faSAmit Daniel Kachhap {
59f981d8faSAmit Daniel Kachhap ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes");
60f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "merge_across_nodes", 1);
61f981d8faSAmit Daniel Kachhap ksm_sysfs[1] = read_sysfs(PATH_KSM "sleep_millisecs");
62f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "sleep_millisecs", 0);
63f981d8faSAmit Daniel Kachhap ksm_sysfs[2] = read_sysfs(PATH_KSM "run");
64f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "run", 1);
65f981d8faSAmit Daniel Kachhap ksm_sysfs[3] = read_sysfs(PATH_KSM "max_page_sharing");
66f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3] + TEST_UNIT);
67f981d8faSAmit Daniel Kachhap ksm_sysfs[4] = read_sysfs(PATH_KSM "pages_to_scan");
68f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4] + TEST_UNIT);
69f981d8faSAmit Daniel Kachhap }
70f981d8faSAmit Daniel Kachhap
mte_ksm_restore(void)71f981d8faSAmit Daniel Kachhap static void mte_ksm_restore(void)
72f981d8faSAmit Daniel Kachhap {
73f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]);
74f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "sleep_millisecs", ksm_sysfs[1]);
75f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "run", ksm_sysfs[2]);
76f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3]);
77f981d8faSAmit Daniel Kachhap write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4]);
78f981d8faSAmit Daniel Kachhap }
79f981d8faSAmit Daniel Kachhap
mte_ksm_scan(void)80f981d8faSAmit Daniel Kachhap static void mte_ksm_scan(void)
81f981d8faSAmit Daniel Kachhap {
82f981d8faSAmit Daniel Kachhap int cur_count = read_sysfs(PATH_KSM "full_scans");
83f981d8faSAmit Daniel Kachhap int scan_count = cur_count + 1;
84f981d8faSAmit Daniel Kachhap int max_loop_count = MAX_LOOP;
85f981d8faSAmit Daniel Kachhap
86f981d8faSAmit Daniel Kachhap while ((cur_count < scan_count) && max_loop_count) {
87f981d8faSAmit Daniel Kachhap sleep(1);
88f981d8faSAmit Daniel Kachhap cur_count = read_sysfs(PATH_KSM "full_scans");
89f981d8faSAmit Daniel Kachhap max_loop_count--;
90f981d8faSAmit Daniel Kachhap }
91f981d8faSAmit Daniel Kachhap #ifdef DEBUG
92f981d8faSAmit Daniel Kachhap ksft_print_msg("INFO: pages_shared=%lu pages_sharing=%lu\n",
93f981d8faSAmit Daniel Kachhap read_sysfs(PATH_KSM "pages_shared"),
94f981d8faSAmit Daniel Kachhap read_sysfs(PATH_KSM "pages_sharing"));
95f981d8faSAmit Daniel Kachhap #endif
96f981d8faSAmit Daniel Kachhap }
97f981d8faSAmit Daniel Kachhap
check_madvise_options(int mem_type,int mode,int mapping)98f981d8faSAmit Daniel Kachhap static int check_madvise_options(int mem_type, int mode, int mapping)
99f981d8faSAmit Daniel Kachhap {
100f981d8faSAmit Daniel Kachhap char *ptr;
101f981d8faSAmit Daniel Kachhap int err, ret;
102f981d8faSAmit Daniel Kachhap
103f981d8faSAmit Daniel Kachhap err = KSFT_FAIL;
104f981d8faSAmit Daniel Kachhap if (access(PATH_KSM, F_OK) == -1) {
105f981d8faSAmit Daniel Kachhap ksft_print_msg("ERR: Kernel KSM config not enabled\n");
106f981d8faSAmit Daniel Kachhap return err;
107f981d8faSAmit Daniel Kachhap }
108f981d8faSAmit Daniel Kachhap
109f981d8faSAmit Daniel Kachhap mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
110f981d8faSAmit Daniel Kachhap ptr = mte_allocate_memory(TEST_UNIT * page_sz, mem_type, mapping, true);
111f981d8faSAmit Daniel Kachhap if (check_allocated_memory(ptr, TEST_UNIT * page_sz, mem_type, false) != KSFT_PASS)
112f981d8faSAmit Daniel Kachhap return KSFT_FAIL;
113f981d8faSAmit Daniel Kachhap
114f981d8faSAmit Daniel Kachhap /* Insert same data in all the pages */
115f981d8faSAmit Daniel Kachhap memset(ptr, 'A', TEST_UNIT * page_sz);
116f981d8faSAmit Daniel Kachhap ret = madvise(ptr, TEST_UNIT * page_sz, MADV_MERGEABLE);
117f981d8faSAmit Daniel Kachhap if (ret) {
118f981d8faSAmit Daniel Kachhap ksft_print_msg("ERR: madvise failed to set MADV_UNMERGEABLE\n");
119f981d8faSAmit Daniel Kachhap goto madvise_err;
120f981d8faSAmit Daniel Kachhap }
121f981d8faSAmit Daniel Kachhap mte_ksm_scan();
122f981d8faSAmit Daniel Kachhap /* Tagged pages should not merge */
123f981d8faSAmit Daniel Kachhap if ((read_sysfs(PATH_KSM "pages_shared") < 1) ||
124f981d8faSAmit Daniel Kachhap (read_sysfs(PATH_KSM "pages_sharing") < (TEST_UNIT - 1)))
125f981d8faSAmit Daniel Kachhap err = KSFT_PASS;
126f981d8faSAmit Daniel Kachhap madvise_err:
127f981d8faSAmit Daniel Kachhap mte_free_memory(ptr, TEST_UNIT * page_sz, mem_type, true);
128f981d8faSAmit Daniel Kachhap return err;
129f981d8faSAmit Daniel Kachhap }
130f981d8faSAmit Daniel Kachhap
main(int argc,char * argv[])131f981d8faSAmit Daniel Kachhap int main(int argc, char *argv[])
132f981d8faSAmit Daniel Kachhap {
133f981d8faSAmit Daniel Kachhap int err;
134f981d8faSAmit Daniel Kachhap
135f981d8faSAmit Daniel Kachhap err = mte_default_setup();
136f981d8faSAmit Daniel Kachhap if (err)
137f981d8faSAmit Daniel Kachhap return err;
138f981d8faSAmit Daniel Kachhap page_sz = getpagesize();
139f981d8faSAmit Daniel Kachhap if (!page_sz) {
140f981d8faSAmit Daniel Kachhap ksft_print_msg("ERR: Unable to get page size\n");
141f981d8faSAmit Daniel Kachhap return KSFT_FAIL;
142f981d8faSAmit Daniel Kachhap }
143f981d8faSAmit Daniel Kachhap /* Register signal handlers */
144f981d8faSAmit Daniel Kachhap mte_register_signal(SIGBUS, mte_default_handler);
145f981d8faSAmit Daniel Kachhap mte_register_signal(SIGSEGV, mte_default_handler);
146cbb268afSVincenzo Frascino
147cbb268afSVincenzo Frascino /* Set test plan */
148cbb268afSVincenzo Frascino ksft_set_plan(4);
149cbb268afSVincenzo Frascino
150f981d8faSAmit Daniel Kachhap /* Enable KSM */
151f981d8faSAmit Daniel Kachhap mte_ksm_setup();
152f981d8faSAmit Daniel Kachhap
153f981d8faSAmit Daniel Kachhap evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
154f981d8faSAmit Daniel Kachhap "Check KSM mte page merge for private mapping, sync mode and mmap memory\n");
155f981d8faSAmit Daniel Kachhap evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
156f981d8faSAmit Daniel Kachhap "Check KSM mte page merge for private mapping, async mode and mmap memory\n");
157f981d8faSAmit Daniel Kachhap evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
158f981d8faSAmit Daniel Kachhap "Check KSM mte page merge for shared mapping, sync mode and mmap memory\n");
159f981d8faSAmit Daniel Kachhap evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
160f981d8faSAmit Daniel Kachhap "Check KSM mte page merge for shared mapping, async mode and mmap memory\n");
161f981d8faSAmit Daniel Kachhap
162f981d8faSAmit Daniel Kachhap mte_ksm_restore();
163f981d8faSAmit Daniel Kachhap mte_restore_setup();
164f981d8faSAmit Daniel Kachhap ksft_print_cnts();
165f981d8faSAmit Daniel Kachhap return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
166f981d8faSAmit Daniel Kachhap }
167