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