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