]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/mmap.c
Merge over several portability changes from xfstest update.
[thirdparty/xfsprogs-dev.git] / io / mmap.c
1 /*
2 * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33 #include <xfs/libxfs.h>
34 #include <sys/mman.h>
35 #include <signal.h>
36 #include "command.h"
37 #include "input.h"
38 #include "init.h"
39 #include "io.h"
40
41 static cmdinfo_t mmap_cmd;
42 static cmdinfo_t mread_cmd;
43 static cmdinfo_t msync_cmd;
44 static cmdinfo_t munmap_cmd;
45 static cmdinfo_t mwrite_cmd;
46 static cmdinfo_t madvise_cmd;
47 static cmdinfo_t mincore_cmd;
48
49 mmap_region_t *maptable;
50 int mapcount;
51 mmap_region_t *mapping;
52
53 static void
54 print_mapping(
55 mmap_region_t *map,
56 int index,
57 int braces)
58 {
59 unsigned char buffer[8] = { 0 };
60 int i;
61
62 static struct {
63 int prot;
64 int mode;
65 } *p, pflags[] = {
66 { PROT_READ, 'r' },
67 { PROT_WRITE, 'w' },
68 { PROT_EXEC, 'x' },
69 { PROT_NONE, 0 }
70 };
71
72 for (i = 0, p = pflags; p->prot != PROT_NONE; i++, p++)
73 buffer[i] = (map->prot & p->prot) ? p->mode : '-';
74 printf("%c%d%c 0x%lx - 0x%lx %s %14s (%lld : %ld)\n",
75 braces? '[' : ' ', index, braces? ']' : ' ',
76 (unsigned long)map->addr,
77 (unsigned long)(map->addr + map->length),
78 buffer, map->name ? map->name : "???",
79 (long long)map->offset, (long)map->length);
80 }
81
82 static void *
83 check_mapping_range(
84 mmap_region_t *map,
85 off64_t offset,
86 size_t length,
87 int pagealign)
88 {
89 off64_t relative;
90
91 if (offset < mapping->offset) {
92 printf(_("offset (%lld) is before start of mapping (%lld)\n"),
93 (long long)offset, (long long)mapping->offset);
94 return NULL;
95 }
96 relative = offset - mapping->offset;
97 if (relative > mapping->length) {
98 printf(_("offset (%lld) is beyond end of mapping (%lld)\n"),
99 (long long)relative, (long long)mapping->offset);
100 return NULL;
101 }
102 if ((relative + length) > (mapping->offset + mapping->length)) {
103 printf(_("range (%lld:%lld) is beyond mapping (%lld:%ld)\n"),
104 (long long)offset, (long long)relative,
105 (long long)mapping->offset, (long)mapping->length);
106 return NULL;
107 }
108 if (pagealign && (long)(mapping->addr + relative) % pagesize) {
109 printf(_("offset address (%p) is not page aligned\n"),
110 mapping->addr + relative);
111 return NULL;
112 }
113
114 return mapping->addr + relative;
115 }
116
117 int
118 maplist_f(void)
119 {
120 int i;
121
122 for (i = 0; i < mapcount; i++)
123 print_mapping(&maptable[i], i, &maptable[i] == mapping);
124 return 0;
125 }
126
127 static int
128 mapset_f(
129 int argc,
130 char **argv)
131 {
132 int i;
133
134 ASSERT(argc == 2);
135 i = atoi(argv[1]);
136 if (i < 0 || i >= mapcount) {
137 printf("value %d is out of range (0-%d)\n", i, mapcount);
138 } else {
139 mapping = &maptable[i];
140 maplist_f();
141 }
142 return 0;
143 }
144
145 static void
146 mmap_help(void)
147 {
148 printf(_(
149 "\n"
150 " maps a range within the current file into memory\n"
151 "\n"
152 " Example:\n"
153 " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n"
154 "\n"
155 " Memory maps a range of a file for subsequent use by other xfs_io commands.\n"
156 " With no arguments, mmap shows the current mappings. The current mapping\n"
157 " can be set by using the single argument form (mapping number or address).\n"
158 " If two arguments are specified (a range), a new mapping is created and the\n"
159 " following options are available:\n"
160 " -r -- map with PROT_READ protection\n"
161 " -w -- map with PROT_WRITE protection\n"
162 " -x -- map with PROT_EXEC protection\n"
163 " If no protection mode is specified, all are used by default.\n"
164 "\n"));
165 }
166
167 static int
168 mmap_f(
169 int argc,
170 char **argv)
171 {
172 off64_t offset;
173 size_t length;
174 void *address;
175 char *filename;
176 int blocksize, sectsize;
177 int c, prot = 0;
178
179 if (argc == 1) {
180 if (mapping)
181 return maplist_f();
182 fprintf(stderr, file ?
183 _("no mapped regions, try 'help mmap'\n") :
184 _("no files are open, try 'help open'\n"));
185 return 0;
186 } else if (argc == 2) {
187 if (mapping)
188 return mapset_f(argc, argv);
189 fprintf(stderr, file ?
190 _("no mapped regions, try 'help mmap'\n") :
191 _("no files are open, try 'help open'\n"));
192 return 0;
193 } else if (!file) {
194 fprintf(stderr, _("no files are open, try 'help open'\n"));
195 return 0;
196 }
197
198 while ((c = getopt(argc, argv, "rwx")) != EOF) {
199 switch (c) {
200 case 'r':
201 prot |= PROT_READ;
202 break;
203 case 'w':
204 prot |= PROT_WRITE;
205 break;
206 case 'x':
207 prot |= PROT_EXEC;
208 break;
209 default:
210 return command_usage(&mmap_cmd);
211 }
212 }
213 if (!prot)
214 prot = PROT_READ | PROT_WRITE | PROT_EXEC;
215
216 if (optind != argc - 2)
217 return command_usage(&mmap_cmd);
218
219 init_cvtnum(&blocksize, &sectsize);
220 offset = cvtnum(blocksize, sectsize, argv[optind]);
221 if (offset < 0) {
222 printf(_("non-numeric offset argument -- %s\n"), argv[optind]);
223 return 0;
224 }
225 optind++;
226 length = cvtnum(blocksize, sectsize, argv[optind]);
227 if (length < 0) {
228 printf(_("non-numeric length argument -- %s\n"), argv[optind]);
229 return 0;
230 }
231
232 filename = strdup(file->name);
233 if (!filename) {
234 perror("strdup");
235 return 0;
236 }
237
238 address = mmap(NULL, length, prot, MAP_SHARED, file->fd, offset);
239 if (address == MAP_FAILED) {
240 perror("mmap");
241 free(filename);
242 return 0;
243 }
244
245 /* Extend the control array of mmap'd regions */
246 maptable = (mmap_region_t *)realloc(maptable, /* growing */
247 ++mapcount * sizeof(mmap_region_t));
248 if (!maptable) {
249 perror("realloc");
250 mapcount = 0;
251 munmap(address, length);
252 free(filename);
253 return 0;
254 }
255
256 /* Finally, make this the new active mapping */
257 mapping = &maptable[mapcount - 1];
258 mapping->addr = address;
259 mapping->length = length;
260 mapping->offset = offset;
261 mapping->name = filename;
262 mapping->prot = prot;
263 return 0;
264 }
265
266 static void
267 msync_help(void)
268 {
269 printf(_(
270 "\n"
271 " flushes a range of bytes in the current memory mapping\n"
272 "\n"
273 " Writes all modified copies of pages over the specified range (or entire\n"
274 " mapping if no range specified) to their backing storage locations. Also,\n"
275 " optionally invalidates so that subsequent references to the pages will be\n"
276 " obtained from their backing storage locations (instead of cached copies).\n"
277 " -a -- perform asynchronous writes (MS_ASYNC)\n"
278 " -i -- invalidate mapped pages (MS_INVALIDATE)\n"
279 " -s -- perform synchronous writes (MS_SYNC)\n"
280 "\n"));
281 }
282
283 int
284 msync_f(
285 int argc,
286 char **argv)
287 {
288 off64_t offset;
289 size_t length;
290 void *start;
291 int c, flags = 0, blocksize, sectsize;
292
293 while ((c = getopt(argc, argv, "ais")) != EOF) {
294 switch (c) {
295 case 'a':
296 flags |= MS_ASYNC;
297 break;
298 case 'i':
299 flags |= MS_INVALIDATE;
300 break;
301 case 's':
302 flags |= MS_SYNC;
303 break;
304 default:
305 return command_usage(&msync_cmd);
306 }
307 }
308
309 if (optind == argc) {
310 offset = mapping->offset;
311 length = mapping->length;
312 } else if (optind == argc - 2) {
313 init_cvtnum(&blocksize, &sectsize);
314 offset = cvtnum(blocksize, sectsize, argv[optind]);
315 if (offset < 0) {
316 printf(_("non-numeric offset argument -- %s\n"),
317 argv[optind]);
318 return 0;
319 }
320 optind++;
321 length = cvtnum(blocksize, sectsize, argv[optind]);
322 if (length < 0) {
323 printf(_("non-numeric length argument -- %s\n"),
324 argv[optind]);
325 return 0;
326 }
327 } else {
328 return command_usage(&msync_cmd);
329 }
330
331 start = check_mapping_range(mapping, offset, length, 1);
332 if (!start)
333 return 0;
334
335 if (msync(start, length, flags) < 0)
336 perror("msync");
337
338 return 0;
339 }
340
341 static int
342 read_mapping(
343 char *dest,
344 off64_t offset,
345 int dump,
346 off64_t dumpoffset,
347 size_t dumplength)
348 {
349 *dest = *(((char *)mapping->addr) + offset);
350
351 if (offset % pagesize == 0) {
352 if (dump == 2)
353 dumpoffset += mapping->offset;
354 if (dump)
355 dump_buffer(dumpoffset, dumplength);
356 return 1;
357 }
358 return 0;
359 }
360
361 static void
362 mread_help(void)
363 {
364 printf(_(
365 "\n"
366 " reads a range of bytes in the current memory mapping\n"
367 "\n"
368 " Example:\n"
369 " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n"
370 "\n"
371 " Accesses a range of the current memory mapping, optionally dumping it to\n"
372 " the standard output stream (with -v option) for subsequent inspection.\n"
373 " -f -- verbose mode, dump bytes with offsets relative to start of file.\n"
374 " -r -- reverse order; start accessing fom the end of range, moving backward\n"
375 " -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n"
376 " The accesses are performed sequentially from the start offset by default.\n"
377 " Notes:\n"
378 " References to whole pages following the end of the backing file results\n"
379 " in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n"
380 " on various filesystem conditions, including quota exceeded errors, and\n"
381 " for physical device errors (such as unreadable disk blocks). No attempt\n"
382 " has been made to catch signals at this stage...\n"
383 "\n"));
384 }
385
386 int
387 mread_f(
388 int argc,
389 char **argv)
390 {
391 off64_t offset, tmp;
392 size_t length, dumplen;
393 char *bp;
394 void *start;
395 int dump = 0, rflag = 0;
396 int c, blocksize, sectsize;
397
398 while ((c = getopt(argc, argv, "frv")) != EOF) {
399 switch (c) {
400 case 'f':
401 dump = 2; /* file offset dump */
402 break;
403 case 'r':
404 rflag = 1; /* read in reverse */
405 break;
406 case 'v':
407 dump = 1; /* mapping offset dump */
408 break;
409 default:
410 return command_usage(&mread_cmd);
411 }
412 }
413
414 if (optind == argc) {
415 offset = mapping->offset;
416 length = mapping->length;
417 } else if (optind == argc - 2) {
418 init_cvtnum(&blocksize, &sectsize);
419 offset = cvtnum(blocksize, sectsize, argv[optind]);
420 if (offset < 0) {
421 printf(_("non-numeric offset argument -- %s\n"),
422 argv[optind]);
423 return 0;
424 }
425 optind++;
426 length = cvtnum(blocksize, sectsize, argv[optind]);
427 if (length < 0) {
428 printf(_("non-numeric length argument -- %s\n"),
429 argv[optind]);
430 return 0;
431 }
432 } else {
433 return command_usage(&mread_cmd);
434 }
435
436 start = check_mapping_range(mapping, offset, length, 0);
437 if (!start)
438 return 0;
439
440 if (alloc_buffer(pagesize, 0, 0) < 0)
441 return 0;
442 bp = (char *)buffer;
443
444 dumplen = length % pagesize;
445 if (!dumplen)
446 dumplen = pagesize;
447
448 if (rflag) {
449 for (tmp = length, c = 0; tmp > 0; tmp--, bp++, c = 1)
450 if (read_mapping(bp, tmp, c? dump:0, offset, dumplen)) {
451 bp = (char *)buffer;
452 dumplen = pagesize;
453 }
454 } else {
455 for (tmp = 0, c = 0; tmp < length; tmp++, bp++, c = 1)
456 if (read_mapping(bp, tmp, c? dump:0, offset, dumplen)) {
457 bp = (char *)buffer;
458 dumplen = pagesize;
459 }
460 }
461 /* dump the remaining (partial page) part of the read buffer */
462 if (dump) {
463 if (rflag)
464 dumplen = length % pagesize;
465 else
466 dumplen = tmp % pagesize;
467 if (dumplen) {
468 if (dump == 2)
469 tmp += mapping->offset;
470 dump_buffer(tmp, dumplen);
471 }
472 }
473 return 0;
474 }
475
476 int
477 munmap_f(
478 int argc,
479 char **argv)
480 {
481 size_t length;
482 unsigned int offset;
483
484 if (munmap(mapping->addr, mapping->length) < 0) {
485 perror("munmap");
486 return 0;
487 }
488 free(mapping->name);
489
490 /* Shuffle the mapping table entries down over the removed entry */
491 offset = mapping - &maptable[0];
492 length = mapcount * sizeof(mmap_region_t);
493 length -= (offset + 1) * sizeof(mmap_region_t);
494 if (length)
495 memmove(mapping, mapping + 1, length);
496
497 /* Resize the memory allocated for the table, possibly freeing */
498 if (--mapcount) {
499 maptable = (mmap_region_t *)realloc(maptable, /* shrinking */
500 mapcount * sizeof(mmap_region_t));
501 if (offset == mapcount)
502 offset--;
503 mapping = maptable + offset;
504 } else {
505 free(maptable);
506 mapping = maptable = NULL;
507 }
508 maplist_f();
509 return 0;
510 }
511
512 static void
513 mwrite_help(void)
514 {
515 printf(_(
516 "\n"
517 " dirties a range of bytes in the current memory mapping\n"
518 "\n"
519 " Example:\n"
520 " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n"
521 "\n"
522 " Stores a byte into memory for a range within a mapping.\n"
523 " The default stored value is 'X', repeated to fill the range specified.\n"
524 " -S -- use an alternate seed character\n"
525 " -r -- reverse order; start storing fom the end of range, moving backward\n"
526 " The stores are performed sequentially from the start offset by default.\n"
527 "\n"));
528 }
529
530 int
531 mwrite_f(
532 int argc,
533 char **argv)
534 {
535 off64_t offset, tmp;
536 size_t length;
537 void *start;
538 char *sp;
539 int seed = 'X';
540 int rflag = 0;
541 int c, blocksize, sectsize;
542
543 while ((c = getopt(argc, argv, "rS:")) != EOF) {
544 switch (c) {
545 case 'r':
546 rflag = 1;
547 break;
548 case 'S':
549 seed = (int)strtol(optarg, &sp, 0);
550 if (!sp || sp == optarg) {
551 printf(_("non-numeric seed -- %s\n"), optarg);
552 return 0;
553 }
554 break;
555 default:
556 return command_usage(&mwrite_cmd);
557 }
558 }
559
560 if (optind == argc) {
561 offset = mapping->offset;
562 length = mapping->length;
563 } else if (optind == argc - 2) {
564 init_cvtnum(&blocksize, &sectsize);
565 offset = cvtnum(blocksize, sectsize, argv[optind]);
566 if (offset < 0) {
567 printf(_("non-numeric offset argument -- %s\n"),
568 argv[optind]);
569 return 0;
570 }
571 optind++;
572 length = cvtnum(blocksize, sectsize, argv[optind]);
573 if (length < 0) {
574 printf(_("non-numeric length argument -- %s\n"),
575 argv[optind]);
576 return 0;
577 }
578 } else {
579 return command_usage(&mwrite_cmd);
580 }
581
582 start = check_mapping_range(mapping, offset, length, 0);
583 if (!start)
584 return 0;
585
586 if (rflag) {
587 for (tmp = offset + length; tmp > offset; tmp--)
588 ((char *)mapping->addr)[tmp] = seed;
589 } else {
590 for (tmp = offset; tmp < offset + length; tmp++)
591 ((char *)mapping->addr)[tmp] = seed;
592 }
593
594 return 0;
595 }
596
597 static void
598 madvise_help(void)
599 {
600 printf(_(
601 "\n"
602 " advise the page cache about access patterns expected for a mapping\n"
603 "\n"
604 " Modifies page cache behavior when operating on the current mapping.\n"
605 " The range arguments are required by some advise commands ([*] below).\n"
606 " With no arguments, the POSIX_MADV_NORMAL advice is implied.\n"
607 " -d -- don't need these pages (POSIX_MADV_DONTNEED) [*]\n"
608 " -r -- expect random page references (POSIX_MADV_RANDOM)\n"
609 " -s -- expect sequential page references (POSIX_MADV_SEQUENTIAL)\n"
610 " -w -- will need these pages (POSIX_MADV_WILLNEED) [*]\n"
611 " Notes:\n"
612 " NORMAL sets the default readahead setting on the file.\n"
613 " RANDOM sets the readahead setting on the file to zero.\n"
614 " SEQUENTIAL sets double the default readahead setting on the file.\n"
615 " WILLNEED forces the maximum readahead.\n"
616 "\n"));
617 }
618
619 int
620 madvise_f(
621 int argc,
622 char **argv)
623 {
624 off64_t offset;
625 size_t length;
626 void *start;
627 int advise = MADV_NORMAL;
628 int c, blocksize, sectsize;
629
630 while ((c = getopt(argc, argv, "drsw")) != EOF) {
631 switch (c) {
632 case 'd': /* Don't need these pages */
633 advise = MADV_DONTNEED;
634 break;
635 case 'r': /* Expect random page references */
636 advise = MADV_RANDOM;
637 break;
638 case 's': /* Expect sequential page references */
639 advise = MADV_SEQUENTIAL;
640 break;
641 case 'w': /* Will need these pages */
642 advise = MADV_WILLNEED;
643 break;
644 default:
645 return command_usage(&madvise_cmd);
646 }
647 }
648
649 if (optind == argc) {
650 offset = mapping->offset;
651 length = mapping->length;
652 } else if (optind == argc - 2) {
653 init_cvtnum(&blocksize, &sectsize);
654 offset = cvtnum(blocksize, sectsize, argv[optind]);
655 if (offset < 0) {
656 printf(_("non-numeric offset argument -- %s\n"),
657 argv[optind]);
658 return 0;
659 }
660 optind++;
661 length = cvtnum(blocksize, sectsize, argv[optind]);
662 if (length < 0) {
663 printf(_("non-numeric length argument -- %s\n"),
664 argv[optind]);
665 return 0;
666 }
667 } else {
668 return command_usage(&madvise_cmd);
669 }
670
671 start = check_mapping_range(mapping, offset, length, 1);
672 if (!start)
673 return 0;
674
675 if (madvise(start, length, advise) < 0) {
676 perror("madvise");
677 return 0;
678 }
679 return 0;
680 }
681
682 #if defined(__sgi__)
683 int mincore(caddr_t p, size_t s, char *v) { errno = ENOSYS; return -1; }
684 #endif
685
686 int
687 mincore_f(
688 int argc,
689 char **argv)
690 {
691 off64_t offset;
692 size_t length;
693 void *start;
694 void *current, *previous;
695 unsigned char *vec;
696 int i, blocksize, sectsize;
697
698 if (argc == 1) {
699 offset = mapping->offset;
700 length = mapping->length;
701 } else if (argc == 3) {
702 init_cvtnum(&blocksize, &sectsize);
703 offset = cvtnum(blocksize, sectsize, argv[1]);
704 if (offset < 0) {
705 printf(_("non-numeric offset argument -- %s\n"),
706 argv[1]);
707 return 0;
708 }
709 length = cvtnum(blocksize, sectsize, argv[2]);
710 if (length < 0) {
711 printf(_("non-numeric length argument -- %s\n"),
712 argv[2]);
713 return 0;
714 }
715 } else {
716 return command_usage(&mincore_cmd);
717 }
718
719 start = check_mapping_range(mapping, offset, length, 1);
720 if (!start)
721 return 0;
722
723 vec = calloc(length/pagesize, sizeof(unsigned char));
724 if (!vec) {
725 perror("calloc");
726 return 0;
727 }
728
729 if (mincore(start, length, vec) < 0) {
730 perror("mincore");
731 free(vec);
732 return 0;
733 }
734
735 previous = NULL;
736 current = start;
737 for (i = 0; i < length/pagesize; i++, current += pagesize) {
738 if (vec[i]) {
739 if (!previous) { /* print start address */
740 printf("0x%lx - ", (unsigned long)current);
741 previous = start + (i * pagesize);
742 }
743 } else if (previous) { /* print end and page count */
744 printf(_("0x%lx %lu pages (%llu : %lu)\n"),
745 (unsigned long)current,
746 (unsigned long)(current - previous) / pagesize,
747 (unsigned long long)offset +
748 (unsigned long long)(previous - start),
749 (unsigned long)(current - previous));
750 previous = NULL;
751 }
752 }
753 if (previous)
754 printf(_("0x%lx %lu pages (%llu : %lu)\n"),
755 (unsigned long)current,
756 (unsigned long)(current - previous) / pagesize,
757 (unsigned long long)offset +
758 (unsigned long long)(previous - start),
759 (unsigned long)(current - previous));
760
761 free(vec);
762 return 0;
763 }
764
765 void
766 mmap_init(void)
767 {
768 mmap_cmd.name = _("mmap");
769 mmap_cmd.altname = _("mm");
770 mmap_cmd.cfunc = mmap_f;
771 mmap_cmd.argmin = 0;
772 mmap_cmd.argmax = -1;
773 mmap_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
774 mmap_cmd.args = _("[N] | [-rwx] [off len]");
775 mmap_cmd.oneline =
776 _("mmap a range in the current file, show mappings");
777 mmap_cmd.help = mmap_help;
778
779 mread_cmd.name = _("mread");
780 mread_cmd.altname = _("mr");
781 mread_cmd.cfunc = mread_f;
782 mread_cmd.argmin = 0;
783 mread_cmd.argmax = -1;
784 mread_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
785 mread_cmd.args = _("[-r] [off len]");
786 mread_cmd.oneline =
787 _("reads data from a region in the current memory mapping");
788 mread_cmd.help = mread_help;
789
790 msync_cmd.name = _("msync");
791 msync_cmd.altname = _("ms");
792 msync_cmd.cfunc = msync_f;
793 msync_cmd.argmin = 0;
794 msync_cmd.argmax = -1;
795 msync_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
796 msync_cmd.args = _("[-ais] [off len]");
797 msync_cmd.oneline = _("flush a region in the current memory mapping");
798 msync_cmd.help = msync_help;
799
800 munmap_cmd.name = _("munmap");
801 munmap_cmd.altname = _("mu");
802 munmap_cmd.cfunc = munmap_f;
803 munmap_cmd.argmin = 0;
804 munmap_cmd.argmax = 0;
805 munmap_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
806 munmap_cmd.oneline = _("unmaps the current memory mapping");
807
808 mwrite_cmd.name = _("mwrite");
809 mwrite_cmd.altname = _("mw");
810 mwrite_cmd.cfunc = mwrite_f;
811 mwrite_cmd.argmin = 0;
812 mwrite_cmd.argmax = -1;
813 mwrite_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
814 mwrite_cmd.args = _("[-r] [-S seed] [off len]");
815 mwrite_cmd.oneline =
816 _("writes data into a region in the current memory mapping");
817 mwrite_cmd.help = mwrite_help;
818
819 madvise_cmd.name = _("madvise");
820 madvise_cmd.altname = _("ma");
821 madvise_cmd.cfunc = madvise_f;
822 madvise_cmd.argmin = 0;
823 madvise_cmd.argmax = -1;
824 madvise_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
825 madvise_cmd.args = _("[-drsw] [off len]");
826 madvise_cmd.oneline = _("give advice about use of memory");
827 madvise_cmd.help = madvise_help;
828
829 mincore_cmd.name = _("mincore");
830 mincore_cmd.altname = _("mi");
831 mincore_cmd.cfunc = mincore_f;
832 mincore_cmd.argmin = 0;
833 mincore_cmd.argmax = 2;
834 mincore_cmd.flags = CMD_NOFILE_OK | CMD_FOREIGN_OK;
835 mincore_cmd.args = _("[off len]");
836 mincore_cmd.oneline = _("find mapping pages that are memory resident");
837
838 add_command(&mmap_cmd);
839 add_command(&mread_cmd);
840 add_command(&msync_cmd);
841 add_command(&munmap_cmd);
842 add_command(&mwrite_cmd);
843 add_command(&madvise_cmd);
844 add_command(&mincore_cmd);
845 }