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