Home | History | Annotate | Download | only in memory_hotplug
      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  */
     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 
     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  */
    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 
    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  */
    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  */
    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 
    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 
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 
    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  */
    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  */
    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  */
    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  */
    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  */
    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
    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)
    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