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