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 */ 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 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 */ 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 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 */ 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 */ 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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) 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