1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2020 Petr Vorel <[email protected]>
4 * Copyright (c) Linux Test Project, 2009-2020
5 * Copyright (c) Crackerjack Project, 2007-2008, Hitachi, Ltd
6 *
7 * Authors:
8 * Takahiro Yasui <[email protected]>
9 * Yumiko Sugita <[email protected]>
10 * Satoshi Fujiwara <[email protected]>
11 * Manas Kumar Nayak <[email protected]> (original port to the legacy API)
12 */
13
14 /*\
15 * [Description]
16 *
17 * Verify that get_mempolicy() returns a proper return value and errno for various cases.
18 */
19
20 #include "config.h"
21 #include "tst_test.h"
22
23 #ifdef HAVE_NUMA_V2
24 #include <numa.h>
25 #include <numaif.h>
26 #include <errno.h>
27 #include "tst_numa.h"
28
29 #define MEM_LENGTH (4 * 1024 * 1024)
30 #define PAGES_ALLOCATED 16u
31
32 #define POLICY_DESC(x) .policy = x, .desc = "policy: "#x
33 #define POLICY_DESC_NO_TARGET(x) .policy = x, .desc = "policy: "#x", no target"
34 #define POLICY_DESC_FLAGS(x, y) .policy = x, .flags = y, .desc = "policy: "#x", flags: "#y
35 #define POLICY_DESC_FLAGS_NO_TARGET(x, y) .policy = x, .flags = y, .desc = "policy: "#x", flags: "#y", no target"
36
37 static struct tst_nodemap *node;
38 static struct bitmask *nodemask, *getnodemask, *empty_nodemask;
39
40 struct test_case {
41 int policy;
42 const char *desc;
43 unsigned int flags;
44 char *addr;
45 int (*pre_test)(struct test_case *tc);
46 int (*alloc)(struct test_case *tc);
47 struct bitmask **exp_nodemask;
48 };
49
50 static int test_set_mempolicy_default(struct test_case *tc);
51 static int test_set_mempolicy_none(struct test_case *tc);
52 static int test_mbind_none(struct test_case *tc);
53 static int test_mbind_default(struct test_case *tc);
54
55 static struct test_case tcase[] = {
56 {
57 POLICY_DESC_NO_TARGET(MPOL_DEFAULT),
58 .alloc = test_set_mempolicy_none,
59 .exp_nodemask = &nodemask,
60 },
61 {
62 POLICY_DESC(MPOL_BIND),
63 .alloc = test_set_mempolicy_default,
64 .exp_nodemask = &nodemask,
65 },
66 {
67 POLICY_DESC(MPOL_INTERLEAVE),
68 .alloc = test_set_mempolicy_default,
69 .exp_nodemask = &nodemask,
70 },
71 {
72 POLICY_DESC_NO_TARGET(MPOL_PREFERRED),
73 .alloc = test_set_mempolicy_none,
74 .exp_nodemask = &nodemask,
75 },
76 {
77 POLICY_DESC(MPOL_PREFERRED),
78 .alloc = test_set_mempolicy_default,
79 .exp_nodemask = &nodemask,
80 },
81 {
82 POLICY_DESC_FLAGS_NO_TARGET(MPOL_DEFAULT, MPOL_F_ADDR),
83 .pre_test = test_mbind_none,
84 .alloc = test_set_mempolicy_none,
85 .exp_nodemask = &empty_nodemask,
86 },
87 {
88 POLICY_DESC_FLAGS(MPOL_BIND, MPOL_F_ADDR),
89 .pre_test = test_mbind_default,
90 .exp_nodemask = &nodemask,
91 },
92 {
93 POLICY_DESC_FLAGS(MPOL_INTERLEAVE, MPOL_F_ADDR),
94 .pre_test = test_mbind_default,
95 .alloc = test_set_mempolicy_default,
96 .exp_nodemask = &nodemask,
97 },
98 {
99 POLICY_DESC_FLAGS_NO_TARGET(MPOL_PREFERRED, MPOL_F_ADDR),
100 .pre_test = test_mbind_none,
101 .alloc = test_set_mempolicy_none,
102 .exp_nodemask = &empty_nodemask,
103 },
104 {
105 POLICY_DESC_FLAGS(MPOL_PREFERRED, MPOL_F_ADDR),
106 .pre_test = test_mbind_default,
107 .alloc = test_set_mempolicy_default,
108 .exp_nodemask = &nodemask,
109 },
110 };
111
test_set_mempolicy_default(struct test_case * tc)112 static int test_set_mempolicy_default(struct test_case *tc)
113 {
114 TEST(set_mempolicy(tc->policy, nodemask->maskp, nodemask->size));
115 return TST_RET;
116 }
117
test_set_mempolicy_none(struct test_case * tc)118 static int test_set_mempolicy_none(struct test_case *tc)
119 {
120 TEST(set_mempolicy(tc->policy, NULL, 0));
121 return TST_RET;
122 }
123
test_mbind(struct test_case * tc,unsigned long * maskp,unsigned long size)124 static int test_mbind(struct test_case *tc, unsigned long *maskp, unsigned long size)
125 {
126 tc->addr = SAFE_MMAP(NULL, MEM_LENGTH, PROT_READ | PROT_WRITE,
127 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
128
129 TEST(mbind(tc->addr, MEM_LENGTH, tc->policy, maskp, size, 0));
130 return TST_RET;
131 }
132
test_mbind_none(struct test_case * tc)133 static int test_mbind_none(struct test_case *tc)
134 {
135 return test_mbind(tc, NULL, 0);
136 }
137
test_mbind_default(struct test_case * tc)138 static int test_mbind_default(struct test_case *tc)
139 {
140 return test_mbind(tc, nodemask->maskp, nodemask->size);
141 }
142
setup(void)143 static void setup(void)
144 {
145 unsigned int i;
146
147 node = tst_get_nodemap(TST_NUMA_MEM, PAGES_ALLOCATED * getpagesize() / 1024);
148 if (node->cnt < 1)
149 tst_brk(TCONF, "test requires at least one NUMA memory node");
150
151 nodemask = numa_allocate_nodemask();
152 empty_nodemask = numa_allocate_nodemask();
153 getnodemask = numa_allocate_nodemask();
154 numa_bitmask_setbit(nodemask, node->map[0]);
155
156 for (i = 0; i < ARRAY_SIZE(tcase); i++) {
157 struct test_case *tc = &tcase[i];
158
159 if (tc->pre_test && tc->pre_test(tc))
160 tst_brk(TFAIL | TERRNO, "test #%d: mbind() failed", i+1);
161
162 if (tc->alloc && tc->alloc(tc))
163 tst_brk(TFAIL | TERRNO, "test #%d: set_mempolicy() failed", i+1);
164 }
165 }
166
cleanup(void)167 static void cleanup(void)
168 {
169 unsigned int i;
170
171 for (i = 0; i < ARRAY_SIZE(tcase); i++) {
172 struct test_case *tc = &tcase[i];
173
174 if (tc->pre_test)
175 SAFE_MUNMAP(tc->addr, MEM_LENGTH);
176 }
177
178 numa_free_nodemask(nodemask);
179 numa_free_nodemask(getnodemask);
180 tst_nodemap_free(node);
181 }
182
do_test(unsigned int i)183 static void do_test(unsigned int i)
184 {
185 struct test_case *tc = &tcase[i];
186 int policy;
187
188 tst_res(TINFO, "test #%d: %s", i+1, tc->desc);
189
190 TST_EXP_PASS(get_mempolicy(&policy, getnodemask->maskp, getnodemask->size,
191 tc->addr, tc->flags), "%s", tc->desc);
192
193 struct bitmask *exp_mask = *(tc->exp_nodemask);
194
195 if (!numa_bitmask_equal(exp_mask, getnodemask)) {
196 tst_res(TFAIL, "masks are not equal");
197 tst_res_hexd(TINFO, exp_mask->maskp,
198 exp_mask->size / 8, "expected:");
199 tst_res_hexd(TINFO, getnodemask->maskp,
200 getnodemask->size / 8, "returned:");
201 }
202 }
203
204 static struct tst_test test = {
205 .tcnt = ARRAY_SIZE(tcase),
206 .test = do_test,
207 .setup = setup,
208 .cleanup = cleanup,
209 };
210
211 #else
212 TST_TEST_TCONF(NUMA_ERROR_MSG);
213 #endif /* HAVE_NUMA_V2 */
214