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