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 */
segment_init(struct global_context * gcp)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
new_segment(void)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 */
get_seg_slot(void)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
unmap_segment(segment_t * segp)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 */
free_seg_slot(segment_t * segp)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 */
segment_cleanup(struct global_context * gcp)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
round_up_to_pagesize(size_t size)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
round_down_to_pagesize(size_t size)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 */
get_node(void * vaddr)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 */
map_anon_segment(segment_t * segp)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 */
open_file(segment_t * segp)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 */
file_size(int fd)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 */
map_file_segment(segment_t * segp)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 */
get_shm_segment(segment_t * segp)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 */
map_shm_segment(segment_t * segp)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 */
segment_get(char * name)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 */
segment_register(seg_type_t type,char * name,range_t * range,int flags)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
show_one_segment(segment_t * segp,bool header)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 */
segment_show(char * name)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 */
segment_remove(char * name)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 */
segment_touch(char * name,range_t * range,int rw)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 */
segment_unmap(char * name)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 */
segment_map(char * name,range_t * range,int flags)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
segment_mbind(char * name,range_t * range,int policy,nodemask_t * nodemask,int flags)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)
segment_location(char * name,range_t * range)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