]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/mmap.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2004-2005 Silicon Graphics, Inc.
14 static cmdinfo_t mmap_cmd
;
15 static cmdinfo_t mread_cmd
;
16 static cmdinfo_t msync_cmd
;
17 static cmdinfo_t munmap_cmd
;
18 static cmdinfo_t mwrite_cmd
;
20 static cmdinfo_t mremap_cmd
;
21 #endif /* HAVE_MREMAP */
23 mmap_region_t
*maptable
;
25 mmap_region_t
*mapping
;
33 char buffer
[8] = { 0 };
46 for (i
= 0, p
= pflags
; p
->prot
!= PROT_NONE
; i
++, p
++)
47 buffer
[i
] = (map
->prot
& p
->prot
) ? p
->mode
: '-';
50 if ((map
->flags
& (MAP_SYNC
| MAP_SHARED_VALIDATE
)) ==
51 (MAP_SYNC
| MAP_SHARED_VALIDATE
))
52 sprintf(&buffer
[i
], " S");
55 printf("%c%03d%c 0x%lx - 0x%lx %s %14s (%lld : %ld)\n",
56 braces
? '[' : ' ', index
, braces
? ']' : ' ',
57 (unsigned long)map
->addr
,
58 (unsigned long)((char *)map
->addr
+ map
->length
),
59 buffer
, map
->name
? map
->name
: "???",
60 (long long)map
->offset
, (long)map
->length
);
72 if (offset
< mapping
->offset
) {
73 printf(_("offset (%lld) is before start of mapping (%lld)\n"),
74 (long long)offset
, (long long)mapping
->offset
);
77 relative
= offset
- mapping
->offset
;
78 if (relative
> mapping
->length
) {
79 printf(_("offset (%lld) is beyond end of mapping (%lld)\n"),
80 (long long)relative
, (long long)mapping
->offset
);
83 if ((relative
+ length
) > (mapping
->offset
+ mapping
->length
)) {
84 printf(_("range (%lld:%lld) is beyond mapping (%lld:%ld)\n"),
85 (long long)offset
, (long long)relative
,
86 (long long)mapping
->offset
, (long)mapping
->length
);
89 if (pagealign
&& (long)((char *)mapping
->addr
+ relative
) % pagesize
) {
90 printf(_("offset address (%p) is not page aligned\n"),
91 (char *)mapping
->addr
+ relative
);
95 return (char *)mapping
->addr
+ relative
;
103 for (i
= 0; i
< mapcount
; i
++)
104 print_mapping(&maptable
[i
], i
, &maptable
[i
] == mapping
);
117 if (i
< 0 || i
>= mapcount
) {
118 printf("value %d is out of range (0-%d)\n", i
, mapcount
);
121 mapping
= &maptable
[i
];
132 " maps a range within the current file into memory\n"
135 " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n"
137 " Memory maps a range of a file for subsequent use by other xfs_io commands.\n"
138 " With no arguments, mmap shows the current mappings. The current mapping\n"
139 " can be set by using the single argument form (mapping number or address).\n"
140 " If two arguments are specified (a range), a new mapping is created and the\n"
141 " following options are available:\n"
142 " -r -- map with PROT_READ protection\n"
143 " -w -- map with PROT_WRITE protection\n"
144 " -x -- map with PROT_EXEC protection\n"
146 " -S -- map with MAP_SYNC and MAP_SHARED_VALIDATE flags\n"
148 " -s <size> -- first do mmap(size)/munmap(size), try to reserve some free space\n"
149 " If no protection mode is specified, all are used by default.\n"
159 ssize_t length
= 0, length2
= 0;
160 void *address
= NULL
;
162 size_t blocksize
, sectsize
;
163 int c
, prot
= 0, flags
= MAP_SHARED
;
168 fprintf(stderr
, file
?
169 _("no mapped regions, try 'help mmap'\n") :
170 _("no files are open, try 'help open'\n"));
173 } else if (argc
== 2) {
175 return mapset_f(argc
, argv
);
176 fprintf(stderr
, file
?
177 _("no mapped regions, try 'help mmap'\n") :
178 _("no files are open, try 'help open'\n"));
182 fprintf(stderr
, _("no files are open, try 'help open'\n"));
187 init_cvtnum(&blocksize
, §size
);
189 while ((c
= getopt(argc
, argv
, "rwxSs:")) != EOF
) {
202 flags
= MAP_SYNC
| MAP_SHARED_VALIDATE
;
205 printf("MAP_SYNC not supported\n");
207 return command_usage(&mmap_cmd
);
210 length2
= cvtnum(blocksize
, sectsize
, optarg
);
214 return command_usage(&mmap_cmd
);
218 prot
= PROT_READ
| PROT_WRITE
| PROT_EXEC
;
220 if (optind
!= argc
- 2) {
222 return command_usage(&mmap_cmd
);
225 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
227 printf(_("non-numeric offset argument -- %s\n"), argv
[optind
]);
232 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
234 printf(_("non-numeric length argument -- %s\n"), argv
[optind
]);
239 filename
= strdup(file
->name
);
247 * mmap and munmap memory area of length2 region is helpful to
248 * make a region of extendible free memory. It's generally used
249 * for later mremap operation(no MREMAP_MAYMOVE flag). But there
250 * isn't guarantee that the memory after length (up to length2)
253 if (length2
> length
) {
254 address
= mmap(NULL
, length2
, prot
,
255 MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
256 munmap(address
, length2
);
258 address
= mmap(address
, length
, prot
, flags
, file
->fd
, offset
);
259 if (address
== MAP_FAILED
) {
266 /* Extend the control array of mmap'd regions */
267 maptable
= (mmap_region_t
*)realloc(maptable
, /* growing */
268 ++mapcount
* sizeof(mmap_region_t
));
272 munmap(address
, length
);
278 /* Finally, make this the new active mapping */
279 mapping
= &maptable
[mapcount
- 1];
280 mapping
->addr
= address
;
281 mapping
->length
= length
;
282 mapping
->offset
= offset
;
283 mapping
->name
= filename
;
284 mapping
->prot
= prot
;
285 mapping
->flags
= flags
;
294 " flushes a range of bytes in the current memory mapping\n"
296 " Writes all modified copies of pages over the specified range (or entire\n"
297 " mapping if no range specified) to their backing storage locations. Also,\n"
298 " optionally invalidates so that subsequent references to the pages will be\n"
299 " obtained from their backing storage locations (instead of cached copies).\n"
300 " -a -- perform asynchronous writes (MS_ASYNC)\n"
301 " -i -- invalidate mapped pages (MS_INVALIDATE)\n"
302 " -s -- perform synchronous writes (MS_SYNC)\n"
315 size_t blocksize
, sectsize
;
317 while ((c
= getopt(argc
, argv
, "ais")) != EOF
) {
323 flags
|= MS_INVALIDATE
;
330 return command_usage(&msync_cmd
);
334 if (optind
== argc
) {
335 offset
= mapping
->offset
;
336 length
= mapping
->length
;
337 } else if (optind
== argc
- 2) {
338 init_cvtnum(&blocksize
, §size
);
339 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
341 printf(_("non-numeric offset argument -- %s\n"),
347 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
349 printf(_("non-numeric length argument -- %s\n"),
356 return command_usage(&msync_cmd
);
359 start
= check_mapping_range(mapping
, offset
, length
, 1);
365 if (msync(start
, length
, flags
) < 0) {
379 " reads a range of bytes in the current memory mapping\n"
382 " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n"
384 " Accesses a range of the current memory mapping, optionally dumping it to\n"
385 " the standard output stream (with -v option) for subsequent inspection.\n"
386 " -f -- verbose mode, dump bytes with offsets relative to start of file.\n"
387 " -r -- reverse order; start accessing from the end of range, moving backward\n"
388 " -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n"
389 " The accesses are performed sequentially from the start offset by default.\n"
391 " References to whole pages following the end of the backing file results\n"
392 " in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n"
393 " on various filesystem conditions, including quota exceeded errors, and\n"
394 " for physical device errors (such as unreadable disk blocks). No attempt\n"
395 " has been made to catch signals at this stage...\n"
404 off64_t offset
, tmp
, dumpoffset
, printoffset
;
406 size_t dumplen
, cnt
= 0;
409 int dump
= 0, rflag
= 0, c
;
410 size_t blocksize
, sectsize
;
412 while ((c
= getopt(argc
, argv
, "frv")) != EOF
) {
415 dump
= 2; /* file offset dump */
418 rflag
= 1; /* read in reverse */
421 dump
= 1; /* mapping offset dump */
425 return command_usage(&mread_cmd
);
429 if (optind
== argc
) {
430 offset
= mapping
->offset
;
431 length
= mapping
->length
;
432 } else if (optind
== argc
- 2) {
433 init_cvtnum(&blocksize
, §size
);
434 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
436 printf(_("non-numeric offset argument -- %s\n"),
442 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
444 printf(_("non-numeric length argument -- %s\n"),
450 return command_usage(&mread_cmd
);
453 start
= check_mapping_range(mapping
, offset
, length
, 0);
458 dumpoffset
= offset
- mapping
->offset
;
460 printoffset
= offset
;
462 printoffset
= dumpoffset
;
464 if (alloc_buffer(pagesize
, 0, 0) < 0) {
468 bp
= (char *)io_buffer
;
470 dumplen
= length
% pagesize
;
475 for (tmp
= length
- 1, c
= 0; tmp
>= 0; tmp
--, c
= 1) {
476 *bp
= *(((char *)mapping
->addr
) + dumpoffset
+ tmp
);
478 if (c
&& cnt
== dumplen
) {
480 dump_buffer(printoffset
, dumplen
);
481 printoffset
+= dumplen
;
483 bp
= (char *)io_buffer
;
491 for (tmp
= 0, c
= 0; tmp
< length
; tmp
++, c
= 1) {
492 *bp
= *(((char *)mapping
->addr
) + dumpoffset
+ tmp
);
494 if (c
&& cnt
== dumplen
) {
496 dump_buffer(printoffset
+ tmp
-
497 (dumplen
- 1), dumplen
);
498 bp
= (char *)io_buffer
;
517 if (munmap(mapping
->addr
, mapping
->length
) < 0) {
524 /* Shuffle the mapping table entries down over the removed entry */
525 offset
= mapping
- &maptable
[0];
526 length
= mapcount
* sizeof(mmap_region_t
);
527 length
-= (offset
+ 1) * sizeof(mmap_region_t
);
529 memmove(mapping
, mapping
+ 1, length
);
531 /* Resize the memory allocated for the table, possibly freeing */
533 maptable
= (mmap_region_t
*)realloc(maptable
, /* shrinking */
534 mapcount
* sizeof(mmap_region_t
));
535 if (offset
== mapcount
)
537 mapping
= maptable
+ offset
;
540 mapping
= maptable
= NULL
;
551 " dirties a range of bytes in the current memory mapping\n"
554 " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n"
556 " Stores a byte into memory for a range within a mapping.\n"
557 " The default stored value is 'X', repeated to fill the range specified.\n"
558 " -S -- use an alternate seed character\n"
559 " -r -- reverse order; start storing from the end of range, moving backward\n"
560 " The stores are performed sequentially from the start offset by default.\n"
576 size_t blocksize
, sectsize
;
578 while ((c
= getopt(argc
, argv
, "rS:")) != EOF
) {
584 seed
= (int)strtol(optarg
, &sp
, 0);
585 if (!sp
|| sp
== optarg
) {
586 printf(_("non-numeric seed -- %s\n"), optarg
);
592 return command_usage(&mwrite_cmd
);
596 if (optind
== argc
) {
597 offset
= mapping
->offset
;
598 length
= mapping
->length
;
599 } else if (optind
== argc
- 2) {
600 init_cvtnum(&blocksize
, §size
);
601 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
603 printf(_("non-numeric offset argument -- %s\n"),
609 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
611 printf(_("non-numeric length argument -- %s\n"),
618 return command_usage(&mwrite_cmd
);
621 start
= check_mapping_range(mapping
, offset
, length
, 0);
627 offset
-= mapping
->offset
;
629 for (tmp
= offset
+ length
-1; tmp
>= offset
; tmp
--)
630 ((char *)mapping
->addr
)[tmp
] = seed
;
632 for (tmp
= offset
; tmp
< offset
+ length
; tmp
++)
633 ((char *)mapping
->addr
)[tmp
] = seed
;
645 " resizes the current memory mapping\n"
648 " 'mremap 8192' - resizes the current mapping to 8192 bytes.\n"
650 " Resizes the mapping, growing or shrinking from the current size.\n"
651 " The default stored value is 'X', repeated to fill the range specified.\n"
652 " -f <new_address> -- use MREMAP_FIXED flag to mremap on new_address\n"
653 " -m -- use the MREMAP_MAYMOVE flag\n"
663 void *new_addr
= NULL
;
666 size_t blocksize
, sectsize
;
668 init_cvtnum(&blocksize
, §size
);
670 while ((c
= getopt(argc
, argv
, "f:m")) != EOF
) {
673 flags
= MREMAP_FIXED
|MREMAP_MAYMOVE
;
674 new_addr
= (void *)(unsigned long)cvtnum(blocksize
,
678 flags
= MREMAP_MAYMOVE
;
682 return command_usage(&mremap_cmd
);
686 if (optind
!= argc
- 1) {
688 return command_usage(&mremap_cmd
);
691 new_length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
692 if (new_length
< 0) {
693 printf(_("non-numeric offset argument -- %s\n"),
700 new_addr
= mremap(mapping
->addr
, mapping
->length
,
703 new_addr
= mremap(mapping
->addr
, mapping
->length
,
704 new_length
, flags
, new_addr
);
705 if (new_addr
== MAP_FAILED
) {
711 mapping
->addr
= new_addr
;
712 mapping
->length
= new_length
;
715 #endif /* HAVE_MREMAP */
720 mmap_cmd
.name
= "mmap";
721 mmap_cmd
.altname
= "mm";
722 mmap_cmd
.cfunc
= mmap_f
;
724 mmap_cmd
.argmax
= -1;
725 mmap_cmd
.flags
= CMD_NOMAP_OK
| CMD_NOFILE_OK
|
726 CMD_FOREIGN_OK
| CMD_FLAG_ONESHOT
;
727 mmap_cmd
.args
= _("[N] | [-rwxS] [-s size] [off len]");
729 _("mmap a range in the current file, show mappings");
730 mmap_cmd
.help
= mmap_help
;
732 mread_cmd
.name
= "mread";
733 mread_cmd
.altname
= "mr";
734 mread_cmd
.cfunc
= mread_f
;
735 mread_cmd
.argmin
= 0;
736 mread_cmd
.argmax
= -1;
737 mread_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
738 mread_cmd
.args
= _("[-r] [off len]");
740 _("reads data from a region in the current memory mapping");
741 mread_cmd
.help
= mread_help
;
743 msync_cmd
.name
= "msync";
744 msync_cmd
.altname
= "ms";
745 msync_cmd
.cfunc
= msync_f
;
746 msync_cmd
.argmin
= 0;
747 msync_cmd
.argmax
= -1;
748 msync_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
749 msync_cmd
.args
= _("[-ais] [off len]");
750 msync_cmd
.oneline
= _("flush a region in the current memory mapping");
751 msync_cmd
.help
= msync_help
;
753 munmap_cmd
.name
= "munmap";
754 munmap_cmd
.altname
= "mu";
755 munmap_cmd
.cfunc
= munmap_f
;
756 munmap_cmd
.argmin
= 0;
757 munmap_cmd
.argmax
= 0;
758 munmap_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
759 munmap_cmd
.oneline
= _("unmaps the current memory mapping");
761 mwrite_cmd
.name
= "mwrite";
762 mwrite_cmd
.altname
= "mw";
763 mwrite_cmd
.cfunc
= mwrite_f
;
764 mwrite_cmd
.argmin
= 0;
765 mwrite_cmd
.argmax
= -1;
766 mwrite_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
767 mwrite_cmd
.args
= _("[-r] [-S seed] [off len]");
769 _("writes data into a region in the current memory mapping");
770 mwrite_cmd
.help
= mwrite_help
;
773 mremap_cmd
.name
= "mremap";
774 mremap_cmd
.altname
= "mrm";
775 mremap_cmd
.cfunc
= mremap_f
;
776 mremap_cmd
.argmin
= 1;
777 mremap_cmd
.argmax
= 3;
778 mremap_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
779 mremap_cmd
.args
= _("[-m|-f <new_address>] newsize");
781 _("alters the size of the current memory mapping");
782 mremap_cmd
.help
= mremap_help
;
783 #endif /* HAVE_MREMAP */
785 add_command(&mmap_cmd
);
786 add_command(&mread_cmd
);
787 add_command(&msync_cmd
);
788 add_command(&munmap_cmd
);
789 add_command(&mwrite_cmd
);
791 add_command(&mremap_cmd
);
792 #endif /* HAVE_MREMAP */