1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * memtoy:  segment.c - manage memory segments
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * create/destroy/map/unmap - anonymous, file and SysV shmem segments
5f08c3bdfSopenharmony_ci * touch [read or write] - ranges of segments
6f08c3bdfSopenharmony_ci * mbind - ranges of segments
7f08c3bdfSopenharmony_ci * show mappings or locations of segment pages
8f08c3bdfSopenharmony_ci */
9f08c3bdfSopenharmony_ci/*
10f08c3bdfSopenharmony_ci *  Copyright (c) 2005 Hewlett-Packard, Inc
11f08c3bdfSopenharmony_ci *  All rights reserved.
12f08c3bdfSopenharmony_ci */
13f08c3bdfSopenharmony_ci
14f08c3bdfSopenharmony_ci/*
15f08c3bdfSopenharmony_ci *  This program is free software; you can redistribute it and/or modify
16f08c3bdfSopenharmony_ci *  it under the terms of the GNU General Public License as published by
17f08c3bdfSopenharmony_ci *  the Free Software Foundation; either version 2 of the License, or
18f08c3bdfSopenharmony_ci *  (at your option) any later version.
19f08c3bdfSopenharmony_ci *
20f08c3bdfSopenharmony_ci *  This program is distributed in the hope that it will be useful,
21f08c3bdfSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22f08c3bdfSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23f08c3bdfSopenharmony_ci *  GNU General Public License for more details.
24f08c3bdfSopenharmony_ci *
25f08c3bdfSopenharmony_ci *  You should have received a copy of the GNU General Public License
26f08c3bdfSopenharmony_ci *  along with this program; if not, write to the Free Software
27f08c3bdfSopenharmony_ci *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
28f08c3bdfSopenharmony_ci */
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_ci#include "config.h"
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_ci#ifdef HAVE_NUMA_V2
33f08c3bdfSopenharmony_ci
34f08c3bdfSopenharmony_ci#include <sys/types.h>
35f08c3bdfSopenharmony_ci#include <sys/ipc.h>
36f08c3bdfSopenharmony_ci#include <sys/mman.h>
37f08c3bdfSopenharmony_ci#include <sys/shm.h>
38f08c3bdfSopenharmony_ci#include <sys/stat.h>
39f08c3bdfSopenharmony_ci#include <sys/time.h>
40f08c3bdfSopenharmony_ci#include <errno.h>
41f08c3bdfSopenharmony_ci#include <fcntl.h>
42f08c3bdfSopenharmony_ci#include <libgen.h>
43f08c3bdfSopenharmony_ci#include <numa.h>
44f08c3bdfSopenharmony_ci#include <numaif.h>
45f08c3bdfSopenharmony_ci#include <stdarg.h>
46f08c3bdfSopenharmony_ci#include <stdlib.h>
47f08c3bdfSopenharmony_ci#include <stdio.h>
48f08c3bdfSopenharmony_ci#include <string.h>
49f08c3bdfSopenharmony_ci#include <unistd.h>
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci#include "memtoy.h"
52f08c3bdfSopenharmony_ci#include "segment.h"
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_cistruct segment {
55f08c3bdfSopenharmony_ci	char *seg_name;
56f08c3bdfSopenharmony_ci	void *seg_start;
57f08c3bdfSopenharmony_ci	size_t seg_length;
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci	off_t seg_offset;	/* memory mapped files */
60f08c3bdfSopenharmony_ci	char *seg_path;		/*   "      "      "   */
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_ci	seg_type_t seg_type;
63f08c3bdfSopenharmony_ci	int seg_slot;
64f08c3bdfSopenharmony_ci	int seg_flags;		/* shared|private */
65f08c3bdfSopenharmony_ci	int seg_prot;
66f08c3bdfSopenharmony_ci	int seg_fd;		/* saved file descriptor */
67f08c3bdfSopenharmony_ci	int seg_shmid;
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci};
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci#define MAX_SEGMENTS 63		/* arbitrary max */
72f08c3bdfSopenharmony_ci#define SEG_FD_NONE (-1)
73f08c3bdfSopenharmony_ci#define SHM_ID_NONE (-1)
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci#define SEG_ERR (0)
76f08c3bdfSopenharmony_ci#define SEG_OK  (1)
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ci#define SEG_OFFSET(SEGP, ADDR) ((char *)(ADDR) - (char *)(SEGP->seg_start))
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ci/*
81f08c3bdfSopenharmony_ci * =========================================================================
82f08c3bdfSopenharmony_ci */
83f08c3bdfSopenharmony_civoid segment_init(struct global_context *gcp)
84f08c3bdfSopenharmony_ci{
85f08c3bdfSopenharmony_ci	/*
86f08c3bdfSopenharmony_ci	 * one extra slot to terminate the list
87f08c3bdfSopenharmony_ci	 */
88f08c3bdfSopenharmony_ci	gcp->seglist = calloc(MAX_SEGMENTS + 1, sizeof(segment_t *));
89f08c3bdfSopenharmony_ci	if (!gcp->seglist)
90f08c3bdfSopenharmony_ci		die(4, "%s: can't alloc segment table\n", gcp->program_name);
91f08c3bdfSopenharmony_ci	gcp->seg_avail = NULL;
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci}
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_cistatic segment_t *new_segment(void)
96f08c3bdfSopenharmony_ci{
97f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
98f08c3bdfSopenharmony_ci	segment_t *segp = (segment_t *) calloc(1, sizeof(segment_t));
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_ci	if (segp == NULL)
101f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  failed to allocate segment\n",
102f08c3bdfSopenharmony_ci			gcp->program_name);
103f08c3bdfSopenharmony_ci	return segp;
104f08c3bdfSopenharmony_ci}
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_ci/*
107f08c3bdfSopenharmony_ci * get_seg_slot() -- allocate a segment table slot for a new segment
108f08c3bdfSopenharmony_ci */
109f08c3bdfSopenharmony_cistatic segment_t *get_seg_slot(void)
110f08c3bdfSopenharmony_ci{
111f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
112f08c3bdfSopenharmony_ci	segment_t *segp, **segpp;
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci	/*
115f08c3bdfSopenharmony_ci	 * consume saved slot, if any
116f08c3bdfSopenharmony_ci	 */
117f08c3bdfSopenharmony_ci	segp = gcp->seg_avail;
118f08c3bdfSopenharmony_ci	if (segp != NULL) {
119f08c3bdfSopenharmony_ci		gcp->seg_avail = NULL;
120f08c3bdfSopenharmony_ci		return segp;
121f08c3bdfSopenharmony_ci	}
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_ci	/*
124f08c3bdfSopenharmony_ci	 * simple linear scan for first available slot
125f08c3bdfSopenharmony_ci	 */
126f08c3bdfSopenharmony_ci	for (segpp = gcp->seglist; (segp = *segpp); ++segpp) {
127f08c3bdfSopenharmony_ci		if (segp->seg_type == SEGT_NONE)
128f08c3bdfSopenharmony_ci			return segp;
129f08c3bdfSopenharmony_ci	}
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_ci	if (segpp < &gcp->seglist[MAX_SEGMENTS]) {
132f08c3bdfSopenharmony_ci		/*
133f08c3bdfSopenharmony_ci		 * previously unused slot
134f08c3bdfSopenharmony_ci		 */
135f08c3bdfSopenharmony_ci		*segpp = segp = new_segment();
136f08c3bdfSopenharmony_ci		segp->seg_slot = segpp - gcp->seglist;
137f08c3bdfSopenharmony_ci		return segp;
138f08c3bdfSopenharmony_ci	}
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci	fprintf(stderr, "%s:  segment table full\n", gcp->program_name);
141f08c3bdfSopenharmony_ci	return NULL;
142f08c3bdfSopenharmony_ci}
143f08c3bdfSopenharmony_ci
144f08c3bdfSopenharmony_cistatic void unmap_segment(segment_t * segp)
145f08c3bdfSopenharmony_ci{
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	if (segp->seg_start == MAP_FAILED)
148f08c3bdfSopenharmony_ci		return;		/* already unmapped */
149f08c3bdfSopenharmony_ci
150f08c3bdfSopenharmony_ci	switch (segp->seg_type) {
151f08c3bdfSopenharmony_ci	case SEGT_ANON:
152f08c3bdfSopenharmony_ci	case SEGT_FILE:
153f08c3bdfSopenharmony_ci		munmap(segp->seg_start, segp->seg_length);
154f08c3bdfSopenharmony_ci		break;
155f08c3bdfSopenharmony_ci
156f08c3bdfSopenharmony_ci	case SEGT_SHM:
157f08c3bdfSopenharmony_ci		shmdt(segp->seg_start);
158f08c3bdfSopenharmony_ci		break;
159f08c3bdfSopenharmony_ci
160f08c3bdfSopenharmony_ci	default:
161f08c3bdfSopenharmony_ci		// shouldn't happen?
162f08c3bdfSopenharmony_ci		break;
163f08c3bdfSopenharmony_ci	}
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ci	segp->seg_start = MAP_FAILED;
166f08c3bdfSopenharmony_ci}
167f08c3bdfSopenharmony_ci
168f08c3bdfSopenharmony_ci/*
169f08c3bdfSopenharmony_ci * free up a segment table slot, freeing any string storage
170f08c3bdfSopenharmony_ci * and removing shm segment, if necessary
171f08c3bdfSopenharmony_ci * clear out the segment, but preserve slot #
172f08c3bdfSopenharmony_ci */
173f08c3bdfSopenharmony_cistatic void free_seg_slot(segment_t * segp)
174f08c3bdfSopenharmony_ci{
175f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
176f08c3bdfSopenharmony_ci	int slot = segp->seg_slot;
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_ci	if (segp->seg_name != NULL)
179f08c3bdfSopenharmony_ci		free(segp->seg_name);
180f08c3bdfSopenharmony_ci
181f08c3bdfSopenharmony_ci	if (segp->seg_path != NULL)
182f08c3bdfSopenharmony_ci		free(segp->seg_path);
183f08c3bdfSopenharmony_ci
184f08c3bdfSopenharmony_ci	if (segp->seg_type == SEGT_FILE && segp->seg_fd != SEG_FD_NONE)
185f08c3bdfSopenharmony_ci		close(segp->seg_fd);
186f08c3bdfSopenharmony_ci
187f08c3bdfSopenharmony_ci	if (segp->seg_type == SEGT_SHM && segp->seg_shmid != SHM_ID_NONE)
188f08c3bdfSopenharmony_ci		shmctl(segp->seg_shmid, IPC_RMID, NULL);
189f08c3bdfSopenharmony_ci
190f08c3bdfSopenharmony_ci	(void)memset(segp, 0, sizeof(*segp));
191f08c3bdfSopenharmony_ci
192f08c3bdfSopenharmony_ci	segp->seg_slot = slot;
193f08c3bdfSopenharmony_ci	if (gcp->seg_avail == NULL)
194f08c3bdfSopenharmony_ci		gcp->seg_avail = segp;
195f08c3bdfSopenharmony_ci
196f08c3bdfSopenharmony_ci}
197f08c3bdfSopenharmony_ci
198f08c3bdfSopenharmony_ci/*
199f08c3bdfSopenharmony_ci * called from memtoy "at exit" cleanup().
200f08c3bdfSopenharmony_ci * primarily to remove any shm segments created.
201f08c3bdfSopenharmony_ci */
202f08c3bdfSopenharmony_civoid segment_cleanup(struct global_context *gcp)
203f08c3bdfSopenharmony_ci{
204f08c3bdfSopenharmony_ci	segment_t *segp, **segpp;
205f08c3bdfSopenharmony_ci
206f08c3bdfSopenharmony_ci	segpp = gcp->seglist;
207f08c3bdfSopenharmony_ci	if (segpp == NULL)
208f08c3bdfSopenharmony_ci		return;
209f08c3bdfSopenharmony_ci
210f08c3bdfSopenharmony_ci	for (; (segp = *segpp); ++segpp) {
211f08c3bdfSopenharmony_ci		if (segp->seg_type != SEGT_SHM) {
212f08c3bdfSopenharmony_ci			continue;
213f08c3bdfSopenharmony_ci		}
214f08c3bdfSopenharmony_ci		free_seg_slot(segp);	/* to remove shared mem */
215f08c3bdfSopenharmony_ci	}
216f08c3bdfSopenharmony_ci}
217f08c3bdfSopenharmony_ci
218f08c3bdfSopenharmony_cistatic size_t round_up_to_pagesize(size_t size)
219f08c3bdfSopenharmony_ci{
220f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
221f08c3bdfSopenharmony_ci	size_t pagemask = gcp->pagesize - 1;
222f08c3bdfSopenharmony_ci
223f08c3bdfSopenharmony_ci	return ((size + pagemask) & ~pagemask);
224f08c3bdfSopenharmony_ci
225f08c3bdfSopenharmony_ci}
226f08c3bdfSopenharmony_ci
227f08c3bdfSopenharmony_cistatic size_t round_down_to_pagesize(size_t size)
228f08c3bdfSopenharmony_ci{
229f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
230f08c3bdfSopenharmony_ci	size_t pagemask = gcp->pagesize - 1;
231f08c3bdfSopenharmony_ci
232f08c3bdfSopenharmony_ci	return (size & ~pagemask);
233f08c3bdfSopenharmony_ci
234f08c3bdfSopenharmony_ci}
235f08c3bdfSopenharmony_ci
236f08c3bdfSopenharmony_ci/*
237f08c3bdfSopenharmony_ci * get_node() -- fetch numa node id of page at vaddr
238f08c3bdfSopenharmony_ci * [from Ray Bryant's [SGI] memory migration tests]
239f08c3bdfSopenharmony_ci */
240f08c3bdfSopenharmony_cistatic int get_node(void *vaddr)
241f08c3bdfSopenharmony_ci{
242f08c3bdfSopenharmony_ci	int rc, node;
243f08c3bdfSopenharmony_ci
244f08c3bdfSopenharmony_ci	rc = get_mempolicy(&node, NULL, 0, vaddr, MPOL_F_NODE | MPOL_F_ADDR);
245f08c3bdfSopenharmony_ci	if (rc)
246f08c3bdfSopenharmony_ci		return -1;
247f08c3bdfSopenharmony_ci
248f08c3bdfSopenharmony_ci	return node;
249f08c3bdfSopenharmony_ci}
250f08c3bdfSopenharmony_ci
251f08c3bdfSopenharmony_ci/*
252f08c3bdfSopenharmony_ci * =========================================================================
253f08c3bdfSopenharmony_ci */
254f08c3bdfSopenharmony_cistatic int map_anon_segment(segment_t * segp)
255f08c3bdfSopenharmony_ci{
256f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
257f08c3bdfSopenharmony_ci
258f08c3bdfSopenharmony_ci	char *memp;
259f08c3bdfSopenharmony_ci	int flags = segp->seg_flags;
260f08c3bdfSopenharmony_ci
261f08c3bdfSopenharmony_ci	if (!flags)
262f08c3bdfSopenharmony_ci		flags = MAP_PRIVATE;	/* default */
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_ci	memp = (char *)mmap(0, segp->seg_length, segp->seg_prot, flags | MAP_ANONYMOUS, 0,	/* fd -- ignored */
265f08c3bdfSopenharmony_ci			    0);	/* offset -- ignored */
266f08c3bdfSopenharmony_ci
267f08c3bdfSopenharmony_ci	if (memp == MAP_FAILED) {
268f08c3bdfSopenharmony_ci		int err = errno;
269f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  anonymous mmap failed - %s\n",
270f08c3bdfSopenharmony_ci			__FUNCTION__, strerror(err));
271f08c3bdfSopenharmony_ci		return SEG_ERR;
272f08c3bdfSopenharmony_ci	}
273f08c3bdfSopenharmony_ci
274f08c3bdfSopenharmony_ci	vprint("%s:  mmap()ed anon seg %s at 0x%lx-0x%lx\n",
275f08c3bdfSopenharmony_ci	       gcp->program_name, segp->seg_name,
276f08c3bdfSopenharmony_ci	       memp, memp + segp->seg_length - 1);
277f08c3bdfSopenharmony_ci
278f08c3bdfSopenharmony_ci	segp->seg_start = memp;
279f08c3bdfSopenharmony_ci
280f08c3bdfSopenharmony_ci	return SEG_OK;
281f08c3bdfSopenharmony_ci}
282f08c3bdfSopenharmony_ci
283f08c3bdfSopenharmony_ci/*
284f08c3bdfSopenharmony_ci * open_file() -- open and validate file when registering a file segment.
285f08c3bdfSopenharmony_ci * remember fd in segment struct.
286f08c3bdfSopenharmony_ci */
287f08c3bdfSopenharmony_cistatic int open_file(segment_t * segp)
288f08c3bdfSopenharmony_ci{
289f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
290f08c3bdfSopenharmony_ci
291f08c3bdfSopenharmony_ci	struct stat stbuf;
292f08c3bdfSopenharmony_ci	int fd, flags;
293f08c3bdfSopenharmony_ci
294f08c3bdfSopenharmony_ci	if (stat(segp->seg_path, &stbuf) < 0) {
295f08c3bdfSopenharmony_ci		int err = errno;
296f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  can't stat %s - %s\n",
297f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_path, strerror(err));
298f08c3bdfSopenharmony_ci		free_seg_slot(segp);
299f08c3bdfSopenharmony_ci		return SEG_ERR;
300f08c3bdfSopenharmony_ci	}
301f08c3bdfSopenharmony_ci
302f08c3bdfSopenharmony_ci	/*
303f08c3bdfSopenharmony_ci	 * TODO:  for now, just regular files.  later?
304f08c3bdfSopenharmony_ci	 */
305f08c3bdfSopenharmony_ci	if (!S_ISREG(stbuf.st_mode)) {
306f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  %s - is not a regular file\n",
307f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_path);
308f08c3bdfSopenharmony_ci		free_seg_slot(segp);
309f08c3bdfSopenharmony_ci		return SEG_ERR;
310f08c3bdfSopenharmony_ci	}
311f08c3bdfSopenharmony_ci
312f08c3bdfSopenharmony_ci	/*
313f08c3bdfSopenharmony_ci	 * Open file with maximal privileges;  adjust segment mapping
314f08c3bdfSopenharmony_ci	 * protections if permissions don't allow full R/W access.
315f08c3bdfSopenharmony_ci	 */
316f08c3bdfSopenharmony_ci	if (!access(segp->seg_path, R_OK | W_OK))
317f08c3bdfSopenharmony_ci		flags = O_RDWR;
318f08c3bdfSopenharmony_ci	else if (!access(segp->seg_path, R_OK)) {
319f08c3bdfSopenharmony_ci		flags = O_RDONLY;
320f08c3bdfSopenharmony_ci		segp->seg_prot &= ~PROT_WRITE;
321f08c3bdfSopenharmony_ci	} else if (!access(segp->seg_path, W_OK)) {
322f08c3bdfSopenharmony_ci		flags = O_WRONLY;
323f08c3bdfSopenharmony_ci		segp->seg_prot &= ~PROT_READ;
324f08c3bdfSopenharmony_ci	} else {
325f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  can't access %s\n",
326f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_path);
327f08c3bdfSopenharmony_ci		free_seg_slot(segp);
328f08c3bdfSopenharmony_ci		return SEG_ERR;
329f08c3bdfSopenharmony_ci	}
330f08c3bdfSopenharmony_ci
331f08c3bdfSopenharmony_ci	fd = open(segp->seg_path, flags);
332f08c3bdfSopenharmony_ci	if (fd < 0) {
333f08c3bdfSopenharmony_ci		int err = errno;
334f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  can't open %s - %s\n",
335f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_path, strerror(err));
336f08c3bdfSopenharmony_ci		free_seg_slot(segp);
337f08c3bdfSopenharmony_ci		return SEG_ERR;
338f08c3bdfSopenharmony_ci	}
339f08c3bdfSopenharmony_ci
340f08c3bdfSopenharmony_ci	segp->seg_fd = fd;
341f08c3bdfSopenharmony_ci	return SEG_OK;
342f08c3bdfSopenharmony_ci}
343f08c3bdfSopenharmony_ci
344f08c3bdfSopenharmony_ci/*
345f08c3bdfSopenharmony_ci * re-fetch file size at map time -- just in case it's changed
346f08c3bdfSopenharmony_ci */
347f08c3bdfSopenharmony_cistatic size_t file_size(int fd)
348f08c3bdfSopenharmony_ci{
349f08c3bdfSopenharmony_ci	struct stat stbuf;
350f08c3bdfSopenharmony_ci
351f08c3bdfSopenharmony_ci	if (fstat(fd, &stbuf) != 0) {
352f08c3bdfSopenharmony_ci		return BOGUS_SIZE;
353f08c3bdfSopenharmony_ci	}
354f08c3bdfSopenharmony_ci
355f08c3bdfSopenharmony_ci	return stbuf.st_size;
356f08c3bdfSopenharmony_ci}
357f08c3bdfSopenharmony_ci
358f08c3bdfSopenharmony_ci/*
359f08c3bdfSopenharmony_ci * map_file_segment() -- map a [range of a] registered file segment.
360f08c3bdfSopenharmony_ci */
361f08c3bdfSopenharmony_cistatic int map_file_segment(segment_t * segp)
362f08c3bdfSopenharmony_ci{
363f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
364f08c3bdfSopenharmony_ci
365f08c3bdfSopenharmony_ci	char *memp;
366f08c3bdfSopenharmony_ci	size_t size;
367f08c3bdfSopenharmony_ci	int fd;
368f08c3bdfSopenharmony_ci	int flags = segp->seg_flags;
369f08c3bdfSopenharmony_ci
370f08c3bdfSopenharmony_ci	if (!flags)
371f08c3bdfSopenharmony_ci		flags = MAP_PRIVATE;	/* default */
372f08c3bdfSopenharmony_ci
373f08c3bdfSopenharmony_ci	if ((fd = segp->seg_fd) == SEG_FD_NONE) {
374f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  file %s not open\n",
375f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_path);
376f08c3bdfSopenharmony_ci		return SEG_ERR;
377f08c3bdfSopenharmony_ci	}
378f08c3bdfSopenharmony_ci
379f08c3bdfSopenharmony_ci	size = file_size(fd);
380f08c3bdfSopenharmony_ci
381f08c3bdfSopenharmony_ci	/*
382f08c3bdfSopenharmony_ci	 * page align offset/length;  verify fit in file
383f08c3bdfSopenharmony_ci	 */
384f08c3bdfSopenharmony_ci	segp->seg_offset = round_down_to_pagesize(segp->seg_offset);
385f08c3bdfSopenharmony_ci	if (segp->seg_offset > size) {
386f08c3bdfSopenharmony_ci		fprintf(stderr, "%s: offset 0x%lx beyond end of file %s\n",
387f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_offset, segp->seg_path);
388f08c3bdfSopenharmony_ci		return SEG_ERR;
389f08c3bdfSopenharmony_ci	}
390f08c3bdfSopenharmony_ci
391f08c3bdfSopenharmony_ci	if (segp->seg_length == 0)
392f08c3bdfSopenharmony_ci		segp->seg_length = round_up_to_pagesize(size) -
393f08c3bdfSopenharmony_ci		    segp->seg_offset;
394f08c3bdfSopenharmony_ci	else
395f08c3bdfSopenharmony_ci		segp->seg_length = round_up_to_pagesize(segp->seg_length);
396f08c3bdfSopenharmony_ci
397f08c3bdfSopenharmony_ci	memp = (char *)mmap(0, segp->seg_length,
398f08c3bdfSopenharmony_ci			    segp->seg_prot, flags, fd, segp->seg_offset);
399f08c3bdfSopenharmony_ci
400f08c3bdfSopenharmony_ci	if (memp == MAP_FAILED) {
401f08c3bdfSopenharmony_ci		int err = errno;
402f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  mmap of %s failed - %s\n",
403f08c3bdfSopenharmony_ci			__FUNCTION__, segp->seg_path, strerror(err));
404f08c3bdfSopenharmony_ci		return SEG_ERR;
405f08c3bdfSopenharmony_ci	}
406f08c3bdfSopenharmony_ci
407f08c3bdfSopenharmony_ci	vprint("%s:  mmap()ed file seg %s at 0x%lx-0x%lx\n",
408f08c3bdfSopenharmony_ci	       gcp->program_name, segp->seg_name,
409f08c3bdfSopenharmony_ci	       memp, memp + segp->seg_length - 1);
410f08c3bdfSopenharmony_ci
411f08c3bdfSopenharmony_ci	segp->seg_start = memp;
412f08c3bdfSopenharmony_ci
413f08c3bdfSopenharmony_ci	return SEG_OK;
414f08c3bdfSopenharmony_ci}
415f08c3bdfSopenharmony_ci
416f08c3bdfSopenharmony_ci/*
417f08c3bdfSopenharmony_ci * get_shm_segment() -- create [shmget] a new shared memory segment
418f08c3bdfSopenharmony_ci */
419f08c3bdfSopenharmony_cistatic int get_shm_segment(segment_t * segp)
420f08c3bdfSopenharmony_ci{
421f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
422f08c3bdfSopenharmony_ci
423f08c3bdfSopenharmony_ci	int shmid;
424f08c3bdfSopenharmony_ci
425f08c3bdfSopenharmony_ci	shmid = shmget(IPC_PRIVATE, segp->seg_length, SHM_R | SHM_W);
426f08c3bdfSopenharmony_ci	if (shmid == -1) {
427f08c3bdfSopenharmony_ci		int err = errno;
428f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  failed to get shm segment %s - %s\n",
429f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_name, strerror(err));
430f08c3bdfSopenharmony_ci		free_seg_slot(segp);
431f08c3bdfSopenharmony_ci		return SEG_ERR;
432f08c3bdfSopenharmony_ci	}
433f08c3bdfSopenharmony_ci
434f08c3bdfSopenharmony_ci	segp->seg_shmid = shmid;
435f08c3bdfSopenharmony_ci	vprint("%s:  shm seg %s id:  %d\n",
436f08c3bdfSopenharmony_ci	       gcp->program_name, segp->seg_name, segp->seg_shmid);
437f08c3bdfSopenharmony_ci	return SEG_OK;
438f08c3bdfSopenharmony_ci}
439f08c3bdfSopenharmony_ci
440f08c3bdfSopenharmony_ci/*
441f08c3bdfSopenharmony_ci * map_shm_segment() -- attach [shmat] a shared memory segment
442f08c3bdfSopenharmony_ci */
443f08c3bdfSopenharmony_cistatic int map_shm_segment(segment_t * segp)
444f08c3bdfSopenharmony_ci{
445f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
446f08c3bdfSopenharmony_ci
447f08c3bdfSopenharmony_ci	segp->seg_start = shmat(segp->seg_shmid, NULL, 0);
448f08c3bdfSopenharmony_ci	if (segp->seg_start == MAP_FAILED) {
449f08c3bdfSopenharmony_ci		int err = errno;
450f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  failed to attach shm segment %s: %s\n",
451f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_name, strerror(err));
452f08c3bdfSopenharmony_ci		return SEG_ERR;
453f08c3bdfSopenharmony_ci	}
454f08c3bdfSopenharmony_ci
455f08c3bdfSopenharmony_ci	vprint("%s:  mmap()ed shm seg %s at 0x%lx-0x%lx\n",
456f08c3bdfSopenharmony_ci	       gcp->program_name, segp->seg_name,
457f08c3bdfSopenharmony_ci	       segp->seg_start, segp->seg_start + segp->seg_length - 1);
458f08c3bdfSopenharmony_ci
459f08c3bdfSopenharmony_ci	return SEG_OK;
460f08c3bdfSopenharmony_ci}
461f08c3bdfSopenharmony_ci
462f08c3bdfSopenharmony_ci/*
463f08c3bdfSopenharmony_ci * =========================================================================
464f08c3bdfSopenharmony_ci * segment API
465f08c3bdfSopenharmony_ci */
466f08c3bdfSopenharmony_ci/*
467f08c3bdfSopenharmony_ci * segment_get(name) - lookup named segment
468f08c3bdfSopenharmony_ciTODO:  move to segment private functions?
469f08c3bdfSopenharmony_ci */
470f08c3bdfSopenharmony_cisegment_t *segment_get(char *name)
471f08c3bdfSopenharmony_ci{
472f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
473f08c3bdfSopenharmony_ci	segment_t *segp, **segpp;
474f08c3bdfSopenharmony_ci
475f08c3bdfSopenharmony_ci	for (segpp = gcp->seglist; (segp = *segpp); ++segpp) {
476f08c3bdfSopenharmony_ci		if (segp->seg_type == SEGT_NONE) {
477f08c3bdfSopenharmony_ci			if (gcp->seg_avail == NULL)
478f08c3bdfSopenharmony_ci				gcp->seg_avail = *segpp;
479f08c3bdfSopenharmony_ci			continue;
480f08c3bdfSopenharmony_ci		}
481f08c3bdfSopenharmony_ci		if (!strcmp(name, segp->seg_name))
482f08c3bdfSopenharmony_ci			return segp;
483f08c3bdfSopenharmony_ci	}
484f08c3bdfSopenharmony_ci
485f08c3bdfSopenharmony_ci	if (gcp->seg_avail == NULL && segpp < &gcp->seglist[MAX_SEGMENTS]) {
486f08c3bdfSopenharmony_ci		/*
487f08c3bdfSopenharmony_ci		 * prealloc an available segment
488f08c3bdfSopenharmony_ci		 */
489f08c3bdfSopenharmony_ci		*segpp = segp = new_segment();
490f08c3bdfSopenharmony_ci		if (segp != NULL) {
491f08c3bdfSopenharmony_ci			segp->seg_slot = segpp - gcp->seglist;
492f08c3bdfSopenharmony_ci			gcp->seg_avail = segp;
493f08c3bdfSopenharmony_ci		}
494f08c3bdfSopenharmony_ci	}
495f08c3bdfSopenharmony_ci
496f08c3bdfSopenharmony_ci	return NULL;
497f08c3bdfSopenharmony_ci}
498f08c3bdfSopenharmony_ci
499f08c3bdfSopenharmony_ci/*
500f08c3bdfSopenharmony_ci * segment_register:  register an anon, file or shm segment based on args.
501f08c3bdfSopenharmony_ci *	for anon and shm, 'name' = segment name.
502f08c3bdfSopenharmony_ci *	for file, 'name' = path name; segment name = basename(path)
503f08c3bdfSopenharmony_ci *
504f08c3bdfSopenharmony_ci * returns: !0 on success; 0 on failure
505f08c3bdfSopenharmony_ci */
506f08c3bdfSopenharmony_ciint segment_register(seg_type_t type, char *name, range_t * range, int flags)
507f08c3bdfSopenharmony_ci{
508f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
509f08c3bdfSopenharmony_ci	segment_t *segp;
510f08c3bdfSopenharmony_ci	char *path;
511f08c3bdfSopenharmony_ci
512f08c3bdfSopenharmony_ci	segp = segment_get(basename(name));	/* ensure unique name */
513f08c3bdfSopenharmony_ci	if (segp != NULL) {
514f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  segment %s already exists\n",
515f08c3bdfSopenharmony_ci			gcp->program_name, segp->seg_name);
516f08c3bdfSopenharmony_ci		return SEG_ERR;
517f08c3bdfSopenharmony_ci	}
518f08c3bdfSopenharmony_ci
519f08c3bdfSopenharmony_ci	segp = get_seg_slot();
520f08c3bdfSopenharmony_ci	if (segp == NULL)
521f08c3bdfSopenharmony_ci		return SEG_ERR;
522f08c3bdfSopenharmony_ci
523f08c3bdfSopenharmony_ci	path = strdup(name);	/* save a copy */
524f08c3bdfSopenharmony_ci	segp->seg_name = strdup(basename(name));
525f08c3bdfSopenharmony_ci	segp->seg_start = MAP_FAILED;
526f08c3bdfSopenharmony_ci	segp->seg_length = round_up_to_pagesize(range->length);
527f08c3bdfSopenharmony_ci	segp->seg_offset = round_down_to_pagesize(range->offset);
528f08c3bdfSopenharmony_ci	segp->seg_type = type;
529f08c3bdfSopenharmony_ci	segp->seg_flags = flags;	/* possibly 0 */
530f08c3bdfSopenharmony_ci	segp->seg_prot = PROT_READ | PROT_WRITE;	/* default */
531f08c3bdfSopenharmony_ci	segp->seg_fd = SEG_FD_NONE;
532f08c3bdfSopenharmony_ci	segp->seg_shmid = SHM_ID_NONE;
533f08c3bdfSopenharmony_ci
534f08c3bdfSopenharmony_ci	switch (type) {
535f08c3bdfSopenharmony_ci	case SEGT_ANON:
536f08c3bdfSopenharmony_ci		free(path);
537f08c3bdfSopenharmony_ci		break;
538f08c3bdfSopenharmony_ci
539f08c3bdfSopenharmony_ci	case SEGT_FILE:
540f08c3bdfSopenharmony_ci		segp->seg_path = path;
541f08c3bdfSopenharmony_ci		return open_file(segp);
542f08c3bdfSopenharmony_ci		break;
543f08c3bdfSopenharmony_ci
544f08c3bdfSopenharmony_ci	case SEGT_SHM:
545f08c3bdfSopenharmony_ci		free(path);
546f08c3bdfSopenharmony_ci		return get_shm_segment(segp);
547f08c3bdfSopenharmony_ci		break;
548f08c3bdfSopenharmony_ci
549f08c3bdfSopenharmony_ci	default:
550f08c3bdfSopenharmony_ci		free(path);
551f08c3bdfSopenharmony_ci	}
552f08c3bdfSopenharmony_ci	return SEG_OK;
553f08c3bdfSopenharmony_ci}
554f08c3bdfSopenharmony_ci
555f08c3bdfSopenharmony_cistatic char *segment_header =
556f08c3bdfSopenharmony_ci    "  _____address______ ____length____ ____offset____ prot  share  name\n";
557f08c3bdfSopenharmony_ci
558f08c3bdfSopenharmony_cistatic char seg_type[] = { '.', 'a', 'f', 's' };
559f08c3bdfSopenharmony_ci
560f08c3bdfSopenharmony_cistatic int show_one_segment(segment_t * segp, bool header)
561f08c3bdfSopenharmony_ci{
562f08c3bdfSopenharmony_ci	char *protection, *share, *name;
563f08c3bdfSopenharmony_ci
564f08c3bdfSopenharmony_ci	switch (segp->seg_prot & (PROT_READ | PROT_WRITE)) {
565f08c3bdfSopenharmony_ci	case PROT_READ | PROT_WRITE:
566f08c3bdfSopenharmony_ci		protection = "rw";
567f08c3bdfSopenharmony_ci		break;
568f08c3bdfSopenharmony_ci
569f08c3bdfSopenharmony_ci	case PROT_READ:
570f08c3bdfSopenharmony_ci		protection = "r-";
571f08c3bdfSopenharmony_ci		break;
572f08c3bdfSopenharmony_ci
573f08c3bdfSopenharmony_ci	case PROT_WRITE:
574f08c3bdfSopenharmony_ci		protection = "-w";
575f08c3bdfSopenharmony_ci		break;
576f08c3bdfSopenharmony_ci
577f08c3bdfSopenharmony_ci	default:
578f08c3bdfSopenharmony_ci		protection = "--";
579f08c3bdfSopenharmony_ci		break;
580f08c3bdfSopenharmony_ci	}
581f08c3bdfSopenharmony_ci
582f08c3bdfSopenharmony_ci	if (segp->seg_flags)
583f08c3bdfSopenharmony_ci		share = (segp->seg_flags & MAP_SHARED) ? "shared " : "private";
584f08c3bdfSopenharmony_ci	else
585f08c3bdfSopenharmony_ci		share = "default";
586f08c3bdfSopenharmony_ci
587f08c3bdfSopenharmony_ci	name = (segp->seg_type == SEGT_FILE) ? segp->seg_path : segp->seg_name;
588f08c3bdfSopenharmony_ci
589f08c3bdfSopenharmony_ci	if (header)
590f08c3bdfSopenharmony_ci		puts(segment_header);
591f08c3bdfSopenharmony_ci
592f08c3bdfSopenharmony_ci	if (segp->seg_start != MAP_FAILED) {
593f08c3bdfSopenharmony_ci		printf("%c 0x%p 0x%012zx 0x%012lx  %s  %s %s\n",
594f08c3bdfSopenharmony_ci		       seg_type[segp->seg_type],
595f08c3bdfSopenharmony_ci		       segp->seg_start,
596f08c3bdfSopenharmony_ci		       segp->seg_length,
597f08c3bdfSopenharmony_ci		       segp->seg_offset, protection, share, name);
598f08c3bdfSopenharmony_ci	} else {
599f08c3bdfSopenharmony_ci		printf("%c *** not-mapped *** 0x%012zx 0x%012lx  %s  %s %s\n",
600f08c3bdfSopenharmony_ci		       seg_type[segp->seg_type],
601f08c3bdfSopenharmony_ci		       segp->seg_length,
602f08c3bdfSopenharmony_ci		       segp->seg_offset, protection, share, name);
603f08c3bdfSopenharmony_ci	}
604f08c3bdfSopenharmony_ci
605f08c3bdfSopenharmony_ci	return SEG_OK;
606f08c3bdfSopenharmony_ci}
607f08c3bdfSopenharmony_ci
608f08c3bdfSopenharmony_ci/*
609f08c3bdfSopenharmony_ci * segment_show() -- show specified segment, or all, if none specified.
610f08c3bdfSopenharmony_ci */
611f08c3bdfSopenharmony_ciint segment_show(char *name)
612f08c3bdfSopenharmony_ci{
613f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
614f08c3bdfSopenharmony_ci	segment_t *segp, **segpp;
615f08c3bdfSopenharmony_ci	bool header;
616f08c3bdfSopenharmony_ci
617f08c3bdfSopenharmony_ci	if (name != NULL) {
618f08c3bdfSopenharmony_ci		segp = segment_get(name);
619f08c3bdfSopenharmony_ci		if (segp == NULL) {
620f08c3bdfSopenharmony_ci			fprintf(stderr, "%s:  no such segment:  %s\n",
621f08c3bdfSopenharmony_ci				gcp->program_name, name);
622f08c3bdfSopenharmony_ci			return SEG_ERR;
623f08c3bdfSopenharmony_ci		}
624f08c3bdfSopenharmony_ci		show_one_segment(segp, false);
625f08c3bdfSopenharmony_ci		return SEG_OK;
626f08c3bdfSopenharmony_ci	}
627f08c3bdfSopenharmony_ci
628f08c3bdfSopenharmony_ci	/*
629f08c3bdfSopenharmony_ci	 * show all
630f08c3bdfSopenharmony_ci	 */
631f08c3bdfSopenharmony_ci	header = true;
632f08c3bdfSopenharmony_ci	for (segpp = gcp->seglist; (segp = *segpp); ++segpp) {
633f08c3bdfSopenharmony_ci		if (segp->seg_type != SEGT_NONE) {
634f08c3bdfSopenharmony_ci			show_one_segment(segp, header);
635f08c3bdfSopenharmony_ci			header = false;	/* first time only */
636f08c3bdfSopenharmony_ci		}
637f08c3bdfSopenharmony_ci	}
638f08c3bdfSopenharmony_ci
639f08c3bdfSopenharmony_ci	return SEG_OK;
640f08c3bdfSopenharmony_ci
641f08c3bdfSopenharmony_ci}
642f08c3bdfSopenharmony_ci
643f08c3bdfSopenharmony_ci/*
644f08c3bdfSopenharmony_ci * segment_remove() - remove the specified segment, if exists.
645f08c3bdfSopenharmony_ci */
646f08c3bdfSopenharmony_ciint segment_remove(char *name)
647f08c3bdfSopenharmony_ci{
648f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
649f08c3bdfSopenharmony_ci	segment_t *segp;
650f08c3bdfSopenharmony_ci
651f08c3bdfSopenharmony_ci	segp = segment_get(name);
652f08c3bdfSopenharmony_ci	if (segp == NULL) {
653f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  no such segment:  %s\n",
654f08c3bdfSopenharmony_ci			gcp->program_name, name);
655f08c3bdfSopenharmony_ci		return SEG_ERR;
656f08c3bdfSopenharmony_ci	}
657f08c3bdfSopenharmony_ci
658f08c3bdfSopenharmony_ci	unmap_segment(segp);
659f08c3bdfSopenharmony_ci
660f08c3bdfSopenharmony_ci	free_seg_slot(segp);
661f08c3bdfSopenharmony_ci
662f08c3bdfSopenharmony_ci	return SEG_OK;
663f08c3bdfSopenharmony_ci}
664f08c3bdfSopenharmony_ci
665f08c3bdfSopenharmony_ci/*
666f08c3bdfSopenharmony_ci * segment_touch() - "touch" [read or write] each page of specified range
667f08c3bdfSopenharmony_ci *                   -- from offset to offset+length -- to fault in or to
668f08c3bdfSopenharmony_ci *                   test protection.
669f08c3bdfSopenharmony_ci * NOTE:  offset is relative to start of mapping, not start of file!
670f08c3bdfSopenharmony_ci */
671f08c3bdfSopenharmony_ciint segment_touch(char *name, range_t * range, int rw)
672f08c3bdfSopenharmony_ci{
673f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
674f08c3bdfSopenharmony_ci	segment_t *segp;
675f08c3bdfSopenharmony_ci	off_t offset;
676f08c3bdfSopenharmony_ci	size_t length, maxlength;
677f08c3bdfSopenharmony_ci	unsigned long *memp;
678f08c3bdfSopenharmony_ci	struct timeval t_start, t_end;
679f08c3bdfSopenharmony_ci
680f08c3bdfSopenharmony_ci	segp = segment_get(name);
681f08c3bdfSopenharmony_ci	if (segp == NULL) {
682f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  no such segment:  %s\n",
683f08c3bdfSopenharmony_ci			gcp->program_name, name);
684f08c3bdfSopenharmony_ci		return SEG_ERR;
685f08c3bdfSopenharmony_ci	}
686f08c3bdfSopenharmony_ci
687f08c3bdfSopenharmony_ci	offset = round_down_to_pagesize(range->offset);
688f08c3bdfSopenharmony_ci	if (offset >= segp->seg_length) {
689f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  offset %ld is past end of segment %s\n",
690f08c3bdfSopenharmony_ci			gcp->program_name, offset, name);
691f08c3bdfSopenharmony_ci		return SEG_ERR;
692f08c3bdfSopenharmony_ci	}
693f08c3bdfSopenharmony_ci
694f08c3bdfSopenharmony_ci	memp = (unsigned long *)(segp->seg_start + offset);
695f08c3bdfSopenharmony_ci	maxlength = segp->seg_length - offset;
696f08c3bdfSopenharmony_ci
697f08c3bdfSopenharmony_ci	length = range->length;
698f08c3bdfSopenharmony_ci	if (length)
699f08c3bdfSopenharmony_ci		length = round_up_to_pagesize(length);
700f08c3bdfSopenharmony_ci
701f08c3bdfSopenharmony_ci	/*
702f08c3bdfSopenharmony_ci	 * note:  we silently truncate to max length [end of segment]
703f08c3bdfSopenharmony_ci	 */
704f08c3bdfSopenharmony_ci	if (length == 0 || length > maxlength)
705f08c3bdfSopenharmony_ci		length = maxlength;
706f08c3bdfSopenharmony_ci
707f08c3bdfSopenharmony_ci	gettimeofday(&t_start, NULL);
708f08c3bdfSopenharmony_ci	touch_memory(rw, memp, length);
709f08c3bdfSopenharmony_ci	gettimeofday(&t_end, NULL);
710f08c3bdfSopenharmony_ci	printf("%s:  touched %d pages in %6.3f secs\n",
711f08c3bdfSopenharmony_ci	       gcp->program_name, length / gcp->pagesize,
712f08c3bdfSopenharmony_ci	       (float)(tv_diff_usec(&t_start, &t_end)) / 1000000.0);
713f08c3bdfSopenharmony_ci
714f08c3bdfSopenharmony_ci	return SEG_OK;
715f08c3bdfSopenharmony_ci}
716f08c3bdfSopenharmony_ci
717f08c3bdfSopenharmony_ci/*
718f08c3bdfSopenharmony_ci * segment_unmap() -  unmap the specified segment, if any, from seg_start
719f08c3bdfSopenharmony_ci *                    to seg_start+seg_lenth.  Leave the segment in the
720f08c3bdfSopenharmony_ci *                    table;
721f08c3bdfSopenharmony_ci */
722f08c3bdfSopenharmony_ciint segment_unmap(char *name)
723f08c3bdfSopenharmony_ci{
724f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
725f08c3bdfSopenharmony_ci	segment_t *segp;
726f08c3bdfSopenharmony_ci
727f08c3bdfSopenharmony_ci	segp = segment_get(name);
728f08c3bdfSopenharmony_ci	if (segp == NULL) {
729f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  no such segment:  %s\n",
730f08c3bdfSopenharmony_ci			gcp->program_name, name);
731f08c3bdfSopenharmony_ci		return SEG_ERR;
732f08c3bdfSopenharmony_ci	}
733f08c3bdfSopenharmony_ci
734f08c3bdfSopenharmony_ci	if (segp->seg_start == MAP_FAILED)
735f08c3bdfSopenharmony_ci		return SEG_OK;	/* silent success */
736f08c3bdfSopenharmony_ci
737f08c3bdfSopenharmony_ci	switch (segp->seg_type) {
738f08c3bdfSopenharmony_ci	case SEGT_ANON:
739f08c3bdfSopenharmony_ci	case SEGT_FILE:
740f08c3bdfSopenharmony_ci		munmap(segp->seg_start, segp->seg_length);
741f08c3bdfSopenharmony_ci		break;
742f08c3bdfSopenharmony_ci
743f08c3bdfSopenharmony_ci	case SEGT_SHM:
744f08c3bdfSopenharmony_ci		//TODO:  shmdt()...
745f08c3bdfSopenharmony_ci		break;
746f08c3bdfSopenharmony_ci		/* Handle default to get rid of -Wswitch-enum */
747f08c3bdfSopenharmony_ci	default:
748f08c3bdfSopenharmony_ci		break;
749f08c3bdfSopenharmony_ci	}
750f08c3bdfSopenharmony_ci
751f08c3bdfSopenharmony_ci	segp->seg_start = MAP_FAILED;
752f08c3bdfSopenharmony_ci
753f08c3bdfSopenharmony_ci	return SEG_OK;
754f08c3bdfSopenharmony_ci}
755f08c3bdfSopenharmony_ci
756f08c3bdfSopenharmony_ci/*
757f08c3bdfSopenharmony_ci * segment_map() -- [re] map() a previously unmapped segment
758f08c3bdfSopenharmony_ci *                  no-op if already mapped.
759f08c3bdfSopenharmony_ci *                  range only applies to mapped file.
760f08c3bdfSopenharmony_ci */
761f08c3bdfSopenharmony_ciint segment_map(char *name, range_t * range, int flags)
762f08c3bdfSopenharmony_ci{
763f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
764f08c3bdfSopenharmony_ci	segment_t *segp;
765f08c3bdfSopenharmony_ci
766f08c3bdfSopenharmony_ci	segp = segment_get(name);
767f08c3bdfSopenharmony_ci	if (segp == NULL) {
768f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  no such segment:  %s\n",
769f08c3bdfSopenharmony_ci			gcp->program_name, name);
770f08c3bdfSopenharmony_ci		return SEG_ERR;
771f08c3bdfSopenharmony_ci	}
772f08c3bdfSopenharmony_ci
773f08c3bdfSopenharmony_ci	if (segp->seg_start != MAP_FAILED) {
774f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  segment %s already mapped\n",
775f08c3bdfSopenharmony_ci			gcp->program_name, name);
776f08c3bdfSopenharmony_ci		return SEG_OK;	/* treat as success */
777f08c3bdfSopenharmony_ci	}
778f08c3bdfSopenharmony_ci
779f08c3bdfSopenharmony_ci	if (flags != 0)
780f08c3bdfSopenharmony_ci		segp->seg_flags = flags;
781f08c3bdfSopenharmony_ci
782f08c3bdfSopenharmony_ci	switch (segp->seg_type) {
783f08c3bdfSopenharmony_ci	case SEGT_ANON:
784f08c3bdfSopenharmony_ci		return map_anon_segment(segp);
785f08c3bdfSopenharmony_ci		break;
786f08c3bdfSopenharmony_ci
787f08c3bdfSopenharmony_ci	case SEGT_FILE:
788f08c3bdfSopenharmony_ci		if (range != NULL) {
789f08c3bdfSopenharmony_ci			segp->seg_offset = range->offset;
790f08c3bdfSopenharmony_ci			segp->seg_length = range->length;
791f08c3bdfSopenharmony_ci		}
792f08c3bdfSopenharmony_ci		return map_file_segment(segp);
793f08c3bdfSopenharmony_ci		break;
794f08c3bdfSopenharmony_ci
795f08c3bdfSopenharmony_ci	case SEGT_SHM:
796f08c3bdfSopenharmony_ci		return map_shm_segment(segp);
797f08c3bdfSopenharmony_ci		break;
798f08c3bdfSopenharmony_ci		/* Handle default to get rid of -Wswitch-enum */
799f08c3bdfSopenharmony_ci	default:
800f08c3bdfSopenharmony_ci		break;
801f08c3bdfSopenharmony_ci	}
802f08c3bdfSopenharmony_ci
803f08c3bdfSopenharmony_ci	return SEG_ERR;		/* unrecognized segment type -- shouldn't happen */
804f08c3bdfSopenharmony_ci
805f08c3bdfSopenharmony_ci}
806f08c3bdfSopenharmony_ci
807f08c3bdfSopenharmony_ci/*
808f08c3bdfSopenharmony_ci * segment_mbind() - set memory policy for a range of specified segment
809f08c3bdfSopenharmony_ci *
810f08c3bdfSopenharmony_ci * NOTE:  offset is relative to start of mapping, not start of file
811f08c3bdfSopenharmony_ci */
812f08c3bdfSopenharmony_ciint
813f08c3bdfSopenharmony_cisegment_mbind(char *name, range_t * range, int policy,
814f08c3bdfSopenharmony_ci	      nodemask_t * nodemask, int flags)
815f08c3bdfSopenharmony_ci{
816f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
817f08c3bdfSopenharmony_ci	segment_t *segp;
818f08c3bdfSopenharmony_ci	char *start;
819f08c3bdfSopenharmony_ci	off_t offset;
820f08c3bdfSopenharmony_ci	size_t length, maxlength;
821f08c3bdfSopenharmony_ci	int ret;
822f08c3bdfSopenharmony_ci
823f08c3bdfSopenharmony_ci	segp = segment_get(name);
824f08c3bdfSopenharmony_ci	if (segp == NULL) {
825f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  no such segment:  %s\n",
826f08c3bdfSopenharmony_ci			gcp->program_name, name);
827f08c3bdfSopenharmony_ci		return SEG_ERR;
828f08c3bdfSopenharmony_ci	}
829f08c3bdfSopenharmony_ci
830f08c3bdfSopenharmony_ci	if (segp->seg_start == MAP_FAILED) {
831f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  segment %s not mapped\n",
832f08c3bdfSopenharmony_ci			gcp->program_name, name);
833f08c3bdfSopenharmony_ci		return SEG_ERR;
834f08c3bdfSopenharmony_ci	}
835f08c3bdfSopenharmony_ci
836f08c3bdfSopenharmony_ci	offset = round_down_to_pagesize(range->offset);
837f08c3bdfSopenharmony_ci	if (offset >= segp->seg_length) {
838f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  offset %ld is past end of segment %s\n",
839f08c3bdfSopenharmony_ci			gcp->program_name, offset, name);
840f08c3bdfSopenharmony_ci		return SEG_ERR;
841f08c3bdfSopenharmony_ci	}
842f08c3bdfSopenharmony_ci
843f08c3bdfSopenharmony_ci	start = segp->seg_start + offset;
844f08c3bdfSopenharmony_ci	maxlength = segp->seg_length - offset;
845f08c3bdfSopenharmony_ci
846f08c3bdfSopenharmony_ci	length = range->length;
847f08c3bdfSopenharmony_ci	if (length)
848f08c3bdfSopenharmony_ci		length = round_up_to_pagesize(length);
849f08c3bdfSopenharmony_ci
850f08c3bdfSopenharmony_ci	/*
851f08c3bdfSopenharmony_ci	 * note:  we silently truncate to max length [end of segment]
852f08c3bdfSopenharmony_ci	 */
853f08c3bdfSopenharmony_ci	if (length == 0 || length > maxlength)
854f08c3bdfSopenharmony_ci		length = maxlength;
855f08c3bdfSopenharmony_ci
856f08c3bdfSopenharmony_ci	ret = mbind(segp->seg_start + offset, length, policy, nodemask->n,
857f08c3bdfSopenharmony_ci		    NUMA_NUM_NODES, flags);
858f08c3bdfSopenharmony_ci
859f08c3bdfSopenharmony_ci	if (ret == -1) {
860f08c3bdfSopenharmony_ci		int err = errno;
861f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  mbind() of segment %s failed - %s\n",
862f08c3bdfSopenharmony_ci			gcp->program_name, name, strerror(err));
863f08c3bdfSopenharmony_ci		return SEG_ERR;
864f08c3bdfSopenharmony_ci	}
865f08c3bdfSopenharmony_ci
866f08c3bdfSopenharmony_ci	return SEG_OK;
867f08c3bdfSopenharmony_ci}
868f08c3bdfSopenharmony_ci
869f08c3bdfSopenharmony_ci/*
870f08c3bdfSopenharmony_ci * segment_location() - report node location of specified range of segment
871f08c3bdfSopenharmony_ci *
872f08c3bdfSopenharmony_ci * NOTE:  offset is relative to start of mapping, not start of file
873f08c3bdfSopenharmony_ci */
874f08c3bdfSopenharmony_ci#define PG_PER_LINE 8
875f08c3bdfSopenharmony_ci#define PPL_MASK (PG_PER_LINE - 1)
876f08c3bdfSopenharmony_ciint segment_location(char *name, range_t * range)
877f08c3bdfSopenharmony_ci{
878f08c3bdfSopenharmony_ci	glctx_t *gcp = &glctx;
879f08c3bdfSopenharmony_ci	segment_t *segp;
880f08c3bdfSopenharmony_ci	char *apage, *end;
881f08c3bdfSopenharmony_ci	off_t offset;
882f08c3bdfSopenharmony_ci	size_t length, maxlength;
883f08c3bdfSopenharmony_ci	int pgid, i;
884f08c3bdfSopenharmony_ci	bool need_nl;
885f08c3bdfSopenharmony_ci
886f08c3bdfSopenharmony_ci	segp = segment_get(name);
887f08c3bdfSopenharmony_ci	if (segp == NULL) {
888f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  no such segment:  %s\n",
889f08c3bdfSopenharmony_ci			gcp->program_name, name);
890f08c3bdfSopenharmony_ci		return SEG_ERR;
891f08c3bdfSopenharmony_ci	}
892f08c3bdfSopenharmony_ci
893f08c3bdfSopenharmony_ci	if (segp->seg_start == MAP_FAILED) {
894f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  segment %s not mapped\n",
895f08c3bdfSopenharmony_ci			gcp->program_name, name);
896f08c3bdfSopenharmony_ci		return SEG_ERR;
897f08c3bdfSopenharmony_ci	}
898f08c3bdfSopenharmony_ci
899f08c3bdfSopenharmony_ci	offset = round_down_to_pagesize(range->offset);
900f08c3bdfSopenharmony_ci	if (offset >= segp->seg_length) {
901f08c3bdfSopenharmony_ci		fprintf(stderr, "%s:  offset %ld is past end of segment %s\n",
902f08c3bdfSopenharmony_ci			gcp->program_name, offset, name);
903f08c3bdfSopenharmony_ci		return SEG_ERR;
904f08c3bdfSopenharmony_ci	}
905f08c3bdfSopenharmony_ci
906f08c3bdfSopenharmony_ci	apage = segp->seg_start + offset;
907f08c3bdfSopenharmony_ci	maxlength = segp->seg_length - offset;
908f08c3bdfSopenharmony_ci
909f08c3bdfSopenharmony_ci	length = range->length;
910f08c3bdfSopenharmony_ci	if (length)
911f08c3bdfSopenharmony_ci		length = round_up_to_pagesize(length);
912f08c3bdfSopenharmony_ci
913f08c3bdfSopenharmony_ci	/*
914f08c3bdfSopenharmony_ci	 * note:  we silently truncate to max length [end of segment]
915f08c3bdfSopenharmony_ci	 */
916f08c3bdfSopenharmony_ci	if (length == 0 || length > maxlength)
917f08c3bdfSopenharmony_ci		length = maxlength;
918f08c3bdfSopenharmony_ci
919f08c3bdfSopenharmony_ci	end = apage + length;
920f08c3bdfSopenharmony_ci	pgid = offset / gcp->pagesize;
921f08c3bdfSopenharmony_ci
922f08c3bdfSopenharmony_ci	show_one_segment(segp, false);	/* show mapping, no header */
923f08c3bdfSopenharmony_ci
924f08c3bdfSopenharmony_ci	printf("page offset   ");
925f08c3bdfSopenharmony_ci	for (i = 0; i < PG_PER_LINE; ++i)
926f08c3bdfSopenharmony_ci		printf(" +%02d", i);
927f08c3bdfSopenharmony_ci	printf("\n");
928f08c3bdfSopenharmony_ci	if (pgid & PPL_MASK) {
929f08c3bdfSopenharmony_ci		/*
930f08c3bdfSopenharmony_ci		 * start partial line
931f08c3bdfSopenharmony_ci		 */
932f08c3bdfSopenharmony_ci		int pgid2 = pgid & ~PPL_MASK;
933f08c3bdfSopenharmony_ci		printf("%12x: ", pgid2);
934f08c3bdfSopenharmony_ci		while (pgid2 < pgid) {
935f08c3bdfSopenharmony_ci			printf("    ");
936f08c3bdfSopenharmony_ci			++pgid2;
937f08c3bdfSopenharmony_ci		}
938f08c3bdfSopenharmony_ci		need_nl = true;
939f08c3bdfSopenharmony_ci	} else
940f08c3bdfSopenharmony_ci		need_nl = false;
941f08c3bdfSopenharmony_ci
942f08c3bdfSopenharmony_ci	for (; apage < end; apage += gcp->pagesize, ++pgid) {
943f08c3bdfSopenharmony_ci		int node;
944f08c3bdfSopenharmony_ci
945f08c3bdfSopenharmony_ci		node = get_node(apage);
946f08c3bdfSopenharmony_ci		if (node < 0) {
947f08c3bdfSopenharmony_ci			fprintf(stderr, "\n%s:  "
948f08c3bdfSopenharmony_ci				"failed to get node for segment %s, offset 0x%x\n",
949f08c3bdfSopenharmony_ci				gcp->program_name, name, SEG_OFFSET(segp,
950f08c3bdfSopenharmony_ci								    apage));
951f08c3bdfSopenharmony_ci			return SEG_ERR;
952f08c3bdfSopenharmony_ci		}
953f08c3bdfSopenharmony_ci
954f08c3bdfSopenharmony_ci		if ((pgid & PPL_MASK) == 0) {
955f08c3bdfSopenharmony_ci			if (need_nl)
956f08c3bdfSopenharmony_ci				printf("\n");
957f08c3bdfSopenharmony_ci			printf("%12x: ", pgid);	/* start a new line */
958f08c3bdfSopenharmony_ci			need_nl = true;
959f08c3bdfSopenharmony_ci		}
960f08c3bdfSopenharmony_ci		printf(" %3d", node);
961f08c3bdfSopenharmony_ci
962f08c3bdfSopenharmony_ci		if (signalled(gcp)) {
963f08c3bdfSopenharmony_ci			reset_signal();
964f08c3bdfSopenharmony_ci			break;
965f08c3bdfSopenharmony_ci		}
966f08c3bdfSopenharmony_ci	}
967f08c3bdfSopenharmony_ci	printf("\n");
968f08c3bdfSopenharmony_ci
969f08c3bdfSopenharmony_ci	return SEG_OK;
970f08c3bdfSopenharmony_ci}
971f08c3bdfSopenharmony_ci#endif
972