]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/mmap.c
2 * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
33 #include <xfs/libxfs.h>
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
;
49 mmap_region_t
*maptable
;
51 mmap_region_t
*mapping
;
59 unsigned char buffer
[8] = { 0 };
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
);
91 if (offset
< mapping
->offset
) {
92 printf(_("offset (%lld) is before start of mapping (%lld)\n"),
93 (long long)offset
, (long long)mapping
->offset
);
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
);
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
);
108 if (pagealign
&& (long)(mapping
->addr
+ relative
) % pagesize
) {
109 printf(_("offset address (%p) is not page aligned\n"),
110 mapping
->addr
+ relative
);
114 return mapping
->addr
+ relative
;
122 for (i
= 0; i
< mapcount
; i
++)
123 print_mapping(&maptable
[i
], i
, &maptable
[i
] == mapping
);
136 if (i
< 0 || i
>= mapcount
) {
137 printf("value %d is out of range (0-%d)\n", i
, mapcount
);
139 mapping
= &maptable
[i
];
150 " maps a range within the current file into memory\n"
153 " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\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"
176 int blocksize
, sectsize
;
182 fprintf(stderr
, file
?
183 _("no mapped regions, try 'help mmap'\n") :
184 _("no files are open, try 'help open'\n"));
186 } else if (argc
== 2) {
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"));
194 fprintf(stderr
, _("no files are open, try 'help open'\n"));
198 while ((c
= getopt(argc
, argv
, "rwx")) != EOF
) {
210 return command_usage(&mmap_cmd
);
214 prot
= PROT_READ
| PROT_WRITE
| PROT_EXEC
;
216 if (optind
!= argc
- 2)
217 return command_usage(&mmap_cmd
);
219 init_cvtnum(&blocksize
, §size
);
220 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
222 printf(_("non-numeric offset argument -- %s\n"), argv
[optind
]);
226 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
228 printf(_("non-numeric length argument -- %s\n"), argv
[optind
]);
232 filename
= strdup(file
->name
);
238 address
= mmap(NULL
, length
, prot
, MAP_SHARED
, file
->fd
, offset
);
239 if (address
== MAP_FAILED
) {
245 /* Extend the control array of mmap'd regions */
246 maptable
= (mmap_region_t
*)realloc(maptable
, /* growing */
247 ++mapcount
* sizeof(mmap_region_t
));
251 munmap(address
, length
);
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
;
271 " flushes a range of bytes in the current memory mapping\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"
291 int c
, flags
= 0, blocksize
, sectsize
;
293 while ((c
= getopt(argc
, argv
, "ais")) != EOF
) {
299 flags
|= MS_INVALIDATE
;
305 return command_usage(&msync_cmd
);
309 if (optind
== argc
) {
310 offset
= mapping
->offset
;
311 length
= mapping
->length
;
312 } else if (optind
== argc
- 2) {
313 init_cvtnum(&blocksize
, §size
);
314 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
316 printf(_("non-numeric offset argument -- %s\n"),
321 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
323 printf(_("non-numeric length argument -- %s\n"),
328 return command_usage(&msync_cmd
);
331 start
= check_mapping_range(mapping
, offset
, length
, 1);
335 if (msync(start
, length
, flags
) < 0)
349 *dest
= *(((char *)mapping
->addr
) + offset
);
351 if (offset
% pagesize
== 0) {
353 dumpoffset
+= mapping
->offset
;
355 dump_buffer(dumpoffset
, dumplength
);
366 " reads a range of bytes in the current memory mapping\n"
369 " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\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"
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"
392 size_t length
, dumplen
;
395 int dump
= 0, rflag
= 0;
396 int c
, blocksize
, sectsize
;
398 while ((c
= getopt(argc
, argv
, "frv")) != EOF
) {
401 dump
= 2; /* file offset dump */
404 rflag
= 1; /* read in reverse */
407 dump
= 1; /* mapping offset dump */
410 return command_usage(&mread_cmd
);
414 if (optind
== argc
) {
415 offset
= mapping
->offset
;
416 length
= mapping
->length
;
417 } else if (optind
== argc
- 2) {
418 init_cvtnum(&blocksize
, §size
);
419 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
421 printf(_("non-numeric offset argument -- %s\n"),
426 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
428 printf(_("non-numeric length argument -- %s\n"),
433 return command_usage(&mread_cmd
);
436 start
= check_mapping_range(mapping
, offset
, length
, 0);
440 if (alloc_buffer(pagesize
, 0, 0) < 0)
444 dumplen
= length
% pagesize
;
449 for (tmp
= length
, c
= 0; tmp
> 0; tmp
--, bp
++, c
= 1)
450 if (read_mapping(bp
, tmp
, c
? dump
:0, offset
, dumplen
)) {
455 for (tmp
= 0, c
= 0; tmp
< length
; tmp
++, bp
++, c
= 1)
456 if (read_mapping(bp
, tmp
, c
? dump
:0, offset
, dumplen
)) {
461 /* dump the remaining (partial page) part of the read buffer */
464 dumplen
= length
% pagesize
;
466 dumplen
= tmp
% pagesize
;
469 tmp
+= mapping
->offset
;
470 dump_buffer(tmp
, dumplen
);
484 if (munmap(mapping
->addr
, mapping
->length
) < 0) {
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
);
495 memmove(mapping
, mapping
+ 1, length
);
497 /* Resize the memory allocated for the table, possibly freeing */
499 maptable
= (mmap_region_t
*)realloc(maptable
, /* shrinking */
500 mapcount
* sizeof(mmap_region_t
));
501 if (offset
== mapcount
)
503 mapping
= maptable
+ offset
;
506 mapping
= maptable
= NULL
;
517 " dirties a range of bytes in the current memory mapping\n"
520 " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\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"
541 int c
, blocksize
, sectsize
;
543 while ((c
= getopt(argc
, argv
, "rS:")) != EOF
) {
549 seed
= (int)strtol(optarg
, &sp
, 0);
550 if (!sp
|| sp
== optarg
) {
551 printf(_("non-numeric seed -- %s\n"), optarg
);
556 return command_usage(&mwrite_cmd
);
560 if (optind
== argc
) {
561 offset
= mapping
->offset
;
562 length
= mapping
->length
;
563 } else if (optind
== argc
- 2) {
564 init_cvtnum(&blocksize
, §size
);
565 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
567 printf(_("non-numeric offset argument -- %s\n"),
572 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
574 printf(_("non-numeric length argument -- %s\n"),
579 return command_usage(&mwrite_cmd
);
582 start
= check_mapping_range(mapping
, offset
, length
, 0);
587 for (tmp
= offset
+ length
; tmp
> offset
; tmp
--)
588 ((char *)mapping
->addr
)[tmp
] = seed
;
590 for (tmp
= offset
; tmp
< offset
+ length
; tmp
++)
591 ((char *)mapping
->addr
)[tmp
] = seed
;
602 " advise the page cache about access patterns expected for a mapping\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"
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"
627 int advise
= MADV_NORMAL
;
628 int c
, blocksize
, sectsize
;
630 while ((c
= getopt(argc
, argv
, "drsw")) != EOF
) {
632 case 'd': /* Don't need these pages */
633 advise
= MADV_DONTNEED
;
635 case 'r': /* Expect random page references */
636 advise
= MADV_RANDOM
;
638 case 's': /* Expect sequential page references */
639 advise
= MADV_SEQUENTIAL
;
641 case 'w': /* Will need these pages */
642 advise
= MADV_WILLNEED
;
645 return command_usage(&madvise_cmd
);
649 if (optind
== argc
) {
650 offset
= mapping
->offset
;
651 length
= mapping
->length
;
652 } else if (optind
== argc
- 2) {
653 init_cvtnum(&blocksize
, §size
);
654 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
656 printf(_("non-numeric offset argument -- %s\n"),
661 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
663 printf(_("non-numeric length argument -- %s\n"),
668 return command_usage(&madvise_cmd
);
671 start
= check_mapping_range(mapping
, offset
, length
, 1);
675 if (madvise(start
, length
, advise
) < 0) {
683 int mincore(caddr_t p
, size_t s
, char *v
) { errno
= ENOSYS
; return -1; }
694 void *current
, *previous
;
696 int i
, blocksize
, sectsize
;
699 offset
= mapping
->offset
;
700 length
= mapping
->length
;
701 } else if (argc
== 3) {
702 init_cvtnum(&blocksize
, §size
);
703 offset
= cvtnum(blocksize
, sectsize
, argv
[1]);
705 printf(_("non-numeric offset argument -- %s\n"),
709 length
= cvtnum(blocksize
, sectsize
, argv
[2]);
711 printf(_("non-numeric length argument -- %s\n"),
716 return command_usage(&mincore_cmd
);
719 start
= check_mapping_range(mapping
, offset
, length
, 1);
723 vec
= calloc(length
/pagesize
, sizeof(unsigned char));
729 if (mincore(start
, length
, vec
) < 0) {
737 for (i
= 0; i
< length
/pagesize
; i
++, current
+= pagesize
) {
739 if (!previous
) { /* print start address */
740 printf("0x%lx - ", (unsigned long)current
);
741 previous
= start
+ (i
* pagesize
);
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
));
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
));
768 mmap_cmd
.name
= _("mmap");
769 mmap_cmd
.altname
= _("mm");
770 mmap_cmd
.cfunc
= mmap_f
;
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]");
776 _("mmap a range in the current file, show mappings");
777 mmap_cmd
.help
= mmap_help
;
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]");
787 _("reads data from a region in the current memory mapping");
788 mread_cmd
.help
= mread_help
;
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
;
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");
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]");
816 _("writes data into a region in the current memory mapping");
817 mwrite_cmd
.help
= mwrite_help
;
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
;
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");
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
);