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