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