1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
5 */
6
7 /*
8 * We are testing mbind() EIO error.
9 *
10 * We first fault a allocated page, then attempt to mbind it to a different node.
11 *
12 * This is a regression test for:
13 *
14 * a7f40cfe3b7a mm: mempolicy: make mbind() return -EIO when MPOL_MF_STRICT is specified
15 *
16 */
17
18 #include <errno.h>
19 #include "config.h"
20 #ifdef HAVE_NUMA_H
21 # include <numa.h>
22 # include <numaif.h>
23 #endif
24 #include "tst_test.h"
25 #include "tst_numa.h"
26
27 #ifdef HAVE_NUMA_V2
28
29 static size_t page_size;
30 static struct tst_nodemap *nodes;
31
setup(void)32 static void setup(void)
33 {
34 page_size = getpagesize();
35
36 nodes = tst_get_nodemap(TST_NUMA_MEM, 2 * page_size / 1024);
37 if (nodes->cnt <= 1)
38 tst_brk(TCONF, "Test requires at least two NUMA memory nodes");
39 }
40
cleanup(void)41 static void cleanup(void)
42 {
43 tst_nodemap_free(nodes);
44 }
45
verify_policy(int mode)46 static void verify_policy(int mode)
47 {
48 struct bitmask *bm = numa_allocate_nodemask();
49 unsigned int i;
50 void *ptr;
51 unsigned long size = page_size;
52 int node = 0;
53
54 ptr = tst_numa_map(NULL, size);
55 tst_nodemap_reset_counters(nodes);
56 tst_numa_fault(ptr, size);
57 tst_nodemap_count_pages(nodes, ptr, size);
58 tst_nodemap_print_counters(nodes);
59
60 for (i = 0; i < nodes->cnt; i++) {
61 if (!nodes->counters[i]) {
62 node = nodes->map[i];
63 tst_res(TINFO, "Attempting to bind to node %i", node);
64 numa_bitmask_setbit(bm, node);
65 break;
66 }
67 }
68
69 TEST(mbind(ptr, size, mode, bm->maskp, bm->size + 1, MPOL_MF_STRICT));
70
71 tst_numa_unmap(ptr, size);
72 numa_free_nodemask(bm);
73
74 if (TST_RET != -1) {
75 tst_res(TFAIL,
76 "mbind(%s, MPOL_MF_STRICT) node %u returned %li, expected -1",
77 tst_numa_mode_name(mode), node, TST_RET);
78 return;
79 }
80
81 if (TST_ERR == EIO) {
82 tst_res(TPASS | TTERRNO,
83 "mbind(%s, MPOL_MF_STRICT) node %u",
84 tst_numa_mode_name(mode), node);
85 } else {
86 tst_res(TFAIL | TTERRNO,
87 "mbind(%s, MPOL_MF_STRICT) node %u expected EIO",
88 tst_numa_mode_name(mode), node);
89 }
90 }
91
92 static const int modes[] = {
93 MPOL_PREFERRED,
94 MPOL_BIND,
95 MPOL_INTERLEAVE,
96 };
97
verify_mbind(unsigned int n)98 static void verify_mbind(unsigned int n)
99 {
100 verify_policy(modes[n]);
101 }
102
103 static struct tst_test test = {
104 .setup = setup,
105 .cleanup = cleanup,
106 .test = verify_mbind,
107 .tcnt = ARRAY_SIZE(modes),
108 .tags = (const struct tst_tag[]) {
109 {"linux-git", "a7f40cfe3b7a"},
110 {}
111 }
112 };
113
114 #else
115
116 TST_TEST_TCONF(NUMA_ERROR_MSG);
117
118 #endif /* HAVE_NUMA_H */
119