xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/mbind/mbind03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2019 Cyril Hrubis <[email protected]>
4  */
5 
6 /*
7  * We are testing mbind() MPOL_MF_MOVE and MPOL_MF_MOVE_ALL.
8  *
9  * If one of these flags is passed along with the policy kernel attempts to
10  * move already faulted pages to match the requested policy.
11  */
12 
13 #include <errno.h>
14 #include "config.h"
15 #ifdef HAVE_NUMA_H
16 # include <numa.h>
17 # include <numaif.h>
18 # include "mbind.h"
19 #endif
20 #include "tst_test.h"
21 #include "tst_numa.h"
22 
23 #ifdef HAVE_NUMA_V2
24 
25 static size_t page_size;
26 static struct tst_nodemap *nodes;
27 
setup(void)28 static void setup(void)
29 {
30 	page_size = getpagesize();
31 
32 	nodes = tst_get_nodemap(TST_NUMA_MEM, 2 * page_size / 1024);
33 	if (nodes->cnt <= 1)
34 		tst_brk(TCONF, "Test requires at least two NUMA memory nodes");
35 }
36 
cleanup(void)37 static void cleanup(void)
38 {
39 	tst_nodemap_free(nodes);
40 }
41 
verify_policy(int mode,unsigned flag)42 static void verify_policy(int mode, unsigned flag)
43 {
44 	struct bitmask *bm = numa_allocate_nodemask();
45 	unsigned int i;
46 	void *ptr;
47 	unsigned long size = page_size;
48 	unsigned int node = 0;
49 
50 	ptr = tst_numa_map(NULL, size);
51 	tst_nodemap_reset_counters(nodes);
52 	tst_numa_fault(ptr, size);
53 	tst_nodemap_count_pages(nodes, ptr, size);
54 	tst_nodemap_print_counters(nodes);
55 
56 	for (i = 0; i < nodes->cnt; i++) {
57 		if (!nodes->counters[i]) {
58 			node = nodes->map[i];
59 			tst_res(TINFO, "Attempting to move to node %i", node);
60 			numa_bitmask_setbit(bm, node);
61 			break;
62 		}
63 	}
64 
65 	TEST(mbind(ptr, size, mode, bm->maskp, bm->size + 1, flag));
66 
67 	if (TST_RET) {
68 		tst_res(TFAIL | TTERRNO,
69 		        "mbind(%s, %s) node %u",
70 		        tst_mempolicy_mode_name(mode), mbind_flag_name(flag), node);
71 		goto exit;
72 	} else {
73 		tst_res(TPASS, "mbind(%s, %s) node %u succeded",
74 		        tst_mempolicy_mode_name(mode), mbind_flag_name(flag), node);
75 	}
76 
77 	tst_nodemap_reset_counters(nodes);
78 	tst_nodemap_count_pages(nodes, ptr, size);
79 
80 	for (i = 0; i < nodes->cnt; i++) {
81 		if (nodes->map[i] == node) {
82 			if (nodes->counters[i] == 1) {
83 				tst_res(TPASS, "Node %u allocated %u", node, 1);
84 			} else {
85 				tst_res(TFAIL, "Node %u allocated %u, expected %u",
86 				        node, nodes->counters[i], 0);
87 			}
88 			continue;
89 		}
90 
91 		if (nodes->counters[i]) {
92 			tst_res(TFAIL, "Node %u allocated %u, expected 0",
93 			        i, nodes->counters[i]);
94 		}
95 	}
96 
97 exit:
98 	tst_numa_unmap(ptr, size);
99 	numa_free_nodemask(bm);
100 }
101 
102 static const int modes[] = {
103 	MPOL_PREFERRED,
104 	MPOL_BIND,
105 	MPOL_INTERLEAVE,
106 };
107 
verify_mbind(unsigned int n)108 static void verify_mbind(unsigned int n)
109 {
110 	verify_policy(modes[n], MPOL_MF_MOVE);
111 	verify_policy(modes[n], MPOL_MF_MOVE_ALL);
112 }
113 
114 static struct tst_test test = {
115 	.setup = setup,
116 	.cleanup = cleanup,
117 	.test = verify_mbind,
118 	.tcnt = ARRAY_SIZE(modes),
119 	.needs_root = 1,
120 };
121 
122 #else
123 
124 TST_TEST_TCONF(NUMA_ERROR_MSG);
125 
126 #endif /* HAVE_NUMA_H */
127