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