Merge tag 'tty-5.10-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[platform/kernel/linux-rpi.git] / tools / testing / selftests / arm64 / mte / check_ksm_options.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2020 ARM Limited
3
4 #define _GNU_SOURCE
5
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <signal.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ucontext.h>
13 #include <sys/mman.h>
14
15 #include "kselftest.h"
16 #include "mte_common_util.h"
17 #include "mte_def.h"
18
19 #define TEST_UNIT       10
20 #define PATH_KSM        "/sys/kernel/mm/ksm/"
21 #define MAX_LOOP        4
22
23 static size_t page_sz;
24 static unsigned long ksm_sysfs[5];
25
26 static unsigned long read_sysfs(char *str)
27 {
28         FILE *f;
29         unsigned long val = 0;
30
31         f = fopen(str, "r");
32         if (!f) {
33                 ksft_print_msg("ERR: missing %s\n", str);
34                 return 0;
35         }
36         fscanf(f, "%lu", &val);
37         fclose(f);
38         return val;
39 }
40
41 static void write_sysfs(char *str, unsigned long val)
42 {
43         FILE *f;
44
45         f = fopen(str, "w");
46         if (!f) {
47                 ksft_print_msg("ERR: missing %s\n", str);
48                 return;
49         }
50         fprintf(f, "%lu", val);
51         fclose(f);
52 }
53
54 static void mte_ksm_setup(void)
55 {
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);
66 }
67
68 static void mte_ksm_restore(void)
69 {
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]);
75 }
76
77 static void mte_ksm_scan(void)
78 {
79         int cur_count = read_sysfs(PATH_KSM "full_scans");
80         int scan_count = cur_count + 1;
81         int max_loop_count = MAX_LOOP;
82
83         while ((cur_count < scan_count) && max_loop_count) {
84                 sleep(1);
85                 cur_count = read_sysfs(PATH_KSM "full_scans");
86                 max_loop_count--;
87         }
88 #ifdef DEBUG
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"));
92 #endif
93 }
94
95 static int check_madvise_options(int mem_type, int mode, int mapping)
96 {
97         char *ptr;
98         int err, ret;
99
100         err = KSFT_FAIL;
101         if (access(PATH_KSM, F_OK) == -1) {
102                 ksft_print_msg("ERR: Kernel KSM config not enabled\n");
103                 return err;
104         }
105
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)
109                 return KSFT_FAIL;
110
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);
114         if (ret) {
115                 ksft_print_msg("ERR: madvise failed to set MADV_UNMERGEABLE\n");
116                 goto madvise_err;
117         }
118         mte_ksm_scan();
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)))
122                 err = KSFT_PASS;
123 madvise_err:
124         mte_free_memory(ptr, TEST_UNIT * page_sz, mem_type, true);
125         return err;
126 }
127
128 int main(int argc, char *argv[])
129 {
130         int err;
131
132         err = mte_default_setup();
133         if (err)
134                 return err;
135         page_sz = getpagesize();
136         if (!page_sz) {
137                 ksft_print_msg("ERR: Unable to get page size\n");
138                 return KSFT_FAIL;
139         }
140         /* Register signal handlers */
141         mte_register_signal(SIGBUS, mte_default_handler);
142         mte_register_signal(SIGSEGV, mte_default_handler);
143
144         /* Set test plan */
145         ksft_set_plan(4);
146
147         /* Enable KSM */
148         mte_ksm_setup();
149
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");
158
159         mte_ksm_restore();
160         mte_restore_setup();
161         ksft_print_cnts();
162         return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
163 }