1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <linux/membarrier.h>
4 #include <syscall.h>
5 #include <stdio.h>
6 #include <errno.h>
7 #include <string.h>
8 
9 #include "../kselftest.h"
10 
sys_membarrier(int cmd,int flags)11 static int sys_membarrier(int cmd, int flags)
12 {
13 	return syscall(__NR_membarrier, cmd, flags);
14 }
15 
test_membarrier_cmd_fail(void)16 static int test_membarrier_cmd_fail(void)
17 {
18 	int cmd = -1, flags = 0;
19 	const char *test_name = "sys membarrier invalid command";
20 
21 	if (sys_membarrier(cmd, flags) != -1) {
22 		ksft_exit_fail_msg(
23 			"%s test: command = %d, flags = %d. Should fail, but passed\n",
24 			test_name, cmd, flags);
25 	}
26 	if (errno != EINVAL) {
27 		ksft_exit_fail_msg(
28 			"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",
29 			test_name, flags, EINVAL, strerror(EINVAL),
30 			errno, strerror(errno));
31 	}
32 
33 	ksft_test_result_pass(
34 		"%s test: command = %d, flags = %d, errno = %d. Failed as expected\n",
35 		test_name, cmd, flags, errno);
36 	return 0;
37 }
38 
test_membarrier_flags_fail(void)39 static int test_membarrier_flags_fail(void)
40 {
41 	int cmd = MEMBARRIER_CMD_QUERY, flags = 1;
42 	const char *test_name = "sys membarrier MEMBARRIER_CMD_QUERY invalid flags";
43 
44 	if (sys_membarrier(cmd, flags) != -1) {
45 		ksft_exit_fail_msg(
46 			"%s test: flags = %d. Should fail, but passed\n",
47 			test_name, flags);
48 	}
49 	if (errno != EINVAL) {
50 		ksft_exit_fail_msg(
51 			"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",
52 			test_name, flags, EINVAL, strerror(EINVAL),
53 			errno, strerror(errno));
54 	}
55 
56 	ksft_test_result_pass(
57 		"%s test: flags = %d, errno = %d. Failed as expected\n",
58 		test_name, flags, errno);
59 	return 0;
60 }
61 
test_membarrier_global_success(void)62 static int test_membarrier_global_success(void)
63 {
64 	int cmd = MEMBARRIER_CMD_GLOBAL, flags = 0;
65 	const char *test_name = "sys membarrier MEMBARRIER_CMD_GLOBAL";
66 
67 	if (sys_membarrier(cmd, flags) != 0) {
68 		ksft_exit_fail_msg(
69 			"%s test: flags = %d, errno = %d\n",
70 			test_name, flags, errno);
71 	}
72 
73 	ksft_test_result_pass(
74 		"%s test: flags = %d\n", test_name, flags);
75 	return 0;
76 }
77 
test_membarrier_private_expedited_fail(void)78 static int test_membarrier_private_expedited_fail(void)
79 {
80 	int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0;
81 	const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED not registered failure";
82 
83 	if (sys_membarrier(cmd, flags) != -1) {
84 		ksft_exit_fail_msg(
85 			"%s test: flags = %d. Should fail, but passed\n",
86 			test_name, flags);
87 	}
88 	if (errno != EPERM) {
89 		ksft_exit_fail_msg(
90 			"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",
91 			test_name, flags, EPERM, strerror(EPERM),
92 			errno, strerror(errno));
93 	}
94 
95 	ksft_test_result_pass(
96 		"%s test: flags = %d, errno = %d\n",
97 		test_name, flags, errno);
98 	return 0;
99 }
100 
test_membarrier_register_private_expedited_success(void)101 static int test_membarrier_register_private_expedited_success(void)
102 {
103 	int cmd = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, flags = 0;
104 	const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED";
105 
106 	if (sys_membarrier(cmd, flags) != 0) {
107 		ksft_exit_fail_msg(
108 			"%s test: flags = %d, errno = %d\n",
109 			test_name, flags, errno);
110 	}
111 
112 	ksft_test_result_pass(
113 		"%s test: flags = %d\n",
114 		test_name, flags);
115 	return 0;
116 }
117 
test_membarrier_private_expedited_success(void)118 static int test_membarrier_private_expedited_success(void)
119 {
120 	int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0;
121 	const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED";
122 
123 	if (sys_membarrier(cmd, flags) != 0) {
124 		ksft_exit_fail_msg(
125 			"%s test: flags = %d, errno = %d\n",
126 			test_name, flags, errno);
127 	}
128 
129 	ksft_test_result_pass(
130 		"%s test: flags = %d\n",
131 		test_name, flags);
132 	return 0;
133 }
134 
test_membarrier_private_expedited_sync_core_fail(void)135 static int test_membarrier_private_expedited_sync_core_fail(void)
136 {
137 	int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, flags = 0;
138 	const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE not registered failure";
139 
140 	if (sys_membarrier(cmd, flags) != -1) {
141 		ksft_exit_fail_msg(
142 			"%s test: flags = %d. Should fail, but passed\n",
143 			test_name, flags);
144 	}
145 	if (errno != EPERM) {
146 		ksft_exit_fail_msg(
147 			"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",
148 			test_name, flags, EPERM, strerror(EPERM),
149 			errno, strerror(errno));
150 	}
151 
152 	ksft_test_result_pass(
153 		"%s test: flags = %d, errno = %d\n",
154 		test_name, flags, errno);
155 	return 0;
156 }
157 
test_membarrier_register_private_expedited_sync_core_success(void)158 static int test_membarrier_register_private_expedited_sync_core_success(void)
159 {
160 	int cmd = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, flags = 0;
161 	const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE";
162 
163 	if (sys_membarrier(cmd, flags) != 0) {
164 		ksft_exit_fail_msg(
165 			"%s test: flags = %d, errno = %d\n",
166 			test_name, flags, errno);
167 	}
168 
169 	ksft_test_result_pass(
170 		"%s test: flags = %d\n",
171 		test_name, flags);
172 	return 0;
173 }
174 
test_membarrier_private_expedited_sync_core_success(void)175 static int test_membarrier_private_expedited_sync_core_success(void)
176 {
177 	int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0;
178 	const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE";
179 
180 	if (sys_membarrier(cmd, flags) != 0) {
181 		ksft_exit_fail_msg(
182 			"%s test: flags = %d, errno = %d\n",
183 			test_name, flags, errno);
184 	}
185 
186 	ksft_test_result_pass(
187 		"%s test: flags = %d\n",
188 		test_name, flags);
189 	return 0;
190 }
191 
test_membarrier_register_global_expedited_success(void)192 static int test_membarrier_register_global_expedited_success(void)
193 {
194 	int cmd = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, flags = 0;
195 	const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED";
196 
197 	if (sys_membarrier(cmd, flags) != 0) {
198 		ksft_exit_fail_msg(
199 			"%s test: flags = %d, errno = %d\n",
200 			test_name, flags, errno);
201 	}
202 
203 	ksft_test_result_pass(
204 		"%s test: flags = %d\n",
205 		test_name, flags);
206 	return 0;
207 }
208 
test_membarrier_global_expedited_success(void)209 static int test_membarrier_global_expedited_success(void)
210 {
211 	int cmd = MEMBARRIER_CMD_GLOBAL_EXPEDITED, flags = 0;
212 	const char *test_name = "sys membarrier MEMBARRIER_CMD_GLOBAL_EXPEDITED";
213 
214 	if (sys_membarrier(cmd, flags) != 0) {
215 		ksft_exit_fail_msg(
216 			"%s test: flags = %d, errno = %d\n",
217 			test_name, flags, errno);
218 	}
219 
220 	ksft_test_result_pass(
221 		"%s test: flags = %d\n",
222 		test_name, flags);
223 	return 0;
224 }
225 
test_membarrier(void)226 static int test_membarrier(void)
227 {
228 	int status;
229 
230 	status = test_membarrier_cmd_fail();
231 	if (status)
232 		return status;
233 	status = test_membarrier_flags_fail();
234 	if (status)
235 		return status;
236 	status = test_membarrier_global_success();
237 	if (status)
238 		return status;
239 	status = test_membarrier_private_expedited_fail();
240 	if (status)
241 		return status;
242 	status = test_membarrier_register_private_expedited_success();
243 	if (status)
244 		return status;
245 	status = test_membarrier_private_expedited_success();
246 	if (status)
247 		return status;
248 	status = sys_membarrier(MEMBARRIER_CMD_QUERY, 0);
249 	if (status < 0) {
250 		ksft_test_result_fail("sys_membarrier() failed\n");
251 		return status;
252 	}
253 	if (status & MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE) {
254 		status = test_membarrier_private_expedited_sync_core_fail();
255 		if (status)
256 			return status;
257 		status = test_membarrier_register_private_expedited_sync_core_success();
258 		if (status)
259 			return status;
260 		status = test_membarrier_private_expedited_sync_core_success();
261 		if (status)
262 			return status;
263 	}
264 	/*
265 	 * It is valid to send a global membarrier from a non-registered
266 	 * process.
267 	 */
268 	status = test_membarrier_global_expedited_success();
269 	if (status)
270 		return status;
271 	status = test_membarrier_register_global_expedited_success();
272 	if (status)
273 		return status;
274 	status = test_membarrier_global_expedited_success();
275 	if (status)
276 		return status;
277 	return 0;
278 }
279 
test_membarrier_query(void)280 static int test_membarrier_query(void)
281 {
282 	int flags = 0, ret;
283 
284 	ret = sys_membarrier(MEMBARRIER_CMD_QUERY, flags);
285 	if (ret < 0) {
286 		if (errno == ENOSYS) {
287 			/*
288 			 * It is valid to build a kernel with
289 			 * CONFIG_MEMBARRIER=n. However, this skips the tests.
290 			 */
291 			ksft_exit_skip(
292 				"sys membarrier (CONFIG_MEMBARRIER) is disabled.\n");
293 		}
294 		ksft_exit_fail_msg("sys_membarrier() failed\n");
295 	}
296 	if (!(ret & MEMBARRIER_CMD_GLOBAL))
297 		ksft_exit_skip(
298 			"sys_membarrier unsupported: CMD_GLOBAL not found.\n");
299 
300 	ksft_test_result_pass("sys_membarrier available\n");
301 	return 0;
302 }
303 
main(int argc,char ** argv)304 int main(int argc, char **argv)
305 {
306 	ksft_print_header();
307 
308 	test_membarrier_query();
309 	test_membarrier();
310 
311 	return ksft_exit_pass();
312 }
313