1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (C) 2010-2017  Red Hat, Inc.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * This program is free software;  you can redistribute it and/or modify
5f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by
6f08c3bdfSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
7f08c3bdfSopenharmony_ci * (at your option) any later version.
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful,
10f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY;  without even the implied warranty of
11f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12f08c3bdfSopenharmony_ci * the GNU General Public License for more details.
13f08c3bdfSopenharmony_ci *
14f08c3bdfSopenharmony_ci * Out Of Memory when changing cpuset's mems on NUMA. There was a
15f08c3bdfSopenharmony_ci * problem reported upstream that the allocator may see an empty
16f08c3bdfSopenharmony_ci * nodemask when changing cpuset's mems.
17f08c3bdfSopenharmony_ci * http://lkml.org/lkml/2010/5/4/77
18f08c3bdfSopenharmony_ci * http://lkml.org/lkml/2010/5/4/79
19f08c3bdfSopenharmony_ci * http://lkml.org/lkml/2010/5/4/80
20f08c3bdfSopenharmony_ci * This test is based on the reproducers for the above issue.
21f08c3bdfSopenharmony_ci */
22f08c3bdfSopenharmony_ci
23f08c3bdfSopenharmony_ci#include "config.h"
24f08c3bdfSopenharmony_ci#include <stdio.h>
25f08c3bdfSopenharmony_ci#include <sys/wait.h>
26f08c3bdfSopenharmony_ci#if HAVE_NUMA_H
27f08c3bdfSopenharmony_ci#include <numa.h>
28f08c3bdfSopenharmony_ci#endif
29f08c3bdfSopenharmony_ci#if HAVE_NUMAIF_H
30f08c3bdfSopenharmony_ci#include <numaif.h>
31f08c3bdfSopenharmony_ci#endif
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_ci#include "mem.h"
34f08c3bdfSopenharmony_ci#include "numa_helper.h"
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_ci#ifdef HAVE_NUMA_V2
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_civolatile int end;
39f08c3bdfSopenharmony_cistatic int *nodes;
40f08c3bdfSopenharmony_cistatic int nnodes;
41f08c3bdfSopenharmony_cistatic long ncpus;
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_cistatic void sighandler(int signo LTP_ATTRIBUTE_UNUSED);
44f08c3bdfSopenharmony_cistatic int mem_hog(void);
45f08c3bdfSopenharmony_cistatic int mem_hog_cpuset(int ntasks);
46f08c3bdfSopenharmony_cistatic long count_cpu(void);
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_cistatic void test_cpuset(void)
49f08c3bdfSopenharmony_ci{
50f08c3bdfSopenharmony_ci	int child, i;
51f08c3bdfSopenharmony_ci	unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 };
52f08c3bdfSopenharmony_ci	char buf[BUFSIZ];
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_ci	SAFE_CG_READ(tst_cg, "cpuset.cpus", buf, sizeof(buf));
55f08c3bdfSopenharmony_ci	SAFE_CG_PRINT(tst_cg, "cpuset.cpus", buf);
56f08c3bdfSopenharmony_ci	SAFE_CG_READ(tst_cg, "cpuset.mems", buf, sizeof(buf));
57f08c3bdfSopenharmony_ci	SAFE_CG_PRINT(tst_cg, "cpuset.mems", buf);
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci	child = SAFE_FORK();
60f08c3bdfSopenharmony_ci	if (child == 0) {
61f08c3bdfSopenharmony_ci		for (i = 0; i < nnodes; i++) {
62f08c3bdfSopenharmony_ci			if (nodes[i] >= MAXNODES)
63f08c3bdfSopenharmony_ci				continue;
64f08c3bdfSopenharmony_ci			set_node(nmask, nodes[i]);
65f08c3bdfSopenharmony_ci		}
66f08c3bdfSopenharmony_ci		if (set_mempolicy(MPOL_BIND, nmask, MAXNODES) == -1)
67f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "set_mempolicy");
68f08c3bdfSopenharmony_ci		exit(mem_hog_cpuset(ncpus > 1 ? ncpus : 1));
69f08c3bdfSopenharmony_ci	}
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci	SAFE_CG_PRINTF(tst_cg, "cpuset.mems", "%d", nodes[0]);
72f08c3bdfSopenharmony_ci	SAFE_CG_PRINTF(tst_cg, "cpuset.mems", "%d", nodes[1]);
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	tst_reap_children();
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	tst_res(TPASS, "cpuset test pass");
77f08c3bdfSopenharmony_ci}
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_cistatic void setup(void)
80f08c3bdfSopenharmony_ci{
81f08c3bdfSopenharmony_ci	ncpus = count_cpu();
82f08c3bdfSopenharmony_ci	if (get_allowed_nodes_arr(NH_MEMS | NH_CPUS, &nnodes, &nodes) < 0)
83f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "get_allowed_nodes_arr");
84f08c3bdfSopenharmony_ci	if (nnodes <= 1)
85f08c3bdfSopenharmony_ci		tst_brk(TCONF, "requires a NUMA system.");
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci	SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid());
88f08c3bdfSopenharmony_ci}
89f08c3bdfSopenharmony_ci
90f08c3bdfSopenharmony_cistatic void sighandler(int signo LTP_ATTRIBUTE_UNUSED)
91f08c3bdfSopenharmony_ci{
92f08c3bdfSopenharmony_ci	end = 1;
93f08c3bdfSopenharmony_ci}
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_cistatic int mem_hog(void)
96f08c3bdfSopenharmony_ci{
97f08c3bdfSopenharmony_ci	long pagesize;
98f08c3bdfSopenharmony_ci	unsigned long *addr;
99f08c3bdfSopenharmony_ci	int ret = 0;
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	pagesize = getpagesize();
102f08c3bdfSopenharmony_ci	while (!end) {
103f08c3bdfSopenharmony_ci		addr = SAFE_MMAP(NULL, pagesize * 10, PROT_READ | PROT_WRITE,
104f08c3bdfSopenharmony_ci			    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
105f08c3bdfSopenharmony_ci		memset(addr, 0xF7, pagesize * 10);
106f08c3bdfSopenharmony_ci		SAFE_MUNMAP(addr, pagesize * 10);
107f08c3bdfSopenharmony_ci	}
108f08c3bdfSopenharmony_ci	return ret;
109f08c3bdfSopenharmony_ci}
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_cistatic int mem_hog_cpuset(int ntasks)
112f08c3bdfSopenharmony_ci{
113f08c3bdfSopenharmony_ci	int i, status, ret = 0;
114f08c3bdfSopenharmony_ci	struct sigaction sa;
115f08c3bdfSopenharmony_ci	pid_t *pids;
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci	if (ntasks <= 0)
118f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "ntasks is small.");
119f08c3bdfSopenharmony_ci	sa.sa_handler = sighandler;
120f08c3bdfSopenharmony_ci	if (sigemptyset(&sa.sa_mask) < 0)
121f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "sigemptyset");
122f08c3bdfSopenharmony_ci	sa.sa_flags = 0;
123f08c3bdfSopenharmony_ci	if (sigaction(SIGUSR1, &sa, NULL) < 0)
124f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "sigaction");
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_ci	pids = SAFE_MALLOC(sizeof(pid_t) * ntasks);
127f08c3bdfSopenharmony_ci	for (i = 0; i < ntasks; i++) {
128f08c3bdfSopenharmony_ci		switch (pids[i] = fork()) {
129f08c3bdfSopenharmony_ci		case -1:
130f08c3bdfSopenharmony_ci			tst_res(TFAIL | TERRNO, "fork %d", pids[i]);
131f08c3bdfSopenharmony_ci			ret = 1;
132f08c3bdfSopenharmony_ci			break;
133f08c3bdfSopenharmony_ci		case 0:
134f08c3bdfSopenharmony_ci			ret = mem_hog();
135f08c3bdfSopenharmony_ci			exit(ret);
136f08c3bdfSopenharmony_ci		default:
137f08c3bdfSopenharmony_ci			break;
138f08c3bdfSopenharmony_ci		}
139f08c3bdfSopenharmony_ci	}
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_ci	while (i--) {
142f08c3bdfSopenharmony_ci		if (kill(pids[i], SIGUSR1) == -1) {
143f08c3bdfSopenharmony_ci			tst_res(TFAIL | TERRNO, "kill %d", pids[i]);
144f08c3bdfSopenharmony_ci			ret = 1;
145f08c3bdfSopenharmony_ci		}
146f08c3bdfSopenharmony_ci	}
147f08c3bdfSopenharmony_ci	while (waitpid(-1, &status, WUNTRACED | WCONTINUED) > 0) {
148f08c3bdfSopenharmony_ci		if (WIFEXITED(status)) {
149f08c3bdfSopenharmony_ci			if (WEXITSTATUS(status) != 0) {
150f08c3bdfSopenharmony_ci				tst_res(TFAIL, "child exit status is %d",
151f08c3bdfSopenharmony_ci					 WEXITSTATUS(status));
152f08c3bdfSopenharmony_ci				ret = 1;
153f08c3bdfSopenharmony_ci			}
154f08c3bdfSopenharmony_ci		} else if (WIFSIGNALED(status)) {
155f08c3bdfSopenharmony_ci			tst_res(TFAIL, "child caught signal %d",
156f08c3bdfSopenharmony_ci				 WTERMSIG(status));
157f08c3bdfSopenharmony_ci			ret = 1;
158f08c3bdfSopenharmony_ci		}
159f08c3bdfSopenharmony_ci	}
160f08c3bdfSopenharmony_ci	return ret;
161f08c3bdfSopenharmony_ci}
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_cistatic long count_cpu(void)
164f08c3bdfSopenharmony_ci{
165f08c3bdfSopenharmony_ci	int ncpus = 0;
166f08c3bdfSopenharmony_ci
167f08c3bdfSopenharmony_ci	while (path_exist(PATH_SYS_SYSTEM "/cpu/cpu%d", ncpus))
168f08c3bdfSopenharmony_ci		ncpus++;
169f08c3bdfSopenharmony_ci
170f08c3bdfSopenharmony_ci	return ncpus;
171f08c3bdfSopenharmony_ci}
172f08c3bdfSopenharmony_ci
173f08c3bdfSopenharmony_cistatic struct tst_test test = {
174f08c3bdfSopenharmony_ci	.needs_root = 1,
175f08c3bdfSopenharmony_ci	.forks_child = 1,
176f08c3bdfSopenharmony_ci	.setup = setup,
177f08c3bdfSopenharmony_ci	.test_all = test_cpuset,
178f08c3bdfSopenharmony_ci	.needs_cgroup_ctrls = (const char *const []){ "cpuset", NULL },
179f08c3bdfSopenharmony_ci};
180f08c3bdfSopenharmony_ci
181f08c3bdfSopenharmony_ci#else
182f08c3bdfSopenharmony_ci	TST_TEST_TCONF(NUMA_ERROR_MSG);
183f08c3bdfSopenharmony_ci#endif
184