xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/membarrier/membarrier01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2018 Linaro Limited. All rights reserved.
4  * Author: Rafael David Tinoco <[email protected]>
5  */
6 /*
7  * Basic tests for membarrier(2) syscall. Tests below are responsible for
8  * testing the membarrier(2) interface only, without checking if the barrier
9  * was successful or not. Check test_case structure for each test description.
10  */
11 
12 #include "config.h"
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/wait.h>
16 #include <syscall.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "tst_test.h"
25 #include "lapi/syscalls.h"
26 #include "lapi/membarrier.h"
27 
28 struct test_case {
29 	char testname[80];
30 	int command;		/* membarrier cmd                            */
31 	int needregister;	/* membarrier cmd needs register cmd	     */
32 	int flags;		/* flags for given membarrier cmd	     */
33 	long exp_ret;		/* expected return code for given cmd        */
34 	int exp_errno;		/* expected errno for given cmd failure      */
35 	int enabled;		/* enabled, despite results from CMD_QUERY   */
36 	int always;		/* CMD_QUERY should always enable this test  */
37 	int force;		/* force if CMD_QUERY reports not enabled    */
38 	int force_exp_errno;	/* expected errno after forced cmd           */
39 	int change_exp_errno;	/* previous kernels forced errno result      */
40 	int change_kernver[3];	/* kernel version having diff expected errno */
41 };
42 
43 struct test_case tc[] = {
44 	{
45 	 /*
46 	  * case 00) invalid cmd
47 	  *     - enabled by default
48 	  *     - should always fail with EINVAL
49 	  */
50 	 .testname = "cmd_fail",
51 	 .command = -1,
52 	 .exp_ret = -1,
53 	 .exp_errno = EINVAL,
54 	 .enabled = 1,
55 	 },
56 	{
57 	 /*
58 	  * case 01) invalid flags
59 	  *     - enabled by default
60 	  *     - should always fail with EINVAL
61 	  */
62 	 .testname = "cmd_flags_fail",
63 	 .command = MEMBARRIER_CMD_QUERY,
64 	 .flags = 1,
65 	 .exp_ret = -1,
66 	 .exp_errno = EINVAL,
67 	 .enabled = 1,
68 	 },
69 	{
70 	 /*
71 	  * case 02) global barrier
72 	  *     - should ALWAYS be enabled by CMD_QUERY
73 	  *     - should always succeed
74 	  */
75 	 .testname = "cmd_global_success",
76 	 .command = MEMBARRIER_CMD_GLOBAL,
77 	 .flags = 0,
78 	 .exp_ret = 0,
79 	 .always = 1,
80 	 },
81 	 /*
82 	  * commit 22e4ebb975 (v4.14-rc1) added cases 03, 04 and 05 features:
83 	  */
84 	{
85 	 /*
86 	  * case 03) private expedited barrier with no registrations
87 	  *     - should fail with errno=EPERM due to no registrations
88 	  *     - or be skipped if unsupported by running kernel
89 	  */
90 	 .testname = "cmd_private_expedited_fail",
91 	 .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED,
92 	 .flags = 0,
93 	 .exp_ret = -1,
94 	 .exp_errno = EPERM,
95 	 },
96 	{
97 	 /*
98 	  * case 04) register private expedited
99 	  *     - should succeed when supported by running kernel
100 	  *     - or fail with errno=EINVAL if unsupported and forced
101 	  */
102 	 .testname = "cmd_private_expedited_register_success",
103 	 .command = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED,
104 	 .flags = 0,
105 	 .exp_ret = 0,
106 	 .force = 1,
107 	 .force_exp_errno = EINVAL,
108 	 },
109 	{
110 	 /*
111 	  * case 05) private expedited barrier with registration
112 	  *     - should succeed due to existing registration
113 	  *     - or fail with errno=EINVAL if unsupported and forced
114 	  *     - NOTE: commit 70216e18e5 (v4.16-rc1) changed behavior:
115 	  *     -       (a) if unsupported, and forced, < 4.16 , errno is EINVAL
116 	  *     -       (b) if unsupported, and forced, >= 4.16, errno is EPERM
117 	  */
118 	 .testname = "cmd_private_expedited_success",
119 	 .needregister = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED,
120 	 .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED,
121 	 .flags = 0,
122 	 .exp_ret = 0,
123 	 .force = 1,
124 	 .force_exp_errno = EPERM,
125 	 .change_exp_errno = EINVAL,
126 	 .change_kernver = { 4, 16, 0 },
127 	 },
128 	 /*
129 	  * commit 70216e18e5 (v4.16-rc1) added cases 06, 07 and 08 features:
130 	  */
131 	{
132 	 /*
133 	  * case 06) private expedited sync core barrier with no registrations
134 	  *     - should fail with errno=EPERM due to no registrations
135 	  *     - or be skipped if unsupported by running kernel
136 	  */
137 	 .testname = "cmd_private_expedited_sync_core_fail",
138 	 .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE,
139 	 .flags = 0,
140 	 .exp_ret = -1,
141 	 .exp_errno = EPERM,
142 	 },
143 	{
144 	 /*
145 	  * case 07) register private expedited sync core
146 	  *     - should succeed when supported by running kernel
147 	  *     - or fail with errno=EINVAL if unsupported and forced
148 	  */
149 	 .testname = "cmd_private_expedited_sync_core_register_success",
150 	 .command = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
151 	 .flags = 0,
152 	 .exp_ret = 0,
153 	 .force = 1,
154 	 .force_exp_errno = EINVAL,
155 	 },
156 	{
157 	 /*
158 	  * case 08) private expedited sync core barrier with registration
159 	  *     - should succeed due to existing registration
160 	  *     - or fail with errno=EINVAL if unsupported and forced
161 	  */
162 	 .testname = "cmd_private_expedited_sync_core_success",
163 	 .needregister = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,
164 	 .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE,
165 	 .flags = 0,
166 	 .exp_ret = 0,
167 	 .force = 1,
168 	 .force_exp_errno = EINVAL,
169 	 },
170 	 /*
171 	  * commit c5f58bd58f4 (v4.16-rc1) added cases 09, 10 and 11 features:
172 	  */
173 	{
174 	 /*
175 	  * case 09) global expedited barrier with no registrations
176 	  *     - should never fail due to no registrations
177 	  *     - or be skipped if unsupported by running kernel
178 	  */
179 	 .testname = "cmd_global_expedited_success",
180 	 .command = MEMBARRIER_CMD_GLOBAL_EXPEDITED,
181 	 .flags = 0,
182 	 .exp_ret = 0,
183 	 },
184 	{
185 	 /*
186 	  * case 10) register global expedited
187 	  *     - should succeed when supported by running kernel
188 	  *     - or fail with errno=EINVAL if unsupported and forced
189 	  */
190 	 .testname = "cmd_global_expedited_register_success",
191 	 .command = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED,
192 	 .flags = 0,
193 	 .exp_ret = 0,
194 	 .force = 1,
195 	 .force_exp_errno = EINVAL,
196 	 },
197 	{
198 	 /*
199 	  * case 11) global expedited barrier with registration
200 	  *     - should also succeed with registrations
201 	  *     - or fail with errno=EINVAL if unsupported and forced
202 	  */
203 	 .testname = "cmd_global_expedited_success",
204 	 .needregister = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED,
205 	 .command = MEMBARRIER_CMD_GLOBAL_EXPEDITED,
206 	 .flags = 0,
207 	 .exp_ret = 0,
208 	 .force = 1,
209 	 .force_exp_errno = EINVAL,
210 	 },
211 };
212 
213 #define passed_ok(_test)						       \
214 	do {								       \
215 		tst_res(TPASS, "membarrier(2): %s passed", _test.testname);    \
216 		return;							       \
217 	} while (0)
218 
219 #define passed_unexpec(_test)						       \
220 	do {								       \
221 		tst_res(TFAIL, "membarrier(2): %s passed unexpectedly. "       \
222 			"ret = %ld with errno %d were expected. (force: %d)",  \
223 			_test.testname, _test.exp_ret, _test.exp_errno,        \
224 			_test.force);					       \
225 		return;							       \
226 	} while (0)
227 
228 #define failed_ok(_test)						       \
229 	do {								       \
230 		tst_res(TPASS, "membarrier(2): %s failed as expected",	       \
231 			_test.testname);				       \
232 		return;							       \
233 	} while (0)
234 
235 #define failed_ok_unsupported(_test)					       \
236 	do {								       \
237 		tst_res(TPASS, "membarrier(2): %s failed as expected "	       \
238 			"(unsupported)", _test.testname);		       \
239 		return;							       \
240 	} while (0)
241 
242 #define failed_not_ok(_test, _gotret, _goterr)				       \
243 	do {								       \
244 		tst_res(TFAIL, "membarrier(2): %s failed. "		       \
245 			"ret = %ld when expected was %ld. "		       \
246 			"errno = %d when expected was %d. (force: %d)",        \
247 			_test.testname, _gotret, _test.exp_ret, _goterr,       \
248 			_test.exp_errno, _test.force);			       \
249 		return;							       \
250 	} while (0)
251 
252 #define failed_unexpec(_test, _gotret, _goterr) 			       \
253 	do {								       \
254 		tst_res(TFAIL, "membarrier(2): %s failed unexpectedly. "       \
255 			"Got ret = %ld with errno %d. (force: %d)",	       \
256 			_test.testname, _gotret, _goterr, _test.force);	       \
257 		return;							       \
258 	} while (0)
259 
260 #define skipped(_test)							       \
261 	do {								       \
262 		tst_res(TPASS, "membarrier(2): %s skipped (unsupported)",      \
263 			_test.testname);				       \
264 		return;							       \
265 	} while (0)
266 
267 #define skipped_fail(_test)						       \
268 	do {								       \
269 		tst_res(TFAIL, "membarrier(2): %s reported as not supported",  \
270 			_test.testname);				       \
271 		return;							       \
272 	} while (0)
273 
sys_membarrier(int cmd,int flags)274 static int sys_membarrier(int cmd, int flags)
275 {
276 	return tst_syscall(__NR_membarrier, cmd, flags);
277 }
278 
verify_membarrier(unsigned int i)279 static void verify_membarrier(unsigned int i)
280 {
281 	int ret;
282 
283 	/* not enabled and not enforced: test is skipped */
284 
285 	if (!tc[i].enabled && !tc[i].force) {
286 
287 		if (tc[i].always == 0)
288 			skipped(tc[i]);
289 
290 		skipped_fail(tc[i]);
291 	}
292 
293 	/* iterations: registration needed for some cases */
294 
295 	if (tc[i].needregister && tc[i].enabled) {
296 		ret = sys_membarrier(tc[i].needregister, 0);
297 		if (ret < 0) {
298 			tst_brk(TBROK, "membarrier(2): %s could not register",
299 					tc[i].testname);
300 		}
301 	}
302 
303 	TEST(sys_membarrier(tc[i].command, tc[i].flags));
304 
305 	/* enabled and not enforced: regular expected results only */
306 
307 	if (tc[i].enabled && !tc[i].force) {
308 
309 		if (TST_RET >= 0 && tc[i].exp_ret == TST_RET)
310 			passed_ok(tc[i]);
311 
312 		if (TST_RET < 0) {
313 			if (tc[i].exp_ret == TST_RET)
314 				failed_ok(tc[i]);
315 			else
316 				failed_not_ok(tc[i], TST_RET, TST_ERR);
317 		}
318 	}
319 
320 	/* not enabled and enforced: failure and expected errors */
321 
322 	if (!tc[i].enabled && tc[i].force) {
323 
324 		if (TST_RET >= 0)
325 			passed_unexpec(tc[i]);
326 
327 		if (TST_RET < 0) {
328 			if (tc[i].force_exp_errno == TST_ERR)
329 				failed_ok_unsupported(tc[i]);
330 			else
331 				failed_unexpec(tc[i], TST_RET, TST_ERR);
332 		}
333 	}
334 
335 	/* enabled and enforced: tricky */
336 
337 	if (tc[i].enabled && tc[i].force) {
338 
339 		if (TST_RET >= 0) {
340 			if (tc[i].exp_ret == TST_RET)
341 				passed_ok(tc[i]);
342 			else
343 				passed_unexpec(tc[i]);
344 		}
345 
346 		if (TST_RET < 0) {
347 
348 			if (tc[i].exp_ret == TST_RET) {
349 
350 				if (tc[i].exp_errno == TST_ERR)
351 					failed_ok(tc[i]);
352 				else
353 					failed_unexpec(tc[i], TST_RET, TST_ERR);
354 			}
355 
356 			/* unknown on force failure if enabled and forced */
357 			failed_unexpec(tc[i], TST_RET, TST_ERR);
358 		}
359 	}
360 }
361 
wrap_verify_membarrier(unsigned int i)362 static void wrap_verify_membarrier(unsigned int i)
363 {
364 	pid_t pid;
365 
366 	/*
367 	 * The Linux kernel does not provide a way to unregister the process
368 	 * (mm->membarrier_state) intent of being affected by the membarrier(2)
369 	 * system call, thus the need of having a wrapper to fork() a child.
370 	 */
371 
372 	pid = SAFE_FORK();
373 
374 	if (pid)
375 		SAFE_WAITPID(pid, NULL, 0);
376 	else
377 		verify_membarrier(i);
378 }
379 
setup(void)380 static void setup(void)
381 {
382 	size_t i;
383 	int ret;
384 
385 	ret = sys_membarrier(MEMBARRIER_CMD_QUERY, 0);
386 	if (ret < 0) {
387 		if (errno == ENOSYS)
388 			tst_brk(TBROK, "membarrier(2): not supported");
389 	}
390 
391 	for (i = 0; i < ARRAY_SIZE(tc); i++) {
392 		if ((tc[i].command > 0) && (ret & tc[i].command))
393 			tc[i].enabled = 1;
394 
395 		/* forcing unsupported command might have different errno */
396 
397 		if (tc[i].change_exp_errno && tc[i].enabled == 0) {
398 			if (tst_kvercmp(tc[i].change_kernver[0],
399 					tc[i].change_kernver[1],
400 					tc[i].change_kernver[2]) < 0)
401 				tc[i].force_exp_errno = tc[i].change_exp_errno;
402 		}
403 	}
404 }
405 
406 static struct tst_test test = {
407 	.setup = setup,
408 	.test = wrap_verify_membarrier,
409 	.tcnt = ARRAY_SIZE(tc),
410 	.min_kver = "4.3.0",	/* commit: 5b25b13ab0 (sys_membarrier(): ...) */
411 	.forks_child = 1,
412 };
413