1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * cpuset user library implementation.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * Copyright (c) 2006-2007 Silicon Graphics, Inc. All rights reserved.
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * Paul Jackson <pj@sgi.com>
7f08c3bdfSopenharmony_ci */
8f08c3bdfSopenharmony_ci
9f08c3bdfSopenharmony_ci/*
10f08c3bdfSopenharmony_ci *  This program is free software; you can redistribute it and/or modify
11f08c3bdfSopenharmony_ci *  it under the terms of the GNU Lesser General Public License as published by
12f08c3bdfSopenharmony_ci *  the Free Software Foundation; either version 2.1 of the License, or
13f08c3bdfSopenharmony_ci *  (at your option) any later version.
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci *  This program is distributed in the hope that it will be useful,
16f08c3bdfSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17f08c3bdfSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18f08c3bdfSopenharmony_ci *  GNU Lesser General Public License for more details.
19f08c3bdfSopenharmony_ci *
20f08c3bdfSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public License
21f08c3bdfSopenharmony_ci *  along with this program; if not, write to the Free Software
22f08c3bdfSopenharmony_ci *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23f08c3bdfSopenharmony_ci */
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_ci#define _GNU_SOURCE	/* need to see pread() and syscall() */
26f08c3bdfSopenharmony_ci#include <unistd.h>
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_ci#include <ctype.h>
29f08c3bdfSopenharmony_ci#include <dirent.h>
30f08c3bdfSopenharmony_ci#include <errno.h>
31f08c3bdfSopenharmony_ci#include <fcntl.h>
32f08c3bdfSopenharmony_ci#include <fts.h>
33f08c3bdfSopenharmony_ci#include <limits.h>
34f08c3bdfSopenharmony_ci#include <signal.h>
35f08c3bdfSopenharmony_ci#include <stdint.h>
36f08c3bdfSopenharmony_ci#include <stdio.h>
37f08c3bdfSopenharmony_ci#include <stdlib.h>
38f08c3bdfSopenharmony_ci#include <string.h>
39f08c3bdfSopenharmony_ci#include <sys/stat.h>
40f08c3bdfSopenharmony_ci#include <sys/syscall.h>
41f08c3bdfSopenharmony_ci#include <sys/types.h>
42f08c3bdfSopenharmony_ci#include <time.h>
43f08c3bdfSopenharmony_ci#include <utime.h>
44f08c3bdfSopenharmony_ci#include <sys/utsname.h>	/* for cpuset_would_crash_kernel() */
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ci#include "bitmask.h"
47f08c3bdfSopenharmony_ci#include "cpuset.h"
48f08c3bdfSopenharmony_ci#include "common.h"
49f08c3bdfSopenharmony_ci#include "test.h"
50f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
51f08c3bdfSopenharmony_ci#include "config.h"
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci#if HAVE_LINUX_MEMPOLICY_H
54f08c3bdfSopenharmony_ci#include <linux/mempolicy.h>
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci/* Bump version, and update Change History, when libcpuset API changes */
57f08c3bdfSopenharmony_ci#define CPUSET_VERSION 3
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci/*
60f08c3bdfSopenharmony_ci * For a history of what changed in each version, see the "Change
61f08c3bdfSopenharmony_ci * History" section, at the end of the libcpuset master document.
62f08c3bdfSopenharmony_ci */
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ciint cpuset_version(void)
65f08c3bdfSopenharmony_ci{
66f08c3bdfSopenharmony_ci	return CPUSET_VERSION;
67f08c3bdfSopenharmony_ci}
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_cistruct cpuset {
70f08c3bdfSopenharmony_ci	struct bitmask *cpus;
71f08c3bdfSopenharmony_ci	struct bitmask *mems;
72f08c3bdfSopenharmony_ci	char cpu_exclusive;
73f08c3bdfSopenharmony_ci	char mem_exclusive;
74f08c3bdfSopenharmony_ci	char mem_hardwall;
75f08c3bdfSopenharmony_ci	char notify_on_release;
76f08c3bdfSopenharmony_ci	char memory_migrate;
77f08c3bdfSopenharmony_ci	char memory_pressure_enabled;
78f08c3bdfSopenharmony_ci	char memory_spread_page;
79f08c3bdfSopenharmony_ci	char memory_spread_slab;
80f08c3bdfSopenharmony_ci	char sched_load_balance;
81f08c3bdfSopenharmony_ci	int sched_relax_domain_level;
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci	/*
84f08c3bdfSopenharmony_ci	 * Each field 'x' above gets an 'x_valid' field below.
85f08c3bdfSopenharmony_ci	 * The apply_cpuset_settings() will only set those fields whose
86f08c3bdfSopenharmony_ci	 * corresponding *_valid flags are set.  The cpuset_alloc()
87f08c3bdfSopenharmony_ci	 * routine clears these flags as part of the clear in calloc(),
88f08c3bdfSopenharmony_ci	 * and the various cpuset_set*() routines set these flags when
89f08c3bdfSopenharmony_ci	 * setting the corresponding value.
90f08c3bdfSopenharmony_ci	 *
91f08c3bdfSopenharmony_ci	 * The purpose of these valid fields is to ensure that when
92f08c3bdfSopenharmony_ci	 * we create a new cpuset, we don't accidentally overwrite
93f08c3bdfSopenharmony_ci	 * some non-zero kernel default, such as an inherited
94f08c3bdfSopenharmony_ci	 * memory_spread_* flag, just because the user application
95f08c3bdfSopenharmony_ci	 * code didn't override the default zero settings resulting
96f08c3bdfSopenharmony_ci	 * from the calloc() call in cpuset_alloc().
97f08c3bdfSopenharmony_ci	 *
98f08c3bdfSopenharmony_ci	 * The choice of 'char' for the type of the flags above,
99f08c3bdfSopenharmony_ci	 * but a bitfield for the flags below, is somewhat capricious.
100f08c3bdfSopenharmony_ci	 */
101f08c3bdfSopenharmony_ci	unsigned cpus_valid:1;
102f08c3bdfSopenharmony_ci	unsigned mems_valid:1;
103f08c3bdfSopenharmony_ci	unsigned cpu_exclusive_valid:1;
104f08c3bdfSopenharmony_ci	unsigned mem_exclusive_valid:1;
105f08c3bdfSopenharmony_ci	unsigned mem_hardwall_valid:1;
106f08c3bdfSopenharmony_ci	unsigned notify_on_release_valid:1;
107f08c3bdfSopenharmony_ci	unsigned memory_migrate_valid:1;
108f08c3bdfSopenharmony_ci	unsigned memory_pressure_enabled_valid:1;
109f08c3bdfSopenharmony_ci	unsigned memory_spread_page_valid:1;
110f08c3bdfSopenharmony_ci	unsigned memory_spread_slab_valid:1;
111f08c3bdfSopenharmony_ci	unsigned sched_load_balance_valid:1;
112f08c3bdfSopenharmony_ci	unsigned sched_relax_domain_level_valid:1;
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci	/*
115f08c3bdfSopenharmony_ci	 * if the relative variable was modified, use following flags
116f08c3bdfSopenharmony_ci	 * to put a mark
117f08c3bdfSopenharmony_ci	 */
118f08c3bdfSopenharmony_ci	unsigned cpus_dirty:1;
119f08c3bdfSopenharmony_ci	unsigned mems_dirty:1;
120f08c3bdfSopenharmony_ci	unsigned cpu_exclusive_dirty:1;
121f08c3bdfSopenharmony_ci	unsigned mem_exclusive_dirty:1;
122f08c3bdfSopenharmony_ci	unsigned mem_hardwall_dirty:1;
123f08c3bdfSopenharmony_ci	unsigned notify_on_release_dirty:1;
124f08c3bdfSopenharmony_ci	unsigned memory_migrate_dirty:1;
125f08c3bdfSopenharmony_ci	unsigned memory_pressure_enabled_dirty:1;
126f08c3bdfSopenharmony_ci	unsigned memory_spread_page_dirty:1;
127f08c3bdfSopenharmony_ci	unsigned memory_spread_slab_dirty:1;
128f08c3bdfSopenharmony_ci	unsigned sched_load_balance_dirty:1;
129f08c3bdfSopenharmony_ci	unsigned sched_relax_domain_level_dirty:1;
130f08c3bdfSopenharmony_ci};
131f08c3bdfSopenharmony_ci
132f08c3bdfSopenharmony_ci/* Presumed cpuset file system mount point */
133f08c3bdfSopenharmony_cistatic const char *cpusetmnt = "/dev/cpuset";
134f08c3bdfSopenharmony_ci
135f08c3bdfSopenharmony_ci/* Stashed copy of cpunodemap[], mapping each cpu to its node. */
136f08c3bdfSopenharmony_cistatic const char *mapfile = "/var/run/cpunodemap";
137f08c3bdfSopenharmony_ci
138f08c3bdfSopenharmony_ci/* The primary source for the cpunodemap[] is available below here. */
139f08c3bdfSopenharmony_cistatic const char *sysdevices = "/sys/devices/system";
140f08c3bdfSopenharmony_ci
141f08c3bdfSopenharmony_ci/* small buffer size - for reading boolean flags or map file (1 or 2 ints) */
142f08c3bdfSopenharmony_ci#define SMALL_BUFSZ 16
143f08c3bdfSopenharmony_ci
144f08c3bdfSopenharmony_ci/*
145f08c3bdfSopenharmony_ci * The 'mask_size_file' is used to ferrit out the kernel cpumask_t
146f08c3bdfSopenharmony_ci * and nodemask_t sizes.  The lines in this file that begin with the
147f08c3bdfSopenharmony_ci * strings 'cpumask_prefix' and 'nodemask_prefix' display a cpumask
148f08c3bdfSopenharmony_ci * and nodemask string, respectively.  The lengths of these strings
149f08c3bdfSopenharmony_ci * reflect the kernel's internal cpumask_t and nodemask_t sizes,
150f08c3bdfSopenharmony_ci * which sizes are needed to correctly call the sched_setaffinity
151f08c3bdfSopenharmony_ci * and set_mempolicy system calls, and to size user level
152f08c3bdfSopenharmony_ci * bitmasks to match the kernels.
153f08c3bdfSopenharmony_ci */
154f08c3bdfSopenharmony_ci
155f08c3bdfSopenharmony_cistatic const char *mask_size_file = "/proc/self/status";
156f08c3bdfSopenharmony_cistatic const char *cpumask_prefix = "Cpus_allowed:\t";
157f08c3bdfSopenharmony_cistatic const char *nodemask_prefix = "Mems_allowed:\t";
158f08c3bdfSopenharmony_ci
159f08c3bdfSopenharmony_ci/*
160f08c3bdfSopenharmony_ci * Sizes of kernel cpumask_t and nodemask_t bitmaps, in bits.
161f08c3bdfSopenharmony_ci *
162f08c3bdfSopenharmony_ci * The first time we need these, we parse the Cpus_allowed and
163f08c3bdfSopenharmony_ci * Mems_allowed lines from mask_size_file ("/proc/self/status").
164f08c3bdfSopenharmony_ci */
165f08c3bdfSopenharmony_ci
166f08c3bdfSopenharmony_cistatic int cpumask_sz;
167f08c3bdfSopenharmony_cistatic int nodemask_sz;
168f08c3bdfSopenharmony_ci
169f08c3bdfSopenharmony_ci/*
170f08c3bdfSopenharmony_ci * These defaults only kick in if we fail to size the kernel
171f08c3bdfSopenharmony_ci * cpumask and nodemask by reading the Cpus_allowed and
172f08c3bdfSopenharmony_ci * Mems_allowed fields from the /proc/self/status file.
173f08c3bdfSopenharmony_ci */
174f08c3bdfSopenharmony_ci
175f08c3bdfSopenharmony_ci#define DEFCPUBITS (512)
176f08c3bdfSopenharmony_ci#define DEFNODEBITS (DEFCPUBITS/2)
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_ci/*
179f08c3bdfSopenharmony_ci * Arch-neutral API for obtaining NUMA distances between CPUs
180f08c3bdfSopenharmony_ci * and Memory Nodes, via the files:
181f08c3bdfSopenharmony_ci *	/sys/devices/system/node/nodeN/distance
182f08c3bdfSopenharmony_ci * which have lines such as:
183f08c3bdfSopenharmony_ci *	46 66 10 20
184f08c3bdfSopenharmony_ci * which say that for cpu on node N (from the path above), the
185f08c3bdfSopenharmony_ci * distance to nodes 0, 1, 2, and 3 are 44, 66, 10, and 20,
186f08c3bdfSopenharmony_ci * respectively.
187f08c3bdfSopenharmony_ci */
188f08c3bdfSopenharmony_ci
189f08c3bdfSopenharmony_cistatic const char *distance_directory = "/sys/devices/system/node";
190f08c3bdfSopenharmony_ci
191f08c3bdfSopenharmony_ci/*
192f08c3bdfSopenharmony_ci * Someday, we should disable, then later discard, the SN code
193f08c3bdfSopenharmony_ci * marked ALTERNATE_SN_DISTMAP.
194f08c3bdfSopenharmony_ci */
195f08c3bdfSopenharmony_ci
196f08c3bdfSopenharmony_ci#define ALTERNATE_SN_DISTMAP 1
197f08c3bdfSopenharmony_ci#ifdef ALTERNATE_SN_DISTMAP
198f08c3bdfSopenharmony_ci
199f08c3bdfSopenharmony_ci/*
200f08c3bdfSopenharmony_ci * Alternative SN (SGI ia64) architecture specific API for obtaining
201f08c3bdfSopenharmony_ci * NUMA distances between CPUs and Memory Nodes is via the file
202f08c3bdfSopenharmony_ci * /proc/sgi_sn/sn_topology, which has lines such as:
203f08c3bdfSopenharmony_ci *
204f08c3bdfSopenharmony_ci *   node 2 001c14#0 local asic SHub_1.1, nasid 0x4, dist 46:66:10:20
205f08c3bdfSopenharmony_ci *
206f08c3bdfSopenharmony_ci * which says that for each CPU on node 2, the distance to nodes
207f08c3bdfSopenharmony_ci * 0, 1, 2 and 3 are 46, 66, 10 and 20, respectively.
208f08c3bdfSopenharmony_ci *
209f08c3bdfSopenharmony_ci * This file has other lines as well, which start with other
210f08c3bdfSopenharmony_ci * keywords than "node".  Ignore these other lines.
211f08c3bdfSopenharmony_ci */
212f08c3bdfSopenharmony_ci
213f08c3bdfSopenharmony_cistatic const char *sn_topology = "/proc/sgi_sn/sn_topology";
214f08c3bdfSopenharmony_cistatic const char *sn_top_node_prefix = "node ";
215f08c3bdfSopenharmony_ci
216f08c3bdfSopenharmony_ci#endif
217f08c3bdfSopenharmony_ci
218f08c3bdfSopenharmony_ci/*
219f08c3bdfSopenharmony_ci * Check that cpusets supported, /dev/cpuset mounted.
220f08c3bdfSopenharmony_ci * If ok, return 0.
221f08c3bdfSopenharmony_ci * If not, return -1 and set errno:
222f08c3bdfSopenharmony_ci *	ENOSYS - kernel doesn't support cpusets
223f08c3bdfSopenharmony_ci *	ENODEV - /dev/cpuset not mounted
224f08c3bdfSopenharmony_ci */
225f08c3bdfSopenharmony_ci
226f08c3bdfSopenharmony_cistatic enum {
227f08c3bdfSopenharmony_ci	check_notdone,
228f08c3bdfSopenharmony_ci	check_enosys,
229f08c3bdfSopenharmony_ci	check_enodev,
230f08c3bdfSopenharmony_ci	check_ok
231f08c3bdfSopenharmony_ci} check_state = check_notdone;
232f08c3bdfSopenharmony_ci
233f08c3bdfSopenharmony_cistatic int check(void)
234f08c3bdfSopenharmony_ci{
235f08c3bdfSopenharmony_ci	if (check_state == check_notdone) {
236f08c3bdfSopenharmony_ci		struct stat statbuf;
237f08c3bdfSopenharmony_ci
238f08c3bdfSopenharmony_ci		if (stat("/proc/self/cpuset", &statbuf) < 0) {
239f08c3bdfSopenharmony_ci			check_state = check_enosys;
240f08c3bdfSopenharmony_ci			goto done;
241f08c3bdfSopenharmony_ci		}
242f08c3bdfSopenharmony_ci
243f08c3bdfSopenharmony_ci		if (stat("/dev/cpuset/tasks", &statbuf) < 0) {
244f08c3bdfSopenharmony_ci			check_state = check_enodev;
245f08c3bdfSopenharmony_ci			goto done;
246f08c3bdfSopenharmony_ci		}
247f08c3bdfSopenharmony_ci
248f08c3bdfSopenharmony_ci		check_state = check_ok;
249f08c3bdfSopenharmony_ci	}
250f08c3bdfSopenharmony_cidone:
251f08c3bdfSopenharmony_ci	switch (check_state) {
252f08c3bdfSopenharmony_ci	case check_enosys:
253f08c3bdfSopenharmony_ci		errno = ENOSYS;
254f08c3bdfSopenharmony_ci		return -1;
255f08c3bdfSopenharmony_ci	case check_enodev:
256f08c3bdfSopenharmony_ci		errno = ENODEV;
257f08c3bdfSopenharmony_ci		return -1;
258f08c3bdfSopenharmony_ci	default:
259f08c3bdfSopenharmony_ci		break;
260f08c3bdfSopenharmony_ci	}
261f08c3bdfSopenharmony_ci	return 0;
262f08c3bdfSopenharmony_ci}
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_cistatic void chomp(char *s)
265f08c3bdfSopenharmony_ci{
266f08c3bdfSopenharmony_ci	char *t;
267f08c3bdfSopenharmony_ci
268f08c3bdfSopenharmony_ci	for (t = s + strlen(s) - 1; t >= s; t--) {
269f08c3bdfSopenharmony_ci		if (*t == '\n' || *t == '\r')
270f08c3bdfSopenharmony_ci			*t = '\0';
271f08c3bdfSopenharmony_ci		else
272f08c3bdfSopenharmony_ci			break;
273f08c3bdfSopenharmony_ci	}
274f08c3bdfSopenharmony_ci}
275f08c3bdfSopenharmony_ci
276f08c3bdfSopenharmony_ci/*
277f08c3bdfSopenharmony_ci * Determine number of bytes in a seekable open file, without
278f08c3bdfSopenharmony_ci * assuming that stat(2) on that file has a useful size.
279f08c3bdfSopenharmony_ci * Has side affect of leaving the file rewound to the beginnning.
280f08c3bdfSopenharmony_ci */
281f08c3bdfSopenharmony_cistatic int filesize(FILE * fp)
282f08c3bdfSopenharmony_ci{
283f08c3bdfSopenharmony_ci	int sz = 0;
284f08c3bdfSopenharmony_ci	rewind(fp);
285f08c3bdfSopenharmony_ci	while (fgetc(fp) != EOF)
286f08c3bdfSopenharmony_ci		sz++;
287f08c3bdfSopenharmony_ci	rewind(fp);
288f08c3bdfSopenharmony_ci	return sz;
289f08c3bdfSopenharmony_ci}
290f08c3bdfSopenharmony_ci
291f08c3bdfSopenharmony_ci/* Are strings s1 and s2 equal? */
292f08c3bdfSopenharmony_cistatic int streq(const char *s1, const char *s2)
293f08c3bdfSopenharmony_ci{
294f08c3bdfSopenharmony_ci	return strcmp(s1, s2) == 0;
295f08c3bdfSopenharmony_ci}
296f08c3bdfSopenharmony_ci
297f08c3bdfSopenharmony_ci/* Is string 'pre' a prefix of string 's'? */
298f08c3bdfSopenharmony_cistatic int strprefix(const char *s, const char *pre)
299f08c3bdfSopenharmony_ci{
300f08c3bdfSopenharmony_ci	return strncmp(s, pre, strlen(pre)) == 0;
301f08c3bdfSopenharmony_ci}
302f08c3bdfSopenharmony_ci
303f08c3bdfSopenharmony_ci/*
304f08c3bdfSopenharmony_ci * char *flgets(char *buf, int buflen, FILE *fp)
305f08c3bdfSopenharmony_ci *
306f08c3bdfSopenharmony_ci * Obtain one line from input file fp.  Copy up to first
307f08c3bdfSopenharmony_ci * buflen-1 chars of line into buffer buf, discarding any remainder
308f08c3bdfSopenharmony_ci * of line.  Stop reading at newline, discarding newline.
309f08c3bdfSopenharmony_ci * Nul terminate result and return pointer to buffer buf
310f08c3bdfSopenharmony_ci * on success, or NULL if nothing more to read or failure.
311f08c3bdfSopenharmony_ci */
312f08c3bdfSopenharmony_ci
313f08c3bdfSopenharmony_cistatic char *flgets(char *buf, int buflen, FILE * fp)
314f08c3bdfSopenharmony_ci{
315f08c3bdfSopenharmony_ci	int c = -1;
316f08c3bdfSopenharmony_ci	char *bp;
317f08c3bdfSopenharmony_ci
318f08c3bdfSopenharmony_ci	bp = buf;
319f08c3bdfSopenharmony_ci	while ((--buflen > 0) && ((c = getc(fp)) >= 0)) {
320f08c3bdfSopenharmony_ci		if (c == '\n')
321f08c3bdfSopenharmony_ci			goto newline;
322f08c3bdfSopenharmony_ci		*bp++ = c;
323f08c3bdfSopenharmony_ci	}
324f08c3bdfSopenharmony_ci	if ((c < 0) && (bp == buf))
325f08c3bdfSopenharmony_ci		return NULL;
326f08c3bdfSopenharmony_ci
327f08c3bdfSopenharmony_ci	if (c > 0) {
328f08c3bdfSopenharmony_ci		while ((c = getc(fp)) >= 0) {
329f08c3bdfSopenharmony_ci			if (c == '\n')
330f08c3bdfSopenharmony_ci				break;
331f08c3bdfSopenharmony_ci		}
332f08c3bdfSopenharmony_ci	}
333f08c3bdfSopenharmony_ci
334f08c3bdfSopenharmony_cinewline:
335f08c3bdfSopenharmony_ci	*bp++ = '\0';
336f08c3bdfSopenharmony_ci	return buf;
337f08c3bdfSopenharmony_ci}
338f08c3bdfSopenharmony_ci
339f08c3bdfSopenharmony_ci/*
340f08c3bdfSopenharmony_ci * sgetc(const char *inputbuf, int *offsetptr)
341f08c3bdfSopenharmony_ci *
342f08c3bdfSopenharmony_ci * Return next char from nul-terminated input buffer inputbuf,
343f08c3bdfSopenharmony_ci * starting at offset *offsetptr.  Increment *offsetptr.
344f08c3bdfSopenharmony_ci * If next char would be nul ('\0'), return EOF and don't
345f08c3bdfSopenharmony_ci * increment *offsetptr.
346f08c3bdfSopenharmony_ci */
347f08c3bdfSopenharmony_ci
348f08c3bdfSopenharmony_cistatic int sgetc(const char *inputbuf, int *offsetptr)
349f08c3bdfSopenharmony_ci{
350f08c3bdfSopenharmony_ci	char c;
351f08c3bdfSopenharmony_ci
352f08c3bdfSopenharmony_ci	if ((c = inputbuf[*offsetptr]) != 0) {
353f08c3bdfSopenharmony_ci		*offsetptr = *offsetptr + 1;
354f08c3bdfSopenharmony_ci		return c;
355f08c3bdfSopenharmony_ci	} else {
356f08c3bdfSopenharmony_ci		return EOF;
357f08c3bdfSopenharmony_ci	}
358f08c3bdfSopenharmony_ci}
359f08c3bdfSopenharmony_ci
360f08c3bdfSopenharmony_ci/*
361f08c3bdfSopenharmony_ci * char *slgets(char *buf, int buflen, const char *inputbuf, int *offsetptr)
362f08c3bdfSopenharmony_ci *
363f08c3bdfSopenharmony_ci * Obtain next line from nul-terminated input buffer 'inputbuf',
364f08c3bdfSopenharmony_ci * starting at offset *offsetptr.  Copy up to first buflen-1
365f08c3bdfSopenharmony_ci * chars of line into output buffer buf, discarding any remainder
366f08c3bdfSopenharmony_ci * of line.  Stop reading at newline, discarding newline.
367f08c3bdfSopenharmony_ci * Nul terminate result and return pointer to output buffer
368f08c3bdfSopenharmony_ci * buf on success, or NULL if nothing more to read.
369f08c3bdfSopenharmony_ci */
370f08c3bdfSopenharmony_ci
371f08c3bdfSopenharmony_cistatic char *slgets(char *buf, int buflen, const char *inputbuf, int *offsetptr)
372f08c3bdfSopenharmony_ci{
373f08c3bdfSopenharmony_ci	int c = -1;
374f08c3bdfSopenharmony_ci	char *bp;
375f08c3bdfSopenharmony_ci
376f08c3bdfSopenharmony_ci	bp = buf;
377f08c3bdfSopenharmony_ci	while ((--buflen > 0) && ((c = sgetc(inputbuf, offsetptr)) >= 0)) {
378f08c3bdfSopenharmony_ci		if (c == '\n')
379f08c3bdfSopenharmony_ci			goto newline;
380f08c3bdfSopenharmony_ci		*bp++ = c;
381f08c3bdfSopenharmony_ci	}
382f08c3bdfSopenharmony_ci	if ((c < 0) && (bp == buf))
383f08c3bdfSopenharmony_ci		return NULL;
384f08c3bdfSopenharmony_ci
385f08c3bdfSopenharmony_ci	if (c > 0) {
386f08c3bdfSopenharmony_ci		while ((c = sgetc(inputbuf, offsetptr)) >= 0) {
387f08c3bdfSopenharmony_ci			if (c == '\n')
388f08c3bdfSopenharmony_ci				break;
389f08c3bdfSopenharmony_ci		}
390f08c3bdfSopenharmony_ci	}
391f08c3bdfSopenharmony_ci
392f08c3bdfSopenharmony_cinewline:
393f08c3bdfSopenharmony_ci	*bp++ = '\0';
394f08c3bdfSopenharmony_ci	return buf;
395f08c3bdfSopenharmony_ci}
396f08c3bdfSopenharmony_ci
397f08c3bdfSopenharmony_ci/*
398f08c3bdfSopenharmony_ci * time_t get_mtime(char *path)
399f08c3bdfSopenharmony_ci *
400f08c3bdfSopenharmony_ci * Return modtime of file at location path, else return 0.
401f08c3bdfSopenharmony_ci */
402f08c3bdfSopenharmony_ci
403f08c3bdfSopenharmony_cistatic time_t get_mtime(const char *path)
404f08c3bdfSopenharmony_ci{
405f08c3bdfSopenharmony_ci	struct stat statbuf;
406f08c3bdfSopenharmony_ci
407f08c3bdfSopenharmony_ci	if (stat(path, &statbuf) != 0)
408f08c3bdfSopenharmony_ci		return 0;
409f08c3bdfSopenharmony_ci	return statbuf.st_mtime;
410f08c3bdfSopenharmony_ci}
411f08c3bdfSopenharmony_ci
412f08c3bdfSopenharmony_ci/*
413f08c3bdfSopenharmony_ci * int set_mtime(const char *path, time_t mtime)
414f08c3bdfSopenharmony_ci *
415f08c3bdfSopenharmony_ci * Set modtime of file 'path' to 'mtime'.  Return 0 on success,
416f08c3bdfSopenharmony_ci * or -1 on error, setting errno.
417f08c3bdfSopenharmony_ci */
418f08c3bdfSopenharmony_ci
419f08c3bdfSopenharmony_cistatic int set_mtime(const char *path, time_t mtime)
420f08c3bdfSopenharmony_ci{
421f08c3bdfSopenharmony_ci	struct utimbuf times;
422f08c3bdfSopenharmony_ci
423f08c3bdfSopenharmony_ci	times.actime = mtime;
424f08c3bdfSopenharmony_ci	times.modtime = mtime;
425f08c3bdfSopenharmony_ci	return utime(path, &times);
426f08c3bdfSopenharmony_ci}
427f08c3bdfSopenharmony_ci
428f08c3bdfSopenharmony_ci/*
429f08c3bdfSopenharmony_ci * True if two pathnames resolve to same file.
430f08c3bdfSopenharmony_ci * False if either path can not be stat'd,
431f08c3bdfSopenharmony_ci * or if the two paths resolve to a different file.
432f08c3bdfSopenharmony_ci */
433f08c3bdfSopenharmony_ci
434f08c3bdfSopenharmony_cistatic int samefile(const char *path1, const char *path2)
435f08c3bdfSopenharmony_ci{
436f08c3bdfSopenharmony_ci	struct stat sb1, sb2;
437f08c3bdfSopenharmony_ci
438f08c3bdfSopenharmony_ci	if (stat(path1, &sb1) != 0)
439f08c3bdfSopenharmony_ci		return 0;
440f08c3bdfSopenharmony_ci	if (stat(path2, &sb2) != 0)
441f08c3bdfSopenharmony_ci		return 0;
442f08c3bdfSopenharmony_ci	return sb1.st_ino == sb2.st_ino && sb1.st_dev == sb2.st_dev;
443f08c3bdfSopenharmony_ci}
444f08c3bdfSopenharmony_ci
445f08c3bdfSopenharmony_ci#define slash(c) (*(c) == '/')
446f08c3bdfSopenharmony_ci#define eocomp(c) (slash(c) || !*(c))
447f08c3bdfSopenharmony_ci#define dot1(c) (*(c) == '.' && eocomp(c+1))
448f08c3bdfSopenharmony_ci
449f08c3bdfSopenharmony_ci/* In place path compression.  Remove extra dots and slashes. */
450f08c3bdfSopenharmony_cistatic char *pathcomp(char *p)
451f08c3bdfSopenharmony_ci{
452f08c3bdfSopenharmony_ci	char *a = p;
453f08c3bdfSopenharmony_ci	char *b = p;
454f08c3bdfSopenharmony_ci
455f08c3bdfSopenharmony_ci	if (!p || !*p)
456f08c3bdfSopenharmony_ci		return p;
457f08c3bdfSopenharmony_ci	if (slash(p))
458f08c3bdfSopenharmony_ci		*b++ = *a++;
459f08c3bdfSopenharmony_ci	for (;;) {
460f08c3bdfSopenharmony_ci		if (slash(a))
461f08c3bdfSopenharmony_ci			while (slash(++a))
462f08c3bdfSopenharmony_ci				continue;
463f08c3bdfSopenharmony_ci		if (!*a) {
464f08c3bdfSopenharmony_ci			if (b == p)
465f08c3bdfSopenharmony_ci				*b++ = '.';
466f08c3bdfSopenharmony_ci			*b = '\0';
467f08c3bdfSopenharmony_ci			return (p);
468f08c3bdfSopenharmony_ci		} else if (dot1(a)) {
469f08c3bdfSopenharmony_ci			a++;
470f08c3bdfSopenharmony_ci		} else {
471f08c3bdfSopenharmony_ci			if ((b != p) && !slash(b - 1))
472f08c3bdfSopenharmony_ci				*b++ = '/';
473f08c3bdfSopenharmony_ci			while (!eocomp(a))
474f08c3bdfSopenharmony_ci				*b++ = *a++;
475f08c3bdfSopenharmony_ci		}
476f08c3bdfSopenharmony_ci	}
477f08c3bdfSopenharmony_ci}
478f08c3bdfSopenharmony_ci
479f08c3bdfSopenharmony_ci#undef slash
480f08c3bdfSopenharmony_ci#undef eocomp
481f08c3bdfSopenharmony_ci#undef dot1
482f08c3bdfSopenharmony_ci
483f08c3bdfSopenharmony_ci/*
484f08c3bdfSopenharmony_ci * pathcat2(buf, buflen, name1, name2)
485f08c3bdfSopenharmony_ci *
486f08c3bdfSopenharmony_ci * Return buf, of length buflen, with name1/name2 stored in it.
487f08c3bdfSopenharmony_ci */
488f08c3bdfSopenharmony_ci
489f08c3bdfSopenharmony_cistatic char *pathcat2(char *buf, int buflen, const char *name1,
490f08c3bdfSopenharmony_ci		      const char *name2)
491f08c3bdfSopenharmony_ci{
492f08c3bdfSopenharmony_ci	(void)snprintf(buf, buflen, "%s/%s", name1, name2);
493f08c3bdfSopenharmony_ci	return pathcomp(buf);
494f08c3bdfSopenharmony_ci}
495f08c3bdfSopenharmony_ci
496f08c3bdfSopenharmony_ci/*
497f08c3bdfSopenharmony_ci * pathcat3(buf, buflen, name1, name2, name3)
498f08c3bdfSopenharmony_ci *
499f08c3bdfSopenharmony_ci * Return buf, of length buflen, with name1/name2/name3 stored in it.
500f08c3bdfSopenharmony_ci */
501f08c3bdfSopenharmony_ci
502f08c3bdfSopenharmony_cistatic char *pathcat3(char *buf, int buflen, const char *name1,
503f08c3bdfSopenharmony_ci		      const char *name2, const char *name3)
504f08c3bdfSopenharmony_ci{
505f08c3bdfSopenharmony_ci	(void)snprintf(buf, buflen, "%s/%s/%s", name1, name2, name3);
506f08c3bdfSopenharmony_ci	return pathcomp(buf);
507f08c3bdfSopenharmony_ci}
508f08c3bdfSopenharmony_ci
509f08c3bdfSopenharmony_ci/*
510f08c3bdfSopenharmony_ci * fullpath(buf, buflen, name)
511f08c3bdfSopenharmony_ci *
512f08c3bdfSopenharmony_ci * Put full path of cpuset 'name' in buffer 'buf'.  If name
513f08c3bdfSopenharmony_ci * starts with a slash (``/``) character, then this a path
514f08c3bdfSopenharmony_ci * relative to ``/dev/cpuset``, otherwise it is relative to
515f08c3bdfSopenharmony_ci * the current tasks cpuset.  Return 0 on success, else
516f08c3bdfSopenharmony_ci * -1 on error, setting errno.
517f08c3bdfSopenharmony_ci */
518f08c3bdfSopenharmony_ci
519f08c3bdfSopenharmony_cistatic int fullpath(char *buf, int buflen, const char *name)
520f08c3bdfSopenharmony_ci{
521f08c3bdfSopenharmony_ci	int len;
522f08c3bdfSopenharmony_ci
523f08c3bdfSopenharmony_ci	/* easy case */
524f08c3bdfSopenharmony_ci	if (*name == '/') {
525f08c3bdfSopenharmony_ci		pathcat2(buf, buflen, cpusetmnt, name);
526f08c3bdfSopenharmony_ci		pathcomp(buf);
527f08c3bdfSopenharmony_ci		return 0;
528f08c3bdfSopenharmony_ci	}
529f08c3bdfSopenharmony_ci
530f08c3bdfSopenharmony_ci	/* hard case */
531f08c3bdfSopenharmony_ci	snprintf(buf, buflen, "%s/", cpusetmnt);
532f08c3bdfSopenharmony_ci	len = strlen(buf);
533f08c3bdfSopenharmony_ci	if (cpuset_getcpusetpath(0, buf + len, buflen - len) == NULL)
534f08c3bdfSopenharmony_ci		return -1;
535f08c3bdfSopenharmony_ci	if (strlen(buf) >= buflen - 1 - strlen(name)) {
536f08c3bdfSopenharmony_ci		errno = E2BIG;
537f08c3bdfSopenharmony_ci		return -1;
538f08c3bdfSopenharmony_ci	}
539f08c3bdfSopenharmony_ci	strcat(buf, "/");
540f08c3bdfSopenharmony_ci	strcat(buf, name);
541f08c3bdfSopenharmony_ci	pathcomp(buf);
542f08c3bdfSopenharmony_ci	return 0;
543f08c3bdfSopenharmony_ci}
544f08c3bdfSopenharmony_ci
545f08c3bdfSopenharmony_ci/*
546f08c3bdfSopenharmony_ci * fullpath2(buf, buflen, name1, name2)
547f08c3bdfSopenharmony_ci *
548f08c3bdfSopenharmony_ci * Like fullpath(), only concatenate two pathname components on end.
549f08c3bdfSopenharmony_ci */
550f08c3bdfSopenharmony_ci
551f08c3bdfSopenharmony_cistatic int fullpath2(char *buf, int buflen, const char *name1,
552f08c3bdfSopenharmony_ci		     const char *name2)
553f08c3bdfSopenharmony_ci{
554f08c3bdfSopenharmony_ci	if (fullpath(buf, buflen, name1) < 0)
555f08c3bdfSopenharmony_ci		return -1;
556f08c3bdfSopenharmony_ci	if (strlen(buf) >= buflen - 1 - strlen(name2)) {
557f08c3bdfSopenharmony_ci		errno = E2BIG;
558f08c3bdfSopenharmony_ci		return -1;
559f08c3bdfSopenharmony_ci	}
560f08c3bdfSopenharmony_ci	strcat(buf, "/");
561f08c3bdfSopenharmony_ci	strcat(buf, name2);
562f08c3bdfSopenharmony_ci	pathcomp(buf);
563f08c3bdfSopenharmony_ci	return 0;
564f08c3bdfSopenharmony_ci}
565f08c3bdfSopenharmony_ci
566f08c3bdfSopenharmony_ci/*
567f08c3bdfSopenharmony_ci * Convert the string length of an ascii hex mask to the number
568f08c3bdfSopenharmony_ci * of bits represented by that mask.
569f08c3bdfSopenharmony_ci *
570f08c3bdfSopenharmony_ci * The cpumask and nodemask values in /proc/self/status are in an
571f08c3bdfSopenharmony_ci * ascii format that uses 9 characters for each 32 bits of mask.
572f08c3bdfSopenharmony_ci */
573f08c3bdfSopenharmony_cistatic int s2nbits(const char *s)
574f08c3bdfSopenharmony_ci{
575f08c3bdfSopenharmony_ci	return strlen(s) * 32 / 9;
576f08c3bdfSopenharmony_ci}
577f08c3bdfSopenharmony_ci
578f08c3bdfSopenharmony_cistatic void update_mask_sizes(void)
579f08c3bdfSopenharmony_ci{
580f08c3bdfSopenharmony_ci	FILE *fp = NULL;
581f08c3bdfSopenharmony_ci	char *buf = NULL;
582f08c3bdfSopenharmony_ci	int fsize;
583f08c3bdfSopenharmony_ci
584f08c3bdfSopenharmony_ci	if ((fp = fopen(mask_size_file, "r")) == NULL)
585f08c3bdfSopenharmony_ci		goto done;
586f08c3bdfSopenharmony_ci	fsize = filesize(fp);
587f08c3bdfSopenharmony_ci	if ((buf = malloc(fsize)) == NULL)
588f08c3bdfSopenharmony_ci		goto done;
589f08c3bdfSopenharmony_ci
590f08c3bdfSopenharmony_ci	/*
591f08c3bdfSopenharmony_ci	 * Beware: mask sizing arithmetic is fussy.
592f08c3bdfSopenharmony_ci	 * The trailing newline left by fgets() is required.
593f08c3bdfSopenharmony_ci	 */
594f08c3bdfSopenharmony_ci	while (fgets(buf, fsize, fp)) {
595f08c3bdfSopenharmony_ci		if (strprefix(buf, cpumask_prefix))
596f08c3bdfSopenharmony_ci			cpumask_sz = s2nbits(buf + strlen(cpumask_prefix));
597f08c3bdfSopenharmony_ci		if (strprefix(buf, nodemask_prefix))
598f08c3bdfSopenharmony_ci			nodemask_sz = s2nbits(buf + strlen(nodemask_prefix));
599f08c3bdfSopenharmony_ci	}
600f08c3bdfSopenharmony_cidone:
601f08c3bdfSopenharmony_ci	free(buf);
602f08c3bdfSopenharmony_ci	if (fp != NULL)
603f08c3bdfSopenharmony_ci		fclose(fp);
604f08c3bdfSopenharmony_ci	if (cpumask_sz == 0)
605f08c3bdfSopenharmony_ci		cpumask_sz = DEFCPUBITS;
606f08c3bdfSopenharmony_ci	if (nodemask_sz == 0)
607f08c3bdfSopenharmony_ci		nodemask_sz = DEFNODEBITS;
608f08c3bdfSopenharmony_ci}
609f08c3bdfSopenharmony_ci
610f08c3bdfSopenharmony_ci/* Allocate a new struct cpuset */
611f08c3bdfSopenharmony_cistruct cpuset *cpuset_alloc(void)
612f08c3bdfSopenharmony_ci{
613f08c3bdfSopenharmony_ci	struct cpuset *cp = NULL;
614f08c3bdfSopenharmony_ci	int nbits;
615f08c3bdfSopenharmony_ci
616f08c3bdfSopenharmony_ci	if ((cp = calloc(1, sizeof(struct cpuset))) == NULL)
617f08c3bdfSopenharmony_ci		goto err;
618f08c3bdfSopenharmony_ci
619f08c3bdfSopenharmony_ci	nbits = cpuset_cpus_nbits();
620f08c3bdfSopenharmony_ci	if ((cp->cpus = bitmask_alloc(nbits)) == NULL)
621f08c3bdfSopenharmony_ci		goto err;
622f08c3bdfSopenharmony_ci
623f08c3bdfSopenharmony_ci	nbits = cpuset_mems_nbits();
624f08c3bdfSopenharmony_ci	if ((cp->mems = bitmask_alloc(nbits)) == NULL)
625f08c3bdfSopenharmony_ci		goto err;
626f08c3bdfSopenharmony_ci
627f08c3bdfSopenharmony_ci	return cp;
628f08c3bdfSopenharmony_cierr:
629f08c3bdfSopenharmony_ci	if (cp && cp->cpus)
630f08c3bdfSopenharmony_ci		bitmask_free(cp->cpus);
631f08c3bdfSopenharmony_ci	if (cp && cp->mems)
632f08c3bdfSopenharmony_ci		bitmask_free(cp->mems);
633f08c3bdfSopenharmony_ci	free(cp);
634f08c3bdfSopenharmony_ci	return NULL;
635f08c3bdfSopenharmony_ci}
636f08c3bdfSopenharmony_ci
637f08c3bdfSopenharmony_ci/* Free struct cpuset *cp */
638f08c3bdfSopenharmony_civoid cpuset_free(struct cpuset *cp)
639f08c3bdfSopenharmony_ci{
640f08c3bdfSopenharmony_ci	if (!cp)
641f08c3bdfSopenharmony_ci		return;
642f08c3bdfSopenharmony_ci	if (cp->cpus)
643f08c3bdfSopenharmony_ci		bitmask_free(cp->cpus);
644f08c3bdfSopenharmony_ci	if (cp->mems)
645f08c3bdfSopenharmony_ci		bitmask_free(cp->mems);
646f08c3bdfSopenharmony_ci	free(cp);
647f08c3bdfSopenharmony_ci}
648f08c3bdfSopenharmony_ci
649f08c3bdfSopenharmony_ci/* Number of bits in a CPU bitmask on current system */
650f08c3bdfSopenharmony_ciint cpuset_cpus_nbits(void)
651f08c3bdfSopenharmony_ci{
652f08c3bdfSopenharmony_ci	if (cpumask_sz == 0)
653f08c3bdfSopenharmony_ci		update_mask_sizes();
654f08c3bdfSopenharmony_ci	return cpumask_sz;
655f08c3bdfSopenharmony_ci}
656f08c3bdfSopenharmony_ci
657f08c3bdfSopenharmony_ci/* Number of bits in a Memory bitmask on current system */
658f08c3bdfSopenharmony_ciint cpuset_mems_nbits(void)
659f08c3bdfSopenharmony_ci{
660f08c3bdfSopenharmony_ci	if (nodemask_sz == 0)
661f08c3bdfSopenharmony_ci		update_mask_sizes();
662f08c3bdfSopenharmony_ci	return nodemask_sz;
663f08c3bdfSopenharmony_ci}
664f08c3bdfSopenharmony_ci
665f08c3bdfSopenharmony_ci/* Set CPUs in cpuset cp to bitmask cpus */
666f08c3bdfSopenharmony_ciint cpuset_setcpus(struct cpuset *cp, const struct bitmask *cpus)
667f08c3bdfSopenharmony_ci{
668f08c3bdfSopenharmony_ci	if (cp->cpus)
669f08c3bdfSopenharmony_ci		bitmask_free(cp->cpus);
670f08c3bdfSopenharmony_ci	cp->cpus = bitmask_alloc(bitmask_nbits(cpus));
671f08c3bdfSopenharmony_ci	if (cp->cpus == NULL)
672f08c3bdfSopenharmony_ci		return -1;
673f08c3bdfSopenharmony_ci	bitmask_copy(cp->cpus, cpus);
674f08c3bdfSopenharmony_ci	cp->cpus_valid = 1;
675f08c3bdfSopenharmony_ci	cp->cpus_dirty = 1;
676f08c3bdfSopenharmony_ci	return 0;
677f08c3bdfSopenharmony_ci}
678f08c3bdfSopenharmony_ci
679f08c3bdfSopenharmony_ci/* Set Memory Nodes in cpuset cp to bitmask mems */
680f08c3bdfSopenharmony_ciint cpuset_setmems(struct cpuset *cp, const struct bitmask *mems)
681f08c3bdfSopenharmony_ci{
682f08c3bdfSopenharmony_ci	if (cp->mems)
683f08c3bdfSopenharmony_ci		bitmask_free(cp->mems);
684f08c3bdfSopenharmony_ci	cp->mems = bitmask_alloc(bitmask_nbits(mems));
685f08c3bdfSopenharmony_ci	if (cp->mems == NULL)
686f08c3bdfSopenharmony_ci		return -1;
687f08c3bdfSopenharmony_ci	bitmask_copy(cp->mems, mems);
688f08c3bdfSopenharmony_ci	cp->mems_valid = 1;
689f08c3bdfSopenharmony_ci	cp->mems_dirty = 1;
690f08c3bdfSopenharmony_ci	return 0;
691f08c3bdfSopenharmony_ci}
692f08c3bdfSopenharmony_ci
693f08c3bdfSopenharmony_ci/* Set integer value optname of cpuset cp */
694f08c3bdfSopenharmony_ciint cpuset_set_iopt(struct cpuset *cp, const char *optionname, int value)
695f08c3bdfSopenharmony_ci{
696f08c3bdfSopenharmony_ci	if (streq(optionname, "cpu_exclusive")) {
697f08c3bdfSopenharmony_ci		cp->cpu_exclusive = ! !value;
698f08c3bdfSopenharmony_ci		cp->cpu_exclusive_valid = 1;
699f08c3bdfSopenharmony_ci		cp->cpu_exclusive_dirty = 1;
700f08c3bdfSopenharmony_ci	} else if (streq(optionname, "mem_exclusive")) {
701f08c3bdfSopenharmony_ci		cp->mem_exclusive = ! !value;
702f08c3bdfSopenharmony_ci		cp->mem_exclusive_valid = 1;
703f08c3bdfSopenharmony_ci		cp->mem_exclusive_dirty = 1;
704f08c3bdfSopenharmony_ci	} else if (streq(optionname, "mem_hardwall")) {
705f08c3bdfSopenharmony_ci		cp->mem_hardwall = ! !value;
706f08c3bdfSopenharmony_ci		cp->mem_hardwall_valid = 1;
707f08c3bdfSopenharmony_ci		cp->mem_hardwall_dirty = 1;
708f08c3bdfSopenharmony_ci	} else if (streq(optionname, "notify_on_release")) {
709f08c3bdfSopenharmony_ci		cp->notify_on_release = ! !value;
710f08c3bdfSopenharmony_ci		cp->notify_on_release_valid = 1;
711f08c3bdfSopenharmony_ci		cp->notify_on_release_dirty = 1;
712f08c3bdfSopenharmony_ci	} else if (streq(optionname, "memory_pressure_enabled")) {
713f08c3bdfSopenharmony_ci		cp->memory_pressure_enabled = ! !value;
714f08c3bdfSopenharmony_ci		cp->memory_pressure_enabled_valid = 1;
715f08c3bdfSopenharmony_ci		cp->memory_pressure_enabled_dirty = 1;
716f08c3bdfSopenharmony_ci	} else if (streq(optionname, "memory_migrate")) {
717f08c3bdfSopenharmony_ci		cp->memory_migrate = ! !value;
718f08c3bdfSopenharmony_ci		cp->memory_migrate_valid = 1;
719f08c3bdfSopenharmony_ci		cp->memory_migrate_dirty = 1;
720f08c3bdfSopenharmony_ci	} else if (streq(optionname, "memory_spread_page")) {
721f08c3bdfSopenharmony_ci		cp->memory_spread_page = ! !value;
722f08c3bdfSopenharmony_ci		cp->memory_spread_page_valid = 1;
723f08c3bdfSopenharmony_ci		cp->memory_spread_page_dirty = 1;
724f08c3bdfSopenharmony_ci	} else if (streq(optionname, "memory_spread_slab")) {
725f08c3bdfSopenharmony_ci		cp->memory_spread_slab = ! !value;
726f08c3bdfSopenharmony_ci		cp->memory_spread_slab_valid = 1;
727f08c3bdfSopenharmony_ci		cp->memory_spread_slab_dirty = 1;
728f08c3bdfSopenharmony_ci	} else if (streq(optionname, "sched_load_balance")) {
729f08c3bdfSopenharmony_ci		cp->sched_load_balance = ! !value;
730f08c3bdfSopenharmony_ci		cp->sched_load_balance_valid = 1;
731f08c3bdfSopenharmony_ci		cp->sched_load_balance_dirty = 1;
732f08c3bdfSopenharmony_ci	} else if (streq(optionname, "sched_relax_domain_level")) {
733f08c3bdfSopenharmony_ci		cp->sched_relax_domain_level = value;
734f08c3bdfSopenharmony_ci		cp->sched_relax_domain_level_valid = 1;
735f08c3bdfSopenharmony_ci		cp->sched_relax_domain_level_dirty = 1;
736f08c3bdfSopenharmony_ci	} else
737f08c3bdfSopenharmony_ci		return -2;	/* optionname not recognized */
738f08c3bdfSopenharmony_ci	return 0;
739f08c3bdfSopenharmony_ci}
740f08c3bdfSopenharmony_ci
741f08c3bdfSopenharmony_ci/* [optional] Set string value optname */
742f08c3bdfSopenharmony_ciint cpuset_set_sopt(UNUSED struct cpuset *cp, UNUSED const char *optionname,
743f08c3bdfSopenharmony_ci		    UNUSED const char *value)
744f08c3bdfSopenharmony_ci{
745f08c3bdfSopenharmony_ci	return -2;		/* For now, all string options unrecognized */
746f08c3bdfSopenharmony_ci}
747f08c3bdfSopenharmony_ci
748f08c3bdfSopenharmony_ci/* Return handle for reading memory_pressure. */
749f08c3bdfSopenharmony_ciint cpuset_open_memory_pressure(const char *cpusetpath)
750f08c3bdfSopenharmony_ci{
751f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
752f08c3bdfSopenharmony_ci
753f08c3bdfSopenharmony_ci	fullpath2(buf, sizeof(buf), cpusetpath, "memory_pressure");
754f08c3bdfSopenharmony_ci	return open(buf, O_RDONLY);
755f08c3bdfSopenharmony_ci}
756f08c3bdfSopenharmony_ci
757f08c3bdfSopenharmony_ci/* Return current memory_pressure of cpuset. */
758f08c3bdfSopenharmony_ciint cpuset_read_memory_pressure(int han)
759f08c3bdfSopenharmony_ci{
760f08c3bdfSopenharmony_ci	char buf[SMALL_BUFSZ];
761f08c3bdfSopenharmony_ci
762f08c3bdfSopenharmony_ci	if (pread(han, buf, sizeof(buf), 0L) < 0)
763f08c3bdfSopenharmony_ci		return -1;
764f08c3bdfSopenharmony_ci	return atoi(buf);
765f08c3bdfSopenharmony_ci}
766f08c3bdfSopenharmony_ci
767f08c3bdfSopenharmony_ci/* Close handle for reading memory pressure. */
768f08c3bdfSopenharmony_civoid cpuset_close_memory_pressure(int han)
769f08c3bdfSopenharmony_ci{
770f08c3bdfSopenharmony_ci	close(han);
771f08c3bdfSopenharmony_ci}
772f08c3bdfSopenharmony_ci
773f08c3bdfSopenharmony_ci/*
774f08c3bdfSopenharmony_ci * Resolve cpuset pointer (to that of current task if cp == NULL).
775f08c3bdfSopenharmony_ci *
776f08c3bdfSopenharmony_ci * If cp not NULL, just return it.  If cp is NULL, return pointer
777f08c3bdfSopenharmony_ci * to temporary cpuset for current task, and set *cp_tofree to
778f08c3bdfSopenharmony_ci * pointer to that same temporary cpuset, to be freed later.
779f08c3bdfSopenharmony_ci *
780f08c3bdfSopenharmony_ci * Return NULL and set errno on error.  Errors can occur when
781f08c3bdfSopenharmony_ci * resolving the current tasks cpuset.
782f08c3bdfSopenharmony_ci */
783f08c3bdfSopenharmony_cistatic const struct cpuset *resolve_cp(const struct cpuset *cp,
784f08c3bdfSopenharmony_ci				       struct cpuset **cp_tofree)
785f08c3bdfSopenharmony_ci{
786f08c3bdfSopenharmony_ci	const struct cpuset *rcp;
787f08c3bdfSopenharmony_ci
788f08c3bdfSopenharmony_ci	if (cp) {
789f08c3bdfSopenharmony_ci		rcp = cp;
790f08c3bdfSopenharmony_ci	} else {
791f08c3bdfSopenharmony_ci		struct cpuset *cp1 = cpuset_alloc();
792f08c3bdfSopenharmony_ci		if (cp1 == NULL)
793f08c3bdfSopenharmony_ci			goto err;
794f08c3bdfSopenharmony_ci		if (cpuset_cpusetofpid(cp1, 0) < 0) {
795f08c3bdfSopenharmony_ci			cpuset_free(cp1);
796f08c3bdfSopenharmony_ci			goto err;
797f08c3bdfSopenharmony_ci		}
798f08c3bdfSopenharmony_ci		*cp_tofree = cp1;
799f08c3bdfSopenharmony_ci		rcp = cp1;
800f08c3bdfSopenharmony_ci	}
801f08c3bdfSopenharmony_ci	return rcp;
802f08c3bdfSopenharmony_cierr:
803f08c3bdfSopenharmony_ci	return NULL;
804f08c3bdfSopenharmony_ci}
805f08c3bdfSopenharmony_ci
806f08c3bdfSopenharmony_ci/* Write CPUs in cpuset cp (current task if cp == NULL) to bitmask cpus */
807f08c3bdfSopenharmony_ciint cpuset_getcpus(const struct cpuset *cp, struct bitmask *cpus)
808f08c3bdfSopenharmony_ci{
809f08c3bdfSopenharmony_ci	struct cpuset *cp_tofree = NULL;
810f08c3bdfSopenharmony_ci	const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree);
811f08c3bdfSopenharmony_ci
812f08c3bdfSopenharmony_ci	if (!cp1)
813f08c3bdfSopenharmony_ci		goto err;
814f08c3bdfSopenharmony_ci	if (cp1->cpus == NULL) {
815f08c3bdfSopenharmony_ci		errno = EINVAL;
816f08c3bdfSopenharmony_ci		goto err;
817f08c3bdfSopenharmony_ci	}
818f08c3bdfSopenharmony_ci	bitmask_copy(cpus, cp1->cpus);
819f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
820f08c3bdfSopenharmony_ci	return 0;
821f08c3bdfSopenharmony_cierr:
822f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
823f08c3bdfSopenharmony_ci	return -1;
824f08c3bdfSopenharmony_ci}
825f08c3bdfSopenharmony_ci
826f08c3bdfSopenharmony_ci/* Write Memory Nodes in cp (current task if cp == NULL) to bitmask mems */
827f08c3bdfSopenharmony_ciint cpuset_getmems(const struct cpuset *cp, struct bitmask *mems)
828f08c3bdfSopenharmony_ci{
829f08c3bdfSopenharmony_ci	struct cpuset *cp_tofree = NULL;
830f08c3bdfSopenharmony_ci	const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree);
831f08c3bdfSopenharmony_ci
832f08c3bdfSopenharmony_ci	if (!cp1)
833f08c3bdfSopenharmony_ci		goto err;
834f08c3bdfSopenharmony_ci	if (cp1->mems == NULL) {
835f08c3bdfSopenharmony_ci		errno = EINVAL;
836f08c3bdfSopenharmony_ci		goto err;
837f08c3bdfSopenharmony_ci	}
838f08c3bdfSopenharmony_ci	bitmask_copy(mems, cp1->mems);
839f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
840f08c3bdfSopenharmony_ci	return 0;
841f08c3bdfSopenharmony_cierr:
842f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
843f08c3bdfSopenharmony_ci	return -1;
844f08c3bdfSopenharmony_ci}
845f08c3bdfSopenharmony_ci
846f08c3bdfSopenharmony_ci/* Return number of CPUs in cpuset cp (current task if cp == NULL) */
847f08c3bdfSopenharmony_ciint cpuset_cpus_weight(const struct cpuset *cp)
848f08c3bdfSopenharmony_ci{
849f08c3bdfSopenharmony_ci	struct cpuset *cp_tofree = NULL;
850f08c3bdfSopenharmony_ci	const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree);
851f08c3bdfSopenharmony_ci	int w = -1;
852f08c3bdfSopenharmony_ci
853f08c3bdfSopenharmony_ci	if (!cp1)
854f08c3bdfSopenharmony_ci		goto err;
855f08c3bdfSopenharmony_ci	if (cp1->cpus == NULL) {
856f08c3bdfSopenharmony_ci		errno = EINVAL;
857f08c3bdfSopenharmony_ci		goto err;
858f08c3bdfSopenharmony_ci	}
859f08c3bdfSopenharmony_ci	w = bitmask_weight(cp1->cpus);
860f08c3bdfSopenharmony_ci	/* fall into ... */
861f08c3bdfSopenharmony_cierr:
862f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
863f08c3bdfSopenharmony_ci	return w;
864f08c3bdfSopenharmony_ci}
865f08c3bdfSopenharmony_ci
866f08c3bdfSopenharmony_ci/* Return number of Memory Nodes in cpuset cp (current task if cp == NULL) */
867f08c3bdfSopenharmony_ciint cpuset_mems_weight(const struct cpuset *cp)
868f08c3bdfSopenharmony_ci{
869f08c3bdfSopenharmony_ci	struct cpuset *cp_tofree = NULL;
870f08c3bdfSopenharmony_ci	const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree);
871f08c3bdfSopenharmony_ci	int w = -1;
872f08c3bdfSopenharmony_ci
873f08c3bdfSopenharmony_ci	if (!cp1)
874f08c3bdfSopenharmony_ci		goto err;
875f08c3bdfSopenharmony_ci	if (cp1->mems == NULL) {
876f08c3bdfSopenharmony_ci		errno = EINVAL;
877f08c3bdfSopenharmony_ci		goto err;
878f08c3bdfSopenharmony_ci	}
879f08c3bdfSopenharmony_ci	w = bitmask_weight(cp1->mems);
880f08c3bdfSopenharmony_ci	/* fall into ... */
881f08c3bdfSopenharmony_cierr:
882f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
883f08c3bdfSopenharmony_ci	return w;
884f08c3bdfSopenharmony_ci}
885f08c3bdfSopenharmony_ci
886f08c3bdfSopenharmony_ci/* Return integer value of option optname in cp */
887f08c3bdfSopenharmony_ciint cpuset_get_iopt(const struct cpuset *cp, const char *optionname)
888f08c3bdfSopenharmony_ci{
889f08c3bdfSopenharmony_ci	if (streq(optionname, "cpu_exclusive"))
890f08c3bdfSopenharmony_ci		return cp->cpu_exclusive;
891f08c3bdfSopenharmony_ci	else if (streq(optionname, "mem_exclusive"))
892f08c3bdfSopenharmony_ci		return cp->mem_exclusive;
893f08c3bdfSopenharmony_ci	else if (streq(optionname, "mem_hardwall"))
894f08c3bdfSopenharmony_ci		return cp->mem_hardwall;
895f08c3bdfSopenharmony_ci	else if (streq(optionname, "notify_on_release"))
896f08c3bdfSopenharmony_ci		return cp->notify_on_release;
897f08c3bdfSopenharmony_ci	else if (streq(optionname, "memory_pressure_enabled"))
898f08c3bdfSopenharmony_ci		return cp->memory_pressure_enabled;
899f08c3bdfSopenharmony_ci	else if (streq(optionname, "memory_migrate"))
900f08c3bdfSopenharmony_ci		return cp->memory_migrate;
901f08c3bdfSopenharmony_ci	else if (streq(optionname, "memory_spread_page"))
902f08c3bdfSopenharmony_ci		return cp->memory_spread_page;
903f08c3bdfSopenharmony_ci	else if (streq(optionname, "memory_spread_slab"))
904f08c3bdfSopenharmony_ci		return cp->memory_spread_slab;
905f08c3bdfSopenharmony_ci	else if (streq(optionname, "sched_load_balance"))
906f08c3bdfSopenharmony_ci		return cp->sched_load_balance;
907f08c3bdfSopenharmony_ci	else if (streq(optionname, "sched_relax_domain_level"))
908f08c3bdfSopenharmony_ci		return cp->sched_relax_domain_level;
909f08c3bdfSopenharmony_ci	else
910f08c3bdfSopenharmony_ci		return -2;	/* optionname not recognized */
911f08c3bdfSopenharmony_ci}
912f08c3bdfSopenharmony_ci
913f08c3bdfSopenharmony_ci/* [optional] Return string value of optname */
914f08c3bdfSopenharmony_ciconst char *cpuset_get_sopt(UNUSED const struct cpuset *cp,
915f08c3bdfSopenharmony_ci			    UNUSED const char *optionname)
916f08c3bdfSopenharmony_ci{
917f08c3bdfSopenharmony_ci	return NULL;		/* For now, all string options unrecognized */
918f08c3bdfSopenharmony_ci}
919f08c3bdfSopenharmony_ci
920f08c3bdfSopenharmony_cistatic int read_flag(const char *filepath, char *flagp)
921f08c3bdfSopenharmony_ci{
922f08c3bdfSopenharmony_ci	char buf[SMALL_BUFSZ];	/* buffer a "0" or "1" flag line */
923f08c3bdfSopenharmony_ci	int fd = -1;
924f08c3bdfSopenharmony_ci
925f08c3bdfSopenharmony_ci	if ((fd = open(filepath, O_RDONLY)) < 0)
926f08c3bdfSopenharmony_ci		goto err;
927f08c3bdfSopenharmony_ci	if (read(fd, buf, sizeof(buf)) < 1)
928f08c3bdfSopenharmony_ci		goto err;
929f08c3bdfSopenharmony_ci	if (atoi(buf))
930f08c3bdfSopenharmony_ci		*flagp = 1;
931f08c3bdfSopenharmony_ci	else
932f08c3bdfSopenharmony_ci		*flagp = 0;
933f08c3bdfSopenharmony_ci	close(fd);
934f08c3bdfSopenharmony_ci	return 0;
935f08c3bdfSopenharmony_cierr:
936f08c3bdfSopenharmony_ci	if (fd >= 0)
937f08c3bdfSopenharmony_ci		close(fd);
938f08c3bdfSopenharmony_ci	return -1;
939f08c3bdfSopenharmony_ci}
940f08c3bdfSopenharmony_ci
941f08c3bdfSopenharmony_cistatic int load_flag(const char *path, char *flagp, const char *flag)
942f08c3bdfSopenharmony_ci{
943f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
944f08c3bdfSopenharmony_ci
945f08c3bdfSopenharmony_ci	pathcat2(buf, sizeof(buf), path, flag);
946f08c3bdfSopenharmony_ci	return read_flag(buf, flagp);
947f08c3bdfSopenharmony_ci}
948f08c3bdfSopenharmony_ci
949f08c3bdfSopenharmony_cistatic int read_number(const char *filepath, int *numberp)
950f08c3bdfSopenharmony_ci{
951f08c3bdfSopenharmony_ci	char buf[SMALL_BUFSZ];
952f08c3bdfSopenharmony_ci	int fd = -1;
953f08c3bdfSopenharmony_ci
954f08c3bdfSopenharmony_ci	if ((fd = open(filepath, O_RDONLY)) < 0)
955f08c3bdfSopenharmony_ci		goto err;
956f08c3bdfSopenharmony_ci	if (read(fd, buf, sizeof(buf)) < 1)
957f08c3bdfSopenharmony_ci		goto err;
958f08c3bdfSopenharmony_ci	*numberp = atoi(buf);
959f08c3bdfSopenharmony_ci	close(fd);
960f08c3bdfSopenharmony_ci	return 0;
961f08c3bdfSopenharmony_cierr:
962f08c3bdfSopenharmony_ci	if (fd >= 0)
963f08c3bdfSopenharmony_ci		close(fd);
964f08c3bdfSopenharmony_ci	return -1;
965f08c3bdfSopenharmony_ci}
966f08c3bdfSopenharmony_ci
967f08c3bdfSopenharmony_cistatic int load_number(const char *path, int *numberp, const char *file)
968f08c3bdfSopenharmony_ci{
969f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
970f08c3bdfSopenharmony_ci
971f08c3bdfSopenharmony_ci	pathcat2(buf, sizeof(buf), path, file);
972f08c3bdfSopenharmony_ci	return read_number(buf, numberp);
973f08c3bdfSopenharmony_ci}
974f08c3bdfSopenharmony_ci
975f08c3bdfSopenharmony_cistatic int read_mask(const char *filepath, struct bitmask **bmpp, int nbits)
976f08c3bdfSopenharmony_ci{
977f08c3bdfSopenharmony_ci	FILE *fp = NULL;
978f08c3bdfSopenharmony_ci	char *buf = NULL;
979f08c3bdfSopenharmony_ci	int buflen;
980f08c3bdfSopenharmony_ci	struct bitmask *bmp = NULL;
981f08c3bdfSopenharmony_ci
982f08c3bdfSopenharmony_ci	if ((fp = fopen(filepath, "r")) == NULL)
983f08c3bdfSopenharmony_ci		goto err;
984f08c3bdfSopenharmony_ci	buflen = filesize(fp) + 1;	/* + 1 for nul term */
985f08c3bdfSopenharmony_ci	if ((buf = malloc(buflen)) == NULL)
986f08c3bdfSopenharmony_ci		goto err;
987f08c3bdfSopenharmony_ci	if (flgets(buf, buflen, fp) == NULL)
988f08c3bdfSopenharmony_ci		goto err;
989f08c3bdfSopenharmony_ci	fclose(fp);
990f08c3bdfSopenharmony_ci	fp = NULL;
991f08c3bdfSopenharmony_ci
992f08c3bdfSopenharmony_ci	if ((bmp = bitmask_alloc(nbits)) == NULL)
993f08c3bdfSopenharmony_ci		goto err;
994f08c3bdfSopenharmony_ci	if (*buf && bitmask_parselist(buf, bmp) < 0)
995f08c3bdfSopenharmony_ci		goto err;
996f08c3bdfSopenharmony_ci	if (*bmpp)
997f08c3bdfSopenharmony_ci		bitmask_free(*bmpp);
998f08c3bdfSopenharmony_ci	*bmpp = bmp;
999f08c3bdfSopenharmony_ci	free(buf);
1000f08c3bdfSopenharmony_ci	buf = NULL;
1001f08c3bdfSopenharmony_ci	return 0;
1002f08c3bdfSopenharmony_cierr:
1003f08c3bdfSopenharmony_ci	if (buf != NULL)
1004f08c3bdfSopenharmony_ci		free(buf);
1005f08c3bdfSopenharmony_ci	if (fp != NULL)
1006f08c3bdfSopenharmony_ci		fclose(fp);
1007f08c3bdfSopenharmony_ci	if (bmp != NULL)
1008f08c3bdfSopenharmony_ci		bitmask_free(bmp);
1009f08c3bdfSopenharmony_ci	return -1;
1010f08c3bdfSopenharmony_ci}
1011f08c3bdfSopenharmony_ci
1012f08c3bdfSopenharmony_cistatic int load_mask(const char *path, struct bitmask **bmpp,
1013f08c3bdfSopenharmony_ci		     int nbits, const char *mask)
1014f08c3bdfSopenharmony_ci{
1015f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
1016f08c3bdfSopenharmony_ci
1017f08c3bdfSopenharmony_ci	pathcat2(buf, sizeof(buf), path, mask);
1018f08c3bdfSopenharmony_ci	return read_mask(buf, bmpp, nbits);
1019f08c3bdfSopenharmony_ci}
1020f08c3bdfSopenharmony_ci
1021f08c3bdfSopenharmony_ci/* Write string to file at given filepath.  Create or truncate file. */
1022f08c3bdfSopenharmony_cistatic int write_string_file(const char *filepath, const char *str)
1023f08c3bdfSopenharmony_ci{
1024f08c3bdfSopenharmony_ci	int fd = -1;
1025f08c3bdfSopenharmony_ci
1026f08c3bdfSopenharmony_ci	if ((fd = open(filepath, O_WRONLY | O_CREAT, 0644)) < 0)
1027f08c3bdfSopenharmony_ci		goto err;
1028f08c3bdfSopenharmony_ci	if (write(fd, str, strlen(str)) < 0)
1029f08c3bdfSopenharmony_ci		goto err;
1030f08c3bdfSopenharmony_ci	close(fd);
1031f08c3bdfSopenharmony_ci	return 0;
1032f08c3bdfSopenharmony_cierr:
1033f08c3bdfSopenharmony_ci	if (fd >= 0)
1034f08c3bdfSopenharmony_ci		close(fd);
1035f08c3bdfSopenharmony_ci	return -1;
1036f08c3bdfSopenharmony_ci}
1037f08c3bdfSopenharmony_ci
1038f08c3bdfSopenharmony_ci/* Size and allocate buffer.  Write bitmask into it.  Caller must free */
1039f08c3bdfSopenharmony_cistatic char *sprint_mask_buf(const struct bitmask *bmp)
1040f08c3bdfSopenharmony_ci{
1041f08c3bdfSopenharmony_ci	char *buf = NULL;
1042f08c3bdfSopenharmony_ci	int buflen;
1043f08c3bdfSopenharmony_ci	char c;
1044f08c3bdfSopenharmony_ci
1045f08c3bdfSopenharmony_ci	/* First bitmask_displaylist() call just to get the length */
1046f08c3bdfSopenharmony_ci	buflen = bitmask_displaylist(&c, 1, bmp) + 1;	/* "+ 1" for nul */
1047f08c3bdfSopenharmony_ci	if ((buf = malloc(buflen)) == NULL)
1048f08c3bdfSopenharmony_ci		return NULL;
1049f08c3bdfSopenharmony_ci	bitmask_displaylist(buf, buflen, bmp);
1050f08c3bdfSopenharmony_ci	return buf;
1051f08c3bdfSopenharmony_ci}
1052f08c3bdfSopenharmony_ci
1053f08c3bdfSopenharmony_cistatic int exists_flag(const char *path, const char *flag)
1054f08c3bdfSopenharmony_ci{
1055f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
1056f08c3bdfSopenharmony_ci	struct stat statbuf;
1057f08c3bdfSopenharmony_ci	int rc;
1058f08c3bdfSopenharmony_ci
1059f08c3bdfSopenharmony_ci	pathcat2(buf, sizeof(buf), path, flag);
1060f08c3bdfSopenharmony_ci	rc = (stat(buf, &statbuf) == 0);
1061f08c3bdfSopenharmony_ci	errno = 0;
1062f08c3bdfSopenharmony_ci	return rc;
1063f08c3bdfSopenharmony_ci}
1064f08c3bdfSopenharmony_ci
1065f08c3bdfSopenharmony_cistatic int store_flag(const char *path, const char *flag, int val)
1066f08c3bdfSopenharmony_ci{
1067f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
1068f08c3bdfSopenharmony_ci
1069f08c3bdfSopenharmony_ci	pathcat2(buf, sizeof(buf), path, flag);
1070f08c3bdfSopenharmony_ci	return write_string_file(buf, val ? "1" : "0");
1071f08c3bdfSopenharmony_ci}
1072f08c3bdfSopenharmony_ci
1073f08c3bdfSopenharmony_cistatic int store_number(const char *path, const char *file, int val)
1074f08c3bdfSopenharmony_ci{
1075f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
1076f08c3bdfSopenharmony_ci	char data[SMALL_BUFSZ];
1077f08c3bdfSopenharmony_ci
1078f08c3bdfSopenharmony_ci	memset(data, 0, sizeof(data));
1079f08c3bdfSopenharmony_ci	pathcat2(buf, sizeof(buf), path, file);
1080f08c3bdfSopenharmony_ci	snprintf(data, sizeof(data), "%d", val);
1081f08c3bdfSopenharmony_ci	return write_string_file(buf, data);
1082f08c3bdfSopenharmony_ci}
1083f08c3bdfSopenharmony_ci
1084f08c3bdfSopenharmony_cistatic int store_mask(const char *path, const char *mask,
1085f08c3bdfSopenharmony_ci		      const struct bitmask *bmp)
1086f08c3bdfSopenharmony_ci{
1087f08c3bdfSopenharmony_ci	char maskpath[PATH_MAX];
1088f08c3bdfSopenharmony_ci	char *bp = NULL;
1089f08c3bdfSopenharmony_ci	int rc;
1090f08c3bdfSopenharmony_ci
1091f08c3bdfSopenharmony_ci	if (bmp == NULL)
1092f08c3bdfSopenharmony_ci		return 0;
1093f08c3bdfSopenharmony_ci	pathcat2(maskpath, sizeof(maskpath), path, mask);
1094f08c3bdfSopenharmony_ci	if ((bp = sprint_mask_buf(bmp)) == NULL)
1095f08c3bdfSopenharmony_ci		return -1;
1096f08c3bdfSopenharmony_ci	rc = write_string_file(maskpath, bp);
1097f08c3bdfSopenharmony_ci	free(bp);
1098f08c3bdfSopenharmony_ci	return rc;
1099f08c3bdfSopenharmony_ci}
1100f08c3bdfSopenharmony_ci
1101f08c3bdfSopenharmony_ci/*
1102f08c3bdfSopenharmony_ci * Return 1 if 'cpu' is online, else 0 if offline.  Tests the file
1103f08c3bdfSopenharmony_ci * /sys/devices/system/cpu/cpuN/online file for 0 or 1 contents
1104f08c3bdfSopenharmony_ci * were N == cpu number.
1105f08c3bdfSopenharmony_ci */
1106f08c3bdfSopenharmony_ci
1107f08c3bdfSopenharmony_cichar cpu_online(unsigned int cpu)
1108f08c3bdfSopenharmony_ci{
1109f08c3bdfSopenharmony_ci	char online;
1110f08c3bdfSopenharmony_ci	char cpupath[PATH_MAX];
1111f08c3bdfSopenharmony_ci
1112f08c3bdfSopenharmony_ci	(void)snprintf(cpupath, sizeof(cpupath),
1113f08c3bdfSopenharmony_ci		       "/sys/devices/system/cpu/cpu%d/online", cpu);
1114f08c3bdfSopenharmony_ci	if (read_flag(cpupath, &online) < 0)
1115f08c3bdfSopenharmony_ci		return 0;	/* oops - guess that cpu's not there */
1116f08c3bdfSopenharmony_ci	return online;
1117f08c3bdfSopenharmony_ci}
1118f08c3bdfSopenharmony_ci
1119f08c3bdfSopenharmony_ci/*
1120f08c3bdfSopenharmony_ci * The cpunodemap maps each cpu in [0 ... cpuset_cpus_nbits()),
1121f08c3bdfSopenharmony_ci * to the node on which that cpu resides or cpuset_mems_nbits().
1122f08c3bdfSopenharmony_ci *
1123f08c3bdfSopenharmony_ci * To avoid every user having to recalculate this relation
1124f08c3bdfSopenharmony_ci * from various clues in the sysfs file system (below the
1125f08c3bdfSopenharmony_ci * path /sys/devices/system) a copy of this map is kept at
1126f08c3bdfSopenharmony_ci * /var/run/cpunodemap.
1127f08c3bdfSopenharmony_ci *
1128f08c3bdfSopenharmony_ci * The system automatically cleans out files below
1129f08c3bdfSopenharmony_ci * /var/run on each system reboot (see the init script
1130f08c3bdfSopenharmony_ci * /etc/rc.d/boot.d/S*boot.localnet), so we don't have to worry
1131f08c3bdfSopenharmony_ci * about stale data in this file across reboots.  If the file
1132f08c3bdfSopenharmony_ci * is missing, let the first process that needs it, and has
1133f08c3bdfSopenharmony_ci * permission to write in the /var/run directory, rebuild it.
1134f08c3bdfSopenharmony_ci *
1135f08c3bdfSopenharmony_ci * If using this cached data, remember the mtime of the mapfile
1136f08c3bdfSopenharmony_ci * the last time we read it in case something like a hotplug
1137f08c3bdfSopenharmony_ci * event results in the file being removed and rebuilt, so we
1138f08c3bdfSopenharmony_ci * can detect if we're using a stale cache, and need to reload.
1139f08c3bdfSopenharmony_ci *
1140f08c3bdfSopenharmony_ci * The mtime of this file is set to the time when we did
1141f08c3bdfSopenharmony_ci * the recalculation of the map, from the clues beneath
1142f08c3bdfSopenharmony_ci * /sys/devices/system.  This is done so that a program
1143f08c3bdfSopenharmony_ci * won't see the mapfile it just wrote as being newer than what
1144f08c3bdfSopenharmony_ci * it just wrote out (store_map) and read the same map back in
1145f08c3bdfSopenharmony_ci * (load_file).
1146f08c3bdfSopenharmony_ci */
1147f08c3bdfSopenharmony_ci
1148f08c3bdfSopenharmony_ci/*
1149f08c3bdfSopenharmony_ci * Hold flockfile(stdin) while using cpunodemap for posix thread safety.
1150f08c3bdfSopenharmony_ci *
1151f08c3bdfSopenharmony_ci * Note on locking and flockfile(FILE *):
1152f08c3bdfSopenharmony_ci *
1153f08c3bdfSopenharmony_ci *  We use flockfile() and funlockfile() instead of directly
1154f08c3bdfSopenharmony_ci *  calling pthread_mutex_lock and pthread_mutex_unlock on
1155f08c3bdfSopenharmony_ci *  a pthread_mutex_t, because this avoids forcing the app
1156f08c3bdfSopenharmony_ci *  to link with libpthread.  The glibc implementation of
1157f08c3bdfSopenharmony_ci *  flockfile/funlockfile will fall back to no-ops if libpthread
1158f08c3bdfSopenharmony_ci *  doesn't happen to be linked.
1159f08c3bdfSopenharmony_ci *
1160f08c3bdfSopenharmony_ci *  Since flockfile already has the moderately convoluted
1161f08c3bdfSopenharmony_ci *  combination of weak and strong symbols required to accomplish
1162f08c3bdfSopenharmony_ci *  this, it is easier to use flockfile() on some handy FILE *
1163f08c3bdfSopenharmony_ci *  stream as a surrogate for pthread locking than it is to so
1164f08c3bdfSopenharmony_ci *  re-invent that wheel.
1165f08c3bdfSopenharmony_ci *
1166f08c3bdfSopenharmony_ci *  Forcing all apps that use cpusets to link with libpthread
1167f08c3bdfSopenharmony_ci *  would force non-transparent initialization on apps that
1168f08c3bdfSopenharmony_ci *  might not be prepared to handle it.
1169f08c3bdfSopenharmony_ci *
1170f08c3bdfSopenharmony_ci *  The application using libcpuset should never notice this
1171f08c3bdfSopenharmony_ci *  odd use of flockfile(), because we never return to the
1172f08c3bdfSopenharmony_ci *  application from any libcpuset call with any such lock held.
1173f08c3bdfSopenharmony_ci *  We just use this locking for guarding some non-atomic cached
1174f08c3bdfSopenharmony_ci *  data updates and accesses, internal to some libcpuset calls.
1175f08c3bdfSopenharmony_ci *  Also, flockfile() allows recursive nesting, so if the app
1176f08c3bdfSopenharmony_ci *  calls libcpuset holding such a file lock, we won't deadlock
1177f08c3bdfSopenharmony_ci *  if we go to acquire the same lock.  We'll just get the lock
1178f08c3bdfSopenharmony_ci *  and increment its counter while we hold it.
1179f08c3bdfSopenharmony_ci */
1180f08c3bdfSopenharmony_ci
1181f08c3bdfSopenharmony_cistatic struct cpunodemap {
1182f08c3bdfSopenharmony_ci	int *map;		/* map[cpumask_sz]: maps cpu to its node */
1183f08c3bdfSopenharmony_ci	time_t mtime;		/* modtime of mapfile when last read */
1184f08c3bdfSopenharmony_ci} cpunodemap;
1185f08c3bdfSopenharmony_ci
1186f08c3bdfSopenharmony_ci/*
1187f08c3bdfSopenharmony_ci * rebuild_map() - Rebuild cpunodemap[] from scratch.
1188f08c3bdfSopenharmony_ci *
1189f08c3bdfSopenharmony_ci * Situation:
1190f08c3bdfSopenharmony_ci *	Neither our in-memory cpunodemap[] array nor the
1191f08c3bdfSopenharmony_ci *	cache of it in mapfile is current.
1192f08c3bdfSopenharmony_ci * Action:
1193f08c3bdfSopenharmony_ci *	Rebuild it from first principles and the information
1194f08c3bdfSopenharmony_ci *	available below /sys/devices/system.
1195f08c3bdfSopenharmony_ci */
1196f08c3bdfSopenharmony_ci
1197f08c3bdfSopenharmony_cistatic void rebuild_map(void)
1198f08c3bdfSopenharmony_ci{
1199f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
1200f08c3bdfSopenharmony_ci	DIR *dir1, *dir2;
1201f08c3bdfSopenharmony_ci	struct dirent *dent1, *dent2;
1202f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1203f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1204f08c3bdfSopenharmony_ci	unsigned int cpu, mem;
1205f08c3bdfSopenharmony_ci
1206f08c3bdfSopenharmony_ci	for (cpu = 0; cpu < (unsigned int)ncpus; cpu++)
1207f08c3bdfSopenharmony_ci		cpunodemap.map[cpu] = -1;
1208f08c3bdfSopenharmony_ci	pathcat2(buf, sizeof(buf), sysdevices, "node");
1209f08c3bdfSopenharmony_ci	if ((dir1 = opendir(buf)) == NULL)
1210f08c3bdfSopenharmony_ci		return;
1211f08c3bdfSopenharmony_ci	while ((dent1 = readdir(dir1)) != NULL) {
1212f08c3bdfSopenharmony_ci		if (sscanf(dent1->d_name, "node%u", &mem) < 1)
1213f08c3bdfSopenharmony_ci			continue;
1214f08c3bdfSopenharmony_ci		pathcat3(buf, sizeof(buf), sysdevices, "node", dent1->d_name);
1215f08c3bdfSopenharmony_ci		if ((dir2 = opendir(buf)) == NULL)
1216f08c3bdfSopenharmony_ci			continue;
1217f08c3bdfSopenharmony_ci		while ((dent2 = readdir(dir2)) != NULL) {
1218f08c3bdfSopenharmony_ci			if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
1219f08c3bdfSopenharmony_ci				continue;
1220f08c3bdfSopenharmony_ci			if (cpu >= (unsigned int)ncpus
1221f08c3bdfSopenharmony_ci			    || mem >= (unsigned int)nmems)
1222f08c3bdfSopenharmony_ci				continue;
1223f08c3bdfSopenharmony_ci			cpunodemap.map[cpu] = mem;
1224f08c3bdfSopenharmony_ci		}
1225f08c3bdfSopenharmony_ci		closedir(dir2);
1226f08c3bdfSopenharmony_ci	}
1227f08c3bdfSopenharmony_ci	closedir(dir1);
1228f08c3bdfSopenharmony_ci	cpunodemap.mtime = time(0);
1229f08c3bdfSopenharmony_ci}
1230f08c3bdfSopenharmony_ci
1231f08c3bdfSopenharmony_ci/*
1232f08c3bdfSopenharmony_ci * load_map() - Load cpunodemap[] from mapfile.
1233f08c3bdfSopenharmony_ci *
1234f08c3bdfSopenharmony_ci * Situation:
1235f08c3bdfSopenharmony_ci *	The cpunodemap in mapfile is more recent than
1236f08c3bdfSopenharmony_ci *	what we have in the cpunodemap[] array.
1237f08c3bdfSopenharmony_ci * Action:
1238f08c3bdfSopenharmony_ci *	Reload the cpunodemap[] array from the file.
1239f08c3bdfSopenharmony_ci */
1240f08c3bdfSopenharmony_ci
1241f08c3bdfSopenharmony_cistatic void load_map(void)
1242f08c3bdfSopenharmony_ci{
1243f08c3bdfSopenharmony_ci	char buf[SMALL_BUFSZ];	/* buffer 1 line of mapfile */
1244f08c3bdfSopenharmony_ci	FILE *mapfp;		/* File stream on mapfile */
1245f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1246f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1247f08c3bdfSopenharmony_ci	unsigned int cpu, mem;
1248f08c3bdfSopenharmony_ci
1249f08c3bdfSopenharmony_ci	if ((cpunodemap.map = calloc(ncpus, sizeof(int))) == NULL)
1250f08c3bdfSopenharmony_ci		return;
1251f08c3bdfSopenharmony_ci	cpunodemap.mtime = get_mtime(mapfile);
1252f08c3bdfSopenharmony_ci	if ((mapfp = fopen(mapfile, "r")) == NULL)
1253f08c3bdfSopenharmony_ci		return;
1254f08c3bdfSopenharmony_ci	for (cpu = 0; cpu < (unsigned int)ncpus; cpu++)
1255f08c3bdfSopenharmony_ci		cpunodemap.map[cpu] = nmems;
1256f08c3bdfSopenharmony_ci	while (flgets(buf, sizeof(buf), mapfp) != NULL) {
1257f08c3bdfSopenharmony_ci		if (sscanf(buf, "%u %u", &cpu, &mem) < 2)
1258f08c3bdfSopenharmony_ci			continue;
1259f08c3bdfSopenharmony_ci		if (cpu >= (unsigned int)ncpus || mem >= (unsigned int)nmems)
1260f08c3bdfSopenharmony_ci			continue;
1261f08c3bdfSopenharmony_ci		cpunodemap.map[cpu] = mem;
1262f08c3bdfSopenharmony_ci	}
1263f08c3bdfSopenharmony_ci	fclose(mapfp);
1264f08c3bdfSopenharmony_ci}
1265f08c3bdfSopenharmony_ci
1266f08c3bdfSopenharmony_ci/*
1267f08c3bdfSopenharmony_ci * store_map() - Write cpunodemap[] out to mapfile.
1268f08c3bdfSopenharmony_ci *
1269f08c3bdfSopenharmony_ci * Situation:
1270f08c3bdfSopenharmony_ci *	The cpunodemap in the cpunodemap[] array is
1271f08c3bdfSopenharmony_ci *	more recent than the one in mapfile.
1272f08c3bdfSopenharmony_ci * Action:
1273f08c3bdfSopenharmony_ci *	Write cpunodemap[] out to mapfile.
1274f08c3bdfSopenharmony_ci */
1275f08c3bdfSopenharmony_ci
1276f08c3bdfSopenharmony_cistatic void store_map(void)
1277f08c3bdfSopenharmony_ci{
1278f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
1279f08c3bdfSopenharmony_ci	int fd = -1;
1280f08c3bdfSopenharmony_ci	FILE *mapfp = NULL;
1281f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1282f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1283f08c3bdfSopenharmony_ci	unsigned int cpu, mem;
1284f08c3bdfSopenharmony_ci
1285f08c3bdfSopenharmony_ci	snprintf(buf, sizeof(buf), "%s.%s", mapfile, "XXXXXX");
1286f08c3bdfSopenharmony_ci	if ((fd = mkstemp(buf)) < 0)
1287f08c3bdfSopenharmony_ci		goto err;
1288f08c3bdfSopenharmony_ci	if ((mapfp = fdopen(fd, "w")) == NULL)
1289f08c3bdfSopenharmony_ci		goto err;
1290f08c3bdfSopenharmony_ci	for (cpu = 0; cpu < (unsigned int)ncpus; cpu++) {
1291f08c3bdfSopenharmony_ci		mem = cpunodemap.map[cpu];
1292f08c3bdfSopenharmony_ci		if (mem < (unsigned int)nmems)
1293f08c3bdfSopenharmony_ci			fprintf(mapfp, "%u %u\n", cpu, mem);
1294f08c3bdfSopenharmony_ci	}
1295f08c3bdfSopenharmony_ci	fclose(mapfp);
1296f08c3bdfSopenharmony_ci	set_mtime(buf, cpunodemap.mtime);
1297f08c3bdfSopenharmony_ci	if (rename(buf, mapfile) < 0)
1298f08c3bdfSopenharmony_ci		goto err;
1299f08c3bdfSopenharmony_ci	/* mkstemp() creates mode 0600 - change to world readable */
1300f08c3bdfSopenharmony_ci	(void)chmod(mapfile, 0444);
1301f08c3bdfSopenharmony_ci	return;
1302f08c3bdfSopenharmony_cierr:
1303f08c3bdfSopenharmony_ci	if (mapfp != NULL) {
1304f08c3bdfSopenharmony_ci		fclose(mapfp);
1305f08c3bdfSopenharmony_ci		fd = -1;
1306f08c3bdfSopenharmony_ci	}
1307f08c3bdfSopenharmony_ci	if (fd >= 0)
1308f08c3bdfSopenharmony_ci		close(fd);
1309f08c3bdfSopenharmony_ci	(void)unlink(buf);
1310f08c3bdfSopenharmony_ci}
1311f08c3bdfSopenharmony_ci
1312f08c3bdfSopenharmony_ci/*
1313f08c3bdfSopenharmony_ci * Load and gain thread safe access to the <cpu, node> map.
1314f08c3bdfSopenharmony_ci *
1315f08c3bdfSopenharmony_ci * Return 0 on success with flockfile(stdin) held.
1316f08c3bdfSopenharmony_ci * Each successful get_map() call must be matched with a
1317f08c3bdfSopenharmony_ci * following put_map() call to release the lock.
1318f08c3bdfSopenharmony_ci *
1319f08c3bdfSopenharmony_ci * On error, return -1 with errno set and no lock held.
1320f08c3bdfSopenharmony_ci */
1321f08c3bdfSopenharmony_ci
1322f08c3bdfSopenharmony_cistatic int get_map(void)
1323f08c3bdfSopenharmony_ci{
1324f08c3bdfSopenharmony_ci	time_t file_mtime;
1325f08c3bdfSopenharmony_ci
1326f08c3bdfSopenharmony_ci	flockfile(stdin);
1327f08c3bdfSopenharmony_ci
1328f08c3bdfSopenharmony_ci	if (cpunodemap.map == NULL) {
1329f08c3bdfSopenharmony_ci		cpunodemap.map = calloc(cpuset_cpus_nbits(), sizeof(int));
1330f08c3bdfSopenharmony_ci		if (cpunodemap.map == NULL)
1331f08c3bdfSopenharmony_ci			goto err;
1332f08c3bdfSopenharmony_ci	}
1333f08c3bdfSopenharmony_ci
1334f08c3bdfSopenharmony_ci	/* If no one has a good cpunodemap, rebuild from scratch */
1335f08c3bdfSopenharmony_ci	file_mtime = get_mtime(mapfile);
1336f08c3bdfSopenharmony_ci	if (cpunodemap.mtime == 0 && file_mtime == 0)
1337f08c3bdfSopenharmony_ci		rebuild_map();
1338f08c3bdfSopenharmony_ci
1339f08c3bdfSopenharmony_ci	/* If either cpunodemap[] or mapfile newer, update other with it */
1340f08c3bdfSopenharmony_ci	file_mtime = get_mtime(mapfile);
1341f08c3bdfSopenharmony_ci	if (cpunodemap.mtime < file_mtime)
1342f08c3bdfSopenharmony_ci		load_map();
1343f08c3bdfSopenharmony_ci	else if (cpunodemap.mtime > file_mtime)
1344f08c3bdfSopenharmony_ci		store_map();
1345f08c3bdfSopenharmony_ci	return 0;
1346f08c3bdfSopenharmony_cierr:
1347f08c3bdfSopenharmony_ci	funlockfile(stdin);
1348f08c3bdfSopenharmony_ci	return -1;
1349f08c3bdfSopenharmony_ci}
1350f08c3bdfSopenharmony_ci
1351f08c3bdfSopenharmony_cistatic void put_map(void)
1352f08c3bdfSopenharmony_ci{
1353f08c3bdfSopenharmony_ci	funlockfile(stdin);
1354f08c3bdfSopenharmony_ci}
1355f08c3bdfSopenharmony_ci
1356f08c3bdfSopenharmony_ci/* Set cpus to those local to Memory Nodes mems */
1357f08c3bdfSopenharmony_ciint cpuset_localcpus(const struct bitmask *mems, struct bitmask *cpus)
1358f08c3bdfSopenharmony_ci{
1359f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1360f08c3bdfSopenharmony_ci	unsigned int cpu;
1361f08c3bdfSopenharmony_ci
1362f08c3bdfSopenharmony_ci	if (check() < 0)
1363f08c3bdfSopenharmony_ci		return -1;
1364f08c3bdfSopenharmony_ci
1365f08c3bdfSopenharmony_ci	get_map();
1366f08c3bdfSopenharmony_ci	bitmask_clearall(cpus);
1367f08c3bdfSopenharmony_ci	for (cpu = 0; cpu < (unsigned int)ncpus; cpu++) {
1368f08c3bdfSopenharmony_ci		if (bitmask_isbitset(mems, cpunodemap.map[cpu]))
1369f08c3bdfSopenharmony_ci			bitmask_setbit(cpus, cpu);
1370f08c3bdfSopenharmony_ci	}
1371f08c3bdfSopenharmony_ci	put_map();
1372f08c3bdfSopenharmony_ci	return 0;
1373f08c3bdfSopenharmony_ci}
1374f08c3bdfSopenharmony_ci
1375f08c3bdfSopenharmony_ci/* Set mems to those local to CPUs cpus */
1376f08c3bdfSopenharmony_ciint cpuset_localmems(const struct bitmask *cpus, struct bitmask *mems)
1377f08c3bdfSopenharmony_ci{
1378f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1379f08c3bdfSopenharmony_ci	unsigned int cpu;
1380f08c3bdfSopenharmony_ci
1381f08c3bdfSopenharmony_ci	if (check() < 0)
1382f08c3bdfSopenharmony_ci		return -1;
1383f08c3bdfSopenharmony_ci
1384f08c3bdfSopenharmony_ci	get_map();
1385f08c3bdfSopenharmony_ci	bitmask_clearall(mems);
1386f08c3bdfSopenharmony_ci	for (cpu = 0; cpu < (unsigned int)ncpus; cpu++) {
1387f08c3bdfSopenharmony_ci		if (bitmask_isbitset(cpus, cpu))
1388f08c3bdfSopenharmony_ci			bitmask_setbit(mems, cpunodemap.map[cpu]);
1389f08c3bdfSopenharmony_ci	}
1390f08c3bdfSopenharmony_ci	put_map();
1391f08c3bdfSopenharmony_ci	return 0;
1392f08c3bdfSopenharmony_ci}
1393f08c3bdfSopenharmony_ci
1394f08c3bdfSopenharmony_ci/*
1395f08c3bdfSopenharmony_ci * distmap[]
1396f08c3bdfSopenharmony_ci *
1397f08c3bdfSopenharmony_ci * Array of ints of size cpumask_sz by nodemask_sz.
1398f08c3bdfSopenharmony_ci *
1399f08c3bdfSopenharmony_ci * Element distmap[cpu][mem] is the distance between CPU cpu
1400f08c3bdfSopenharmony_ci * and Memory Node mem.  Distances are weighted to roughly
1401f08c3bdfSopenharmony_ci * approximate the cost of memory references, and scaled so that
1402f08c3bdfSopenharmony_ci * the distance from a CPU to its local Memory Node is ten (10).
1403f08c3bdfSopenharmony_ci *
1404f08c3bdfSopenharmony_ci * The first call to cpuset_cpumemdist() builds this map, from
1405f08c3bdfSopenharmony_ci * whatever means the kernel provides to obtain these distances.
1406f08c3bdfSopenharmony_ci *
1407f08c3bdfSopenharmony_ci * These distances derive from ACPI SLIT table entries, which are
1408f08c3bdfSopenharmony_ci * eight bits in size.
1409f08c3bdfSopenharmony_ci *
1410f08c3bdfSopenharmony_ci * Hold flockfile(stdout) while using distmap for posix thread safety.
1411f08c3bdfSopenharmony_ci */
1412f08c3bdfSopenharmony_ci
1413f08c3bdfSopenharmony_citypedef unsigned char distmap_entry_t;	/* type of distmap[] entries */
1414f08c3bdfSopenharmony_ci
1415f08c3bdfSopenharmony_cistatic distmap_entry_t *distmap;	/* maps <cpu, mem> to distance */
1416f08c3bdfSopenharmony_ci
1417f08c3bdfSopenharmony_ci#define DISTMAP_MAX UCHAR_MAX	/* maximum value in distmap[] */
1418f08c3bdfSopenharmony_ci
1419f08c3bdfSopenharmony_ci#define I(i,j) ((i) * nmems + (j))	/* 2-D array index simulation */
1420f08c3bdfSopenharmony_ci
1421f08c3bdfSopenharmony_ci/*
1422f08c3bdfSopenharmony_ci * Parse arch neutral lines from 'distance' files of form:
1423f08c3bdfSopenharmony_ci *
1424f08c3bdfSopenharmony_ci *	46 66 10 20
1425f08c3bdfSopenharmony_ci *
1426f08c3bdfSopenharmony_ci * The lines contain a space separated list of distances, which is parsed
1427f08c3bdfSopenharmony_ci * into array dists[] of each nodes distance from the specified node.
1428f08c3bdfSopenharmony_ci *
1429f08c3bdfSopenharmony_ci * Result is placed in distmap[ncpus][nmems]:
1430f08c3bdfSopenharmony_ci *
1431f08c3bdfSopenharmony_ci *	For each cpu c on node:
1432f08c3bdfSopenharmony_ci *		For each node position n in list of distances:
1433f08c3bdfSopenharmony_ci *			distmap[c][n] = dists[n]
1434f08c3bdfSopenharmony_ci */
1435f08c3bdfSopenharmony_ci
1436f08c3bdfSopenharmony_cistatic int parse_distmap_line(unsigned int node, char *buf)
1437f08c3bdfSopenharmony_ci{
1438f08c3bdfSopenharmony_ci	char *p, *q;
1439f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1440f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1441f08c3bdfSopenharmony_ci	unsigned int c, n;
1442f08c3bdfSopenharmony_ci	distmap_entry_t *dists = NULL;
1443f08c3bdfSopenharmony_ci	struct bitmask *cpus = NULL, *mems = NULL;
1444f08c3bdfSopenharmony_ci	int ret = -1;
1445f08c3bdfSopenharmony_ci
1446f08c3bdfSopenharmony_ci	p = buf;
1447f08c3bdfSopenharmony_ci	if ((dists = calloc(nmems, sizeof(*dists))) == NULL)
1448f08c3bdfSopenharmony_ci		goto err;
1449f08c3bdfSopenharmony_ci	for (n = 0; n < (unsigned int)nmems; n++)
1450f08c3bdfSopenharmony_ci		dists[n] = DISTMAP_MAX;
1451f08c3bdfSopenharmony_ci
1452f08c3bdfSopenharmony_ci	for (n = 0; n < (unsigned int)nmems && *p; n++, p = q) {
1453f08c3bdfSopenharmony_ci		unsigned int d;
1454f08c3bdfSopenharmony_ci
1455f08c3bdfSopenharmony_ci		if ((p = strpbrk(p, "0123456789")) == NULL)
1456f08c3bdfSopenharmony_ci			break;
1457f08c3bdfSopenharmony_ci		d = strtoul(p, &q, 10);
1458f08c3bdfSopenharmony_ci		if (p == q)
1459f08c3bdfSopenharmony_ci			break;
1460f08c3bdfSopenharmony_ci		if (d < DISTMAP_MAX)
1461f08c3bdfSopenharmony_ci			dists[n] = (distmap_entry_t) d;
1462f08c3bdfSopenharmony_ci	}
1463f08c3bdfSopenharmony_ci
1464f08c3bdfSopenharmony_ci	if ((mems = bitmask_alloc(nmems)) == NULL)
1465f08c3bdfSopenharmony_ci		goto err;
1466f08c3bdfSopenharmony_ci	bitmask_setbit(mems, node);
1467f08c3bdfSopenharmony_ci
1468f08c3bdfSopenharmony_ci	if ((cpus = bitmask_alloc(ncpus)) == NULL)
1469f08c3bdfSopenharmony_ci		goto err;
1470f08c3bdfSopenharmony_ci	cpuset_localcpus(mems, cpus);
1471f08c3bdfSopenharmony_ci
1472f08c3bdfSopenharmony_ci	for (c = bitmask_first(cpus); c < (unsigned int)ncpus;
1473f08c3bdfSopenharmony_ci	     c = bitmask_next(cpus, c + 1))
1474f08c3bdfSopenharmony_ci		for (n = 0; n < (unsigned int)nmems; n++)
1475f08c3bdfSopenharmony_ci			distmap[I(c, n)] = dists[n];
1476f08c3bdfSopenharmony_ci	ret = 0;
1477f08c3bdfSopenharmony_ci	/* fall into ... */
1478f08c3bdfSopenharmony_cierr:
1479f08c3bdfSopenharmony_ci	bitmask_free(mems);
1480f08c3bdfSopenharmony_ci	bitmask_free(cpus);
1481f08c3bdfSopenharmony_ci	free(dists);
1482f08c3bdfSopenharmony_ci	return ret;
1483f08c3bdfSopenharmony_ci}
1484f08c3bdfSopenharmony_ci
1485f08c3bdfSopenharmony_cistatic int parse_distance_file(unsigned int node, const char *path)
1486f08c3bdfSopenharmony_ci{
1487f08c3bdfSopenharmony_ci	FILE *fp;
1488f08c3bdfSopenharmony_ci	char *buf = NULL;
1489f08c3bdfSopenharmony_ci	int buflen;
1490f08c3bdfSopenharmony_ci
1491f08c3bdfSopenharmony_ci	if ((fp = fopen(path, "r")) == NULL)
1492f08c3bdfSopenharmony_ci		goto err;
1493f08c3bdfSopenharmony_ci
1494f08c3bdfSopenharmony_ci	buflen = filesize(fp);
1495f08c3bdfSopenharmony_ci
1496f08c3bdfSopenharmony_ci	if ((buf = malloc(buflen)) == NULL)
1497f08c3bdfSopenharmony_ci		goto err;
1498f08c3bdfSopenharmony_ci
1499f08c3bdfSopenharmony_ci	if (flgets(buf, buflen, fp) == NULL)
1500f08c3bdfSopenharmony_ci		goto err;
1501f08c3bdfSopenharmony_ci
1502f08c3bdfSopenharmony_ci	if (parse_distmap_line(node, buf) < 0)
1503f08c3bdfSopenharmony_ci		goto err;
1504f08c3bdfSopenharmony_ci
1505f08c3bdfSopenharmony_ci	free(buf);
1506f08c3bdfSopenharmony_ci	fclose(fp);
1507f08c3bdfSopenharmony_ci	return 0;
1508f08c3bdfSopenharmony_cierr:
1509f08c3bdfSopenharmony_ci	free(buf);
1510f08c3bdfSopenharmony_ci	if (fp)
1511f08c3bdfSopenharmony_ci		fclose(fp);
1512f08c3bdfSopenharmony_ci	return -1;
1513f08c3bdfSopenharmony_ci}
1514f08c3bdfSopenharmony_ci
1515f08c3bdfSopenharmony_cistatic void build_distmap(void)
1516f08c3bdfSopenharmony_ci{
1517f08c3bdfSopenharmony_ci	static int tried_before = 0;
1518f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1519f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1520f08c3bdfSopenharmony_ci	int c, m;
1521f08c3bdfSopenharmony_ci	DIR *dir = NULL;
1522f08c3bdfSopenharmony_ci	struct dirent *dent;
1523f08c3bdfSopenharmony_ci
1524f08c3bdfSopenharmony_ci	if (tried_before)
1525f08c3bdfSopenharmony_ci		goto err;
1526f08c3bdfSopenharmony_ci	tried_before = 1;
1527f08c3bdfSopenharmony_ci
1528f08c3bdfSopenharmony_ci	if ((distmap = calloc(ncpus * nmems, sizeof(*distmap))) == NULL)
1529f08c3bdfSopenharmony_ci		goto err;
1530f08c3bdfSopenharmony_ci
1531f08c3bdfSopenharmony_ci	for (c = 0; c < ncpus; c++)
1532f08c3bdfSopenharmony_ci		for (m = 0; m < nmems; m++)
1533f08c3bdfSopenharmony_ci			distmap[I(c, m)] = DISTMAP_MAX;
1534f08c3bdfSopenharmony_ci
1535f08c3bdfSopenharmony_ci	if ((dir = opendir(distance_directory)) == NULL)
1536f08c3bdfSopenharmony_ci		goto err;
1537f08c3bdfSopenharmony_ci	while ((dent = readdir(dir)) != NULL) {
1538f08c3bdfSopenharmony_ci		char buf[PATH_MAX];
1539f08c3bdfSopenharmony_ci		unsigned int node;
1540f08c3bdfSopenharmony_ci
1541f08c3bdfSopenharmony_ci		if (sscanf(dent->d_name, "node%u", &node) < 1)
1542f08c3bdfSopenharmony_ci			continue;
1543f08c3bdfSopenharmony_ci		pathcat3(buf, sizeof(buf), distance_directory, dent->d_name,
1544f08c3bdfSopenharmony_ci			 "distance");
1545f08c3bdfSopenharmony_ci		if (parse_distance_file(node, buf) < 0)
1546f08c3bdfSopenharmony_ci			goto err;
1547f08c3bdfSopenharmony_ci	}
1548f08c3bdfSopenharmony_ci	closedir(dir);
1549f08c3bdfSopenharmony_ci	return;
1550f08c3bdfSopenharmony_cierr:
1551f08c3bdfSopenharmony_ci	if (dir)
1552f08c3bdfSopenharmony_ci		closedir(dir);
1553f08c3bdfSopenharmony_ci	free(distmap);
1554f08c3bdfSopenharmony_ci	distmap = NULL;
1555f08c3bdfSopenharmony_ci}
1556f08c3bdfSopenharmony_ci
1557f08c3bdfSopenharmony_ci#ifdef ALTERNATE_SN_DISTMAP
1558f08c3bdfSopenharmony_ci
1559f08c3bdfSopenharmony_ci/*
1560f08c3bdfSopenharmony_ci * Parse SN architecture specific line of form:
1561f08c3bdfSopenharmony_ci *
1562f08c3bdfSopenharmony_ci *	node 3 001c14#1 local asic SHub_1.1, nasid 0x6, dist 66:46:20:10
1563f08c3bdfSopenharmony_ci *
1564f08c3bdfSopenharmony_ci * Second field is node number.  The "dist" field is the colon separated list
1565f08c3bdfSopenharmony_ci * of distances, which is parsed into array dists[] of each nodes distance
1566f08c3bdfSopenharmony_ci * from that node.
1567f08c3bdfSopenharmony_ci *
1568f08c3bdfSopenharmony_ci * Result is placed in distmap[ncpus][nmems]:
1569f08c3bdfSopenharmony_ci *
1570f08c3bdfSopenharmony_ci *	For each cpu c on that node:
1571f08c3bdfSopenharmony_ci *		For each node position n in list of distances:
1572f08c3bdfSopenharmony_ci *			distmap[c][n] = dists[n]
1573f08c3bdfSopenharmony_ci */
1574f08c3bdfSopenharmony_ci
1575f08c3bdfSopenharmony_cistatic void parse_distmap_line_sn(char *buf)
1576f08c3bdfSopenharmony_ci{
1577f08c3bdfSopenharmony_ci	char *p, *pend, *q;
1578f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1579f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1580f08c3bdfSopenharmony_ci	unsigned long c, n, node;
1581f08c3bdfSopenharmony_ci	distmap_entry_t *dists = NULL;
1582f08c3bdfSopenharmony_ci	struct bitmask *cpus = NULL, *mems = NULL;
1583f08c3bdfSopenharmony_ci
1584f08c3bdfSopenharmony_ci	if ((p = strchr(buf, ' ')) == NULL)
1585f08c3bdfSopenharmony_ci		goto err;
1586f08c3bdfSopenharmony_ci	if ((node = strtoul(p, &q, 10)) >= (unsigned int)nmems)
1587f08c3bdfSopenharmony_ci		goto err;
1588f08c3bdfSopenharmony_ci	if ((p = strstr(q, " dist ")) == NULL)
1589f08c3bdfSopenharmony_ci		goto err;
1590f08c3bdfSopenharmony_ci	p += strlen(" dist ");
1591f08c3bdfSopenharmony_ci	if ((pend = strchr(p, ' ')) != NULL)
1592f08c3bdfSopenharmony_ci		*pend = '\0';
1593f08c3bdfSopenharmony_ci	if ((dists = calloc(nmems, sizeof(*dists))) == NULL)
1594f08c3bdfSopenharmony_ci		goto err;
1595f08c3bdfSopenharmony_ci	for (n = 0; n < (unsigned int)nmems; n++)
1596f08c3bdfSopenharmony_ci		dists[n] = DISTMAP_MAX;
1597f08c3bdfSopenharmony_ci
1598f08c3bdfSopenharmony_ci	for (n = 0; n < (unsigned int)nmems && *p; n++, p = q) {
1599f08c3bdfSopenharmony_ci		unsigned long d;
1600f08c3bdfSopenharmony_ci
1601f08c3bdfSopenharmony_ci		if ((p = strpbrk(p, "0123456789")) == NULL)
1602f08c3bdfSopenharmony_ci			break;
1603f08c3bdfSopenharmony_ci		d = strtoul(p, &q, 10);
1604f08c3bdfSopenharmony_ci		if (p == q)
1605f08c3bdfSopenharmony_ci			break;
1606f08c3bdfSopenharmony_ci		if (d < DISTMAP_MAX)
1607f08c3bdfSopenharmony_ci			dists[n] = (distmap_entry_t) d;
1608f08c3bdfSopenharmony_ci	}
1609f08c3bdfSopenharmony_ci
1610f08c3bdfSopenharmony_ci	if ((mems = bitmask_alloc(nmems)) == NULL)
1611f08c3bdfSopenharmony_ci		goto err;
1612f08c3bdfSopenharmony_ci	bitmask_setbit(mems, node);
1613f08c3bdfSopenharmony_ci
1614f08c3bdfSopenharmony_ci	if ((cpus = bitmask_alloc(ncpus)) == NULL)
1615f08c3bdfSopenharmony_ci		goto err;
1616f08c3bdfSopenharmony_ci	cpuset_localcpus(mems, cpus);
1617f08c3bdfSopenharmony_ci
1618f08c3bdfSopenharmony_ci	for (c = bitmask_first(cpus); c < (unsigned int)ncpus;
1619f08c3bdfSopenharmony_ci	     c = bitmask_next(cpus, c + 1))
1620f08c3bdfSopenharmony_ci		for (n = 0; n < (unsigned int)nmems; n++)
1621f08c3bdfSopenharmony_ci			distmap[I(c, n)] = dists[n];
1622f08c3bdfSopenharmony_ci	/* fall into ... */
1623f08c3bdfSopenharmony_cierr:
1624f08c3bdfSopenharmony_ci	bitmask_free(mems);
1625f08c3bdfSopenharmony_ci	bitmask_free(cpus);
1626f08c3bdfSopenharmony_ci	free(dists);
1627f08c3bdfSopenharmony_ci}
1628f08c3bdfSopenharmony_ci
1629f08c3bdfSopenharmony_cistatic void build_distmap_sn(void)
1630f08c3bdfSopenharmony_ci{
1631f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1632f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1633f08c3bdfSopenharmony_ci	int c, m;
1634f08c3bdfSopenharmony_ci	static int tried_before = 0;
1635f08c3bdfSopenharmony_ci	FILE *fp = NULL;
1636f08c3bdfSopenharmony_ci	char *buf = NULL;
1637f08c3bdfSopenharmony_ci	int buflen;
1638f08c3bdfSopenharmony_ci
1639f08c3bdfSopenharmony_ci	if (tried_before)
1640f08c3bdfSopenharmony_ci		goto err;
1641f08c3bdfSopenharmony_ci	tried_before = 1;
1642f08c3bdfSopenharmony_ci
1643f08c3bdfSopenharmony_ci	if ((fp = fopen(sn_topology, "r")) == NULL)
1644f08c3bdfSopenharmony_ci		goto err;
1645f08c3bdfSopenharmony_ci
1646f08c3bdfSopenharmony_ci	if ((distmap = calloc(ncpus * nmems, sizeof(*distmap))) == NULL)
1647f08c3bdfSopenharmony_ci		goto err;
1648f08c3bdfSopenharmony_ci
1649f08c3bdfSopenharmony_ci	for (c = 0; c < ncpus; c++)
1650f08c3bdfSopenharmony_ci		for (m = 0; m < nmems; m++)
1651f08c3bdfSopenharmony_ci			distmap[I(c, m)] = DISTMAP_MAX;
1652f08c3bdfSopenharmony_ci
1653f08c3bdfSopenharmony_ci	buflen = filesize(fp);
1654f08c3bdfSopenharmony_ci	if ((buf = malloc(buflen)) == NULL)
1655f08c3bdfSopenharmony_ci		goto err;
1656f08c3bdfSopenharmony_ci
1657f08c3bdfSopenharmony_ci	while (flgets(buf, buflen, fp) != NULL)
1658f08c3bdfSopenharmony_ci		if (strprefix(buf, sn_top_node_prefix))
1659f08c3bdfSopenharmony_ci			parse_distmap_line_sn(buf);
1660f08c3bdfSopenharmony_ci
1661f08c3bdfSopenharmony_ci	free(buf);
1662f08c3bdfSopenharmony_ci	fclose(fp);
1663f08c3bdfSopenharmony_ci	return;
1664f08c3bdfSopenharmony_cierr:
1665f08c3bdfSopenharmony_ci	free(buf);
1666f08c3bdfSopenharmony_ci	free(distmap);
1667f08c3bdfSopenharmony_ci	distmap = NULL;
1668f08c3bdfSopenharmony_ci	if (fp)
1669f08c3bdfSopenharmony_ci		fclose(fp);
1670f08c3bdfSopenharmony_ci}
1671f08c3bdfSopenharmony_ci
1672f08c3bdfSopenharmony_ci#endif
1673f08c3bdfSopenharmony_ci
1674f08c3bdfSopenharmony_ci/* [optional] Hardware distance from CPU to Memory Node */
1675f08c3bdfSopenharmony_ciunsigned int cpuset_cpumemdist(int cpu, int mem)
1676f08c3bdfSopenharmony_ci{
1677f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1678f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1679f08c3bdfSopenharmony_ci	distmap_entry_t r = DISTMAP_MAX;
1680f08c3bdfSopenharmony_ci
1681f08c3bdfSopenharmony_ci	flockfile(stdout);
1682f08c3bdfSopenharmony_ci
1683f08c3bdfSopenharmony_ci	if (check() < 0)
1684f08c3bdfSopenharmony_ci		goto err;
1685f08c3bdfSopenharmony_ci
1686f08c3bdfSopenharmony_ci	if (distmap == NULL)
1687f08c3bdfSopenharmony_ci		build_distmap();
1688f08c3bdfSopenharmony_ci
1689f08c3bdfSopenharmony_ci#ifdef ALTERNATE_SN_DISTMAP
1690f08c3bdfSopenharmony_ci	if (distmap == NULL)
1691f08c3bdfSopenharmony_ci		build_distmap_sn();
1692f08c3bdfSopenharmony_ci#endif
1693f08c3bdfSopenharmony_ci
1694f08c3bdfSopenharmony_ci	if (distmap == NULL)
1695f08c3bdfSopenharmony_ci		goto err;
1696f08c3bdfSopenharmony_ci
1697f08c3bdfSopenharmony_ci	if (cpu < 0 || cpu >= ncpus || mem < 0 || mem >= nmems)
1698f08c3bdfSopenharmony_ci		goto err;
1699f08c3bdfSopenharmony_ci
1700f08c3bdfSopenharmony_ci	r = distmap[I(cpu, mem)];
1701f08c3bdfSopenharmony_ci	/* fall into ... */
1702f08c3bdfSopenharmony_cierr:
1703f08c3bdfSopenharmony_ci	funlockfile(stdout);
1704f08c3bdfSopenharmony_ci	return r;
1705f08c3bdfSopenharmony_ci}
1706f08c3bdfSopenharmony_ci
1707f08c3bdfSopenharmony_ci/* [optional] Return Memory Node closest to cpu */
1708f08c3bdfSopenharmony_ciint cpuset_cpu2node(int cpu)
1709f08c3bdfSopenharmony_ci{
1710f08c3bdfSopenharmony_ci	int ncpus = cpuset_cpus_nbits();
1711f08c3bdfSopenharmony_ci	int nmems = cpuset_mems_nbits();
1712f08c3bdfSopenharmony_ci	struct bitmask *cpus = NULL, *mems = NULL;
1713f08c3bdfSopenharmony_ci	int r = -1;
1714f08c3bdfSopenharmony_ci
1715f08c3bdfSopenharmony_ci	if (check() < 0)
1716f08c3bdfSopenharmony_ci		goto err;
1717f08c3bdfSopenharmony_ci
1718f08c3bdfSopenharmony_ci	if ((cpus = bitmask_alloc(ncpus)) == NULL)
1719f08c3bdfSopenharmony_ci		goto err;
1720f08c3bdfSopenharmony_ci	bitmask_setbit(cpus, cpu);
1721f08c3bdfSopenharmony_ci
1722f08c3bdfSopenharmony_ci	if ((mems = bitmask_alloc(nmems)) == NULL)
1723f08c3bdfSopenharmony_ci		goto err;
1724f08c3bdfSopenharmony_ci	cpuset_localmems(cpus, mems);
1725f08c3bdfSopenharmony_ci	r = bitmask_first(mems);
1726f08c3bdfSopenharmony_ci	/* fall into ... */
1727f08c3bdfSopenharmony_cierr:
1728f08c3bdfSopenharmony_ci	bitmask_free(cpus);
1729f08c3bdfSopenharmony_ci	bitmask_free(mems);
1730f08c3bdfSopenharmony_ci	return r;
1731f08c3bdfSopenharmony_ci}
1732f08c3bdfSopenharmony_ci
1733f08c3bdfSopenharmony_cistatic int apply_cpuset_settings(const char *path, const struct cpuset *cp)
1734f08c3bdfSopenharmony_ci{
1735f08c3bdfSopenharmony_ci	if (cp->cpu_exclusive_valid && cp->cpu_exclusive_dirty) {
1736f08c3bdfSopenharmony_ci		if (store_flag(path, "cpu_exclusive", cp->cpu_exclusive) < 0)
1737f08c3bdfSopenharmony_ci			goto err;
1738f08c3bdfSopenharmony_ci	}
1739f08c3bdfSopenharmony_ci
1740f08c3bdfSopenharmony_ci	if (cp->mem_exclusive_valid && cp->mem_exclusive_dirty) {
1741f08c3bdfSopenharmony_ci		if (store_flag(path, "mem_exclusive", cp->mem_exclusive) < 0)
1742f08c3bdfSopenharmony_ci			goto err;
1743f08c3bdfSopenharmony_ci	}
1744f08c3bdfSopenharmony_ci
1745f08c3bdfSopenharmony_ci	if (cp->mem_hardwall_valid && cp->mem_hardwall_dirty) {
1746f08c3bdfSopenharmony_ci		if (store_flag(path, "mem_hardwall", cp->mem_hardwall) < 0)
1747f08c3bdfSopenharmony_ci			goto err;
1748f08c3bdfSopenharmony_ci	}
1749f08c3bdfSopenharmony_ci
1750f08c3bdfSopenharmony_ci	if (cp->notify_on_release_valid && cp->notify_on_release_dirty) {
1751f08c3bdfSopenharmony_ci		if (store_flag(path, "notify_on_release", cp->notify_on_release)
1752f08c3bdfSopenharmony_ci		    < 0)
1753f08c3bdfSopenharmony_ci			goto err;
1754f08c3bdfSopenharmony_ci	}
1755f08c3bdfSopenharmony_ci
1756f08c3bdfSopenharmony_ci	if (cp->memory_migrate_valid &&
1757f08c3bdfSopenharmony_ci	    cp->memory_migrate_dirty && exists_flag(path, "memory_migrate")) {
1758f08c3bdfSopenharmony_ci		if (store_flag(path, "memory_migrate", cp->memory_migrate) < 0)
1759f08c3bdfSopenharmony_ci			goto err;
1760f08c3bdfSopenharmony_ci	}
1761f08c3bdfSopenharmony_ci
1762f08c3bdfSopenharmony_ci	if (cp->memory_pressure_enabled_valid &&
1763f08c3bdfSopenharmony_ci	    cp->memory_pressure_enabled_dirty &&
1764f08c3bdfSopenharmony_ci	    exists_flag(path, "memory_pressure_enabled")) {
1765f08c3bdfSopenharmony_ci		if (store_flag
1766f08c3bdfSopenharmony_ci		    (path, "memory_pressure_enabled",
1767f08c3bdfSopenharmony_ci		     cp->memory_pressure_enabled) < 0)
1768f08c3bdfSopenharmony_ci			goto err;
1769f08c3bdfSopenharmony_ci	}
1770f08c3bdfSopenharmony_ci
1771f08c3bdfSopenharmony_ci	if (cp->memory_spread_page_valid &&
1772f08c3bdfSopenharmony_ci	    cp->memory_spread_page_dirty &&
1773f08c3bdfSopenharmony_ci	    exists_flag(path, "memory_spread_page")) {
1774f08c3bdfSopenharmony_ci		if (store_flag
1775f08c3bdfSopenharmony_ci		    (path, "memory_spread_page", cp->memory_spread_page) < 0)
1776f08c3bdfSopenharmony_ci			goto err;
1777f08c3bdfSopenharmony_ci	}
1778f08c3bdfSopenharmony_ci
1779f08c3bdfSopenharmony_ci	if (cp->memory_spread_slab_valid &&
1780f08c3bdfSopenharmony_ci	    cp->memory_spread_slab_dirty &&
1781f08c3bdfSopenharmony_ci	    exists_flag(path, "memory_spread_slab")) {
1782f08c3bdfSopenharmony_ci		if (store_flag
1783f08c3bdfSopenharmony_ci		    (path, "memory_spread_slab", cp->memory_spread_slab) < 0)
1784f08c3bdfSopenharmony_ci			goto err;
1785f08c3bdfSopenharmony_ci	}
1786f08c3bdfSopenharmony_ci
1787f08c3bdfSopenharmony_ci	if (cp->sched_load_balance_valid &&
1788f08c3bdfSopenharmony_ci	    cp->sched_load_balance_dirty &&
1789f08c3bdfSopenharmony_ci	    exists_flag(path, "sched_load_balance")) {
1790f08c3bdfSopenharmony_ci		if (store_flag
1791f08c3bdfSopenharmony_ci		    (path, "sched_load_balance", cp->sched_load_balance) < 0)
1792f08c3bdfSopenharmony_ci			goto err;
1793f08c3bdfSopenharmony_ci	}
1794f08c3bdfSopenharmony_ci
1795f08c3bdfSopenharmony_ci	if (cp->sched_relax_domain_level_valid &&
1796f08c3bdfSopenharmony_ci	    cp->sched_relax_domain_level_dirty &&
1797f08c3bdfSopenharmony_ci	    exists_flag(path, "sched_relax_domain_level")) {
1798f08c3bdfSopenharmony_ci		if (store_number
1799f08c3bdfSopenharmony_ci		    (path, "sched_relax_domain_level",
1800f08c3bdfSopenharmony_ci		     cp->sched_relax_domain_level) < 0)
1801f08c3bdfSopenharmony_ci			goto err;
1802f08c3bdfSopenharmony_ci	}
1803f08c3bdfSopenharmony_ci
1804f08c3bdfSopenharmony_ci	if (cp->cpus_valid && cp->cpus_dirty) {
1805f08c3bdfSopenharmony_ci		if (store_mask(path, "cpus", cp->cpus) < 0)
1806f08c3bdfSopenharmony_ci			goto err;
1807f08c3bdfSopenharmony_ci	}
1808f08c3bdfSopenharmony_ci
1809f08c3bdfSopenharmony_ci	if (cp->mems_valid && cp->mems_dirty) {
1810f08c3bdfSopenharmony_ci		if (store_mask(path, "mems", cp->mems) < 0)
1811f08c3bdfSopenharmony_ci			goto err;
1812f08c3bdfSopenharmony_ci	}
1813f08c3bdfSopenharmony_ci	return 0;
1814f08c3bdfSopenharmony_cierr:
1815f08c3bdfSopenharmony_ci	return -1;
1816f08c3bdfSopenharmony_ci}
1817f08c3bdfSopenharmony_ci
1818f08c3bdfSopenharmony_ci/*
1819f08c3bdfSopenharmony_ci * get_siblings() - helper routine for cpuset_would_crash_kernel(), below.
1820f08c3bdfSopenharmony_ci *
1821f08c3bdfSopenharmony_ci * Extract max value of any 'siblings' field in /proc/cpuinfo.
1822f08c3bdfSopenharmony_ci * Cache the result - only need to extract once in lifetime of task.
1823f08c3bdfSopenharmony_ci *
1824f08c3bdfSopenharmony_ci * The siblings field is the number of logical CPUs in a physical
1825f08c3bdfSopenharmony_ci * processor package.  It is equal to the product of the number of
1826f08c3bdfSopenharmony_ci * cores in that package, times the number of hyper-threads per core.
1827f08c3bdfSopenharmony_ci * The bug that cpuset_would_crash_kernel() is detecting arises
1828f08c3bdfSopenharmony_ci * when a cpu_exclusive cpuset tries to include just some, not all,
1829f08c3bdfSopenharmony_ci * of the sibling logical CPUs available in a processor package.
1830f08c3bdfSopenharmony_ci *
1831f08c3bdfSopenharmony_ci * In the improbable case that a system has mixed values of siblings
1832f08c3bdfSopenharmony_ci * (some processor packages have more than others, perhaps due to
1833f08c3bdfSopenharmony_ci * partially enabling Hyper-Threading), we take the worse case value,
1834f08c3bdfSopenharmony_ci * the largest siblings value.  This might be overkill.  I don't know
1835f08c3bdfSopenharmony_ci * if this kernel bug considers each processor package's siblings
1836f08c3bdfSopenharmony_ci * separately or not.  But it sure is easier this way ...
1837f08c3bdfSopenharmony_ci *
1838f08c3bdfSopenharmony_ci * This routine takes about 0.7 msecs on a 4 CPU 2.8 MHz Xeon, from
1839f08c3bdfSopenharmony_ci * open to close, the first time called.
1840f08c3bdfSopenharmony_ci */
1841f08c3bdfSopenharmony_ci
1842f08c3bdfSopenharmony_cistatic int get_siblings(void)
1843f08c3bdfSopenharmony_ci{
1844f08c3bdfSopenharmony_ci	static int siblings;
1845f08c3bdfSopenharmony_ci	char buf[32];		/* big enough for one 'siblings' line */
1846f08c3bdfSopenharmony_ci	FILE *fp;
1847f08c3bdfSopenharmony_ci
1848f08c3bdfSopenharmony_ci	if (siblings)
1849f08c3bdfSopenharmony_ci		return siblings;
1850f08c3bdfSopenharmony_ci
1851f08c3bdfSopenharmony_ci	if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
1852f08c3bdfSopenharmony_ci		return 4;	/* wing it - /proc not mounted ? */
1853f08c3bdfSopenharmony_ci	while (flgets(buf, sizeof(buf), fp) != NULL) {
1854f08c3bdfSopenharmony_ci		int s;
1855f08c3bdfSopenharmony_ci
1856f08c3bdfSopenharmony_ci		if (sscanf(buf, "siblings : %d", &s) < 1)
1857f08c3bdfSopenharmony_ci			continue;
1858f08c3bdfSopenharmony_ci		if (s > siblings)
1859f08c3bdfSopenharmony_ci			siblings = s;
1860f08c3bdfSopenharmony_ci	}
1861f08c3bdfSopenharmony_ci	fclose(fp);
1862f08c3bdfSopenharmony_ci	if (siblings == 0)
1863f08c3bdfSopenharmony_ci		siblings = 1;	/* old kernel, no siblings, default to 1 */
1864f08c3bdfSopenharmony_ci	return siblings;
1865f08c3bdfSopenharmony_ci}
1866f08c3bdfSopenharmony_ci
1867f08c3bdfSopenharmony_ci/*
1868f08c3bdfSopenharmony_ci * Some 2.6.16 and 2.6.17 kernel versions have a bug in the dynamic
1869f08c3bdfSopenharmony_ci * scheduler domain code invoked for cpu_exclusive cpusets that causes
1870f08c3bdfSopenharmony_ci * the kernel to freeze, requiring a hardware reset.
1871f08c3bdfSopenharmony_ci *
1872f08c3bdfSopenharmony_ci * On kernels built with CONFIG_SCHED_MC enabled, if a 'cpu_exclusive'
1873f08c3bdfSopenharmony_ci * cpuset is defined where that cpusets 'cpus' are not on package
1874f08c3bdfSopenharmony_ci * boundaries then the kernel will freeze, usually as soon as this
1875f08c3bdfSopenharmony_ci * cpuset is created, requiring a hardware reset.
1876f08c3bdfSopenharmony_ci *
1877f08c3bdfSopenharmony_ci * A cpusets 'cpus' are not on package boundaries if the cpuset
1878f08c3bdfSopenharmony_ci * includes a proper non-empty subset (some, but not all) of the
1879f08c3bdfSopenharmony_ci * logical cpus on a processor package.  This requires multiple
1880f08c3bdfSopenharmony_ci * logical CPUs per package, available with either Hyper-Thread or
1881f08c3bdfSopenharmony_ci * Multi-Core support.  Without one of these features, there is only
1882f08c3bdfSopenharmony_ci * one logical CPU per physical package, and it's not possible to
1883f08c3bdfSopenharmony_ci * have a proper, non-empty subset of a set of cardinality one.
1884f08c3bdfSopenharmony_ci *
1885f08c3bdfSopenharmony_ci * SUSE SLES10 kernels, as first released, only enable CONFIG_SCHED_MC
1886f08c3bdfSopenharmony_ci * on i386 and x86_64 arch's.
1887f08c3bdfSopenharmony_ci *
1888f08c3bdfSopenharmony_ci * The objective of this routine cpuset_would_crash_kernel() is to
1889f08c3bdfSopenharmony_ci * determine if a proposed cpuset setting would crash the kernel due
1890f08c3bdfSopenharmony_ci * to this bug, so that the caller can avoid the crash.
1891f08c3bdfSopenharmony_ci *
1892f08c3bdfSopenharmony_ci * Ideally we'd check for exactly these conditions here, but computing
1893f08c3bdfSopenharmony_ci * the package (identified by the 'physical id' field of /proc/cpuinfo)
1894f08c3bdfSopenharmony_ci * of each cpu in a cpuset is more effort than it's worth here.
1895f08c3bdfSopenharmony_ci *
1896f08c3bdfSopenharmony_ci * Also there is no obvious way to identify exactly whether the kernel
1897f08c3bdfSopenharmony_ci * one is executing on has this bug, short of trying it, and seeing
1898f08c3bdfSopenharmony_ci * if the kernel just crashed.
1899f08c3bdfSopenharmony_ci *
1900f08c3bdfSopenharmony_ci * So for now, we look for a simpler set of conditions, that meets
1901f08c3bdfSopenharmony_ci * our immediate need - avoid this crash on SUSE SLES10 systems that
1902f08c3bdfSopenharmony_ci * are susceptible to it.  We look for the kernel version 2.6.16.*,
1903f08c3bdfSopenharmony_ci * which is the base kernel of SUSE SLES10, and for i386 or x86_64
1904f08c3bdfSopenharmony_ci * processors, which had CONFIG_SCHED_MC enabled.
1905f08c3bdfSopenharmony_ci *
1906f08c3bdfSopenharmony_ci * If these simpler conditions are met, we further simplify the check,
1907f08c3bdfSopenharmony_ci * by presuming that the logical CPUs are numbered on processor
1908f08c3bdfSopenharmony_ci * package boundaries.  If each package has S siblings, we assume
1909f08c3bdfSopenharmony_ci * that CPUs numbered N through N + S -1 are on the same package,
1910f08c3bdfSopenharmony_ci * for any CPU N such that N mod S == 0.
1911f08c3bdfSopenharmony_ci *
1912f08c3bdfSopenharmony_ci * Yes, this is a hack, focused on avoiding kernel freezes on
1913f08c3bdfSopenharmony_ci * susceptible SUSE SLES10 systems.
1914f08c3bdfSopenharmony_ci */
1915f08c3bdfSopenharmony_ci
1916f08c3bdfSopenharmony_cistatic int cpuset_would_crash_kernel(const struct cpuset *cp)
1917f08c3bdfSopenharmony_ci{
1918f08c3bdfSopenharmony_ci	static int susceptible_system = -1;
1919f08c3bdfSopenharmony_ci
1920f08c3bdfSopenharmony_ci	if (!cp->cpu_exclusive)
1921f08c3bdfSopenharmony_ci		goto ok;
1922f08c3bdfSopenharmony_ci
1923f08c3bdfSopenharmony_ci	if (susceptible_system == -1) {
1924f08c3bdfSopenharmony_ci		struct utsname u;
1925f08c3bdfSopenharmony_ci		int rel_2_6_16, arch_i386, arch_x86_64;
1926f08c3bdfSopenharmony_ci
1927f08c3bdfSopenharmony_ci		if (uname(&u) < 0)
1928f08c3bdfSopenharmony_ci			goto fail;
1929f08c3bdfSopenharmony_ci		rel_2_6_16 = strprefix(u.release, "2.6.16.");
1930f08c3bdfSopenharmony_ci		arch_i386 = streq(u.machine, "i386");
1931f08c3bdfSopenharmony_ci		arch_x86_64 = streq(u.machine, "x86_64");
1932f08c3bdfSopenharmony_ci		susceptible_system = rel_2_6_16 && (arch_i386 || arch_x86_64);
1933f08c3bdfSopenharmony_ci	}
1934f08c3bdfSopenharmony_ci
1935f08c3bdfSopenharmony_ci	if (susceptible_system) {
1936f08c3bdfSopenharmony_ci		int ncpus = cpuset_cpus_nbits();
1937f08c3bdfSopenharmony_ci		int siblings = get_siblings();
1938f08c3bdfSopenharmony_ci		unsigned int cpu;
1939f08c3bdfSopenharmony_ci
1940f08c3bdfSopenharmony_ci		for (cpu = 0; cpu < (unsigned int)ncpus; cpu += siblings) {
1941f08c3bdfSopenharmony_ci			int s, num_set = 0;
1942f08c3bdfSopenharmony_ci
1943f08c3bdfSopenharmony_ci			for (s = 0; s < siblings; s++) {
1944f08c3bdfSopenharmony_ci				if (bitmask_isbitset(cp->cpus, cpu + s))
1945f08c3bdfSopenharmony_ci					num_set++;
1946f08c3bdfSopenharmony_ci			}
1947f08c3bdfSopenharmony_ci
1948f08c3bdfSopenharmony_ci			/* If none or all siblings set, we're still ok */
1949f08c3bdfSopenharmony_ci			if (num_set == 0 || num_set == siblings)
1950f08c3bdfSopenharmony_ci				continue;
1951f08c3bdfSopenharmony_ci
1952f08c3bdfSopenharmony_ci			/* Found one that would crash kernel.  Fail.  */
1953f08c3bdfSopenharmony_ci			errno = ENXIO;
1954f08c3bdfSopenharmony_ci			goto fail;
1955f08c3bdfSopenharmony_ci		}
1956f08c3bdfSopenharmony_ci	}
1957f08c3bdfSopenharmony_ci	/* If not susceptible, or if all ok, fall into "ok" ... */
1958f08c3bdfSopenharmony_ciok:
1959f08c3bdfSopenharmony_ci	return 0;		/* would not crash */
1960f08c3bdfSopenharmony_cifail:
1961f08c3bdfSopenharmony_ci	return 1;		/* would crash */
1962f08c3bdfSopenharmony_ci}
1963f08c3bdfSopenharmony_ci
1964f08c3bdfSopenharmony_ci/* compare two cpuset and mark the dirty variable */
1965f08c3bdfSopenharmony_cistatic void mark_dirty_variable(struct cpuset *cp1, const struct cpuset *cp2)
1966f08c3bdfSopenharmony_ci{
1967f08c3bdfSopenharmony_ci	if (cp1->cpu_exclusive_valid &&
1968f08c3bdfSopenharmony_ci	    cp1->cpu_exclusive != cp2->cpu_exclusive)
1969f08c3bdfSopenharmony_ci		cp1->cpu_exclusive_dirty = 1;
1970f08c3bdfSopenharmony_ci
1971f08c3bdfSopenharmony_ci	if (cp1->mem_exclusive_valid &&
1972f08c3bdfSopenharmony_ci	    cp1->mem_exclusive != cp2->mem_exclusive)
1973f08c3bdfSopenharmony_ci		cp1->mem_exclusive_dirty = 1;
1974f08c3bdfSopenharmony_ci
1975f08c3bdfSopenharmony_ci	if (cp1->mem_hardwall_valid && cp1->mem_hardwall != cp2->mem_hardwall)
1976f08c3bdfSopenharmony_ci		cp1->mem_hardwall_dirty = 1;
1977f08c3bdfSopenharmony_ci
1978f08c3bdfSopenharmony_ci	if (cp1->notify_on_release_valid &&
1979f08c3bdfSopenharmony_ci	    cp1->notify_on_release != cp2->notify_on_release)
1980f08c3bdfSopenharmony_ci		cp1->notify_on_release_dirty = 1;
1981f08c3bdfSopenharmony_ci
1982f08c3bdfSopenharmony_ci	if (cp1->memory_migrate_valid &&
1983f08c3bdfSopenharmony_ci	    cp1->memory_migrate != cp2->memory_migrate)
1984f08c3bdfSopenharmony_ci		cp1->memory_migrate_dirty = 1;
1985f08c3bdfSopenharmony_ci
1986f08c3bdfSopenharmony_ci	if (cp1->memory_pressure_enabled_valid &&
1987f08c3bdfSopenharmony_ci	    cp1->memory_pressure_enabled != cp2->memory_pressure_enabled)
1988f08c3bdfSopenharmony_ci		cp1->memory_pressure_enabled_dirty = 1;
1989f08c3bdfSopenharmony_ci
1990f08c3bdfSopenharmony_ci	if (cp1->memory_spread_page_valid &&
1991f08c3bdfSopenharmony_ci	    cp1->memory_spread_page != cp2->memory_spread_page)
1992f08c3bdfSopenharmony_ci		cp1->memory_spread_page_dirty = 1;
1993f08c3bdfSopenharmony_ci
1994f08c3bdfSopenharmony_ci	if (cp1->memory_spread_slab_valid &&
1995f08c3bdfSopenharmony_ci	    cp1->memory_spread_slab != cp2->memory_spread_slab)
1996f08c3bdfSopenharmony_ci		cp1->memory_spread_slab_dirty = 1;
1997f08c3bdfSopenharmony_ci
1998f08c3bdfSopenharmony_ci	if (cp1->sched_load_balance_valid &&
1999f08c3bdfSopenharmony_ci	    cp1->sched_load_balance != cp2->sched_load_balance)
2000f08c3bdfSopenharmony_ci		cp1->sched_load_balance_dirty = 1;
2001f08c3bdfSopenharmony_ci
2002f08c3bdfSopenharmony_ci	if (cp1->sched_relax_domain_level_valid &&
2003f08c3bdfSopenharmony_ci	    cp1->sched_relax_domain_level != cp2->sched_relax_domain_level)
2004f08c3bdfSopenharmony_ci		cp1->sched_relax_domain_level_dirty = 1;
2005f08c3bdfSopenharmony_ci
2006f08c3bdfSopenharmony_ci	if (cp1->cpus_valid && !bitmask_equal(cp1->cpus, cp2->cpus))
2007f08c3bdfSopenharmony_ci		cp1->cpus_dirty = 1;
2008f08c3bdfSopenharmony_ci	if (cp1->mems_valid && !bitmask_equal(cp1->mems, cp2->mems))
2009f08c3bdfSopenharmony_ci		cp1->mems_dirty = 1;
2010f08c3bdfSopenharmony_ci}
2011f08c3bdfSopenharmony_ci
2012f08c3bdfSopenharmony_ci/* Create (if new set) or modify cpuset 'cp' at location 'relpath' */
2013f08c3bdfSopenharmony_cistatic int cr_or_mod(const char *relpath, const struct cpuset *cp, int new)
2014f08c3bdfSopenharmony_ci{
2015f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2016f08c3bdfSopenharmony_ci	int do_rmdir_on_err = 0;
2017f08c3bdfSopenharmony_ci	int do_restore_cp_sav_on_err = 0;
2018f08c3bdfSopenharmony_ci	struct cpuset *cp_sav = NULL;
2019f08c3bdfSopenharmony_ci	int sav_errno;
2020f08c3bdfSopenharmony_ci
2021f08c3bdfSopenharmony_ci	if (check() < 0)
2022f08c3bdfSopenharmony_ci		goto err;
2023f08c3bdfSopenharmony_ci
2024f08c3bdfSopenharmony_ci	if (cpuset_would_crash_kernel(cp))
2025f08c3bdfSopenharmony_ci		goto err;
2026f08c3bdfSopenharmony_ci
2027f08c3bdfSopenharmony_ci	fullpath(buf, sizeof(buf), relpath);
2028f08c3bdfSopenharmony_ci
2029f08c3bdfSopenharmony_ci	if (new) {
2030f08c3bdfSopenharmony_ci		if (mkdir(buf, 0755) < 0)
2031f08c3bdfSopenharmony_ci			goto err;
2032f08c3bdfSopenharmony_ci		/* we made it, so we should remove it on error */
2033f08c3bdfSopenharmony_ci		do_rmdir_on_err = 1;
2034f08c3bdfSopenharmony_ci	}
2035f08c3bdfSopenharmony_ci
2036f08c3bdfSopenharmony_ci	if ((cp_sav = cpuset_alloc()) == NULL)
2037f08c3bdfSopenharmony_ci		goto err;
2038f08c3bdfSopenharmony_ci	if (cpuset_query(cp_sav, relpath) < 0)
2039f08c3bdfSopenharmony_ci		goto err;
2040f08c3bdfSopenharmony_ci	/* we have old settings to restore on error */
2041f08c3bdfSopenharmony_ci	do_restore_cp_sav_on_err = 1;
2042f08c3bdfSopenharmony_ci
2043f08c3bdfSopenharmony_ci	/* check which variable need to restore on error */
2044f08c3bdfSopenharmony_ci	mark_dirty_variable(cp_sav, cp);
2045f08c3bdfSopenharmony_ci
2046f08c3bdfSopenharmony_ci	if (apply_cpuset_settings(buf, cp) < 0)
2047f08c3bdfSopenharmony_ci		goto err;
2048f08c3bdfSopenharmony_ci
2049f08c3bdfSopenharmony_ci	cpuset_free(cp_sav);
2050f08c3bdfSopenharmony_ci	return 0;
2051f08c3bdfSopenharmony_cierr:
2052f08c3bdfSopenharmony_ci	sav_errno = errno;
2053f08c3bdfSopenharmony_ci	if (do_restore_cp_sav_on_err)
2054f08c3bdfSopenharmony_ci		(void)apply_cpuset_settings(buf, cp_sav);
2055f08c3bdfSopenharmony_ci	if (cp_sav)
2056f08c3bdfSopenharmony_ci		cpuset_free(cp_sav);
2057f08c3bdfSopenharmony_ci	if (do_rmdir_on_err)
2058f08c3bdfSopenharmony_ci		(void)rmdir(buf);
2059f08c3bdfSopenharmony_ci	errno = sav_errno;
2060f08c3bdfSopenharmony_ci	return -1;
2061f08c3bdfSopenharmony_ci}
2062f08c3bdfSopenharmony_ci
2063f08c3bdfSopenharmony_ci/* Create cpuset 'cp' at location 'relpath' */
2064f08c3bdfSopenharmony_ciint cpuset_create(const char *relpath, const struct cpuset *cp)
2065f08c3bdfSopenharmony_ci{
2066f08c3bdfSopenharmony_ci	return cr_or_mod(relpath, cp, 1);
2067f08c3bdfSopenharmony_ci}
2068f08c3bdfSopenharmony_ci
2069f08c3bdfSopenharmony_ci/* Delete cpuset at location 'path' (if empty) */
2070f08c3bdfSopenharmony_ciint cpuset_delete(const char *relpath)
2071f08c3bdfSopenharmony_ci{
2072f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2073f08c3bdfSopenharmony_ci
2074f08c3bdfSopenharmony_ci	if (check() < 0)
2075f08c3bdfSopenharmony_ci		goto err;
2076f08c3bdfSopenharmony_ci
2077f08c3bdfSopenharmony_ci	fullpath(buf, sizeof(buf), relpath);
2078f08c3bdfSopenharmony_ci	if (rmdir(buf) < 0)
2079f08c3bdfSopenharmony_ci		goto err;
2080f08c3bdfSopenharmony_ci
2081f08c3bdfSopenharmony_ci	return 0;
2082f08c3bdfSopenharmony_cierr:
2083f08c3bdfSopenharmony_ci	return -1;
2084f08c3bdfSopenharmony_ci}
2085f08c3bdfSopenharmony_ci
2086f08c3bdfSopenharmony_ci/* Set cpuset cp to the cpuset at location 'path' */
2087f08c3bdfSopenharmony_ciint cpuset_query(struct cpuset *cp, const char *relpath)
2088f08c3bdfSopenharmony_ci{
2089f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2090f08c3bdfSopenharmony_ci
2091f08c3bdfSopenharmony_ci	if (check() < 0)
2092f08c3bdfSopenharmony_ci		goto err;
2093f08c3bdfSopenharmony_ci
2094f08c3bdfSopenharmony_ci	fullpath(buf, sizeof(buf), relpath);
2095f08c3bdfSopenharmony_ci
2096f08c3bdfSopenharmony_ci	if (load_flag(buf, &cp->cpu_exclusive, "cpuset.cpu_exclusive") < 0)
2097f08c3bdfSopenharmony_ci		goto err;
2098f08c3bdfSopenharmony_ci	cp->cpu_exclusive_valid = 1;
2099f08c3bdfSopenharmony_ci
2100f08c3bdfSopenharmony_ci	if (load_flag(buf, &cp->mem_exclusive, "cpuset.mem_exclusive") < 0)
2101f08c3bdfSopenharmony_ci		goto err;
2102f08c3bdfSopenharmony_ci	cp->mem_exclusive_valid = 1;
2103f08c3bdfSopenharmony_ci
2104f08c3bdfSopenharmony_ci	if (load_flag(buf, &cp->notify_on_release, "notify_on_release") < 0)
2105f08c3bdfSopenharmony_ci		goto err;
2106f08c3bdfSopenharmony_ci	cp->notify_on_release_valid = 1;
2107f08c3bdfSopenharmony_ci
2108f08c3bdfSopenharmony_ci	if (exists_flag(buf, "cpuset.memory_migrate")) {
2109f08c3bdfSopenharmony_ci		if (load_flag(buf, &cp->memory_migrate, "cpuset.memory_migrate") < 0)
2110f08c3bdfSopenharmony_ci			goto err;
2111f08c3bdfSopenharmony_ci		cp->memory_migrate_valid = 1;
2112f08c3bdfSopenharmony_ci	}
2113f08c3bdfSopenharmony_ci
2114f08c3bdfSopenharmony_ci	if (exists_flag(buf, "cpuset.mem_hardwall")) {
2115f08c3bdfSopenharmony_ci		if (load_flag(buf, &cp->mem_hardwall, "cpuset.mem_hardwall") < 0)
2116f08c3bdfSopenharmony_ci			goto err;
2117f08c3bdfSopenharmony_ci		cp->mem_hardwall_valid = 1;
2118f08c3bdfSopenharmony_ci	}
2119f08c3bdfSopenharmony_ci
2120f08c3bdfSopenharmony_ci	if (exists_flag(buf, "cpuset.memory_pressure_enabled")) {
2121f08c3bdfSopenharmony_ci		if (load_flag
2122f08c3bdfSopenharmony_ci		    (buf, &cp->memory_pressure_enabled,
2123f08c3bdfSopenharmony_ci		     "cpuset.memory_pressure_enabled") < 0)
2124f08c3bdfSopenharmony_ci			goto err;
2125f08c3bdfSopenharmony_ci		cp->memory_pressure_enabled_valid = 1;
2126f08c3bdfSopenharmony_ci	}
2127f08c3bdfSopenharmony_ci
2128f08c3bdfSopenharmony_ci	if (exists_flag(buf, "cpuset.memory_spread_page")) {
2129f08c3bdfSopenharmony_ci		if (load_flag
2130f08c3bdfSopenharmony_ci		    (buf, &cp->memory_spread_page, "cpuset.memory_spread_page") < 0)
2131f08c3bdfSopenharmony_ci			goto err;
2132f08c3bdfSopenharmony_ci		cp->memory_spread_page_valid = 1;
2133f08c3bdfSopenharmony_ci	}
2134f08c3bdfSopenharmony_ci
2135f08c3bdfSopenharmony_ci	if (exists_flag(buf, "cpuset.memory_spread_slab")) {
2136f08c3bdfSopenharmony_ci		if (load_flag
2137f08c3bdfSopenharmony_ci		    (buf, &cp->memory_spread_slab, "cpuset.memory_spread_slab") < 0)
2138f08c3bdfSopenharmony_ci			goto err;
2139f08c3bdfSopenharmony_ci		cp->memory_spread_slab_valid = 1;
2140f08c3bdfSopenharmony_ci	}
2141f08c3bdfSopenharmony_ci
2142f08c3bdfSopenharmony_ci	if (exists_flag(buf, "cpuset.sched_load_balance")) {
2143f08c3bdfSopenharmony_ci		if (load_flag
2144f08c3bdfSopenharmony_ci		    (buf, &cp->sched_load_balance, "cpuset.sched_load_balance") < 0)
2145f08c3bdfSopenharmony_ci			goto err;
2146f08c3bdfSopenharmony_ci		cp->sched_load_balance_valid = 1;
2147f08c3bdfSopenharmony_ci	}
2148f08c3bdfSopenharmony_ci
2149f08c3bdfSopenharmony_ci	if (exists_flag(buf, "cpuset.sched_relax_domain_level")) {
2150f08c3bdfSopenharmony_ci		if (load_number
2151f08c3bdfSopenharmony_ci		    (buf, &cp->sched_relax_domain_level,
2152f08c3bdfSopenharmony_ci		     "cpuset.sched_relax_domain_level") < 0)
2153f08c3bdfSopenharmony_ci			goto err;
2154f08c3bdfSopenharmony_ci		cp->sched_relax_domain_level_valid = 1;
2155f08c3bdfSopenharmony_ci	}
2156f08c3bdfSopenharmony_ci
2157f08c3bdfSopenharmony_ci	if (load_mask(buf, &cp->cpus, cpuset_cpus_nbits(), "cpuset.cpus") < 0)
2158f08c3bdfSopenharmony_ci		goto err;
2159f08c3bdfSopenharmony_ci	cp->cpus_valid = 1;
2160f08c3bdfSopenharmony_ci
2161f08c3bdfSopenharmony_ci	if (load_mask(buf, &cp->mems, cpuset_mems_nbits(), "cpuset.mems") < 0)
2162f08c3bdfSopenharmony_ci		goto err;
2163f08c3bdfSopenharmony_ci	cp->mems_valid = 1;
2164f08c3bdfSopenharmony_ci
2165f08c3bdfSopenharmony_ci	return 0;
2166f08c3bdfSopenharmony_cierr:
2167f08c3bdfSopenharmony_ci	return -1;
2168f08c3bdfSopenharmony_ci}
2169f08c3bdfSopenharmony_ci
2170f08c3bdfSopenharmony_ci/* Modify cpuset at location 'relpath' to values of 'cp' */
2171f08c3bdfSopenharmony_ciint cpuset_modify(const char *relpath, const struct cpuset *cp)
2172f08c3bdfSopenharmony_ci{
2173f08c3bdfSopenharmony_ci	return cr_or_mod(relpath, cp, 0);
2174f08c3bdfSopenharmony_ci}
2175f08c3bdfSopenharmony_ci
2176f08c3bdfSopenharmony_ci/* Get cpuset path of pid into buf */
2177f08c3bdfSopenharmony_cichar *cpuset_getcpusetpath(pid_t pid, char *buf, size_t size)
2178f08c3bdfSopenharmony_ci{
2179f08c3bdfSopenharmony_ci	int fd;			/* dual use: cpuset file for pid and self */
2180f08c3bdfSopenharmony_ci	int rc;			/* dual use: snprintf and read return codes */
2181f08c3bdfSopenharmony_ci
2182f08c3bdfSopenharmony_ci	if (check() < 0)
2183f08c3bdfSopenharmony_ci		return NULL;
2184f08c3bdfSopenharmony_ci
2185f08c3bdfSopenharmony_ci	/* borrow result buf[] to build cpuset file path */
2186f08c3bdfSopenharmony_ci	if (pid == 0)
2187f08c3bdfSopenharmony_ci		rc = snprintf(buf, size, "/proc/self/cpuset");
2188f08c3bdfSopenharmony_ci	else
2189f08c3bdfSopenharmony_ci		rc = snprintf(buf, size, "/proc/%d/cpuset", pid);
2190f08c3bdfSopenharmony_ci	if (rc >= (int)size) {
2191f08c3bdfSopenharmony_ci		errno = E2BIG;
2192f08c3bdfSopenharmony_ci		return NULL;
2193f08c3bdfSopenharmony_ci	}
2194f08c3bdfSopenharmony_ci	if ((fd = open(buf, O_RDONLY)) < 0) {
2195f08c3bdfSopenharmony_ci		int e = errno;
2196f08c3bdfSopenharmony_ci		if (e == ENOENT)
2197f08c3bdfSopenharmony_ci			e = ESRCH;
2198f08c3bdfSopenharmony_ci		if ((fd = open("/proc/self/cpuset", O_RDONLY)) < 0)
2199f08c3bdfSopenharmony_ci			e = ENOSYS;
2200f08c3bdfSopenharmony_ci		else
2201f08c3bdfSopenharmony_ci			close(fd);
2202f08c3bdfSopenharmony_ci		errno = e;
2203f08c3bdfSopenharmony_ci		return NULL;
2204f08c3bdfSopenharmony_ci	}
2205f08c3bdfSopenharmony_ci	rc = read(fd, buf, size);
2206f08c3bdfSopenharmony_ci	close(fd);
2207f08c3bdfSopenharmony_ci	if (rc < 0)
2208f08c3bdfSopenharmony_ci		return NULL;
2209f08c3bdfSopenharmony_ci	if (rc >= (int)size) {
2210f08c3bdfSopenharmony_ci		errno = E2BIG;
2211f08c3bdfSopenharmony_ci		return NULL;
2212f08c3bdfSopenharmony_ci	}
2213f08c3bdfSopenharmony_ci	buf[rc] = 0;
2214f08c3bdfSopenharmony_ci	chomp(buf);
2215f08c3bdfSopenharmony_ci	return buf;
2216f08c3bdfSopenharmony_ci
2217f08c3bdfSopenharmony_ci}
2218f08c3bdfSopenharmony_ci
2219f08c3bdfSopenharmony_ci/* Get cpuset 'cp' of pid */
2220f08c3bdfSopenharmony_ciint cpuset_cpusetofpid(struct cpuset *cp, pid_t pid)
2221f08c3bdfSopenharmony_ci{
2222f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2223f08c3bdfSopenharmony_ci
2224f08c3bdfSopenharmony_ci	if (cpuset_getcpusetpath(pid, buf, sizeof(buf)) == NULL)
2225f08c3bdfSopenharmony_ci		return -1;
2226f08c3bdfSopenharmony_ci	if (cpuset_query(cp, buf) < 0)
2227f08c3bdfSopenharmony_ci		return -1;
2228f08c3bdfSopenharmony_ci	return 0;
2229f08c3bdfSopenharmony_ci}
2230f08c3bdfSopenharmony_ci
2231f08c3bdfSopenharmony_ci/* [optional] Return mountpoint of cpuset filesystem */
2232f08c3bdfSopenharmony_ciconst char *cpuset_mountpoint(void)
2233f08c3bdfSopenharmony_ci{
2234f08c3bdfSopenharmony_ci	if (check() < 0) {
2235f08c3bdfSopenharmony_ci		switch (errno) {
2236f08c3bdfSopenharmony_ci		case ENODEV:
2237f08c3bdfSopenharmony_ci			return "[cpuset filesystem not mounted]";
2238f08c3bdfSopenharmony_ci		default:
2239f08c3bdfSopenharmony_ci			return "[cpuset filesystem not supported]";
2240f08c3bdfSopenharmony_ci		}
2241f08c3bdfSopenharmony_ci	}
2242f08c3bdfSopenharmony_ci	return cpusetmnt;
2243f08c3bdfSopenharmony_ci}
2244f08c3bdfSopenharmony_ci
2245f08c3bdfSopenharmony_ci/* Return true if path is a directory. */
2246f08c3bdfSopenharmony_cistatic int isdir(const char *path)
2247f08c3bdfSopenharmony_ci{
2248f08c3bdfSopenharmony_ci	struct stat statbuf;
2249f08c3bdfSopenharmony_ci
2250f08c3bdfSopenharmony_ci	if (stat(path, &statbuf) < 0)
2251f08c3bdfSopenharmony_ci		return 0;
2252f08c3bdfSopenharmony_ci	return S_ISDIR(statbuf.st_mode);
2253f08c3bdfSopenharmony_ci}
2254f08c3bdfSopenharmony_ci
2255f08c3bdfSopenharmony_ci/*
2256f08c3bdfSopenharmony_ci * [optional] cpuset_collides_exclusive() - True if would collide exclusive.
2257f08c3bdfSopenharmony_ci *
2258f08c3bdfSopenharmony_ci * Return true iff the specified cpuset would overlap with any
2259f08c3bdfSopenharmony_ci * sibling cpusets in either cpus or mems, where either this
2260f08c3bdfSopenharmony_ci * cpuset or the sibling is cpu_exclusive or mem_exclusive.
2261f08c3bdfSopenharmony_ci *
2262f08c3bdfSopenharmony_ci * cpuset_create() fails with errno == EINVAL if the requested cpuset
2263f08c3bdfSopenharmony_ci * would overlap with any sibling, where either one is cpu_exclusive or
2264f08c3bdfSopenharmony_ci * mem_exclusive.  This is a common, and not obvious error.  The
2265f08c3bdfSopenharmony_ci * following routine checks for this particular case, so that code
2266f08c3bdfSopenharmony_ci * creating cpusets can better identify the situation, perhaps to issue
2267f08c3bdfSopenharmony_ci * a more informative error message.
2268f08c3bdfSopenharmony_ci *
2269f08c3bdfSopenharmony_ci * Can also be used to diagnose cpuset_modify failures.  This
2270f08c3bdfSopenharmony_ci * routine ignores any existing cpuset with the same path as the
2271f08c3bdfSopenharmony_ci * given 'cpusetpath', and only looks for exclusive collisions with
2272f08c3bdfSopenharmony_ci * sibling cpusets of that path.
2273f08c3bdfSopenharmony_ci *
2274f08c3bdfSopenharmony_ci * In case of any error, returns (0) -- does not collide.  Presumably
2275f08c3bdfSopenharmony_ci * any actual attempt to create or modify a cpuset will encounter the
2276f08c3bdfSopenharmony_ci * same error, and report it usefully.
2277f08c3bdfSopenharmony_ci *
2278f08c3bdfSopenharmony_ci * This routine is not particularly efficient; most likely code creating or
2279f08c3bdfSopenharmony_ci * modifying a cpuset will want to try the operation first, and then if that
2280f08c3bdfSopenharmony_ci * fails with errno EINVAL, perhaps call this routine to determine if an
2281f08c3bdfSopenharmony_ci * exclusive cpuset collision caused the error.
2282f08c3bdfSopenharmony_ci */
2283f08c3bdfSopenharmony_ci
2284f08c3bdfSopenharmony_ciint cpuset_collides_exclusive(const char *cpusetpath, const struct cpuset *cp1)
2285f08c3bdfSopenharmony_ci{
2286f08c3bdfSopenharmony_ci	char parent[PATH_MAX];
2287f08c3bdfSopenharmony_ci	char *p;
2288f08c3bdfSopenharmony_ci	char *pathcopy = NULL;
2289f08c3bdfSopenharmony_ci	char *base;
2290f08c3bdfSopenharmony_ci	DIR *dir = NULL;
2291f08c3bdfSopenharmony_ci	struct dirent *dent;
2292f08c3bdfSopenharmony_ci	struct cpuset *cp2 = NULL;
2293f08c3bdfSopenharmony_ci	struct bitmask *cpus1 = NULL, *cpus2 = NULL;
2294f08c3bdfSopenharmony_ci	struct bitmask *mems1 = NULL, *mems2 = NULL;
2295f08c3bdfSopenharmony_ci	int ret;
2296f08c3bdfSopenharmony_ci
2297f08c3bdfSopenharmony_ci	if (check() < 0)
2298f08c3bdfSopenharmony_ci		goto err;
2299f08c3bdfSopenharmony_ci
2300f08c3bdfSopenharmony_ci	fullpath(parent, sizeof(parent), cpusetpath);
2301f08c3bdfSopenharmony_ci	if (streq(parent, cpusetmnt))
2302f08c3bdfSopenharmony_ci		goto err;	/* only one cpuset root - can't collide */
2303f08c3bdfSopenharmony_ci	pathcopy = strdup(parent);
2304f08c3bdfSopenharmony_ci	p = strrchr(parent, '/');
2305f08c3bdfSopenharmony_ci	if (!p)
2306f08c3bdfSopenharmony_ci		goto err;	/* huh? - impossible - run and hide */
2307f08c3bdfSopenharmony_ci	*p = 0;			/* now parent is dirname of fullpath */
2308f08c3bdfSopenharmony_ci
2309f08c3bdfSopenharmony_ci	p = strrchr(pathcopy, '/');
2310f08c3bdfSopenharmony_ci	base = p + 1;		/* now base is basename of fullpath */
2311f08c3bdfSopenharmony_ci	if (!*base)
2312f08c3bdfSopenharmony_ci		goto err;	/* this is also impossible - run away */
2313f08c3bdfSopenharmony_ci
2314f08c3bdfSopenharmony_ci	if ((dir = opendir(parent)) == NULL)
2315f08c3bdfSopenharmony_ci		goto err;
2316f08c3bdfSopenharmony_ci	if ((cp2 = cpuset_alloc()) == NULL)
2317f08c3bdfSopenharmony_ci		goto err;
2318f08c3bdfSopenharmony_ci	if ((cpus1 = bitmask_alloc(cpuset_cpus_nbits())) == NULL)
2319f08c3bdfSopenharmony_ci		goto err;
2320f08c3bdfSopenharmony_ci	if ((cpus2 = bitmask_alloc(cpuset_cpus_nbits())) == NULL)
2321f08c3bdfSopenharmony_ci		goto err;
2322f08c3bdfSopenharmony_ci	if ((mems1 = bitmask_alloc(cpuset_mems_nbits())) == NULL)
2323f08c3bdfSopenharmony_ci		goto err;
2324f08c3bdfSopenharmony_ci	if ((mems2 = bitmask_alloc(cpuset_mems_nbits())) == NULL)
2325f08c3bdfSopenharmony_ci		goto err;
2326f08c3bdfSopenharmony_ci
2327f08c3bdfSopenharmony_ci	while ((dent = readdir(dir)) != NULL) {
2328f08c3bdfSopenharmony_ci		char child[PATH_MAX];
2329f08c3bdfSopenharmony_ci
2330f08c3bdfSopenharmony_ci		if (streq(dent->d_name, ".") || streq(dent->d_name, ".."))
2331f08c3bdfSopenharmony_ci			continue;
2332f08c3bdfSopenharmony_ci		if (streq(dent->d_name, base))
2333f08c3bdfSopenharmony_ci			continue;
2334f08c3bdfSopenharmony_ci		pathcat2(child, sizeof(child), parent, dent->d_name);
2335f08c3bdfSopenharmony_ci		if (!isdir(child))
2336f08c3bdfSopenharmony_ci			continue;
2337f08c3bdfSopenharmony_ci		if (cpuset_query(cp2, child + strlen(cpusetmnt)) < 0)
2338f08c3bdfSopenharmony_ci			goto err;
2339f08c3bdfSopenharmony_ci		if (cp1->cpu_exclusive || cp2->cpu_exclusive) {
2340f08c3bdfSopenharmony_ci			cpuset_getcpus(cp1, cpus1);
2341f08c3bdfSopenharmony_ci			cpuset_getcpus(cp2, cpus2);
2342f08c3bdfSopenharmony_ci			if (bitmask_intersects(cpus1, cpus2))
2343f08c3bdfSopenharmony_ci				goto collides;
2344f08c3bdfSopenharmony_ci		}
2345f08c3bdfSopenharmony_ci		if (cp1->mem_exclusive || cp2->mem_exclusive) {
2346f08c3bdfSopenharmony_ci			cpuset_getmems(cp1, mems1);
2347f08c3bdfSopenharmony_ci			cpuset_getmems(cp2, mems2);
2348f08c3bdfSopenharmony_ci			if (bitmask_intersects(mems1, mems2))
2349f08c3bdfSopenharmony_ci				goto collides;
2350f08c3bdfSopenharmony_ci		}
2351f08c3bdfSopenharmony_ci	}
2352f08c3bdfSopenharmony_cierr:
2353f08c3bdfSopenharmony_ci	/* error, or did not collide */
2354f08c3bdfSopenharmony_ci	ret = 0;
2355f08c3bdfSopenharmony_ci	goto done;
2356f08c3bdfSopenharmony_cicollides:
2357f08c3bdfSopenharmony_ci	/* collides */
2358f08c3bdfSopenharmony_ci	ret = 1;
2359f08c3bdfSopenharmony_ci	/* fall into ... */
2360f08c3bdfSopenharmony_cidone:
2361f08c3bdfSopenharmony_ci	if (dir)
2362f08c3bdfSopenharmony_ci		closedir(dir);
2363f08c3bdfSopenharmony_ci	cpuset_free(cp2);
2364f08c3bdfSopenharmony_ci	free(pathcopy);
2365f08c3bdfSopenharmony_ci	bitmask_free(cpus1);
2366f08c3bdfSopenharmony_ci	bitmask_free(cpus2);
2367f08c3bdfSopenharmony_ci	bitmask_free(mems1);
2368f08c3bdfSopenharmony_ci	bitmask_free(mems2);
2369f08c3bdfSopenharmony_ci	return ret;
2370f08c3bdfSopenharmony_ci}
2371f08c3bdfSopenharmony_ci
2372f08c3bdfSopenharmony_ci/*
2373f08c3bdfSopenharmony_ci * [optional] cpuset_nuke() - Remove cpuset anyway possible
2374f08c3bdfSopenharmony_ci *
2375f08c3bdfSopenharmony_ci * Remove a cpuset, including killing tasks in it, and
2376f08c3bdfSopenharmony_ci * removing any descendent cpusets and killing their tasks.
2377f08c3bdfSopenharmony_ci *
2378f08c3bdfSopenharmony_ci * Tasks can take a long time (minutes on some configurations)
2379f08c3bdfSopenharmony_ci * to exit.  Loop up to 'seconds' seconds, trying to kill them.
2380f08c3bdfSopenharmony_ci *
2381f08c3bdfSopenharmony_ci * How we do it:
2382f08c3bdfSopenharmony_ci *	1) First, kill all the pids, looping until there are
2383f08c3bdfSopenharmony_ci *	   no more pids in this cpuset or below, or until the
2384f08c3bdfSopenharmony_ci *	   'seconds' timeout limit is exceeded.
2385f08c3bdfSopenharmony_ci *	2) Then depth first recursively rmdir the cpuset directories.
2386f08c3bdfSopenharmony_ci *	3) If by this point the original cpuset is gone, we succeeded.
2387f08c3bdfSopenharmony_ci *
2388f08c3bdfSopenharmony_ci * If the timeout is exceeded, and tasks still exist, fail with
2389f08c3bdfSopenharmony_ci * errno == ETIME.
2390f08c3bdfSopenharmony_ci *
2391f08c3bdfSopenharmony_ci * We sleep a variable amount of time.  After the first attempt to
2392f08c3bdfSopenharmony_ci * kill all the tasks in the cpuset or its descendents, we sleep 1
2393f08c3bdfSopenharmony_ci * second, the next time 2 seconds, increasing 1 second each loop
2394f08c3bdfSopenharmony_ci * up to a max of 10 seconds.  If more loops past 10 are required
2395f08c3bdfSopenharmony_ci * to kill all the tasks, we sleep 10 seconds each subsequent loop.
2396f08c3bdfSopenharmony_ci * In any case, before the last loop, we sleep however many seconds
2397f08c3bdfSopenharmony_ci * remain of the original timeout 'seconds' requested.  The total
2398f08c3bdfSopenharmony_ci * time of all sleeps will be no more than the requested 'seconds'.
2399f08c3bdfSopenharmony_ci *
2400f08c3bdfSopenharmony_ci * If the cpuset started out empty of any tasks, or if the passed in
2401f08c3bdfSopenharmony_ci * 'seconds' was zero, then this routine will return quickly, having
2402f08c3bdfSopenharmony_ci * not slept at all.  Otherwise, this routine will at a minimum send
2403f08c3bdfSopenharmony_ci * a SIGKILL to all the tasks in this cpuset subtree, then sleep one
2404f08c3bdfSopenharmony_ci * second, before looking to see if any tasks remain.  If tasks remain
2405f08c3bdfSopenharmony_ci * in the cpuset subtree, and a longer 'seconds' timeout was requested
2406f08c3bdfSopenharmony_ci * (more than one), it will continue to kill remaining tasks and sleep,
2407f08c3bdfSopenharmony_ci * in a loop, for as long as time and tasks remain.
2408f08c3bdfSopenharmony_ci *
2409f08c3bdfSopenharmony_ci * The signal sent for the kill is hardcoded to SIGKILL (9).  If some
2410f08c3bdfSopenharmony_ci * other signal should be sent first, use a separate code loop,
2411f08c3bdfSopenharmony_ci * perhaps based on cpuset_init_pidlist and cpuset_get_pidlist, to
2412f08c3bdfSopenharmony_ci * scan the task pids in a cpuset.  If SIGKILL should -not- be sent,
2413f08c3bdfSopenharmony_ci * this cpuset_nuke() routine can still be called to recursively
2414f08c3bdfSopenharmony_ci * remove a cpuset subtree, by specifying a timeout of zero 'seconds'.
2415f08c3bdfSopenharmony_ci *
2416f08c3bdfSopenharmony_ci * On success, returns 0 with errno == 0.
2417f08c3bdfSopenharmony_ci *
2418f08c3bdfSopenharmony_ci * On failure, returns -1, with errno possibly one of:
2419f08c3bdfSopenharmony_ci *  EACCES - search permission denied on intervening directory
2420f08c3bdfSopenharmony_ci *  ETIME - timed out - tasks remain after 'seconds' timeout
2421f08c3bdfSopenharmony_ci *  EMFILE - too many open files
2422f08c3bdfSopenharmony_ci *  ENODEV - /dev/cpuset not mounted
2423f08c3bdfSopenharmony_ci *  ENOENT - component of cpuset path doesn't exist
2424f08c3bdfSopenharmony_ci *  ENOMEM - out of memory
2425f08c3bdfSopenharmony_ci *  ENOSYS - kernel doesn't support cpusets
2426f08c3bdfSopenharmony_ci *  ENOTDIR - component of cpuset path is not a directory
2427f08c3bdfSopenharmony_ci *  EPERM - lacked permission to kill a task
2428f08c3bdfSopenharmony_ci *  EPERM - lacked permission to read cpusets or files therein
2429f08c3bdfSopenharmony_ci */
2430f08c3bdfSopenharmony_ci
2431f08c3bdfSopenharmony_civoid cpuset_fts_reverse(struct cpuset_fts_tree *cs_tree);
2432f08c3bdfSopenharmony_ci
2433f08c3bdfSopenharmony_ciint cpuset_nuke(const char *relpath, unsigned int seconds)
2434f08c3bdfSopenharmony_ci{
2435f08c3bdfSopenharmony_ci	unsigned int secs_left = seconds;	/* total sleep seconds left */
2436f08c3bdfSopenharmony_ci	unsigned int secs_loop = 1;	/* how much sleep next loop */
2437f08c3bdfSopenharmony_ci	unsigned int secs_slept;	/* seconds slept in sleep() */
2438f08c3bdfSopenharmony_ci	struct cpuset_pidlist *pl = NULL;	/* pids in cpuset subtree */
2439f08c3bdfSopenharmony_ci	struct cpuset_fts_tree *cs_tree;
2440f08c3bdfSopenharmony_ci	const struct cpuset_fts_entry *cs_entry;
2441f08c3bdfSopenharmony_ci	int ret, sav_errno = 0;
2442f08c3bdfSopenharmony_ci
2443f08c3bdfSopenharmony_ci	if (check() < 0)
2444f08c3bdfSopenharmony_ci		return -1;
2445f08c3bdfSopenharmony_ci
2446f08c3bdfSopenharmony_ci	if (seconds == 0)
2447f08c3bdfSopenharmony_ci		goto rmdir_cpusets;
2448f08c3bdfSopenharmony_ci
2449f08c3bdfSopenharmony_ci	while (1) {
2450f08c3bdfSopenharmony_ci		int plen, j;
2451f08c3bdfSopenharmony_ci
2452f08c3bdfSopenharmony_ci		if ((pl = cpuset_init_pidlist(relpath, 1)) == NULL) {
2453f08c3bdfSopenharmony_ci			/* missing cpuset is as good as if already nuked */
2454f08c3bdfSopenharmony_ci			if (errno == ENOENT) {
2455f08c3bdfSopenharmony_ci				ret = 0;
2456f08c3bdfSopenharmony_ci				goto no_more_cpuset;
2457f08c3bdfSopenharmony_ci			}
2458f08c3bdfSopenharmony_ci
2459f08c3bdfSopenharmony_ci			/* other problems reading cpuset are bad news */
2460f08c3bdfSopenharmony_ci			sav_errno = errno;
2461f08c3bdfSopenharmony_ci			goto failed;
2462f08c3bdfSopenharmony_ci		}
2463f08c3bdfSopenharmony_ci
2464f08c3bdfSopenharmony_ci		if ((plen = cpuset_pidlist_length(pl)) == 0)
2465f08c3bdfSopenharmony_ci			goto rmdir_cpusets;
2466f08c3bdfSopenharmony_ci
2467f08c3bdfSopenharmony_ci		for (j = 0; j < plen; j++) {
2468f08c3bdfSopenharmony_ci			pid_t pid;
2469f08c3bdfSopenharmony_ci
2470f08c3bdfSopenharmony_ci			if ((pid = cpuset_get_pidlist(pl, j)) > 1) {
2471f08c3bdfSopenharmony_ci				if (kill(pid, SIGKILL) < 0 && errno != ESRCH) {
2472f08c3bdfSopenharmony_ci					sav_errno = errno;
2473f08c3bdfSopenharmony_ci					goto failed;
2474f08c3bdfSopenharmony_ci				}
2475f08c3bdfSopenharmony_ci			}
2476f08c3bdfSopenharmony_ci		}
2477f08c3bdfSopenharmony_ci
2478f08c3bdfSopenharmony_ci		if (secs_left == 0)
2479f08c3bdfSopenharmony_ci			goto took_too_long;
2480f08c3bdfSopenharmony_ci
2481f08c3bdfSopenharmony_ci		cpuset_freepidlist(pl);
2482f08c3bdfSopenharmony_ci		pl = NULL;
2483f08c3bdfSopenharmony_ci
2484f08c3bdfSopenharmony_ci		secs_slept = secs_loop - sleep(secs_loop);
2485f08c3bdfSopenharmony_ci
2486f08c3bdfSopenharmony_ci		/* Ensure forward progress */
2487f08c3bdfSopenharmony_ci		if (secs_slept == 0)
2488f08c3bdfSopenharmony_ci			secs_slept = 1;
2489f08c3bdfSopenharmony_ci
2490f08c3bdfSopenharmony_ci		/* Ensure sane sleep() return (unnecessary?) */
2491f08c3bdfSopenharmony_ci		if (secs_slept > secs_loop)
2492f08c3bdfSopenharmony_ci			secs_slept = secs_loop;
2493f08c3bdfSopenharmony_ci
2494f08c3bdfSopenharmony_ci		secs_left -= secs_slept;
2495f08c3bdfSopenharmony_ci
2496f08c3bdfSopenharmony_ci		if (secs_loop < 10)
2497f08c3bdfSopenharmony_ci			secs_loop++;
2498f08c3bdfSopenharmony_ci
2499f08c3bdfSopenharmony_ci		secs_loop = MIN(secs_left, secs_loop);
2500f08c3bdfSopenharmony_ci	}
2501f08c3bdfSopenharmony_ci
2502f08c3bdfSopenharmony_citook_too_long:
2503f08c3bdfSopenharmony_ci	sav_errno = ETIME;
2504f08c3bdfSopenharmony_ci	/* fall into ... */
2505f08c3bdfSopenharmony_cifailed:
2506f08c3bdfSopenharmony_ci	cpuset_freepidlist(pl);
2507f08c3bdfSopenharmony_ci	errno = sav_errno;
2508f08c3bdfSopenharmony_ci	return -1;
2509f08c3bdfSopenharmony_ci
2510f08c3bdfSopenharmony_cirmdir_cpusets:
2511f08c3bdfSopenharmony_ci	/* Let's try removing cpuset(s) now. */
2512f08c3bdfSopenharmony_ci	cpuset_freepidlist(pl);
2513f08c3bdfSopenharmony_ci
2514f08c3bdfSopenharmony_ci	if ((cs_tree = cpuset_fts_open(relpath)) == NULL && errno != ENOENT)
2515f08c3bdfSopenharmony_ci		return -1;
2516f08c3bdfSopenharmony_ci	ret = 0;
2517f08c3bdfSopenharmony_ci	cpuset_fts_reverse(cs_tree);	/* rmdir's must be done bottom up */
2518f08c3bdfSopenharmony_ci	while ((cs_entry = cpuset_fts_read(cs_tree)) != NULL) {
2519f08c3bdfSopenharmony_ci		char buf[PATH_MAX];
2520f08c3bdfSopenharmony_ci
2521f08c3bdfSopenharmony_ci		fullpath(buf, sizeof(buf), cpuset_fts_get_path(cs_entry));
2522f08c3bdfSopenharmony_ci		if (rmdir(buf) < 0 && errno != ENOENT) {
2523f08c3bdfSopenharmony_ci			sav_errno = errno;
2524f08c3bdfSopenharmony_ci			ret = -1;
2525f08c3bdfSopenharmony_ci		}
2526f08c3bdfSopenharmony_ci	}
2527f08c3bdfSopenharmony_ci	cpuset_fts_close(cs_tree);
2528f08c3bdfSopenharmony_ci	/* fall into ... */
2529f08c3bdfSopenharmony_cino_more_cpuset:
2530f08c3bdfSopenharmony_ci	if (ret == 0)
2531f08c3bdfSopenharmony_ci		errno = 0;
2532f08c3bdfSopenharmony_ci	else
2533f08c3bdfSopenharmony_ci		errno = sav_errno;
2534f08c3bdfSopenharmony_ci	return ret;
2535f08c3bdfSopenharmony_ci}
2536f08c3bdfSopenharmony_ci
2537f08c3bdfSopenharmony_ci/*
2538f08c3bdfSopenharmony_ci * When recursively reading all the tasks files from a subtree,
2539f08c3bdfSopenharmony_ci * chain together the read results, one pidblock per tasks file,
2540f08c3bdfSopenharmony_ci * containing the raw unprocessed ascii as read(2) in.  After
2541f08c3bdfSopenharmony_ci * we gather up this raw data, we then go back to count how
2542f08c3bdfSopenharmony_ci * many pid's there are in total, allocate an array of pid_t
2543f08c3bdfSopenharmony_ci * of that size, and transform the raw ascii data into this
2544f08c3bdfSopenharmony_ci * array of pid_t's.
2545f08c3bdfSopenharmony_ci */
2546f08c3bdfSopenharmony_ci
2547f08c3bdfSopenharmony_cistruct pidblock {
2548f08c3bdfSopenharmony_ci	char *buf;
2549f08c3bdfSopenharmony_ci	int buflen;
2550f08c3bdfSopenharmony_ci	struct pidblock *next;
2551f08c3bdfSopenharmony_ci};
2552f08c3bdfSopenharmony_ci
2553f08c3bdfSopenharmony_ci/*
2554f08c3bdfSopenharmony_ci * Chain the raw contents of a file onto the pbhead list.
2555f08c3bdfSopenharmony_ci *
2556f08c3bdfSopenharmony_ci * We malloc "+ 1" extra byte for a nul-terminator, so that
2557f08c3bdfSopenharmony_ci * the strtoul() loop in pid_transform() won't scan past
2558f08c3bdfSopenharmony_ci * the end of pb->buf[] and accidentally find more pids.
2559f08c3bdfSopenharmony_ci */
2560f08c3bdfSopenharmony_cistatic void add_pidblock(const char *file, struct pidblock **ppbhead)
2561f08c3bdfSopenharmony_ci{
2562f08c3bdfSopenharmony_ci	FILE *fp = NULL;
2563f08c3bdfSopenharmony_ci	struct pidblock *pb = NULL;
2564f08c3bdfSopenharmony_ci	int fsz;
2565f08c3bdfSopenharmony_ci
2566f08c3bdfSopenharmony_ci	if ((fp = fopen(file, "r")) == NULL)
2567f08c3bdfSopenharmony_ci		goto err;
2568f08c3bdfSopenharmony_ci	fsz = filesize(fp);
2569f08c3bdfSopenharmony_ci	if (fsz == 0)
2570f08c3bdfSopenharmony_ci		goto err;
2571f08c3bdfSopenharmony_ci	if ((pb = calloc(1, sizeof(*pb))) == NULL)
2572f08c3bdfSopenharmony_ci		goto err;
2573f08c3bdfSopenharmony_ci	pb->buflen = fsz;
2574f08c3bdfSopenharmony_ci	if ((pb->buf = malloc(pb->buflen + 1)) == NULL)
2575f08c3bdfSopenharmony_ci		goto err;
2576f08c3bdfSopenharmony_ci	if (fread(pb->buf, 1, pb->buflen, fp) > 0) {
2577f08c3bdfSopenharmony_ci		pb->buf[pb->buflen] = '\0';
2578f08c3bdfSopenharmony_ci		pb->next = *ppbhead;
2579f08c3bdfSopenharmony_ci		*ppbhead = pb;
2580f08c3bdfSopenharmony_ci	}
2581f08c3bdfSopenharmony_ci	fclose(fp);
2582f08c3bdfSopenharmony_ci	return;
2583f08c3bdfSopenharmony_cierr:
2584f08c3bdfSopenharmony_ci	if (fp)
2585f08c3bdfSopenharmony_ci		fclose(fp);
2586f08c3bdfSopenharmony_ci	free(pb);
2587f08c3bdfSopenharmony_ci}
2588f08c3bdfSopenharmony_ci
2589f08c3bdfSopenharmony_cistatic void read_task_file(const char *relpath, struct pidblock **ppbhead)
2590f08c3bdfSopenharmony_ci{
2591f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2592f08c3bdfSopenharmony_ci
2593f08c3bdfSopenharmony_ci	fullpath2(buf, sizeof(buf), relpath, "tasks");
2594f08c3bdfSopenharmony_ci	add_pidblock(buf, ppbhead);
2595f08c3bdfSopenharmony_ci}
2596f08c3bdfSopenharmony_ci
2597f08c3bdfSopenharmony_cistruct cpuset_pidlist {
2598f08c3bdfSopenharmony_ci	pid_t *pids;
2599f08c3bdfSopenharmony_ci	int npids;
2600f08c3bdfSopenharmony_ci};
2601f08c3bdfSopenharmony_ci
2602f08c3bdfSopenharmony_ci/* Count how many pids in buf (one per line - just count newlines) */
2603f08c3bdfSopenharmony_cistatic int pidcount(const char *buf, int buflen)
2604f08c3bdfSopenharmony_ci{
2605f08c3bdfSopenharmony_ci	int n = 0;
2606f08c3bdfSopenharmony_ci	const char *cp;
2607f08c3bdfSopenharmony_ci
2608f08c3bdfSopenharmony_ci	for (cp = buf; cp < buf + buflen; cp++) {
2609f08c3bdfSopenharmony_ci		if (*cp == '\n')
2610f08c3bdfSopenharmony_ci			n++;
2611f08c3bdfSopenharmony_ci	}
2612f08c3bdfSopenharmony_ci	return n;
2613f08c3bdfSopenharmony_ci}
2614f08c3bdfSopenharmony_ci
2615f08c3bdfSopenharmony_ci/* Transform one-per-line ascii pids in pb to pid_t entries in pl */
2616f08c3bdfSopenharmony_cistatic int pid_transform(struct pidblock *pb, struct cpuset_pidlist *pl, int n)
2617f08c3bdfSopenharmony_ci{
2618f08c3bdfSopenharmony_ci	char *a, *b;
2619f08c3bdfSopenharmony_ci
2620f08c3bdfSopenharmony_ci	for (a = pb->buf; a < pb->buf + pb->buflen; a = b) {
2621f08c3bdfSopenharmony_ci		pid_t p = strtoul(a, &b, 10);
2622f08c3bdfSopenharmony_ci		if (a == b)
2623f08c3bdfSopenharmony_ci			break;
2624f08c3bdfSopenharmony_ci		pl->pids[n++] = p;
2625f08c3bdfSopenharmony_ci	}
2626f08c3bdfSopenharmony_ci	return n;
2627f08c3bdfSopenharmony_ci}
2628f08c3bdfSopenharmony_ci
2629f08c3bdfSopenharmony_cistatic void free_pidblocks(struct pidblock *pbhead)
2630f08c3bdfSopenharmony_ci{
2631f08c3bdfSopenharmony_ci	struct pidblock *pb, *nextpb;
2632f08c3bdfSopenharmony_ci
2633f08c3bdfSopenharmony_ci	for (pb = pbhead; pb; pb = nextpb) {
2634f08c3bdfSopenharmony_ci		nextpb = pb->next;
2635f08c3bdfSopenharmony_ci		free(pb->buf);
2636f08c3bdfSopenharmony_ci		free(pb);
2637f08c3bdfSopenharmony_ci	}
2638f08c3bdfSopenharmony_ci}
2639f08c3bdfSopenharmony_ci
2640f08c3bdfSopenharmony_ci/* numeric comparison routine for qsort */
2641f08c3bdfSopenharmony_cistatic int numericsort(const void *m1, const void *m2)
2642f08c3bdfSopenharmony_ci{
2643f08c3bdfSopenharmony_ci	pid_t p1 = *(pid_t *) m1;
2644f08c3bdfSopenharmony_ci	pid_t p2 = *(pid_t *) m2;
2645f08c3bdfSopenharmony_ci
2646f08c3bdfSopenharmony_ci	return p1 - p2;
2647f08c3bdfSopenharmony_ci}
2648f08c3bdfSopenharmony_ci
2649f08c3bdfSopenharmony_ci/* Return list pids in cpuset 'path' */
2650f08c3bdfSopenharmony_cistruct cpuset_pidlist *cpuset_init_pidlist(const char *relpath,
2651f08c3bdfSopenharmony_ci					   int recursiveflag)
2652f08c3bdfSopenharmony_ci{
2653f08c3bdfSopenharmony_ci	struct pidblock *pb = NULL;
2654f08c3bdfSopenharmony_ci	struct cpuset_pidlist *pl = NULL;
2655f08c3bdfSopenharmony_ci	struct pidblock *pbhead = NULL;
2656f08c3bdfSopenharmony_ci	int n;
2657f08c3bdfSopenharmony_ci
2658f08c3bdfSopenharmony_ci	if (check() < 0)
2659f08c3bdfSopenharmony_ci		goto err;
2660f08c3bdfSopenharmony_ci
2661f08c3bdfSopenharmony_ci	if (recursiveflag) {
2662f08c3bdfSopenharmony_ci		struct cpuset_fts_tree *cs_tree;
2663f08c3bdfSopenharmony_ci		const struct cpuset_fts_entry *cs_entry;
2664f08c3bdfSopenharmony_ci
2665f08c3bdfSopenharmony_ci		if ((cs_tree = cpuset_fts_open(relpath)) == NULL)
2666f08c3bdfSopenharmony_ci			goto err;
2667f08c3bdfSopenharmony_ci		while ((cs_entry = cpuset_fts_read(cs_tree)) != NULL) {
2668f08c3bdfSopenharmony_ci			if (cpuset_fts_get_info(cs_entry) != CPUSET_FTS_CPUSET)
2669f08c3bdfSopenharmony_ci				continue;
2670f08c3bdfSopenharmony_ci			read_task_file(cpuset_fts_get_path(cs_entry), &pbhead);
2671f08c3bdfSopenharmony_ci		}
2672f08c3bdfSopenharmony_ci		cpuset_fts_close(cs_tree);
2673f08c3bdfSopenharmony_ci	} else {
2674f08c3bdfSopenharmony_ci		read_task_file(relpath, &pbhead);
2675f08c3bdfSopenharmony_ci	}
2676f08c3bdfSopenharmony_ci
2677f08c3bdfSopenharmony_ci	if ((pl = calloc(1, sizeof(*pl))) == NULL)
2678f08c3bdfSopenharmony_ci		goto err;
2679f08c3bdfSopenharmony_ci	pl->npids = 0;
2680f08c3bdfSopenharmony_ci	for (pb = pbhead; pb; pb = pb->next)
2681f08c3bdfSopenharmony_ci		pl->npids += pidcount(pb->buf, pb->buflen);
2682f08c3bdfSopenharmony_ci	if ((pl->pids = calloc(pl->npids, sizeof(pid_t))) == NULL)
2683f08c3bdfSopenharmony_ci		goto err;
2684f08c3bdfSopenharmony_ci	n = 0;
2685f08c3bdfSopenharmony_ci	for (pb = pbhead; pb; pb = pb->next)
2686f08c3bdfSopenharmony_ci		n = pid_transform(pb, pl, n);
2687f08c3bdfSopenharmony_ci	free_pidblocks(pbhead);
2688f08c3bdfSopenharmony_ci	qsort(pl->pids, pl->npids, sizeof(pid_t), numericsort);
2689f08c3bdfSopenharmony_ci	return pl;
2690f08c3bdfSopenharmony_cierr:
2691f08c3bdfSopenharmony_ci	cpuset_freepidlist(pl);
2692f08c3bdfSopenharmony_ci	free_pidblocks(pbhead);
2693f08c3bdfSopenharmony_ci	return NULL;
2694f08c3bdfSopenharmony_ci}
2695f08c3bdfSopenharmony_ci
2696f08c3bdfSopenharmony_ci/* Return number of elements in pidlist */
2697f08c3bdfSopenharmony_ciint cpuset_pidlist_length(const struct cpuset_pidlist *pl)
2698f08c3bdfSopenharmony_ci{
2699f08c3bdfSopenharmony_ci	if (pl)
2700f08c3bdfSopenharmony_ci		return pl->npids;
2701f08c3bdfSopenharmony_ci	else
2702f08c3bdfSopenharmony_ci		return 0;
2703f08c3bdfSopenharmony_ci}
2704f08c3bdfSopenharmony_ci
2705f08c3bdfSopenharmony_ci/* Return i'th element of pidlist */
2706f08c3bdfSopenharmony_cipid_t cpuset_get_pidlist(const struct cpuset_pidlist * pl, int i)
2707f08c3bdfSopenharmony_ci{
2708f08c3bdfSopenharmony_ci	if (pl && i >= 0 && i < pl->npids)
2709f08c3bdfSopenharmony_ci		return pl->pids[i];
2710f08c3bdfSopenharmony_ci	else
2711f08c3bdfSopenharmony_ci		return (pid_t) - 1;
2712f08c3bdfSopenharmony_ci}
2713f08c3bdfSopenharmony_ci
2714f08c3bdfSopenharmony_ci/* Free pidlist */
2715f08c3bdfSopenharmony_civoid cpuset_freepidlist(struct cpuset_pidlist *pl)
2716f08c3bdfSopenharmony_ci{
2717f08c3bdfSopenharmony_ci	if (pl && pl->pids)
2718f08c3bdfSopenharmony_ci		free(pl->pids);
2719f08c3bdfSopenharmony_ci	free(pl);
2720f08c3bdfSopenharmony_ci}
2721f08c3bdfSopenharmony_ci
2722f08c3bdfSopenharmony_cistatic int __cpuset_move(pid_t pid, const char *path)
2723f08c3bdfSopenharmony_ci{
2724f08c3bdfSopenharmony_ci	char buf[SMALL_BUFSZ];
2725f08c3bdfSopenharmony_ci
2726f08c3bdfSopenharmony_ci	snprintf(buf, sizeof(buf), "%u", pid);
2727f08c3bdfSopenharmony_ci	return write_string_file(path, buf);
2728f08c3bdfSopenharmony_ci}
2729f08c3bdfSopenharmony_ci
2730f08c3bdfSopenharmony_ci/* Move task (pid == 0 for current) to a cpuset */
2731f08c3bdfSopenharmony_ciint cpuset_move(pid_t pid, const char *relpath)
2732f08c3bdfSopenharmony_ci{
2733f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2734f08c3bdfSopenharmony_ci
2735f08c3bdfSopenharmony_ci	if (check() < 0)
2736f08c3bdfSopenharmony_ci		return -1;
2737f08c3bdfSopenharmony_ci
2738f08c3bdfSopenharmony_ci	if (pid == 0)
2739f08c3bdfSopenharmony_ci		pid = getpid();
2740f08c3bdfSopenharmony_ci
2741f08c3bdfSopenharmony_ci	fullpath2(buf, sizeof(buf), relpath, "tasks");
2742f08c3bdfSopenharmony_ci	return __cpuset_move(pid, buf);
2743f08c3bdfSopenharmony_ci}
2744f08c3bdfSopenharmony_ci
2745f08c3bdfSopenharmony_ci/* Move all tasks in pidlist to a cpuset */
2746f08c3bdfSopenharmony_ciint cpuset_move_all(struct cpuset_pidlist *pl, const char *relpath)
2747f08c3bdfSopenharmony_ci{
2748f08c3bdfSopenharmony_ci	int i;
2749f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2750f08c3bdfSopenharmony_ci	int ret;
2751f08c3bdfSopenharmony_ci
2752f08c3bdfSopenharmony_ci	if (check() < 0)
2753f08c3bdfSopenharmony_ci		return -1;
2754f08c3bdfSopenharmony_ci
2755f08c3bdfSopenharmony_ci	fullpath2(buf, sizeof(buf), relpath, "tasks");
2756f08c3bdfSopenharmony_ci
2757f08c3bdfSopenharmony_ci	ret = 0;
2758f08c3bdfSopenharmony_ci	for (i = 0; i < pl->npids; i++)
2759f08c3bdfSopenharmony_ci		if (__cpuset_move(pl->pids[i], buf) < 0)
2760f08c3bdfSopenharmony_ci			ret = -1;
2761f08c3bdfSopenharmony_ci	return ret;
2762f08c3bdfSopenharmony_ci}
2763f08c3bdfSopenharmony_ci
2764f08c3bdfSopenharmony_ci/*
2765f08c3bdfSopenharmony_ci * [optional] cpuset_move_cpuset_tasks() - Move all tasks in a
2766f08c3bdfSopenharmony_ci *                                      cpuset to another cpuset
2767f08c3bdfSopenharmony_ci *
2768f08c3bdfSopenharmony_ci * Move all tasks in cpuset fromrelpath to cpuset torelpath. This may
2769f08c3bdfSopenharmony_ci * race with tasks being added to or forking into fromrelpath. Loop
2770f08c3bdfSopenharmony_ci * repeatedly, reading the tasks file of cpuset fromrelpath and writing
2771f08c3bdfSopenharmony_ci * any task pid's found there to the tasks file of cpuset torelpath,
2772f08c3bdfSopenharmony_ci * up to ten attempts, or until the tasks file of cpuset fromrelpath
2773f08c3bdfSopenharmony_ci * is empty, or until fromrelpath is no longer present.
2774f08c3bdfSopenharmony_ci *
2775f08c3bdfSopenharmony_ci * Returns 0 with errno == 0 if able to empty the tasks file of cpuset
2776f08c3bdfSopenharmony_ci * fromrelpath. Of course it is still possible that some independent
2777f08c3bdfSopenharmony_ci * task could add another task to cpuset fromrelpath at the same time
2778f08c3bdfSopenharmony_ci * that such a successful result is being returned, so there can be
2779f08c3bdfSopenharmony_ci * no guarantee that a successful return means that fromrelpath is
2780f08c3bdfSopenharmony_ci * still empty of tasks.
2781f08c3bdfSopenharmony_ci *
2782f08c3bdfSopenharmony_ci * We are careful to allow for the possibility that the cpuset
2783f08c3bdfSopenharmony_ci * fromrelpath might disappear out from under us, perhaps because it
2784f08c3bdfSopenharmony_ci * has notify_on_release set and gets automatically removed as soon
2785f08c3bdfSopenharmony_ci * as we detach its last task from it.  Consider a missing fromrelpath
2786f08c3bdfSopenharmony_ci * to be a successful move.
2787f08c3bdfSopenharmony_ci *
2788f08c3bdfSopenharmony_ci * If called with fromrelpath and torelpath pathnames that evaluate to
2789f08c3bdfSopenharmony_ci * the same cpuset, then treat that as if cpuset_reattach() was called,
2790f08c3bdfSopenharmony_ci * rebinding each task in this cpuset one time, and return success or
2791f08c3bdfSopenharmony_ci * failure depending on the return of that cpuset_reattach() call.
2792f08c3bdfSopenharmony_ci *
2793f08c3bdfSopenharmony_ci * On failure, returns -1, with errno possibly one of:
2794f08c3bdfSopenharmony_ci *  EACCES - search permission denied on intervening directory
2795f08c3bdfSopenharmony_ci *  ENOTEMPTY - tasks remain after multiple attempts to move them
2796f08c3bdfSopenharmony_ci *  EMFILE - too many open files
2797f08c3bdfSopenharmony_ci *  ENODEV - /dev/cpuset not mounted
2798f08c3bdfSopenharmony_ci *  ENOENT - component of cpuset path doesn't exist
2799f08c3bdfSopenharmony_ci *  ENOMEM - out of memory
2800f08c3bdfSopenharmony_ci *  ENOSYS - kernel doesn't support cpusets
2801f08c3bdfSopenharmony_ci *  ENOTDIR - component of cpuset path is not a directory
2802f08c3bdfSopenharmony_ci *  EPERM - lacked permission to kill a task
2803f08c3bdfSopenharmony_ci *  EPERM - lacked permission to read cpusets or files therein
2804f08c3bdfSopenharmony_ci *
2805f08c3bdfSopenharmony_ci * This is an [optional] function. Use cpuset_function to invoke it.
2806f08c3bdfSopenharmony_ci */
2807f08c3bdfSopenharmony_ci
2808f08c3bdfSopenharmony_ci#define NUMBER_MOVE_TASK_ATTEMPTS 10
2809f08c3bdfSopenharmony_ci
2810f08c3bdfSopenharmony_ciint cpuset_move_cpuset_tasks(const char *fromrelpath, const char *torelpath)
2811f08c3bdfSopenharmony_ci{
2812f08c3bdfSopenharmony_ci	char fromfullpath[PATH_MAX];
2813f08c3bdfSopenharmony_ci	char tofullpath[PATH_MAX];
2814f08c3bdfSopenharmony_ci	int i;
2815f08c3bdfSopenharmony_ci	struct cpuset_pidlist *pl = NULL;
2816f08c3bdfSopenharmony_ci	int sav_errno;
2817f08c3bdfSopenharmony_ci
2818f08c3bdfSopenharmony_ci	fullpath(fromfullpath, sizeof(fromfullpath), fromrelpath);
2819f08c3bdfSopenharmony_ci	fullpath(tofullpath, sizeof(tofullpath), torelpath);
2820f08c3bdfSopenharmony_ci
2821f08c3bdfSopenharmony_ci	if (samefile(fromfullpath, tofullpath))
2822f08c3bdfSopenharmony_ci		return cpuset_reattach(fromrelpath);
2823f08c3bdfSopenharmony_ci
2824f08c3bdfSopenharmony_ci	for (i = 0; i < NUMBER_MOVE_TASK_ATTEMPTS; i++) {
2825f08c3bdfSopenharmony_ci		int plen, j;
2826f08c3bdfSopenharmony_ci
2827f08c3bdfSopenharmony_ci		if ((pl = cpuset_init_pidlist(fromrelpath, 0)) == NULL) {
2828f08c3bdfSopenharmony_ci			/* missing cpuset is as good as if all moved */
2829f08c3bdfSopenharmony_ci			if (errno == ENOENT)
2830f08c3bdfSopenharmony_ci				goto no_more_cpuset;
2831f08c3bdfSopenharmony_ci
2832f08c3bdfSopenharmony_ci			/* other problems reading cpuset are bad news */
2833f08c3bdfSopenharmony_ci			sav_errno = errno;
2834f08c3bdfSopenharmony_ci			goto failed;
2835f08c3bdfSopenharmony_ci		}
2836f08c3bdfSopenharmony_ci
2837f08c3bdfSopenharmony_ci		if ((plen = cpuset_pidlist_length(pl)) == 0)
2838f08c3bdfSopenharmony_ci			goto no_more_pids;
2839f08c3bdfSopenharmony_ci
2840f08c3bdfSopenharmony_ci		for (j = 0; j < plen; j++) {
2841f08c3bdfSopenharmony_ci			pid_t pid;
2842f08c3bdfSopenharmony_ci
2843f08c3bdfSopenharmony_ci			pid = cpuset_get_pidlist(pl, j);
2844f08c3bdfSopenharmony_ci			if (cpuset_move(pid, torelpath) < 0) {
2845f08c3bdfSopenharmony_ci				/* missing task is as good as if moved */
2846f08c3bdfSopenharmony_ci				if (errno == ESRCH)
2847f08c3bdfSopenharmony_ci					continue;
2848f08c3bdfSopenharmony_ci
2849f08c3bdfSopenharmony_ci				/* other per-task errors are bad news */
2850f08c3bdfSopenharmony_ci				sav_errno = errno;
2851f08c3bdfSopenharmony_ci				goto failed;
2852f08c3bdfSopenharmony_ci			}
2853f08c3bdfSopenharmony_ci		}
2854f08c3bdfSopenharmony_ci
2855f08c3bdfSopenharmony_ci		cpuset_freepidlist(pl);
2856f08c3bdfSopenharmony_ci		pl = NULL;
2857f08c3bdfSopenharmony_ci	}
2858f08c3bdfSopenharmony_ci
2859f08c3bdfSopenharmony_ci	sav_errno = ENOTEMPTY;
2860f08c3bdfSopenharmony_ci	/* fall into ... */
2861f08c3bdfSopenharmony_cifailed:
2862f08c3bdfSopenharmony_ci	cpuset_freepidlist(pl);
2863f08c3bdfSopenharmony_ci	errno = sav_errno;
2864f08c3bdfSopenharmony_ci	return -1;
2865f08c3bdfSopenharmony_ci
2866f08c3bdfSopenharmony_cino_more_pids:
2867f08c3bdfSopenharmony_cino_more_cpuset:
2868f08c3bdfSopenharmony_ci	/* Success - all tasks (or entire cpuset ;) gone. */
2869f08c3bdfSopenharmony_ci	cpuset_freepidlist(pl);
2870f08c3bdfSopenharmony_ci	errno = 0;
2871f08c3bdfSopenharmony_ci	return 0;
2872f08c3bdfSopenharmony_ci}
2873f08c3bdfSopenharmony_ci
2874f08c3bdfSopenharmony_ci/* Migrate task (pid == 0 for current) to a cpuset (moves task and memory) */
2875f08c3bdfSopenharmony_ciint cpuset_migrate(pid_t pid, const char *relpath)
2876f08c3bdfSopenharmony_ci{
2877f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2878f08c3bdfSopenharmony_ci	char buf2[PATH_MAX];
2879f08c3bdfSopenharmony_ci	char memory_migrate_flag;
2880f08c3bdfSopenharmony_ci	int r;
2881f08c3bdfSopenharmony_ci
2882f08c3bdfSopenharmony_ci	if (check() < 0)
2883f08c3bdfSopenharmony_ci		return -1;
2884f08c3bdfSopenharmony_ci
2885f08c3bdfSopenharmony_ci	if (pid == 0)
2886f08c3bdfSopenharmony_ci		pid = getpid();
2887f08c3bdfSopenharmony_ci
2888f08c3bdfSopenharmony_ci	fullpath(buf2, sizeof(buf2), relpath);
2889f08c3bdfSopenharmony_ci
2890f08c3bdfSopenharmony_ci	if (load_flag(buf2, &memory_migrate_flag, "memory_migrate") < 0)
2891f08c3bdfSopenharmony_ci		return -1;
2892f08c3bdfSopenharmony_ci	if (store_flag(buf2, "memory_migrate", 1) < 0)
2893f08c3bdfSopenharmony_ci		return -1;
2894f08c3bdfSopenharmony_ci
2895f08c3bdfSopenharmony_ci	fullpath2(buf, sizeof(buf), relpath, "tasks");
2896f08c3bdfSopenharmony_ci
2897f08c3bdfSopenharmony_ci	r = __cpuset_move(pid, buf);
2898f08c3bdfSopenharmony_ci
2899f08c3bdfSopenharmony_ci	store_flag(buf2, "memory_migrate", memory_migrate_flag);
2900f08c3bdfSopenharmony_ci	return r;
2901f08c3bdfSopenharmony_ci}
2902f08c3bdfSopenharmony_ci
2903f08c3bdfSopenharmony_ci/* Migrate all tasks in pidlist to a cpuset (moves task and memory) */
2904f08c3bdfSopenharmony_ciint cpuset_migrate_all(struct cpuset_pidlist *pl, const char *relpath)
2905f08c3bdfSopenharmony_ci{
2906f08c3bdfSopenharmony_ci	int i;
2907f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
2908f08c3bdfSopenharmony_ci	char buf2[PATH_MAX];
2909f08c3bdfSopenharmony_ci	char memory_migrate_flag;
2910f08c3bdfSopenharmony_ci	int ret;
2911f08c3bdfSopenharmony_ci
2912f08c3bdfSopenharmony_ci	if (check() < 0)
2913f08c3bdfSopenharmony_ci		return -1;
2914f08c3bdfSopenharmony_ci
2915f08c3bdfSopenharmony_ci	fullpath(buf2, sizeof(buf2), relpath);
2916f08c3bdfSopenharmony_ci
2917f08c3bdfSopenharmony_ci	if (load_flag(buf2, &memory_migrate_flag, "memory_migrate") < 0)
2918f08c3bdfSopenharmony_ci		return -1;
2919f08c3bdfSopenharmony_ci	if (store_flag(buf2, "memory_migrate", 1) < 0)
2920f08c3bdfSopenharmony_ci		return -1;
2921f08c3bdfSopenharmony_ci
2922f08c3bdfSopenharmony_ci	fullpath2(buf, sizeof(buf), relpath, "tasks");
2923f08c3bdfSopenharmony_ci
2924f08c3bdfSopenharmony_ci	ret = 0;
2925f08c3bdfSopenharmony_ci	for (i = 0; i < pl->npids; i++)
2926f08c3bdfSopenharmony_ci		if (__cpuset_move(pl->pids[i], buf) < 0)
2927f08c3bdfSopenharmony_ci			ret = -1;
2928f08c3bdfSopenharmony_ci
2929f08c3bdfSopenharmony_ci	if (store_flag(buf2, "memory_migrate", memory_migrate_flag) < 0)
2930f08c3bdfSopenharmony_ci		ret = -1;
2931f08c3bdfSopenharmony_ci	return ret;
2932f08c3bdfSopenharmony_ci}
2933f08c3bdfSopenharmony_ci
2934f08c3bdfSopenharmony_ci/* Rebind cpus_allowed of each task in cpuset 'path' */
2935f08c3bdfSopenharmony_ciint cpuset_reattach(const char *relpath)
2936f08c3bdfSopenharmony_ci{
2937f08c3bdfSopenharmony_ci	struct cpuset_pidlist *pl;
2938f08c3bdfSopenharmony_ci	int rc;
2939f08c3bdfSopenharmony_ci
2940f08c3bdfSopenharmony_ci	if ((pl = cpuset_init_pidlist(relpath, 0)) == NULL)
2941f08c3bdfSopenharmony_ci		return -1;
2942f08c3bdfSopenharmony_ci	rc = cpuset_move_all(pl, relpath);
2943f08c3bdfSopenharmony_ci	cpuset_freepidlist(pl);
2944f08c3bdfSopenharmony_ci	return rc;
2945f08c3bdfSopenharmony_ci}
2946f08c3bdfSopenharmony_ci
2947f08c3bdfSopenharmony_ci/* Map cpuset relative cpu number to system wide cpu number */
2948f08c3bdfSopenharmony_ciint cpuset_c_rel_to_sys_cpu(const struct cpuset *cp, int cpu)
2949f08c3bdfSopenharmony_ci{
2950f08c3bdfSopenharmony_ci	struct cpuset *cp_tofree = NULL;
2951f08c3bdfSopenharmony_ci	const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree);
2952f08c3bdfSopenharmony_ci	int pos = -1;
2953f08c3bdfSopenharmony_ci
2954f08c3bdfSopenharmony_ci	if (!cp1)
2955f08c3bdfSopenharmony_ci		goto err;
2956f08c3bdfSopenharmony_ci	pos = bitmask_rel_to_abs_pos(cp1->cpus, cpu);
2957f08c3bdfSopenharmony_ci	/* fall into ... */
2958f08c3bdfSopenharmony_cierr:
2959f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
2960f08c3bdfSopenharmony_ci	return pos;
2961f08c3bdfSopenharmony_ci}
2962f08c3bdfSopenharmony_ci
2963f08c3bdfSopenharmony_ci/* Map system wide cpu number to cpuset relative cpu number */
2964f08c3bdfSopenharmony_ciint cpuset_c_sys_to_rel_cpu(const struct cpuset *cp, int cpu)
2965f08c3bdfSopenharmony_ci{
2966f08c3bdfSopenharmony_ci	struct cpuset *cp_tofree = NULL;
2967f08c3bdfSopenharmony_ci	const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree);
2968f08c3bdfSopenharmony_ci	int pos = -1;
2969f08c3bdfSopenharmony_ci
2970f08c3bdfSopenharmony_ci	if (!cp1)
2971f08c3bdfSopenharmony_ci		goto err;
2972f08c3bdfSopenharmony_ci	pos = bitmask_abs_to_rel_pos(cp1->cpus, cpu);
2973f08c3bdfSopenharmony_ci	/* fall into ... */
2974f08c3bdfSopenharmony_cierr:
2975f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
2976f08c3bdfSopenharmony_ci	return pos;
2977f08c3bdfSopenharmony_ci}
2978f08c3bdfSopenharmony_ci
2979f08c3bdfSopenharmony_ci/* Map cpuset relative mem number to system wide mem number */
2980f08c3bdfSopenharmony_ciint cpuset_c_rel_to_sys_mem(const struct cpuset *cp, int mem)
2981f08c3bdfSopenharmony_ci{
2982f08c3bdfSopenharmony_ci	struct cpuset *cp_tofree = NULL;
2983f08c3bdfSopenharmony_ci	const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree);
2984f08c3bdfSopenharmony_ci	int pos = -1;
2985f08c3bdfSopenharmony_ci
2986f08c3bdfSopenharmony_ci	if (!cp1)
2987f08c3bdfSopenharmony_ci		goto err;
2988f08c3bdfSopenharmony_ci	pos = bitmask_rel_to_abs_pos(cp1->mems, mem);
2989f08c3bdfSopenharmony_ci	/* fall into ... */
2990f08c3bdfSopenharmony_cierr:
2991f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
2992f08c3bdfSopenharmony_ci	return pos;
2993f08c3bdfSopenharmony_ci}
2994f08c3bdfSopenharmony_ci
2995f08c3bdfSopenharmony_ci/* Map system wide mem number to cpuset relative mem number */
2996f08c3bdfSopenharmony_ciint cpuset_c_sys_to_rel_mem(const struct cpuset *cp, int mem)
2997f08c3bdfSopenharmony_ci{
2998f08c3bdfSopenharmony_ci	struct cpuset *cp_tofree = NULL;
2999f08c3bdfSopenharmony_ci	const struct cpuset *cp1 = resolve_cp(cp, &cp_tofree);
3000f08c3bdfSopenharmony_ci	int pos = -1;
3001f08c3bdfSopenharmony_ci
3002f08c3bdfSopenharmony_ci	if (!cp1)
3003f08c3bdfSopenharmony_ci		goto err;
3004f08c3bdfSopenharmony_ci	pos = bitmask_abs_to_rel_pos(cp1->mems, mem);
3005f08c3bdfSopenharmony_ci	/* fall into ... */
3006f08c3bdfSopenharmony_cierr:
3007f08c3bdfSopenharmony_ci	cpuset_free(cp_tofree);
3008f08c3bdfSopenharmony_ci	return pos;
3009f08c3bdfSopenharmony_ci}
3010f08c3bdfSopenharmony_ci
3011f08c3bdfSopenharmony_ci/* Map pid's cpuset relative cpu number to system wide cpu number */
3012f08c3bdfSopenharmony_ciint cpuset_p_rel_to_sys_cpu(pid_t pid, int cpu)
3013f08c3bdfSopenharmony_ci{
3014f08c3bdfSopenharmony_ci	struct cpuset *cp;
3015f08c3bdfSopenharmony_ci	int rc = -1;
3016f08c3bdfSopenharmony_ci
3017f08c3bdfSopenharmony_ci	if ((cp = cpuset_alloc()) == NULL)
3018f08c3bdfSopenharmony_ci		goto done;
3019f08c3bdfSopenharmony_ci	if (cpuset_cpusetofpid(cp, pid) < 0)
3020f08c3bdfSopenharmony_ci		goto done;
3021f08c3bdfSopenharmony_ci	rc = cpuset_c_rel_to_sys_cpu(cp, cpu);
3022f08c3bdfSopenharmony_cidone:
3023f08c3bdfSopenharmony_ci	cpuset_free(cp);
3024f08c3bdfSopenharmony_ci	return rc;
3025f08c3bdfSopenharmony_ci}
3026f08c3bdfSopenharmony_ci
3027f08c3bdfSopenharmony_ci/* Map system wide cpu number to pid's cpuset relative cpu number */
3028f08c3bdfSopenharmony_ciint cpuset_p_sys_to_rel_cpu(pid_t pid, int cpu)
3029f08c3bdfSopenharmony_ci{
3030f08c3bdfSopenharmony_ci	struct cpuset *cp;
3031f08c3bdfSopenharmony_ci	int rc = -1;
3032f08c3bdfSopenharmony_ci
3033f08c3bdfSopenharmony_ci	if ((cp = cpuset_alloc()) == NULL)
3034f08c3bdfSopenharmony_ci		goto done;
3035f08c3bdfSopenharmony_ci	if (cpuset_cpusetofpid(cp, pid) < 0)
3036f08c3bdfSopenharmony_ci		goto done;
3037f08c3bdfSopenharmony_ci	rc = cpuset_c_sys_to_rel_cpu(cp, cpu);
3038f08c3bdfSopenharmony_cidone:
3039f08c3bdfSopenharmony_ci	cpuset_free(cp);
3040f08c3bdfSopenharmony_ci	return rc;
3041f08c3bdfSopenharmony_ci}
3042f08c3bdfSopenharmony_ci
3043f08c3bdfSopenharmony_ci/* Map pid's cpuset relative mem number to system wide mem number */
3044f08c3bdfSopenharmony_ciint cpuset_p_rel_to_sys_mem(pid_t pid, int mem)
3045f08c3bdfSopenharmony_ci{
3046f08c3bdfSopenharmony_ci	struct cpuset *cp;
3047f08c3bdfSopenharmony_ci	int rc = -1;
3048f08c3bdfSopenharmony_ci
3049f08c3bdfSopenharmony_ci	if ((cp = cpuset_alloc()) == NULL)
3050f08c3bdfSopenharmony_ci		goto done;
3051f08c3bdfSopenharmony_ci	if (cpuset_cpusetofpid(cp, pid) < 0)
3052f08c3bdfSopenharmony_ci		goto done;
3053f08c3bdfSopenharmony_ci	rc = cpuset_c_rel_to_sys_mem(cp, mem);
3054f08c3bdfSopenharmony_cidone:
3055f08c3bdfSopenharmony_ci	cpuset_free(cp);
3056f08c3bdfSopenharmony_ci	return rc;
3057f08c3bdfSopenharmony_ci}
3058f08c3bdfSopenharmony_ci
3059f08c3bdfSopenharmony_ci/* Map system wide mem number to pid's cpuset relative mem number */
3060f08c3bdfSopenharmony_ciint cpuset_p_sys_to_rel_mem(pid_t pid, int mem)
3061f08c3bdfSopenharmony_ci{
3062f08c3bdfSopenharmony_ci	struct cpuset *cp;
3063f08c3bdfSopenharmony_ci	int rc = -1;
3064f08c3bdfSopenharmony_ci
3065f08c3bdfSopenharmony_ci	if ((cp = cpuset_alloc()) == NULL)
3066f08c3bdfSopenharmony_ci		goto done;
3067f08c3bdfSopenharmony_ci	if (cpuset_cpusetofpid(cp, pid) < 0)
3068f08c3bdfSopenharmony_ci		goto done;
3069f08c3bdfSopenharmony_ci	rc = cpuset_c_sys_to_rel_mem(cp, mem);
3070f08c3bdfSopenharmony_cidone:
3071f08c3bdfSopenharmony_ci	cpuset_free(cp);
3072f08c3bdfSopenharmony_ci	return rc;
3073f08c3bdfSopenharmony_ci}
3074f08c3bdfSopenharmony_ci
3075f08c3bdfSopenharmony_ci/*
3076f08c3bdfSopenharmony_ci * Override glibc's calls for get/set affinity - they have
3077f08c3bdfSopenharmony_ci * something using cpu_set_t that will die when NR_CPUS > 1024.
3078f08c3bdfSopenharmony_ci * Go directly to the 'real' system calls.  Also override calls
3079f08c3bdfSopenharmony_ci * for get_mempolicy and set_mempolicy.  None of these
3080f08c3bdfSopenharmony_ci * calls are yet (July 2004) guaranteed to be in all glibc versions
3081f08c3bdfSopenharmony_ci * that we care about.
3082f08c3bdfSopenharmony_ci */
3083f08c3bdfSopenharmony_ci
3084f08c3bdfSopenharmony_cistatic int sched_setaffinity(pid_t pid, unsigned len, unsigned long *mask)
3085f08c3bdfSopenharmony_ci{
3086f08c3bdfSopenharmony_ci	return tst_syscall(__NR_sched_setaffinity, pid, len, mask);
3087f08c3bdfSopenharmony_ci}
3088f08c3bdfSopenharmony_ci
3089f08c3bdfSopenharmony_cistatic int get_mempolicy(int *policy, unsigned long *nmask,
3090f08c3bdfSopenharmony_ci			 unsigned long maxnode, void *addr, int flags)
3091f08c3bdfSopenharmony_ci{
3092f08c3bdfSopenharmony_ci	return tst_syscall(__NR_get_mempolicy, policy, nmask, maxnode,
3093f08c3bdfSopenharmony_ci		addr, flags);
3094f08c3bdfSopenharmony_ci}
3095f08c3bdfSopenharmony_ci
3096f08c3bdfSopenharmony_cistatic int set_mempolicy(int mode, unsigned long *nmask, unsigned long maxnode)
3097f08c3bdfSopenharmony_ci{
3098f08c3bdfSopenharmony_ci	return tst_syscall(__NR_set_mempolicy, mode, nmask, maxnode);
3099f08c3bdfSopenharmony_ci}
3100f08c3bdfSopenharmony_ci
3101f08c3bdfSopenharmony_cistruct cpuset_placement {
3102f08c3bdfSopenharmony_ci	struct bitmask *cpus;
3103f08c3bdfSopenharmony_ci	struct bitmask *mems;
3104f08c3bdfSopenharmony_ci	char *path;
3105f08c3bdfSopenharmony_ci};
3106f08c3bdfSopenharmony_ci
3107f08c3bdfSopenharmony_ci/* Allocate and fill in a placement struct - cpatures current placement */
3108f08c3bdfSopenharmony_cistruct cpuset_placement *cpuset_get_placement(pid_t pid)
3109f08c3bdfSopenharmony_ci{
3110f08c3bdfSopenharmony_ci	struct cpuset_placement *plc;
3111f08c3bdfSopenharmony_ci	struct cpuset *cp = NULL;
3112f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
3113f08c3bdfSopenharmony_ci	int nbits;
3114f08c3bdfSopenharmony_ci
3115f08c3bdfSopenharmony_ci	if ((plc = calloc(1, sizeof(*plc))) == NULL)
3116f08c3bdfSopenharmony_ci		goto err;
3117f08c3bdfSopenharmony_ci
3118f08c3bdfSopenharmony_ci	nbits = cpuset_cpus_nbits();
3119f08c3bdfSopenharmony_ci	if ((plc->cpus = bitmask_alloc(nbits)) == NULL)
3120f08c3bdfSopenharmony_ci		goto err;
3121f08c3bdfSopenharmony_ci
3122f08c3bdfSopenharmony_ci	nbits = cpuset_mems_nbits();
3123f08c3bdfSopenharmony_ci	if ((plc->mems = bitmask_alloc(nbits)) == NULL)
3124f08c3bdfSopenharmony_ci		goto err;
3125f08c3bdfSopenharmony_ci
3126f08c3bdfSopenharmony_ci	if ((cp = cpuset_alloc()) == NULL)
3127f08c3bdfSopenharmony_ci		goto err;
3128f08c3bdfSopenharmony_ci	if (cpuset_getcpusetpath(pid, buf, sizeof(buf)) == NULL)
3129f08c3bdfSopenharmony_ci		goto err;
3130f08c3bdfSopenharmony_ci	if (cpuset_query(cp, buf) < 0)
3131f08c3bdfSopenharmony_ci		goto err;
3132f08c3bdfSopenharmony_ci
3133f08c3bdfSopenharmony_ci	bitmask_copy(plc->cpus, cp->cpus);
3134f08c3bdfSopenharmony_ci	bitmask_copy(plc->mems, cp->mems);
3135f08c3bdfSopenharmony_ci	plc->path = strdup(buf);
3136f08c3bdfSopenharmony_ci
3137f08c3bdfSopenharmony_ci	cpuset_free(cp);
3138f08c3bdfSopenharmony_ci	return plc;
3139f08c3bdfSopenharmony_cierr:
3140f08c3bdfSopenharmony_ci	cpuset_free(cp);
3141f08c3bdfSopenharmony_ci	cpuset_free_placement(plc);
3142f08c3bdfSopenharmony_ci	return NULL;
3143f08c3bdfSopenharmony_ci}
3144f08c3bdfSopenharmony_ci
3145f08c3bdfSopenharmony_ci/* Compare two placement structs - use to detect changes in placement */
3146f08c3bdfSopenharmony_ciint cpuset_equal_placement(const struct cpuset_placement *plc1,
3147f08c3bdfSopenharmony_ci			   const struct cpuset_placement *plc2)
3148f08c3bdfSopenharmony_ci{
3149f08c3bdfSopenharmony_ci	return bitmask_equal(plc1->cpus, plc2->cpus) &&
3150f08c3bdfSopenharmony_ci	    bitmask_equal(plc1->mems, plc2->mems) &&
3151f08c3bdfSopenharmony_ci	    streq(plc1->path, plc2->path);
3152f08c3bdfSopenharmony_ci}
3153f08c3bdfSopenharmony_ci
3154f08c3bdfSopenharmony_ci/* Free a placement struct */
3155f08c3bdfSopenharmony_civoid cpuset_free_placement(struct cpuset_placement *plc)
3156f08c3bdfSopenharmony_ci{
3157f08c3bdfSopenharmony_ci	if (!plc)
3158f08c3bdfSopenharmony_ci		return;
3159f08c3bdfSopenharmony_ci	bitmask_free(plc->cpus);
3160f08c3bdfSopenharmony_ci	bitmask_free(plc->mems);
3161f08c3bdfSopenharmony_ci	free(plc->path);
3162f08c3bdfSopenharmony_ci	free(plc);
3163f08c3bdfSopenharmony_ci}
3164f08c3bdfSopenharmony_ci
3165f08c3bdfSopenharmony_ci/*
3166f08c3bdfSopenharmony_ci * A cpuset_fts_open() call constructs a linked list of entries
3167f08c3bdfSopenharmony_ci * called a "cpuset_fts_tree", with one entry per cpuset below
3168f08c3bdfSopenharmony_ci * the specified path.  The cpuset_fts_read() routine returns the
3169f08c3bdfSopenharmony_ci * next entry on this list.  The various cpuset_fts_get_*() calls
3170f08c3bdfSopenharmony_ci * return attributes of the specified entry.  The cpuset_fts_close()
3171f08c3bdfSopenharmony_ci * call frees the linked list and all associated data.  All cpuset
3172f08c3bdfSopenharmony_ci * entries and attributes for the cpuset_fts_tree returned from a
3173f08c3bdfSopenharmony_ci * given cpuset_fts_open() call remain allocated and unchanged until
3174f08c3bdfSopenharmony_ci * that cpuset_fts_tree is closed by a cpuset_fts_close() call.  Any
3175f08c3bdfSopenharmony_ci * subsequent changes to the cpuset filesystem will go unnoticed
3176f08c3bdfSopenharmony_ci * (not affect open cpuset_fts_tree's.)
3177f08c3bdfSopenharmony_ci */
3178f08c3bdfSopenharmony_ci
3179f08c3bdfSopenharmony_cistruct cpuset_fts_entry;
3180f08c3bdfSopenharmony_civoid cpuset_fts_rewind(struct cpuset_fts_tree *cs_tree);
3181f08c3bdfSopenharmony_ci
3182f08c3bdfSopenharmony_cistruct cpuset_fts_tree {
3183f08c3bdfSopenharmony_ci	struct cpuset_fts_entry *head;	/* head of linked entry list */
3184f08c3bdfSopenharmony_ci	struct cpuset_fts_entry *next;	/* cpuset_fts_read() offset */
3185f08c3bdfSopenharmony_ci};
3186f08c3bdfSopenharmony_ci
3187f08c3bdfSopenharmony_cistruct cpuset_fts_entry {
3188f08c3bdfSopenharmony_ci	struct cpuset_fts_entry *next;	/* linked entry list chain */
3189f08c3bdfSopenharmony_ci	struct cpuset *cpuset;
3190f08c3bdfSopenharmony_ci	struct stat *stat;
3191f08c3bdfSopenharmony_ci	char *path;
3192f08c3bdfSopenharmony_ci	int info;
3193f08c3bdfSopenharmony_ci	int err;
3194f08c3bdfSopenharmony_ci};
3195f08c3bdfSopenharmony_ci
3196f08c3bdfSopenharmony_ci/* Open a handle on a cpuset hierarchy.  All the real work is done here. */
3197f08c3bdfSopenharmony_cistruct cpuset_fts_tree *cpuset_fts_open(const char *cpusetpath)
3198f08c3bdfSopenharmony_ci{
3199f08c3bdfSopenharmony_ci	FTS *fts = NULL;
3200f08c3bdfSopenharmony_ci	FTSENT *ftsent;
3201f08c3bdfSopenharmony_ci	char *path_argv[2];
3202f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
3203f08c3bdfSopenharmony_ci	struct cpuset_fts_tree *cs_tree = NULL;
3204f08c3bdfSopenharmony_ci	struct cpuset_fts_entry *ep;	/* the latest new list entry */
3205f08c3bdfSopenharmony_ci	struct cpuset_fts_entry **pnlep;	/* ptr to next list entry ptr */
3206f08c3bdfSopenharmony_ci	char *relpath;
3207f08c3bdfSopenharmony_ci	int fts_flags;
3208f08c3bdfSopenharmony_ci
3209f08c3bdfSopenharmony_ci	fullpath(buf, sizeof(buf), cpusetpath);
3210f08c3bdfSopenharmony_ci	path_argv[0] = buf;
3211f08c3bdfSopenharmony_ci	path_argv[1] = NULL;
3212f08c3bdfSopenharmony_ci
3213f08c3bdfSopenharmony_ci	fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_NOSTAT | FTS_XDEV;
3214f08c3bdfSopenharmony_ci	fts = fts_open(path_argv, fts_flags, NULL);
3215f08c3bdfSopenharmony_ci	if (fts == NULL)
3216f08c3bdfSopenharmony_ci		goto err;
3217f08c3bdfSopenharmony_ci
3218f08c3bdfSopenharmony_ci	cs_tree = malloc(sizeof(*cs_tree));
3219f08c3bdfSopenharmony_ci	if (cs_tree == NULL)
3220f08c3bdfSopenharmony_ci		goto err;
3221f08c3bdfSopenharmony_ci	pnlep = &cs_tree->head;
3222f08c3bdfSopenharmony_ci	*pnlep = NULL;
3223f08c3bdfSopenharmony_ci
3224f08c3bdfSopenharmony_ci	while ((ftsent = fts_read(fts)) != NULL) {
3225f08c3bdfSopenharmony_ci		if (ftsent->fts_info != FTS_D && ftsent->fts_info != FTS_DNR)
3226f08c3bdfSopenharmony_ci			continue;
3227f08c3bdfSopenharmony_ci
3228f08c3bdfSopenharmony_ci		/* ftsent is a directory (perhaps unreadable) ==> cpuset */
3229f08c3bdfSopenharmony_ci		ep = calloc(1, sizeof(*ep));
3230f08c3bdfSopenharmony_ci		if (ep == NULL)
3231f08c3bdfSopenharmony_ci			goto err;
3232f08c3bdfSopenharmony_ci		*pnlep = ep;
3233f08c3bdfSopenharmony_ci		pnlep = &ep->next;
3234f08c3bdfSopenharmony_ci
3235f08c3bdfSopenharmony_ci		/* Set entry's path, and if DNR, error */
3236f08c3bdfSopenharmony_ci		relpath = ftsent->fts_path + strlen(cpusetmnt);
3237f08c3bdfSopenharmony_ci		if (strlen(relpath) == 0)
3238f08c3bdfSopenharmony_ci			relpath = "/";
3239f08c3bdfSopenharmony_ci		ep->path = strdup(relpath);
3240f08c3bdfSopenharmony_ci		if (ep->path == NULL)
3241f08c3bdfSopenharmony_ci			goto err;
3242f08c3bdfSopenharmony_ci		if (ftsent->fts_info == FTS_DNR) {
3243f08c3bdfSopenharmony_ci			ep->info = CPUSET_FTS_ERR_DNR;
3244f08c3bdfSopenharmony_ci			ep->err = ftsent->fts_errno;
3245f08c3bdfSopenharmony_ci			continue;
3246f08c3bdfSopenharmony_ci		}
3247f08c3bdfSopenharmony_ci
3248f08c3bdfSopenharmony_ci		/* ftsent is a -readable- cpuset: set entry's stat, etc */
3249f08c3bdfSopenharmony_ci		ep->stat = calloc(1, sizeof(struct stat));
3250f08c3bdfSopenharmony_ci		if (ep->stat == NULL)
3251f08c3bdfSopenharmony_ci			goto err;
3252f08c3bdfSopenharmony_ci		if (stat(ftsent->fts_path, ep->stat) < 0) {
3253f08c3bdfSopenharmony_ci			ep->info = CPUSET_FTS_ERR_STAT;
3254f08c3bdfSopenharmony_ci			ep->err = ftsent->fts_errno;
3255f08c3bdfSopenharmony_ci			continue;
3256f08c3bdfSopenharmony_ci		}
3257f08c3bdfSopenharmony_ci
3258f08c3bdfSopenharmony_ci		ep->cpuset = calloc(1, sizeof(struct cpuset));
3259f08c3bdfSopenharmony_ci		if (ep->cpuset == NULL)
3260f08c3bdfSopenharmony_ci			goto err;
3261f08c3bdfSopenharmony_ci		if (cpuset_query(ep->cpuset, relpath) < 0) {
3262f08c3bdfSopenharmony_ci			ep->info = CPUSET_FTS_ERR_CPUSET;
3263f08c3bdfSopenharmony_ci			ep->err = errno;
3264f08c3bdfSopenharmony_ci			continue;
3265f08c3bdfSopenharmony_ci		}
3266f08c3bdfSopenharmony_ci		ep->info = CPUSET_FTS_CPUSET;
3267f08c3bdfSopenharmony_ci	}
3268f08c3bdfSopenharmony_ci
3269f08c3bdfSopenharmony_ci	(void)fts_close(fts);
3270f08c3bdfSopenharmony_ci	cpuset_fts_rewind(cs_tree);
3271f08c3bdfSopenharmony_ci	return cs_tree;
3272f08c3bdfSopenharmony_ci
3273f08c3bdfSopenharmony_cierr:
3274f08c3bdfSopenharmony_ci	if (cs_tree)
3275f08c3bdfSopenharmony_ci		cpuset_fts_close(cs_tree);
3276f08c3bdfSopenharmony_ci	if (fts)
3277f08c3bdfSopenharmony_ci		(void)fts_close(fts);
3278f08c3bdfSopenharmony_ci	return NULL;
3279f08c3bdfSopenharmony_ci}
3280f08c3bdfSopenharmony_ci
3281f08c3bdfSopenharmony_ci/* Return pointer to next cpuset entry in hierarchy */
3282f08c3bdfSopenharmony_ciconst struct cpuset_fts_entry *cpuset_fts_read(struct cpuset_fts_tree *cs_tree)
3283f08c3bdfSopenharmony_ci{
3284f08c3bdfSopenharmony_ci	const struct cpuset_fts_entry *cs_entry = cs_tree->next;
3285f08c3bdfSopenharmony_ci	if (cs_tree->next != NULL)	/* seek to next entry */
3286f08c3bdfSopenharmony_ci		cs_tree->next = cs_tree->next->next;
3287f08c3bdfSopenharmony_ci	return cs_entry;
3288f08c3bdfSopenharmony_ci}
3289f08c3bdfSopenharmony_ci
3290f08c3bdfSopenharmony_ci/* Reverse list of cpusets, in place.  Simulates pre-order/post-order flip. */
3291f08c3bdfSopenharmony_civoid cpuset_fts_reverse(struct cpuset_fts_tree *cs_tree)
3292f08c3bdfSopenharmony_ci{
3293f08c3bdfSopenharmony_ci	struct cpuset_fts_entry *cs1, *cs2, *cs3;
3294f08c3bdfSopenharmony_ci
3295f08c3bdfSopenharmony_ci	/*
3296f08c3bdfSopenharmony_ci	 * At each step, cs1 < cs2 < cs3 and the cs2->next pointer
3297f08c3bdfSopenharmony_ci	 * is redirected from cs3 to cs1.
3298f08c3bdfSopenharmony_ci	 */
3299f08c3bdfSopenharmony_ci
3300f08c3bdfSopenharmony_ci	cs1 = cs2 = NULL;
3301f08c3bdfSopenharmony_ci	cs3 = cs_tree->head;
3302f08c3bdfSopenharmony_ci	while (cs3) {
3303f08c3bdfSopenharmony_ci		cs1 = cs2;
3304f08c3bdfSopenharmony_ci		cs2 = cs3;
3305f08c3bdfSopenharmony_ci		cs3 = cs3->next;
3306f08c3bdfSopenharmony_ci		cs2->next = cs1;
3307f08c3bdfSopenharmony_ci	}
3308f08c3bdfSopenharmony_ci	cs_tree->head = cs2;
3309f08c3bdfSopenharmony_ci	cpuset_fts_rewind(cs_tree);
3310f08c3bdfSopenharmony_ci}
3311f08c3bdfSopenharmony_ci
3312f08c3bdfSopenharmony_ci/* Rewind cpuset list to beginning */
3313f08c3bdfSopenharmony_civoid cpuset_fts_rewind(struct cpuset_fts_tree *cs_tree)
3314f08c3bdfSopenharmony_ci{
3315f08c3bdfSopenharmony_ci	cs_tree->next = cs_tree->head;
3316f08c3bdfSopenharmony_ci}
3317f08c3bdfSopenharmony_ci
3318f08c3bdfSopenharmony_ci/* Return pointer to nul-terminated cpuset path of entry in hierarchy */
3319f08c3bdfSopenharmony_ciconst char *cpuset_fts_get_path(const struct cpuset_fts_entry *cs_entry)
3320f08c3bdfSopenharmony_ci{
3321f08c3bdfSopenharmony_ci	return cs_entry->path;
3322f08c3bdfSopenharmony_ci}
3323f08c3bdfSopenharmony_ci
3324f08c3bdfSopenharmony_ci/* Return pointer to stat(2) structure of a cpuset entry's directory */
3325f08c3bdfSopenharmony_ciconst struct stat *cpuset_fts_get_stat(const struct cpuset_fts_entry *cs_entry)
3326f08c3bdfSopenharmony_ci{
3327f08c3bdfSopenharmony_ci	return cs_entry->stat;
3328f08c3bdfSopenharmony_ci}
3329f08c3bdfSopenharmony_ci
3330f08c3bdfSopenharmony_ci/* Return pointer to cpuset structure of a cpuset entry */
3331f08c3bdfSopenharmony_ciconst struct cpuset *cpuset_fts_get_cpuset(const struct cpuset_fts_entry
3332f08c3bdfSopenharmony_ci					   *cs_entry)
3333f08c3bdfSopenharmony_ci{
3334f08c3bdfSopenharmony_ci	return cs_entry->cpuset;
3335f08c3bdfSopenharmony_ci}
3336f08c3bdfSopenharmony_ci
3337f08c3bdfSopenharmony_ci/* Return value of errno (0 if no error) on attempted cpuset operations */
3338f08c3bdfSopenharmony_ciint cpuset_fts_get_errno(const struct cpuset_fts_entry *cs_entry)
3339f08c3bdfSopenharmony_ci{
3340f08c3bdfSopenharmony_ci	return cs_entry->err;
3341f08c3bdfSopenharmony_ci}
3342f08c3bdfSopenharmony_ci
3343f08c3bdfSopenharmony_ci/* Return operation identity causing error */
3344f08c3bdfSopenharmony_ciint cpuset_fts_get_info(const struct cpuset_fts_entry *cs_entry)
3345f08c3bdfSopenharmony_ci{
3346f08c3bdfSopenharmony_ci	return cs_entry->info;
3347f08c3bdfSopenharmony_ci}
3348f08c3bdfSopenharmony_ci
3349f08c3bdfSopenharmony_ci/* Close a cpuset hierarchy handle (free's all associated memory) */
3350f08c3bdfSopenharmony_civoid cpuset_fts_close(struct cpuset_fts_tree *cs_tree)
3351f08c3bdfSopenharmony_ci{
3352f08c3bdfSopenharmony_ci	struct cpuset_fts_entry *cs_entry = cs_tree->head;
3353f08c3bdfSopenharmony_ci
3354f08c3bdfSopenharmony_ci	while (cs_entry) {
3355f08c3bdfSopenharmony_ci		struct cpuset_fts_entry *ep = cs_entry;
3356f08c3bdfSopenharmony_ci
3357f08c3bdfSopenharmony_ci		cs_entry = cs_entry->next;
3358f08c3bdfSopenharmony_ci		free(ep->path);
3359f08c3bdfSopenharmony_ci		free(ep->stat);
3360f08c3bdfSopenharmony_ci		cpuset_free(ep->cpuset);
3361f08c3bdfSopenharmony_ci		free(ep);
3362f08c3bdfSopenharmony_ci	}
3363f08c3bdfSopenharmony_ci	free(cs_tree);
3364f08c3bdfSopenharmony_ci}
3365f08c3bdfSopenharmony_ci
3366f08c3bdfSopenharmony_ci/* Bind current task to cpu (uses sched_setaffinity(2)) */
3367f08c3bdfSopenharmony_ciint cpuset_cpubind(int cpu)
3368f08c3bdfSopenharmony_ci{
3369f08c3bdfSopenharmony_ci	struct bitmask *bmp;
3370f08c3bdfSopenharmony_ci	int r;
3371f08c3bdfSopenharmony_ci
3372f08c3bdfSopenharmony_ci	if ((bmp = bitmask_alloc(cpuset_cpus_nbits())) == NULL)
3373f08c3bdfSopenharmony_ci		return -1;
3374f08c3bdfSopenharmony_ci	bitmask_setbit(bmp, cpu);
3375f08c3bdfSopenharmony_ci	r = sched_setaffinity(0, bitmask_nbytes(bmp), bitmask_mask(bmp));
3376f08c3bdfSopenharmony_ci	bitmask_free(bmp);
3377f08c3bdfSopenharmony_ci	return r;
3378f08c3bdfSopenharmony_ci}
3379f08c3bdfSopenharmony_ci
3380f08c3bdfSopenharmony_ci/*
3381f08c3bdfSopenharmony_ci * int cpuset_latestcpu(pid_t pid)
3382f08c3bdfSopenharmony_ci *
3383f08c3bdfSopenharmony_ci * Return most recent CPU on which task pid executed.  If pid == 0,
3384f08c3bdfSopenharmony_ci * examine current task.
3385f08c3bdfSopenharmony_ci *
3386f08c3bdfSopenharmony_ci * The last used CPU is visible for a given pid as field #39 (starting
3387f08c3bdfSopenharmony_ci * with #1) in the file /proc/pid/stat.  Currently this file has 41
3388f08c3bdfSopenharmony_ci * fields, in which case this is the 3rd to the last field.
3389f08c3bdfSopenharmony_ci *
3390f08c3bdfSopenharmony_ci * Unfortunately field #2 is a command name and might have embedded
3391f08c3bdfSopenharmony_ci * whitespace.  So we can't just count white space separated fields.
3392f08c3bdfSopenharmony_ci * Fortunately, this command name is surrounded by parentheses, as
3393f08c3bdfSopenharmony_ci * for example "(sh)", and that closing parenthesis is the last ')'
3394f08c3bdfSopenharmony_ci * character in the line.  No remaining fields can have embedded
3395f08c3bdfSopenharmony_ci * whitespace or parentheses.  So instead of looking for the 39th
3396f08c3bdfSopenharmony_ci * white space separated field, we can look for the 37th white space
3397f08c3bdfSopenharmony_ci * separated field past the last ')' character on the line.
3398f08c3bdfSopenharmony_ci */
3399f08c3bdfSopenharmony_ci
3400f08c3bdfSopenharmony_ci/* Return most recent CPU on which task pid executed */
3401f08c3bdfSopenharmony_ciint cpuset_latestcpu(pid_t pid)
3402f08c3bdfSopenharmony_ci{
3403f08c3bdfSopenharmony_ci	char buf[PATH_MAX];
3404f08c3bdfSopenharmony_ci	char *bp;
3405f08c3bdfSopenharmony_ci	int fd = -1;
3406f08c3bdfSopenharmony_ci	int cpu = -1;
3407f08c3bdfSopenharmony_ci
3408f08c3bdfSopenharmony_ci	if (pid == 0)
3409f08c3bdfSopenharmony_ci		snprintf(buf, sizeof(buf), "/proc/self/stat");
3410f08c3bdfSopenharmony_ci	else
3411f08c3bdfSopenharmony_ci		snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
3412f08c3bdfSopenharmony_ci
3413f08c3bdfSopenharmony_ci	if ((fd = open(buf, O_RDONLY)) < 0)
3414f08c3bdfSopenharmony_ci		goto err;
3415f08c3bdfSopenharmony_ci	if (read(fd, buf, sizeof(buf)) < 1)
3416f08c3bdfSopenharmony_ci		goto err;
3417f08c3bdfSopenharmony_ci	close(fd);
3418f08c3bdfSopenharmony_ci
3419f08c3bdfSopenharmony_ci	bp = strrchr(buf, ')');
3420f08c3bdfSopenharmony_ci	if (bp)
3421f08c3bdfSopenharmony_ci		sscanf(bp + 1, "%*s %*u %*u %*u %*u %*u %*u %*u " "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u " "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u " "%*u %*u %*u %*u %*u %*u %*u %*u %u",	/* 37th field past ')' */
3422f08c3bdfSopenharmony_ci		       &cpu);
3423f08c3bdfSopenharmony_ci	if (cpu < 0)
3424f08c3bdfSopenharmony_ci		errno = EINVAL;
3425f08c3bdfSopenharmony_ci	return cpu;
3426f08c3bdfSopenharmony_cierr:
3427f08c3bdfSopenharmony_ci	if (fd >= 0)
3428f08c3bdfSopenharmony_ci		close(fd);
3429f08c3bdfSopenharmony_ci	return -1;
3430f08c3bdfSopenharmony_ci}
3431f08c3bdfSopenharmony_ci
3432f08c3bdfSopenharmony_ci/* Bind current task to memory (uses set_mempolicy(2)) */
3433f08c3bdfSopenharmony_ciint cpuset_membind(int mem)
3434f08c3bdfSopenharmony_ci{
3435f08c3bdfSopenharmony_ci	struct bitmask *bmp;
3436f08c3bdfSopenharmony_ci	int r;
3437f08c3bdfSopenharmony_ci
3438f08c3bdfSopenharmony_ci	if ((bmp = bitmask_alloc(cpuset_mems_nbits())) == NULL)
3439f08c3bdfSopenharmony_ci		return -1;
3440f08c3bdfSopenharmony_ci	bitmask_setbit(bmp, mem);
3441f08c3bdfSopenharmony_ci	r = set_mempolicy(MPOL_BIND, bitmask_mask(bmp), bitmask_nbits(bmp) + 1);
3442f08c3bdfSopenharmony_ci	bitmask_free(bmp);
3443f08c3bdfSopenharmony_ci	return r;
3444f08c3bdfSopenharmony_ci}
3445f08c3bdfSopenharmony_ci
3446f08c3bdfSopenharmony_ci/* [optional] Return Memory Node holding page at specified addr */
3447f08c3bdfSopenharmony_ciint cpuset_addr2node(void *addr)
3448f08c3bdfSopenharmony_ci{
3449f08c3bdfSopenharmony_ci	int node = -1;
3450f08c3bdfSopenharmony_ci
3451f08c3bdfSopenharmony_ci	if (get_mempolicy(&node, NULL, 0, addr, MPOL_F_NODE | MPOL_F_ADDR)) {
3452f08c3bdfSopenharmony_ci		/* I realize this seems redundant, but I _want_ to make sure
3453f08c3bdfSopenharmony_ci		 * that this value is -1. */
3454f08c3bdfSopenharmony_ci		node = -1;
3455f08c3bdfSopenharmony_ci	}
3456f08c3bdfSopenharmony_ci	return node;
3457f08c3bdfSopenharmony_ci}
3458f08c3bdfSopenharmony_ci
3459f08c3bdfSopenharmony_ci/*
3460f08c3bdfSopenharmony_ci * Transform cpuset into Text Format Representation in buffer 'buf',
3461f08c3bdfSopenharmony_ci * of length 'buflen', nul-terminated if space allows.  Return number
3462f08c3bdfSopenharmony_ci * of characters that would have been written, if enough space had
3463f08c3bdfSopenharmony_ci * been available, in the same way that snprintf() does.
3464f08c3bdfSopenharmony_ci */
3465f08c3bdfSopenharmony_ci
3466f08c3bdfSopenharmony_ci/* Export cpuset settings to a regular file */
3467f08c3bdfSopenharmony_ciint cpuset_export(const struct cpuset *cp, char *buf, int buflen)
3468f08c3bdfSopenharmony_ci{
3469f08c3bdfSopenharmony_ci	char *tmp = NULL;
3470f08c3bdfSopenharmony_ci	int n = 0;
3471f08c3bdfSopenharmony_ci
3472f08c3bdfSopenharmony_ci	if (cp->cpu_exclusive)
3473f08c3bdfSopenharmony_ci		n += snprintf(buf + n, MAX(buflen - n, 0), "cpu_exclusive\n");
3474f08c3bdfSopenharmony_ci
3475f08c3bdfSopenharmony_ci	if (cp->mem_exclusive)
3476f08c3bdfSopenharmony_ci		n += snprintf(buf + n, MAX(buflen - n, 0), "mem_exclusive\n");
3477f08c3bdfSopenharmony_ci
3478f08c3bdfSopenharmony_ci	if (cp->notify_on_release)
3479f08c3bdfSopenharmony_ci		n += snprintf(buf + n, MAX(buflen - n, 0),
3480f08c3bdfSopenharmony_ci			      "notify_on_release\n");
3481f08c3bdfSopenharmony_ci
3482f08c3bdfSopenharmony_ci	if (cp->memory_pressure_enabled)
3483f08c3bdfSopenharmony_ci		n += snprintf(buf + n, MAX(buflen - n, 0),
3484f08c3bdfSopenharmony_ci			      "memory_pressure_enabled\n");
3485f08c3bdfSopenharmony_ci
3486f08c3bdfSopenharmony_ci	if (cp->memory_migrate)
3487f08c3bdfSopenharmony_ci		n += snprintf(buf + n, MAX(buflen - n, 0), "memory_migrate\n");
3488f08c3bdfSopenharmony_ci
3489f08c3bdfSopenharmony_ci	if (cp->memory_spread_page)
3490f08c3bdfSopenharmony_ci		n += snprintf(buf + n, MAX(buflen - n, 0),
3491f08c3bdfSopenharmony_ci			      "memory_spread_page\n");
3492f08c3bdfSopenharmony_ci
3493f08c3bdfSopenharmony_ci	if (cp->memory_spread_slab)
3494f08c3bdfSopenharmony_ci		n += snprintf(buf + n, MAX(buflen - n, 0),
3495f08c3bdfSopenharmony_ci			      "memory_spread_slab\n");
3496f08c3bdfSopenharmony_ci
3497f08c3bdfSopenharmony_ci	if ((tmp = sprint_mask_buf(cp->cpus)) == NULL)
3498f08c3bdfSopenharmony_ci		return -1;
3499f08c3bdfSopenharmony_ci	n += snprintf(buf + n, MAX(buflen - n, 0), "cpus %s\n", tmp);
3500f08c3bdfSopenharmony_ci	free(tmp);
3501f08c3bdfSopenharmony_ci	tmp = NULL;
3502f08c3bdfSopenharmony_ci
3503f08c3bdfSopenharmony_ci	if ((tmp = sprint_mask_buf(cp->mems)) == NULL)
3504f08c3bdfSopenharmony_ci		return -1;
3505f08c3bdfSopenharmony_ci	n += snprintf(buf + n, MAX(buflen - n, 0), "mems %s\n", tmp);
3506f08c3bdfSopenharmony_ci	free(tmp);
3507f08c3bdfSopenharmony_ci	tmp = NULL;
3508f08c3bdfSopenharmony_ci
3509f08c3bdfSopenharmony_ci	return n;
3510f08c3bdfSopenharmony_ci}
3511f08c3bdfSopenharmony_ci
3512f08c3bdfSopenharmony_cistatic int import_list(UNUSED const char *tok, const char *arg,
3513f08c3bdfSopenharmony_ci		       struct bitmask *bmp, char *emsg, int elen)
3514f08c3bdfSopenharmony_ci{
3515f08c3bdfSopenharmony_ci	if (bitmask_parselist(arg, bmp) < 0) {
3516f08c3bdfSopenharmony_ci		if (emsg)
3517f08c3bdfSopenharmony_ci			snprintf(emsg, elen, "Invalid list format: %s", arg);
3518f08c3bdfSopenharmony_ci		return -1;
3519f08c3bdfSopenharmony_ci	}
3520f08c3bdfSopenharmony_ci	return 0;
3521f08c3bdfSopenharmony_ci}
3522f08c3bdfSopenharmony_ci
3523f08c3bdfSopenharmony_cistatic void stolower(char *s)
3524f08c3bdfSopenharmony_ci{
3525f08c3bdfSopenharmony_ci	while (*s) {
3526f08c3bdfSopenharmony_ci		unsigned char c = *s;
3527f08c3bdfSopenharmony_ci		*s = tolower(c);
3528f08c3bdfSopenharmony_ci		s++;
3529f08c3bdfSopenharmony_ci	}
3530f08c3bdfSopenharmony_ci}
3531f08c3bdfSopenharmony_ci
3532f08c3bdfSopenharmony_ci/* Import cpuset settings from a regular file */
3533f08c3bdfSopenharmony_ciint cpuset_import(struct cpuset *cp, const char *buf, int *elinenum,
3534f08c3bdfSopenharmony_ci		  char *emsg, int elen)
3535f08c3bdfSopenharmony_ci{
3536f08c3bdfSopenharmony_ci	char *linebuf = NULL;
3537f08c3bdfSopenharmony_ci	int linebuflen;
3538f08c3bdfSopenharmony_ci	int linenum = 0;
3539f08c3bdfSopenharmony_ci	int offset = 0;
3540f08c3bdfSopenharmony_ci
3541f08c3bdfSopenharmony_ci	linebuflen = strlen(buf) + 1;
3542f08c3bdfSopenharmony_ci	if ((linebuf = malloc(linebuflen)) == NULL) {
3543f08c3bdfSopenharmony_ci		if (emsg)
3544f08c3bdfSopenharmony_ci			snprintf(emsg, elen, "Insufficient memory");
3545f08c3bdfSopenharmony_ci		goto err;
3546f08c3bdfSopenharmony_ci	}
3547f08c3bdfSopenharmony_ci
3548f08c3bdfSopenharmony_ci	while (slgets(linebuf, linebuflen, buf, &offset)) {
3549f08c3bdfSopenharmony_ci		char *tok, *arg;
3550f08c3bdfSopenharmony_ci		char *ptr;	/* for strtok_r */
3551f08c3bdfSopenharmony_ci
3552f08c3bdfSopenharmony_ci		linenum++;
3553f08c3bdfSopenharmony_ci		if ((tok = strchr(linebuf, '#')) != NULL)
3554f08c3bdfSopenharmony_ci			*tok = 0;
3555f08c3bdfSopenharmony_ci		if ((tok = strtok_r(linebuf, " \t", &ptr)) == NULL)
3556f08c3bdfSopenharmony_ci			continue;
3557f08c3bdfSopenharmony_ci		stolower(tok);
3558f08c3bdfSopenharmony_ci
3559f08c3bdfSopenharmony_ci		arg = strtok_r(0, " \t", &ptr);
3560f08c3bdfSopenharmony_ci
3561f08c3bdfSopenharmony_ci		if (streq(tok, "cpu_exclusive")) {
3562f08c3bdfSopenharmony_ci			cp->cpu_exclusive = 1;
3563f08c3bdfSopenharmony_ci			goto eol;
3564f08c3bdfSopenharmony_ci		}
3565f08c3bdfSopenharmony_ci		if (streq(tok, "mem_exclusive")) {
3566f08c3bdfSopenharmony_ci			cp->mem_exclusive = 1;
3567f08c3bdfSopenharmony_ci			goto eol;
3568f08c3bdfSopenharmony_ci		}
3569f08c3bdfSopenharmony_ci		if (streq(tok, "notify_on_release")) {
3570f08c3bdfSopenharmony_ci			cp->notify_on_release = 1;
3571f08c3bdfSopenharmony_ci			goto eol;
3572f08c3bdfSopenharmony_ci		}
3573f08c3bdfSopenharmony_ci		if (streq(tok, "memory_pressure_enabled")) {
3574f08c3bdfSopenharmony_ci			cp->memory_pressure_enabled = 1;
3575f08c3bdfSopenharmony_ci			goto eol;
3576f08c3bdfSopenharmony_ci		}
3577f08c3bdfSopenharmony_ci		if (streq(tok, "memory_migrate")) {
3578f08c3bdfSopenharmony_ci			cp->memory_migrate = 1;
3579f08c3bdfSopenharmony_ci			goto eol;
3580f08c3bdfSopenharmony_ci		}
3581f08c3bdfSopenharmony_ci		if (streq(tok, "memory_spread_page")) {
3582f08c3bdfSopenharmony_ci			cp->memory_spread_page = 1;
3583f08c3bdfSopenharmony_ci			goto eol;
3584f08c3bdfSopenharmony_ci		}
3585f08c3bdfSopenharmony_ci		if (streq(tok, "memory_spread_slab")) {
3586f08c3bdfSopenharmony_ci			cp->memory_spread_slab = 1;
3587f08c3bdfSopenharmony_ci			goto eol;
3588f08c3bdfSopenharmony_ci		}
3589f08c3bdfSopenharmony_ci		if (streq(tok, "cpu") || streq(tok, "cpus")) {
3590f08c3bdfSopenharmony_ci			if (import_list(tok, arg, cp->cpus, emsg, elen) < 0)
3591f08c3bdfSopenharmony_ci				goto err;
3592f08c3bdfSopenharmony_ci			goto eol;
3593f08c3bdfSopenharmony_ci		}
3594f08c3bdfSopenharmony_ci		if (streq(tok, "mem") || streq(tok, "mems")) {
3595f08c3bdfSopenharmony_ci			if (import_list(tok, arg, cp->mems, emsg, elen) < 0)
3596f08c3bdfSopenharmony_ci				goto err;
3597f08c3bdfSopenharmony_ci			goto eol;
3598f08c3bdfSopenharmony_ci		}
3599f08c3bdfSopenharmony_ci		if (emsg)
3600f08c3bdfSopenharmony_ci			snprintf(emsg, elen, "Unrecognized token: '%s'", tok);
3601f08c3bdfSopenharmony_ci		goto err;
3602f08c3bdfSopenharmony_cieol:
3603f08c3bdfSopenharmony_ci		if ((tok = strtok_r(0, " \t", &ptr)) != NULL) {
3604f08c3bdfSopenharmony_ci			if (emsg)
3605f08c3bdfSopenharmony_ci				snprintf(emsg, elen, "Surplus token: '%s'",
3606f08c3bdfSopenharmony_ci					 tok);
3607f08c3bdfSopenharmony_ci			goto err;
3608f08c3bdfSopenharmony_ci		}
3609f08c3bdfSopenharmony_ci		continue;
3610f08c3bdfSopenharmony_ci	}
3611f08c3bdfSopenharmony_ci
3612f08c3bdfSopenharmony_ci	free(linebuf);
3613f08c3bdfSopenharmony_ci
3614f08c3bdfSopenharmony_ci	if (bitmask_isallclear(cp->cpus) && !bitmask_isallclear(cp->mems))
3615f08c3bdfSopenharmony_ci		cpuset_localcpus(cp->mems, cp->cpus);
3616f08c3bdfSopenharmony_ci	else if (!bitmask_isallclear(cp->cpus) && bitmask_isallclear(cp->mems))
3617f08c3bdfSopenharmony_ci		cpuset_localmems(cp->cpus, cp->mems);
3618f08c3bdfSopenharmony_ci
3619f08c3bdfSopenharmony_ci	/*
3620f08c3bdfSopenharmony_ci	 * All cpuset attributes are determined in an import.
3621f08c3bdfSopenharmony_ci	 * Those that aren't explicitly specified are presumed
3622f08c3bdfSopenharmony_ci	 * to be unchanged (zero, if it's a freshly allocated
3623f08c3bdfSopenharmony_ci	 * struct cpuset.)
3624f08c3bdfSopenharmony_ci	 */
3625f08c3bdfSopenharmony_ci
3626f08c3bdfSopenharmony_ci	cp->cpus_valid = 1;
3627f08c3bdfSopenharmony_ci	cp->mems_valid = 1;
3628f08c3bdfSopenharmony_ci	cp->cpu_exclusive_valid = 1;
3629f08c3bdfSopenharmony_ci	cp->mem_exclusive_valid = 1;
3630f08c3bdfSopenharmony_ci	cp->notify_on_release_valid = 1;
3631f08c3bdfSopenharmony_ci	cp->memory_migrate_valid = 1;
3632f08c3bdfSopenharmony_ci	cp->memory_pressure_enabled_valid = 1;
3633f08c3bdfSopenharmony_ci	cp->memory_spread_page_valid = 1;
3634f08c3bdfSopenharmony_ci	cp->memory_spread_slab_valid = 1;
3635f08c3bdfSopenharmony_ci
3636f08c3bdfSopenharmony_ci	return 0;
3637f08c3bdfSopenharmony_cierr:
3638f08c3bdfSopenharmony_ci	if (elinenum)
3639f08c3bdfSopenharmony_ci		*elinenum = linenum;
3640f08c3bdfSopenharmony_ci	free(linebuf);
3641f08c3bdfSopenharmony_ci	return -1;
3642f08c3bdfSopenharmony_ci}
3643f08c3bdfSopenharmony_ci
3644f08c3bdfSopenharmony_ci/* Pin current task CPU (and memory) */
3645f08c3bdfSopenharmony_ciint cpuset_pin(int relcpu)
3646f08c3bdfSopenharmony_ci{
3647f08c3bdfSopenharmony_ci	struct cpuset_placement *plc1 = NULL, *plc2 = NULL;
3648f08c3bdfSopenharmony_ci	int cpu, r;
3649f08c3bdfSopenharmony_ci
3650f08c3bdfSopenharmony_ci	if (check() < 0)
3651f08c3bdfSopenharmony_ci		return -1;
3652f08c3bdfSopenharmony_ci
3653f08c3bdfSopenharmony_ci	do {
3654f08c3bdfSopenharmony_ci		cpuset_free_placement(plc1);
3655f08c3bdfSopenharmony_ci		plc1 = cpuset_get_placement(0);
3656f08c3bdfSopenharmony_ci
3657f08c3bdfSopenharmony_ci		r = 0;
3658f08c3bdfSopenharmony_ci		if (cpuset_unpin() < 0)
3659f08c3bdfSopenharmony_ci			r = -1;
3660f08c3bdfSopenharmony_ci		cpu = cpuset_p_rel_to_sys_cpu(0, relcpu);
3661f08c3bdfSopenharmony_ci		if (cpuset_cpubind(cpu) < 0)
3662f08c3bdfSopenharmony_ci			r = -1;
3663f08c3bdfSopenharmony_ci
3664f08c3bdfSopenharmony_ci		cpuset_free_placement(plc2);
3665f08c3bdfSopenharmony_ci		plc2 = cpuset_get_placement(0);
3666f08c3bdfSopenharmony_ci	} while (!cpuset_equal_placement(plc1, plc2));
3667f08c3bdfSopenharmony_ci
3668f08c3bdfSopenharmony_ci	cpuset_free_placement(plc1);
3669f08c3bdfSopenharmony_ci	cpuset_free_placement(plc2);
3670f08c3bdfSopenharmony_ci	return r;
3671f08c3bdfSopenharmony_ci}
3672f08c3bdfSopenharmony_ci
3673f08c3bdfSopenharmony_ci/* Return number CPUs in current tasks cpuset */
3674f08c3bdfSopenharmony_ciint cpuset_size(void)
3675f08c3bdfSopenharmony_ci{
3676f08c3bdfSopenharmony_ci	struct cpuset_placement *plc1 = NULL, *plc2 = NULL;
3677f08c3bdfSopenharmony_ci	int r;
3678f08c3bdfSopenharmony_ci
3679f08c3bdfSopenharmony_ci	if (check() < 0)
3680f08c3bdfSopenharmony_ci		return -1;
3681f08c3bdfSopenharmony_ci
3682f08c3bdfSopenharmony_ci	do {
3683f08c3bdfSopenharmony_ci		cpuset_free_placement(plc1);
3684f08c3bdfSopenharmony_ci		plc1 = cpuset_get_placement(0);
3685f08c3bdfSopenharmony_ci
3686f08c3bdfSopenharmony_ci		r = cpuset_cpus_weight(0);
3687f08c3bdfSopenharmony_ci
3688f08c3bdfSopenharmony_ci		cpuset_free_placement(plc2);
3689f08c3bdfSopenharmony_ci		plc2 = cpuset_get_placement(0);
3690f08c3bdfSopenharmony_ci	} while (!cpuset_equal_placement(plc1, plc2));
3691f08c3bdfSopenharmony_ci
3692f08c3bdfSopenharmony_ci	cpuset_free_placement(plc1);
3693f08c3bdfSopenharmony_ci	cpuset_free_placement(plc2);
3694f08c3bdfSopenharmony_ci	return r;
3695f08c3bdfSopenharmony_ci}
3696f08c3bdfSopenharmony_ci
3697f08c3bdfSopenharmony_ci/* Return relative CPU number, within current cpuset, last executed on */
3698f08c3bdfSopenharmony_ciint cpuset_where(void)
3699f08c3bdfSopenharmony_ci{
3700f08c3bdfSopenharmony_ci	struct cpuset_placement *plc1 = NULL, *plc2 = NULL;
3701f08c3bdfSopenharmony_ci	int r;
3702f08c3bdfSopenharmony_ci
3703f08c3bdfSopenharmony_ci	if (check() < 0)
3704f08c3bdfSopenharmony_ci		return -1;
3705f08c3bdfSopenharmony_ci
3706f08c3bdfSopenharmony_ci	do {
3707f08c3bdfSopenharmony_ci		cpuset_free_placement(plc1);
3708f08c3bdfSopenharmony_ci		plc1 = cpuset_get_placement(0);
3709f08c3bdfSopenharmony_ci
3710f08c3bdfSopenharmony_ci		r = cpuset_p_sys_to_rel_cpu(0, cpuset_latestcpu(0));
3711f08c3bdfSopenharmony_ci
3712f08c3bdfSopenharmony_ci		cpuset_free_placement(plc2);
3713f08c3bdfSopenharmony_ci		plc2 = cpuset_get_placement(0);
3714f08c3bdfSopenharmony_ci	} while (!cpuset_equal_placement(plc1, plc2));
3715f08c3bdfSopenharmony_ci
3716f08c3bdfSopenharmony_ci	cpuset_free_placement(plc1);
3717f08c3bdfSopenharmony_ci	cpuset_free_placement(plc2);
3718f08c3bdfSopenharmony_ci	return r;
3719f08c3bdfSopenharmony_ci}
3720f08c3bdfSopenharmony_ci
3721f08c3bdfSopenharmony_ci/* Undo cpuset_pin - let current task have the run of all CPUs in its cpuset */
3722f08c3bdfSopenharmony_ciint cpuset_unpin(void)
3723f08c3bdfSopenharmony_ci{
3724f08c3bdfSopenharmony_ci	struct bitmask *cpus = NULL, *mems = NULL;
3725f08c3bdfSopenharmony_ci	int r = -1;
3726f08c3bdfSopenharmony_ci
3727f08c3bdfSopenharmony_ci	if (check() < 0)
3728f08c3bdfSopenharmony_ci		goto err;
3729f08c3bdfSopenharmony_ci
3730f08c3bdfSopenharmony_ci	/*
3731f08c3bdfSopenharmony_ci	 * Don't need cpuset_*_placement() guard against concurrent
3732f08c3bdfSopenharmony_ci	 * cpuset migration, because none of the following depends
3733f08c3bdfSopenharmony_ci	 * on the tasks cpuset placement.
3734f08c3bdfSopenharmony_ci	 */
3735f08c3bdfSopenharmony_ci
3736f08c3bdfSopenharmony_ci	if ((cpus = bitmask_alloc(cpuset_cpus_nbits())) == NULL)
3737f08c3bdfSopenharmony_ci		goto err;
3738f08c3bdfSopenharmony_ci	bitmask_setall(cpus);
3739f08c3bdfSopenharmony_ci	if (sched_setaffinity(0, bitmask_nbytes(cpus), bitmask_mask(cpus)) < 0)
3740f08c3bdfSopenharmony_ci		goto err;
3741f08c3bdfSopenharmony_ci
3742f08c3bdfSopenharmony_ci	if ((mems = bitmask_alloc(cpuset_mems_nbits())) == NULL)
3743f08c3bdfSopenharmony_ci		goto err;
3744f08c3bdfSopenharmony_ci	if (set_mempolicy(MPOL_DEFAULT, bitmask_mask(mems),
3745f08c3bdfSopenharmony_ci			  bitmask_nbits(mems) + 1) < 0)
3746f08c3bdfSopenharmony_ci		goto err;
3747f08c3bdfSopenharmony_ci	r = 0;
3748f08c3bdfSopenharmony_ci	/* fall into ... */
3749f08c3bdfSopenharmony_cierr:
3750f08c3bdfSopenharmony_ci	bitmask_free(cpus);
3751f08c3bdfSopenharmony_ci	bitmask_free(mems);
3752f08c3bdfSopenharmony_ci	return r;
3753f08c3bdfSopenharmony_ci
3754f08c3bdfSopenharmony_ci}
3755f08c3bdfSopenharmony_ci
3756f08c3bdfSopenharmony_cistruct cpuset_function_list {
3757f08c3bdfSopenharmony_ci	const char *fname;
3758f08c3bdfSopenharmony_ci	void *func;
3759f08c3bdfSopenharmony_ci} flist[] = {
3760f08c3bdfSopenharmony_ci	{
3761f08c3bdfSopenharmony_ci	"cpuset_version", cpuset_version}, {
3762f08c3bdfSopenharmony_ci	"cpuset_alloc", cpuset_alloc}, {
3763f08c3bdfSopenharmony_ci	"cpuset_free", cpuset_free}, {
3764f08c3bdfSopenharmony_ci	"cpuset_cpus_nbits", cpuset_cpus_nbits}, {
3765f08c3bdfSopenharmony_ci	"cpuset_mems_nbits", cpuset_mems_nbits}, {
3766f08c3bdfSopenharmony_ci	"cpuset_setcpus", cpuset_setcpus}, {
3767f08c3bdfSopenharmony_ci	"cpuset_setmems", cpuset_setmems}, {
3768f08c3bdfSopenharmony_ci	"cpuset_set_iopt", cpuset_set_iopt}, {
3769f08c3bdfSopenharmony_ci	"cpuset_set_sopt", cpuset_set_sopt}, {
3770f08c3bdfSopenharmony_ci	"cpuset_getcpus", cpuset_getcpus}, {
3771f08c3bdfSopenharmony_ci	"cpuset_getmems", cpuset_getmems}, {
3772f08c3bdfSopenharmony_ci	"cpuset_cpus_weight", cpuset_cpus_weight}, {
3773f08c3bdfSopenharmony_ci	"cpuset_mems_weight", cpuset_mems_weight}, {
3774f08c3bdfSopenharmony_ci	"cpuset_get_iopt", cpuset_get_iopt}, {
3775f08c3bdfSopenharmony_ci	"cpuset_get_sopt", cpuset_get_sopt}, {
3776f08c3bdfSopenharmony_ci	"cpuset_localcpus", cpuset_localcpus}, {
3777f08c3bdfSopenharmony_ci	"cpuset_localmems", cpuset_localmems}, {
3778f08c3bdfSopenharmony_ci	"cpuset_cpumemdist", cpuset_cpumemdist}, {
3779f08c3bdfSopenharmony_ci	"cpuset_cpu2node", cpuset_cpu2node}, {
3780f08c3bdfSopenharmony_ci	"cpuset_addr2node", cpuset_addr2node}, {
3781f08c3bdfSopenharmony_ci	"cpuset_create", cpuset_create}, {
3782f08c3bdfSopenharmony_ci	"cpuset_delete", cpuset_delete}, {
3783f08c3bdfSopenharmony_ci	"cpuset_query", cpuset_query}, {
3784f08c3bdfSopenharmony_ci	"cpuset_modify", cpuset_modify}, {
3785f08c3bdfSopenharmony_ci	"cpuset_getcpusetpath", cpuset_getcpusetpath}, {
3786f08c3bdfSopenharmony_ci	"cpuset_cpusetofpid", cpuset_cpusetofpid}, {
3787f08c3bdfSopenharmony_ci	"cpuset_mountpoint", cpuset_mountpoint}, {
3788f08c3bdfSopenharmony_ci	"cpuset_collides_exclusive", cpuset_collides_exclusive}, {
3789f08c3bdfSopenharmony_ci	"cpuset_nuke", cpuset_nuke}, {
3790f08c3bdfSopenharmony_ci	"cpuset_init_pidlist", cpuset_init_pidlist}, {
3791f08c3bdfSopenharmony_ci	"cpuset_pidlist_length", cpuset_pidlist_length}, {
3792f08c3bdfSopenharmony_ci	"cpuset_get_pidlist", cpuset_get_pidlist}, {
3793f08c3bdfSopenharmony_ci	"cpuset_freepidlist", cpuset_freepidlist}, {
3794f08c3bdfSopenharmony_ci	"cpuset_move", cpuset_move}, {
3795f08c3bdfSopenharmony_ci	"cpuset_move_all", cpuset_move_all}, {
3796f08c3bdfSopenharmony_ci	"cpuset_move_cpuset_tasks", cpuset_move_cpuset_tasks}, {
3797f08c3bdfSopenharmony_ci	"cpuset_migrate", cpuset_migrate}, {
3798f08c3bdfSopenharmony_ci	"cpuset_migrate_all", cpuset_migrate_all}, {
3799f08c3bdfSopenharmony_ci	"cpuset_reattach", cpuset_reattach}, {
3800f08c3bdfSopenharmony_ci	"cpuset_open_memory_pressure", cpuset_open_memory_pressure}, {
3801f08c3bdfSopenharmony_ci	"cpuset_read_memory_pressure", cpuset_read_memory_pressure}, {
3802f08c3bdfSopenharmony_ci	"cpuset_close_memory_pressure", cpuset_close_memory_pressure}, {
3803f08c3bdfSopenharmony_ci	"cpuset_c_rel_to_sys_cpu", cpuset_c_rel_to_sys_cpu}, {
3804f08c3bdfSopenharmony_ci	"cpuset_c_sys_to_rel_cpu", cpuset_c_sys_to_rel_cpu}, {
3805f08c3bdfSopenharmony_ci	"cpuset_c_rel_to_sys_mem", cpuset_c_rel_to_sys_mem}, {
3806f08c3bdfSopenharmony_ci	"cpuset_c_sys_to_rel_mem", cpuset_c_sys_to_rel_mem}, {
3807f08c3bdfSopenharmony_ci	"cpuset_p_rel_to_sys_cpu", cpuset_p_rel_to_sys_cpu}, {
3808f08c3bdfSopenharmony_ci	"cpuset_p_sys_to_rel_cpu", cpuset_p_sys_to_rel_cpu}, {
3809f08c3bdfSopenharmony_ci	"cpuset_p_rel_to_sys_mem", cpuset_p_rel_to_sys_mem}, {
3810f08c3bdfSopenharmony_ci	"cpuset_p_sys_to_rel_mem", cpuset_p_sys_to_rel_mem}, {
3811f08c3bdfSopenharmony_ci	"cpuset_get_placement", cpuset_get_placement}, {
3812f08c3bdfSopenharmony_ci	"cpuset_equal_placement", cpuset_equal_placement}, {
3813f08c3bdfSopenharmony_ci	"cpuset_free_placement", cpuset_free_placement}, {
3814f08c3bdfSopenharmony_ci	"cpuset_fts_open", cpuset_fts_open}, {
3815f08c3bdfSopenharmony_ci	"cpuset_fts_read", cpuset_fts_read}, {
3816f08c3bdfSopenharmony_ci	"cpuset_fts_reverse", cpuset_fts_reverse}, {
3817f08c3bdfSopenharmony_ci	"cpuset_fts_rewind", cpuset_fts_rewind}, {
3818f08c3bdfSopenharmony_ci	"cpuset_fts_get_path", cpuset_fts_get_path}, {
3819f08c3bdfSopenharmony_ci	"cpuset_fts_get_stat", cpuset_fts_get_stat}, {
3820f08c3bdfSopenharmony_ci	"cpuset_fts_get_cpuset", cpuset_fts_get_cpuset}, {
3821f08c3bdfSopenharmony_ci	"cpuset_fts_get_errno", cpuset_fts_get_errno}, {
3822f08c3bdfSopenharmony_ci	"cpuset_fts_get_info", cpuset_fts_get_info}, {
3823f08c3bdfSopenharmony_ci	"cpuset_fts_close", cpuset_fts_close}, {
3824f08c3bdfSopenharmony_ci	"cpuset_cpubind", cpuset_cpubind}, {
3825f08c3bdfSopenharmony_ci	"cpuset_latestcpu", cpuset_latestcpu}, {
3826f08c3bdfSopenharmony_ci	"cpuset_membind", cpuset_membind}, {
3827f08c3bdfSopenharmony_ci	"cpuset_export", cpuset_export}, {
3828f08c3bdfSopenharmony_ci	"cpuset_import", cpuset_import}, {
3829f08c3bdfSopenharmony_ci	"cpuset_function", cpuset_function}, {
3830f08c3bdfSopenharmony_ci	"cpuset_pin", cpuset_pin}, {
3831f08c3bdfSopenharmony_ci	"cpuset_size", cpuset_size}, {
3832f08c3bdfSopenharmony_ci	"cpuset_where", cpuset_where}, {
3833f08c3bdfSopenharmony_ci"cpuset_unpin", cpuset_unpin},};
3834f08c3bdfSopenharmony_ci
3835f08c3bdfSopenharmony_ci/* Return pointer to a libcpuset.so function, or NULL */
3836f08c3bdfSopenharmony_civoid *cpuset_function(const char *function_name)
3837f08c3bdfSopenharmony_ci{
3838f08c3bdfSopenharmony_ci	unsigned int i;
3839f08c3bdfSopenharmony_ci
3840f08c3bdfSopenharmony_ci	for (i = 0; i < sizeof(flist) / sizeof(flist[0]); i++)
3841f08c3bdfSopenharmony_ci		if (streq(function_name, flist[i].fname))
3842f08c3bdfSopenharmony_ci			return flist[i].func;
3843f08c3bdfSopenharmony_ci	return NULL;
3844f08c3bdfSopenharmony_ci}
3845f08c3bdfSopenharmony_ci
3846f08c3bdfSopenharmony_ci/* Fortran interface to basic cpuset routines */
3847f08c3bdfSopenharmony_ciint cpuset_pin_(int *ptr_relcpu)
3848f08c3bdfSopenharmony_ci{
3849f08c3bdfSopenharmony_ci	return cpuset_pin(*ptr_relcpu);
3850f08c3bdfSopenharmony_ci}
3851f08c3bdfSopenharmony_ci
3852f08c3bdfSopenharmony_ciint cpuset_size_(void)
3853f08c3bdfSopenharmony_ci{
3854f08c3bdfSopenharmony_ci	return cpuset_size();
3855f08c3bdfSopenharmony_ci}
3856f08c3bdfSopenharmony_ci
3857f08c3bdfSopenharmony_ciint cpuset_where_(void)
3858f08c3bdfSopenharmony_ci{
3859f08c3bdfSopenharmony_ci	return cpuset_where();
3860f08c3bdfSopenharmony_ci}
3861f08c3bdfSopenharmony_ci
3862f08c3bdfSopenharmony_ciint cpuset_unpin_(void)
3863f08c3bdfSopenharmony_ci{
3864f08c3bdfSopenharmony_ci	return cpuset_unpin();
3865f08c3bdfSopenharmony_ci}
3866f08c3bdfSopenharmony_ci
3867f08c3bdfSopenharmony_ci#endif /* HAVE_LINUX_MEMPOLICY_H */
3868