1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2017 FUJITSU LIMITED. All rights reserved.
4f08c3bdfSopenharmony_ci * Author(s): Xiao Yang <yangx.jy@cn.fujitsu.com>
5f08c3bdfSopenharmony_ci *            Jie Fei <feij.fnst@cn.fujitsu.com>
6f08c3bdfSopenharmony_ci */
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci/*
9f08c3bdfSopenharmony_ci * Description:
10f08c3bdfSopenharmony_ci * This is a regression test for ksm page migration which is miscalculated.
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * The kernel bug has been fixed by:
13f08c3bdfSopenharmony_ci *
14f08c3bdfSopenharmony_ci * commit 4b0ece6fa0167b22c004ff69e137dc94ee2e469e
15f08c3bdfSopenharmony_ci * Author: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
16f08c3bdfSopenharmony_ci * Date:   Fri Mar 31 15:11:44 2017 -0700
17f08c3bdfSopenharmony_ci *
18f08c3bdfSopenharmony_ci *     mm: migrate: fix remove_migration_pte() for ksm pages
19f08c3bdfSopenharmony_ci */
20f08c3bdfSopenharmony_ci
21f08c3bdfSopenharmony_ci#include <errno.h>
22f08c3bdfSopenharmony_ci#include <unistd.h>
23f08c3bdfSopenharmony_ci#include <stdlib.h>
24f08c3bdfSopenharmony_ci#include <pwd.h>
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_ci#include "tst_test.h"
27f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
28f08c3bdfSopenharmony_ci#include "lapi/mmap.h"
29f08c3bdfSopenharmony_ci#include "ksm_helper.h"
30f08c3bdfSopenharmony_ci#include "numa_helper.h"
31f08c3bdfSopenharmony_ci#include "migrate_pages_common.h"
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_ci#ifdef HAVE_NUMA_V2
34f08c3bdfSopenharmony_ci#define N_PAGES 20
35f08c3bdfSopenharmony_ci#define N_LOOPS 600
36f08c3bdfSopenharmony_ci#define TEST_NODES 2
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_cistatic int orig_ksm_run = -1;
39f08c3bdfSopenharmony_cistatic unsigned int page_size;
40f08c3bdfSopenharmony_cistatic void *test_pages[N_PAGES];
41f08c3bdfSopenharmony_cistatic int num_nodes, max_node;
42f08c3bdfSopenharmony_cistatic int *nodes;
43f08c3bdfSopenharmony_cistatic unsigned long *new_nodes[2];
44f08c3bdfSopenharmony_cistatic const char nobody_uid[] = "nobody";
45f08c3bdfSopenharmony_cistatic struct passwd *ltpuser;
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_cistatic void setup(void)
48f08c3bdfSopenharmony_ci{
49f08c3bdfSopenharmony_ci	int n;
50f08c3bdfSopenharmony_ci	unsigned long nodemask_size;
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci	if (access(PATH_KSM, F_OK))
53f08c3bdfSopenharmony_ci		tst_brk(TCONF, "KSM configuration was not enabled");
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	if (get_allowed_nodes_arr(NH_MEMS, &num_nodes, &nodes) < 0)
56f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "get_allowed_nodes() failed");
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_ci	if (num_nodes < TEST_NODES) {
59f08c3bdfSopenharmony_ci		tst_brk(TCONF, "requires NUMA with at least %d node",
60f08c3bdfSopenharmony_ci			TEST_NODES);
61f08c3bdfSopenharmony_ci	}
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	ltpuser = SAFE_GETPWNAM(nobody_uid);
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci	max_node = LTP_ALIGN(get_max_node(), sizeof(unsigned long) * 8);
66f08c3bdfSopenharmony_ci	nodemask_size = max_node / 8;
67f08c3bdfSopenharmony_ci	new_nodes[0] = SAFE_MALLOC(nodemask_size);
68f08c3bdfSopenharmony_ci	new_nodes[1] = SAFE_MALLOC(nodemask_size);
69f08c3bdfSopenharmony_ci	memset(new_nodes[0], 0, nodemask_size);
70f08c3bdfSopenharmony_ci	memset(new_nodes[1], 0, nodemask_size);
71f08c3bdfSopenharmony_ci	set_bit(new_nodes[0], nodes[0], 1);
72f08c3bdfSopenharmony_ci	set_bit(new_nodes[1], nodes[1], 1);
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	page_size = getpagesize();
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	for (n = 0; n < N_PAGES; n++) {
77f08c3bdfSopenharmony_ci		test_pages[n] = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE | PROT_EXEC,
78f08c3bdfSopenharmony_ci					  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
79f08c3bdfSopenharmony_ci		if (madvise(test_pages[n], page_size, MADV_MERGEABLE)) {
80f08c3bdfSopenharmony_ci			if (errno == EINVAL) {
81f08c3bdfSopenharmony_ci				tst_brk(TCONF | TERRNO, "madvise() didn't "
82f08c3bdfSopenharmony_ci					"support MADV_MERGEABLE");
83f08c3bdfSopenharmony_ci			}
84f08c3bdfSopenharmony_ci
85f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO,
86f08c3bdfSopenharmony_ci				"madvise(MADV_MERGEABLE) failed");
87f08c3bdfSopenharmony_ci		}
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci		if (mbind(test_pages[n], page_size, MPOL_BIND, new_nodes[0],
90f08c3bdfSopenharmony_ci			  max_node, 0))
91f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "mbind(MPOL_BIND) failed");
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci		memset(test_pages[n], 0, page_size);
94f08c3bdfSopenharmony_ci	}
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci	SAFE_FILE_SCANF(PATH_KSM "run", "%d", &orig_ksm_run);
97f08c3bdfSopenharmony_ci	SAFE_FILE_PRINTF(PATH_KSM "run", "%d", 1);
98f08c3bdfSopenharmony_ci	wait_ksmd_full_scan();
99f08c3bdfSopenharmony_ci}
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_cistatic void cleanup(void)
102f08c3bdfSopenharmony_ci{
103f08c3bdfSopenharmony_ci	int n;
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_ci	for (n = 0; n < N_PAGES; n++) {
106f08c3bdfSopenharmony_ci		if (test_pages[n])
107f08c3bdfSopenharmony_ci			SAFE_MUNMAP(test_pages[n], page_size);
108f08c3bdfSopenharmony_ci	}
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci	free(new_nodes[0]);
111f08c3bdfSopenharmony_ci	free(new_nodes[1]);
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_ci	if (orig_ksm_run != -1)
114f08c3bdfSopenharmony_ci		SAFE_FILE_PRINTF(PATH_KSM "run", "%d", orig_ksm_run);
115f08c3bdfSopenharmony_ci}
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_cistatic void migrate_test(void)
118f08c3bdfSopenharmony_ci{
119f08c3bdfSopenharmony_ci	int loop, i, ret;
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_ci	SAFE_SETEUID(ltpuser->pw_uid);
122f08c3bdfSopenharmony_ci	for (loop = 0; loop < N_LOOPS; loop++) {
123f08c3bdfSopenharmony_ci		i = loop % 2;
124f08c3bdfSopenharmony_ci		ret = tst_syscall(__NR_migrate_pages, 0, max_node,
125f08c3bdfSopenharmony_ci				   new_nodes[i], new_nodes[i ? 0 : 1]);
126f08c3bdfSopenharmony_ci		if (ret < 0) {
127f08c3bdfSopenharmony_ci			tst_res(TFAIL | TERRNO, "migrate_pages() failed");
128f08c3bdfSopenharmony_ci			return;
129f08c3bdfSopenharmony_ci		}
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_ci		if (!tst_remaining_runtime()) {
132f08c3bdfSopenharmony_ci			tst_res(TINFO, "Out of runtime, exiting...");
133f08c3bdfSopenharmony_ci			break;
134f08c3bdfSopenharmony_ci		}
135f08c3bdfSopenharmony_ci	}
136f08c3bdfSopenharmony_ci	SAFE_SETEUID(0);
137f08c3bdfSopenharmony_ci
138f08c3bdfSopenharmony_ci	tst_res(TPASS, "migrate_pages() passed");
139f08c3bdfSopenharmony_ci}
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_cistatic struct tst_test test = {
142f08c3bdfSopenharmony_ci	.max_runtime = 300,
143f08c3bdfSopenharmony_ci	.needs_root = 1,
144f08c3bdfSopenharmony_ci	.setup = setup,
145f08c3bdfSopenharmony_ci	.cleanup = cleanup,
146f08c3bdfSopenharmony_ci	.test_all = migrate_test,
147f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
148f08c3bdfSopenharmony_ci		{"linux-git", "4b0ece6fa016"},
149f08c3bdfSopenharmony_ci		{}
150f08c3bdfSopenharmony_ci	}
151f08c3bdfSopenharmony_ci};
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_ci#else
154f08c3bdfSopenharmony_ci	TST_TEST_TCONF("require libnuma >= 2 and it's development packages");
155f08c3bdfSopenharmony_ci#endif
156