~ubuntu-branches/ubuntu/edgy/xfsprogs/edgy

« back to all changes in this revision

Viewing changes to io/mmap.c

  • Committer: Bazaar Package Importer
  • Author(s): Nathan Scott
  • Date: 2004-07-28 21:11:38 UTC
  • Revision ID: james.westby@ubuntu.com-20040728211138-0v4pdnunnp7na5lm
Tags: 2.6.20-1
* New upstream release.
* Fix xfs_io segfault on non-XFS files.  (closes: #260470)
* Fix packaging botch, deleted files included.  (closes: #260491)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}