Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/mte/check_ksm_options.c
26296 views
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
if (fscanf(f, "%lu", &val) != 1) {
37
ksft_print_msg("ERR: parsing %s\n", str);
38
val = 0;
39
}
40
fclose(f);
41
return val;
42
}
43
44
static void write_sysfs(char *str, unsigned long val)
45
{
46
FILE *f;
47
48
f = fopen(str, "w");
49
if (!f) {
50
ksft_print_msg("ERR: missing %s\n", str);
51
return;
52
}
53
fprintf(f, "%lu", val);
54
fclose(f);
55
}
56
57
static void mte_ksm_setup(void)
58
{
59
ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes");
60
write_sysfs(PATH_KSM "merge_across_nodes", 1);
61
ksm_sysfs[1] = read_sysfs(PATH_KSM "sleep_millisecs");
62
write_sysfs(PATH_KSM "sleep_millisecs", 0);
63
ksm_sysfs[2] = read_sysfs(PATH_KSM "run");
64
write_sysfs(PATH_KSM "run", 1);
65
ksm_sysfs[3] = read_sysfs(PATH_KSM "max_page_sharing");
66
write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3] + TEST_UNIT);
67
ksm_sysfs[4] = read_sysfs(PATH_KSM "pages_to_scan");
68
write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4] + TEST_UNIT);
69
}
70
71
static void mte_ksm_restore(void)
72
{
73
write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]);
74
write_sysfs(PATH_KSM "sleep_millisecs", ksm_sysfs[1]);
75
write_sysfs(PATH_KSM "run", ksm_sysfs[2]);
76
write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3]);
77
write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4]);
78
}
79
80
static void mte_ksm_scan(void)
81
{
82
int cur_count = read_sysfs(PATH_KSM "full_scans");
83
int scan_count = cur_count + 1;
84
int max_loop_count = MAX_LOOP;
85
86
while ((cur_count < scan_count) && max_loop_count) {
87
sleep(1);
88
cur_count = read_sysfs(PATH_KSM "full_scans");
89
max_loop_count--;
90
}
91
#ifdef DEBUG
92
ksft_print_msg("INFO: pages_shared=%lu pages_sharing=%lu\n",
93
read_sysfs(PATH_KSM "pages_shared"),
94
read_sysfs(PATH_KSM "pages_sharing"));
95
#endif
96
}
97
98
static int check_madvise_options(int mem_type, int mode, int mapping)
99
{
100
char *ptr;
101
int err, ret;
102
103
err = KSFT_FAIL;
104
if (access(PATH_KSM, F_OK) == -1) {
105
ksft_print_msg("ERR: Kernel KSM config not enabled\n");
106
return err;
107
}
108
109
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
110
ptr = mte_allocate_memory(TEST_UNIT * page_sz, mem_type, mapping, true);
111
if (check_allocated_memory(ptr, TEST_UNIT * page_sz, mem_type, false) != KSFT_PASS)
112
return KSFT_FAIL;
113
114
/* Insert same data in all the pages */
115
memset(ptr, 'A', TEST_UNIT * page_sz);
116
ret = madvise(ptr, TEST_UNIT * page_sz, MADV_MERGEABLE);
117
if (ret) {
118
ksft_print_msg("ERR: madvise failed to set MADV_UNMERGEABLE\n");
119
goto madvise_err;
120
}
121
mte_ksm_scan();
122
/* Tagged pages should not merge */
123
if ((read_sysfs(PATH_KSM "pages_shared") < 1) ||
124
(read_sysfs(PATH_KSM "pages_sharing") < (TEST_UNIT - 1)))
125
err = KSFT_PASS;
126
madvise_err:
127
mte_free_memory(ptr, TEST_UNIT * page_sz, mem_type, true);
128
return err;
129
}
130
131
int main(int argc, char *argv[])
132
{
133
int err;
134
135
err = mte_default_setup();
136
if (err)
137
return err;
138
page_sz = getpagesize();
139
if (!page_sz) {
140
ksft_print_msg("ERR: Unable to get page size\n");
141
return KSFT_FAIL;
142
}
143
/* Register signal handlers */
144
mte_register_signal(SIGBUS, mte_default_handler, false);
145
mte_register_signal(SIGSEGV, mte_default_handler, false);
146
147
/* Set test plan */
148
ksft_set_plan(4);
149
150
/* Enable KSM */
151
mte_ksm_setup();
152
153
evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
154
"Check KSM mte page merge for private mapping, sync mode and mmap memory\n");
155
evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
156
"Check KSM mte page merge for private mapping, async mode and mmap memory\n");
157
evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
158
"Check KSM mte page merge for shared mapping, sync mode and mmap memory\n");
159
evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
160
"Check KSM mte page merge for shared mapping, async mode and mmap memory\n");
161
162
mte_ksm_restore();
163
mte_restore_setup();
164
ksft_print_cnts();
165
return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
166
}
167
168