]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/mmap.c
2 * Copyright (c) 2004-2005 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 static cmdinfo_t mmap_cmd
;
28 static cmdinfo_t mread_cmd
;
29 static cmdinfo_t msync_cmd
;
30 static cmdinfo_t munmap_cmd
;
31 static cmdinfo_t mwrite_cmd
;
32 static cmdinfo_t mremap_cmd
;
34 mmap_region_t
*maptable
;
36 mmap_region_t
*mapping
;
44 unsigned char buffer
[8] = { 0 };
57 for (i
= 0, p
= pflags
; p
->prot
!= PROT_NONE
; i
++, p
++)
58 buffer
[i
] = (map
->prot
& p
->prot
) ? p
->mode
: '-';
59 printf("%c%03d%c 0x%lx - 0x%lx %s %14s (%lld : %ld)\n",
60 braces
? '[' : ' ', index
, braces
? ']' : ' ',
61 (unsigned long)map
->addr
,
62 (unsigned long)((char *)map
->addr
+ map
->length
),
63 buffer
, map
->name
? map
->name
: "???",
64 (long long)map
->offset
, (long)map
->length
);
76 if (offset
< mapping
->offset
) {
77 printf(_("offset (%lld) is before start of mapping (%lld)\n"),
78 (long long)offset
, (long long)mapping
->offset
);
81 relative
= offset
- mapping
->offset
;
82 if (relative
> mapping
->length
) {
83 printf(_("offset (%lld) is beyond end of mapping (%lld)\n"),
84 (long long)relative
, (long long)mapping
->offset
);
87 if ((relative
+ length
) > (mapping
->offset
+ mapping
->length
)) {
88 printf(_("range (%lld:%lld) is beyond mapping (%lld:%ld)\n"),
89 (long long)offset
, (long long)relative
,
90 (long long)mapping
->offset
, (long)mapping
->length
);
93 if (pagealign
&& (long)((char *)mapping
->addr
+ relative
) % pagesize
) {
94 printf(_("offset address (%p) is not page aligned\n"),
95 (char *)mapping
->addr
+ relative
);
99 return (char *)mapping
->addr
+ relative
;
107 for (i
= 0; i
< mapcount
; i
++)
108 print_mapping(&maptable
[i
], i
, &maptable
[i
] == mapping
);
121 if (i
< 0 || i
>= mapcount
) {
122 printf("value %d is out of range (0-%d)\n", i
, mapcount
);
124 mapping
= &maptable
[i
];
135 " maps a range within the current file into memory\n"
138 " 'mmap -rw 0 1m' - maps one megabyte from the start of the current file\n"
140 " Memory maps a range of a file for subsequent use by other xfs_io commands.\n"
141 " With no arguments, mmap shows the current mappings. The current mapping\n"
142 " can be set by using the single argument form (mapping number or address).\n"
143 " If two arguments are specified (a range), a new mapping is created and the\n"
144 " following options are available:\n"
145 " -r -- map with PROT_READ protection\n"
146 " -w -- map with PROT_WRITE protection\n"
147 " -x -- map with PROT_EXEC protection\n"
148 " If no protection mode is specified, all are used by default.\n"
161 size_t blocksize
, sectsize
;
167 fprintf(stderr
, file
?
168 _("no mapped regions, try 'help mmap'\n") :
169 _("no files are open, try 'help open'\n"));
171 } else if (argc
== 2) {
173 return mapset_f(argc
, argv
);
174 fprintf(stderr
, file
?
175 _("no mapped regions, try 'help mmap'\n") :
176 _("no files are open, try 'help open'\n"));
179 fprintf(stderr
, _("no files are open, try 'help open'\n"));
183 while ((c
= getopt(argc
, argv
, "rwx")) != EOF
) {
195 return command_usage(&mmap_cmd
);
199 prot
= PROT_READ
| PROT_WRITE
| PROT_EXEC
;
201 if (optind
!= argc
- 2)
202 return command_usage(&mmap_cmd
);
204 init_cvtnum(&blocksize
, §size
);
205 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
207 printf(_("non-numeric offset argument -- %s\n"), argv
[optind
]);
211 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
213 printf(_("non-numeric length argument -- %s\n"), argv
[optind
]);
217 filename
= strdup(file
->name
);
223 address
= mmap(NULL
, length
, prot
, MAP_SHARED
, file
->fd
, offset
);
224 if (address
== MAP_FAILED
) {
230 /* Extend the control array of mmap'd regions */
231 maptable
= (mmap_region_t
*)realloc(maptable
, /* growing */
232 ++mapcount
* sizeof(mmap_region_t
));
236 munmap(address
, length
);
241 /* Finally, make this the new active mapping */
242 mapping
= &maptable
[mapcount
- 1];
243 mapping
->addr
= address
;
244 mapping
->length
= length
;
245 mapping
->offset
= offset
;
246 mapping
->name
= filename
;
247 mapping
->prot
= prot
;
256 " flushes a range of bytes in the current memory mapping\n"
258 " Writes all modified copies of pages over the specified range (or entire\n"
259 " mapping if no range specified) to their backing storage locations. Also,\n"
260 " optionally invalidates so that subsequent references to the pages will be\n"
261 " obtained from their backing storage locations (instead of cached copies).\n"
262 " -a -- perform asynchronous writes (MS_ASYNC)\n"
263 " -i -- invalidate mapped pages (MS_INVALIDATE)\n"
264 " -s -- perform synchronous writes (MS_SYNC)\n"
277 size_t blocksize
, sectsize
;
279 while ((c
= getopt(argc
, argv
, "ais")) != EOF
) {
285 flags
|= MS_INVALIDATE
;
291 return command_usage(&msync_cmd
);
295 if (optind
== argc
) {
296 offset
= mapping
->offset
;
297 length
= mapping
->length
;
298 } else if (optind
== argc
- 2) {
299 init_cvtnum(&blocksize
, §size
);
300 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
302 printf(_("non-numeric offset argument -- %s\n"),
307 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
309 printf(_("non-numeric length argument -- %s\n"),
314 return command_usage(&msync_cmd
);
317 start
= check_mapping_range(mapping
, offset
, length
, 1);
321 if (msync(start
, length
, flags
) < 0)
332 " reads a range of bytes in the current memory mapping\n"
335 " 'mread -v 512 20' - dumps 20 bytes read from 512 bytes into the mapping\n"
337 " Accesses a range of the current memory mapping, optionally dumping it to\n"
338 " the standard output stream (with -v option) for subsequent inspection.\n"
339 " -f -- verbose mode, dump bytes with offsets relative to start of file.\n"
340 " -r -- reverse order; start accessing from the end of range, moving backward\n"
341 " -v -- verbose mode, dump bytes with offsets relative to start of mapping.\n"
342 " The accesses are performed sequentially from the start offset by default.\n"
344 " References to whole pages following the end of the backing file results\n"
345 " in delivery of the SIGBUS signal. SIGBUS signals may also be delivered\n"
346 " on various filesystem conditions, including quota exceeded errors, and\n"
347 " for physical device errors (such as unreadable disk blocks). No attempt\n"
348 " has been made to catch signals at this stage...\n"
357 off64_t offset
, tmp
, dumpoffset
, printoffset
;
359 size_t dumplen
, cnt
= 0;
362 int dump
= 0, rflag
= 0, c
;
363 size_t blocksize
, sectsize
;
365 while ((c
= getopt(argc
, argv
, "frv")) != EOF
) {
368 dump
= 2; /* file offset dump */
371 rflag
= 1; /* read in reverse */
374 dump
= 1; /* mapping offset dump */
377 return command_usage(&mread_cmd
);
381 if (optind
== argc
) {
382 offset
= mapping
->offset
;
383 length
= mapping
->length
;
384 } else if (optind
== argc
- 2) {
385 init_cvtnum(&blocksize
, §size
);
386 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
388 printf(_("non-numeric offset argument -- %s\n"),
393 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
395 printf(_("non-numeric length argument -- %s\n"),
400 return command_usage(&mread_cmd
);
403 start
= check_mapping_range(mapping
, offset
, length
, 0);
406 dumpoffset
= offset
- mapping
->offset
;
408 printoffset
= offset
;
410 printoffset
= dumpoffset
;
412 if (alloc_buffer(pagesize
, 0, 0) < 0)
416 dumplen
= length
% pagesize
;
421 for (tmp
= length
- 1, c
= 0; tmp
>= 0; tmp
--, c
= 1) {
422 *bp
= *(((char *)mapping
->addr
) + dumpoffset
+ tmp
);
424 if (c
&& cnt
== dumplen
) {
426 dump_buffer(printoffset
, dumplen
);
427 printoffset
+= dumplen
;
437 for (tmp
= 0, c
= 0; tmp
< length
; tmp
++, c
= 1) {
438 *bp
= *(((char *)mapping
->addr
) + dumpoffset
+ tmp
);
440 if (c
&& cnt
== dumplen
) {
442 dump_buffer(printoffset
+ tmp
-
443 (dumplen
- 1), dumplen
);
463 if (munmap(mapping
->addr
, mapping
->length
) < 0) {
469 /* Shuffle the mapping table entries down over the removed entry */
470 offset
= mapping
- &maptable
[0];
471 length
= mapcount
* sizeof(mmap_region_t
);
472 length
-= (offset
+ 1) * sizeof(mmap_region_t
);
474 memmove(mapping
, mapping
+ 1, length
);
476 /* Resize the memory allocated for the table, possibly freeing */
478 maptable
= (mmap_region_t
*)realloc(maptable
, /* shrinking */
479 mapcount
* sizeof(mmap_region_t
));
480 if (offset
== mapcount
)
482 mapping
= maptable
+ offset
;
485 mapping
= maptable
= NULL
;
496 " dirties a range of bytes in the current memory mapping\n"
499 " 'mwrite 512 20 - writes 20 bytes at 512 bytes into the current mapping.\n"
501 " Stores a byte into memory for a range within a mapping.\n"
502 " The default stored value is 'X', repeated to fill the range specified.\n"
503 " -S -- use an alternate seed character\n"
504 " -r -- reverse order; start storing from the end of range, moving backward\n"
505 " The stores are performed sequentially from the start offset by default.\n"
521 size_t blocksize
, sectsize
;
523 while ((c
= getopt(argc
, argv
, "rS:")) != EOF
) {
529 seed
= (int)strtol(optarg
, &sp
, 0);
530 if (!sp
|| sp
== optarg
) {
531 printf(_("non-numeric seed -- %s\n"), optarg
);
536 return command_usage(&mwrite_cmd
);
540 if (optind
== argc
) {
541 offset
= mapping
->offset
;
542 length
= mapping
->length
;
543 } else if (optind
== argc
- 2) {
544 init_cvtnum(&blocksize
, §size
);
545 offset
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
547 printf(_("non-numeric offset argument -- %s\n"),
552 length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
554 printf(_("non-numeric length argument -- %s\n"),
559 return command_usage(&mwrite_cmd
);
562 start
= check_mapping_range(mapping
, offset
, length
, 0);
566 offset
-= mapping
->offset
;
568 for (tmp
= offset
+ length
-1; tmp
>= offset
; tmp
--)
569 ((char *)mapping
->addr
)[tmp
] = seed
;
571 for (tmp
= offset
; tmp
< offset
+ length
; tmp
++)
572 ((char *)mapping
->addr
)[tmp
] = seed
;
583 " resizes the current memory mapping\n"
586 " 'mremap 8192' - resizes the current mapping to 8192 bytes.\n"
588 " Resizes the mappping, growing or shrinking from the current size.\n"
589 " The default stored value is 'X', repeated to fill the range specified.\n"
590 " -f -- use the MREMAP_FIXED flag\n"
591 " -m -- use the MREMAP_MAYMOVE flag\n"
604 size_t blocksize
, sectsize
;
606 while ((c
= getopt(argc
, argv
, "fm")) != EOF
) {
609 flags
= MREMAP_FIXED
|MREMAP_MAYMOVE
;
612 flags
= MREMAP_MAYMOVE
;
615 return command_usage(&mremap_cmd
);
619 init_cvtnum(&blocksize
, §size
);
620 new_length
= cvtnum(blocksize
, sectsize
, argv
[optind
]);
621 if (new_length
< 0) {
622 printf(_("non-numeric offset argument -- %s\n"),
627 new_addr
= mremap(mapping
->addr
, mapping
->length
, new_length
, flags
);
628 if (new_addr
== MAP_FAILED
)
631 mapping
->addr
= new_addr
;
632 mapping
->length
= new_length
;
641 mmap_cmd
.name
= "mmap";
642 mmap_cmd
.altname
= "mm";
643 mmap_cmd
.cfunc
= mmap_f
;
645 mmap_cmd
.argmax
= -1;
646 mmap_cmd
.flags
= CMD_NOMAP_OK
| CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
647 mmap_cmd
.args
= _("[N] | [-rwx] [off len]");
649 _("mmap a range in the current file, show mappings");
650 mmap_cmd
.help
= mmap_help
;
652 mread_cmd
.name
= "mread";
653 mread_cmd
.altname
= "mr";
654 mread_cmd
.cfunc
= mread_f
;
655 mread_cmd
.argmin
= 0;
656 mread_cmd
.argmax
= -1;
657 mread_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
658 mread_cmd
.args
= _("[-r] [off len]");
660 _("reads data from a region in the current memory mapping");
661 mread_cmd
.help
= mread_help
;
663 msync_cmd
.name
= "msync";
664 msync_cmd
.altname
= "ms";
665 msync_cmd
.cfunc
= msync_f
;
666 msync_cmd
.argmin
= 0;
667 msync_cmd
.argmax
= -1;
668 msync_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
669 msync_cmd
.args
= _("[-ais] [off len]");
670 msync_cmd
.oneline
= _("flush a region in the current memory mapping");
671 msync_cmd
.help
= msync_help
;
673 munmap_cmd
.name
= "munmap";
674 munmap_cmd
.altname
= "mu";
675 munmap_cmd
.cfunc
= munmap_f
;
676 munmap_cmd
.argmin
= 0;
677 munmap_cmd
.argmax
= 0;
678 munmap_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
679 munmap_cmd
.oneline
= _("unmaps the current memory mapping");
681 mwrite_cmd
.name
= "mwrite";
682 mwrite_cmd
.altname
= "mw";
683 mwrite_cmd
.cfunc
= mwrite_f
;
684 mwrite_cmd
.argmin
= 0;
685 mwrite_cmd
.argmax
= -1;
686 mwrite_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
687 mwrite_cmd
.args
= _("[-r] [-S seed] [off len]");
689 _("writes data into a region in the current memory mapping");
690 mwrite_cmd
.help
= mwrite_help
;
692 mremap_cmd
.name
= "mremap";
693 mremap_cmd
.altname
= "mrm";
694 mremap_cmd
.cfunc
= mremap_f
;
695 mremap_cmd
.argmin
= 1;
696 mremap_cmd
.argmax
= 2;
697 mremap_cmd
.flags
= CMD_NOFILE_OK
| CMD_FOREIGN_OK
;
698 mremap_cmd
.args
= _("[-m|-f] newsize");
700 _("alters the size of the current memory mapping");
701 mremap_cmd
.help
= mremap_help
;
703 add_command(&mmap_cmd
);
704 add_command(&mread_cmd
);
705 add_command(&msync_cmd
);
706 add_command(&munmap_cmd
);
707 add_command(&mwrite_cmd
);
708 add_command(&mremap_cmd
);