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

« back to all changes in this revision

Viewing changes to io/bmap.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) 2000-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 "command.h"
 
35
#include "init.h"
 
36
#include "io.h"
 
37
 
 
38
static cmdinfo_t bmap_cmd;
 
39
 
 
40
static void
 
41
bmap_help(void)
 
42
{
 
43
        printf(_(
 
44
"\n"
 
45
" prints the block mapping for an XFS file's data or attribute forks"
 
46
"\n"
 
47
" Example:\n"
 
48
" 'bmap -vp' - tabular format verbose map, including unwritten extents\n"
 
49
"\n"
 
50
" bmap prints the map of disk blocks used by the current file.\n"
 
51
" The map lists each extent used by the file, as well as regions in the\n"
 
52
" file that do not have any corresponding blocks (holes).\n"
 
53
" By default, each line of the listing takes the following form:\n"
 
54
"     extent: [startoffset..endoffset]: startblock..endblock\n"
 
55
" Holes are marked by replacing the startblock..endblock with 'hole'.\n"
 
56
" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
 
57
" -a -- prints the attribute fork map instead of the data fork.\n"
 
58
" -d -- suppresses a DMAPI read event, offline portions shown as holes.\n"
 
59
" -l -- also displays the length of each extent in 512-byte blocks.\n"
 
60
" Note: the bmap for non-regular files can be obtained provided the file\n"
 
61
" was opened appropriately (in particular, must be opened read-only).\n"
 
62
"\n"));
 
63
}
 
64
 
 
65
static int
 
66
numlen(
 
67
        off64_t val)
 
68
{
 
69
        off64_t tmp;
 
70
        int     len;
 
71
 
 
72
        for (len = 0, tmp = val; tmp > 0; tmp = tmp/10)
 
73
                len++;
 
74
        return (len == 0 ? 1 : len);
 
75
}
 
76
 
 
77
int
 
78
bmap_f(
 
79
        int                     argc,
 
80
        char                    **argv)
 
81
{
 
82
        struct fsxattr          fsx;
 
83
        struct getbmapx         *map;
 
84
        struct xfs_fsop_geom    fsgeo;
 
85
        int                     map_size;
 
86
        int                     loop = 0;
 
87
        int                     flg = 0;
 
88
        int                     aflag = 0;
 
89
        int                     lflag = 0;
 
90
        int                     nflag = 0;
 
91
        int                     vflag = 0;
 
92
        int                     bmv_iflags = 0; /* flags for XFS_IOC_GETBMAPX */
 
93
        int                     i = 0;
 
94
        int                     c;
 
95
 
 
96
        while ((c = getopt(argc, argv, "adln:pv")) != EOF) {
 
97
                switch (c) {
 
98
                case 'a':       /* Attribute fork. */
 
99
                        bmv_iflags |= BMV_IF_ATTRFORK;
 
100
                        aflag = 1;
 
101
                        break;
 
102
                case 'l':       /* list number of blocks with each extent */
 
103
                        lflag = 1;
 
104
                        break;
 
105
                case 'n':       /* number of extents specified */
 
106
                        nflag = atoi(optarg);
 
107
                        break;
 
108
                case 'd':
 
109
                /* do not recall possibly offline DMAPI files */
 
110
                        bmv_iflags |= BMV_IF_NO_DMAPI_READ;
 
111
                        break;
 
112
                case 'p':
 
113
                /* report unwritten preallocated blocks */
 
114
                        bmv_iflags |= BMV_IF_PREALLOC;
 
115
                        break;
 
116
                case 'v':       /* Verbose output */
 
117
                        vflag++;
 
118
                        break;
 
119
                default:
 
120
                        return command_usage(&bmap_cmd);
 
121
                }
 
122
        }
 
123
        if (aflag)
 
124
                bmv_iflags &= ~(BMV_IF_PREALLOC|BMV_IF_NO_DMAPI_READ);
 
125
 
 
126
        if (vflag) {
 
127
                c = xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo);
 
128
                if (c < 0) {
 
129
                        fprintf(stderr,
 
130
                                _("%s: can't get geometry [\"%s\"]: %s\n"),
 
131
                                progname, file->name, strerror(errno));
 
132
                        exitcode = 1;
 
133
                        return 0;
 
134
                }
 
135
                c = xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx);
 
136
                if (c < 0) {
 
137
                        fprintf(stderr,
 
138
                                _("%s: cannot read attrs on \"%s\": %s\n"),
 
139
                                progname, file->name, strerror(errno));
 
140
                        exitcode = 1;
 
141
                        return 0;
 
142
                }
 
143
 
 
144
                if (fsx.fsx_xflags == XFS_XFLAG_REALTIME) {
 
145
                        /*
 
146
                         * ag info not applicable to rt, continue
 
147
                         * without ag output.
 
148
                         */
 
149
                        vflag = 0;
 
150
                }
 
151
        }
 
152
 
 
153
        map_size = nflag ? nflag+1 : 32;        /* initial guess - 256 */
 
154
        map = malloc(map_size*sizeof(*map));
 
155
        if (map == NULL) {
 
156
                fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
 
157
                        progname, (int)(map_size * sizeof(*map)));
 
158
                exitcode = 1;
 
159
                return 0;
 
160
        }
 
161
 
 
162
 
 
163
/*      Try the xfsctl(XFS_IOC_GETBMAPX) for the number of extents specified
 
164
 *      by nflag, or the initial guess number of extents (256).
 
165
 *
 
166
 *      If there are more extents than we guessed, use xfsctl
 
167
 *      (XFS_IOC_FSGETXATTR[A]) to get the extent count, realloc some more
 
168
 *      space based on this count, and try again.
 
169
 *
 
170
 *      If the initial FGETBMAPX attempt returns EINVAL, this may mean
 
171
 *      that we tried the FGETBMAPX on a zero length file.  If we get
 
172
 *      EINVAL, check the length with fstat() and return "no extents"
 
173
 *      if the length == 0.
 
174
 *
 
175
 *      Why not do the xfsctl(XFS_IOC_FSGETXATTR[A]) first?  Two reasons:
 
176
 *      (1)     The extent count may be wrong for a file with delayed
 
177
 *              allocation blocks.  The XFS_IOC_GETBMAPX forces the real
 
178
 *              allocation and fixes up the extent count.
 
179
 *      (2)     For XFS_IOC_GETBMAP[X] on a DMAPI file that has been moved
 
180
 *              offline by a DMAPI application (e.g., DMF) the
 
181
 *              XFS_IOC_FSGETXATTR only reflects the extents actually online.
 
182
 *              Doing XFS_IOC_GETBMAPX call first forces that data blocks online
 
183
 *              and then everything proceeds normally (see PV #545725).
 
184
 *
 
185
 *              If you don't want this behavior on a DMAPI offline file,
 
186
 *              try the "-d" option which sets the BMV_IF_NO_DMAPI_READ
 
187
 *              iflag for XFS_IOC_GETBMAPX.
 
188
 */
 
189
 
 
190
        do {    /* loop a miximum of two times */
 
191
 
 
192
                bzero(map, sizeof(*map));       /* zero header */
 
193
 
 
194
                map->bmv_length = -1;
 
195
                map->bmv_count = map_size;
 
196
                map->bmv_iflags = bmv_iflags;
 
197
 
 
198
                i = xfsctl(file->name, file->fd, XFS_IOC_GETBMAPX, map);
 
199
                if (i < 0) {
 
200
                        if (   errno == EINVAL
 
201
                            && !aflag && filesize() == 0) {
 
202
                                break;
 
203
                        } else  {
 
204
                                fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETBMAPX)"
 
205
                                        " iflags=0x%x [\"%s\"]: %s\n"),
 
206
                                        progname, map->bmv_iflags, file->name,
 
207
                                        strerror(errno));
 
208
                                free(map);
 
209
                                exitcode = 1;
 
210
                                return 0;
 
211
                        }
 
212
                }
 
213
                if (nflag)
 
214
                        break;
 
215
                if (map->bmv_entries < map->bmv_count-1)
 
216
                        break;
 
217
                /* Get number of extents from xfsctl XFS_IOC_FSGETXATTR[A]
 
218
                 * syscall.
 
219
                 */
 
220
                i = xfsctl(file->name, file->fd, aflag ?
 
221
                                XFS_IOC_FSGETXATTRA : XFS_IOC_FSGETXATTR, &fsx);
 
222
                if (i < 0) {
 
223
                        fprintf(stderr, "%s: xfsctl(XFS_IOC_FSGETXATTR%s) "
 
224
                                "[\"%s\"]: %s\n", progname, aflag ? "A" : "",
 
225
                                file->name, strerror(errno));
 
226
                        free(map);
 
227
                        exitcode = 1;
 
228
                        return 0;
 
229
                }
 
230
                if (fsx.fsx_nextents >= map_size-1) {
 
231
                        map_size = 2*(fsx.fsx_nextents+1);
 
232
                        map = realloc(map, map_size*sizeof(*map));
 
233
                        if (map == NULL) {
 
234
                                fprintf(stderr,
 
235
                                        _("%s: cannot realloc %d bytes\n"),
 
236
                                        progname, (int)(map_size*sizeof(*map)));
 
237
                                exitcode = 1;
 
238
                                return 0;
 
239
                        }
 
240
                }
 
241
        } while (++loop < 2);
 
242
        if (!nflag) {
 
243
                if (map->bmv_entries <= 0) {
 
244
                        printf(_("%s: no extents\n"), file->name);
 
245
                        free(map);
 
246
                        return 0;
 
247
                }
 
248
        }
 
249
        printf("%s:\n", file->name);
 
250
        if (!vflag) {
 
251
                for (i = 0; i < map->bmv_entries; i++) {
 
252
                        printf("\t%d: [%lld..%lld]: ", i,
 
253
                                (long long) map[i + 1].bmv_offset,
 
254
                                (long long)(map[i + 1].bmv_offset +
 
255
                                map[i + 1].bmv_length - 1LL));
 
256
                        if (map[i + 1].bmv_block == -1)
 
257
                                printf(_("hole"));
 
258
                        else {
 
259
                                printf("%lld..%lld",
 
260
                                        (long long) map[i + 1].bmv_block,
 
261
                                        (long long)(map[i + 1].bmv_block +
 
262
                                                map[i + 1].bmv_length - 1LL));
 
263
 
 
264
                        }
 
265
                        if (lflag)
 
266
                                printf(_(" %lld blocks\n"),
 
267
                                        (long long)map[i+1].bmv_length);
 
268
                        else
 
269
                                printf("\n");
 
270
                }
 
271
        } else {
 
272
                /*
 
273
                 * Verbose mode displays:
 
274
                 *   extent: [startoffset..endoffset]: startblock..endblock \
 
275
                 *      ag# (agoffset..agendoffset) totalbbs
 
276
                 */
 
277
#define MINRANGE_WIDTH  16
 
278
#define MINAG_WIDTH     2
 
279
#define MINTOT_WIDTH    5
 
280
#define max(a,b)        (a > b ? a : b)
 
281
#define NFLG            5       /* count of flags */
 
282
#define FLG_NULL        000000  /* Null flag */
 
283
#define FLG_PRE         010000  /* Unwritten extent */
 
284
#define FLG_BSU         001000  /* Not on begin of stripe unit  */
 
285
#define FLG_ESU         000100  /* Not on end   of stripe unit  */
 
286
#define FLG_BSW         000010  /* Not on begin of stripe width */
 
287
#define FLG_ESW         000001  /* Not on end   of stripe width */
 
288
                int     agno;
 
289
                off64_t agoff, bbperag;
 
290
                int     foff_w, boff_w, aoff_w, tot_w, agno_w;
 
291
                char    rbuf[32], bbuf[32], abuf[32];
 
292
                int     sunit, swidth;
 
293
 
 
294
                foff_w = boff_w = aoff_w = MINRANGE_WIDTH;
 
295
                tot_w = MINTOT_WIDTH;
 
296
                bbperag = (off64_t)fsgeo.agblocks *
 
297
                          (off64_t)fsgeo.blocksize / BBSIZE;
 
298
                sunit = (fsgeo.sunit * fsgeo.blocksize) / BBSIZE;
 
299
                swidth = (fsgeo.swidth * fsgeo.blocksize) / BBSIZE;
 
300
                flg = sunit;
 
301
 
 
302
                /*
 
303
                 * Go through the extents and figure out the width
 
304
                 * needed for all columns.
 
305
                 */
 
306
                for (i = 0; i < map->bmv_entries; i++) {
 
307
                        snprintf(rbuf, sizeof(rbuf), "[%lld..%lld]:",
 
308
                                (long long) map[i + 1].bmv_offset,
 
309
                                (long long)(map[i + 1].bmv_offset +
 
310
                                map[i + 1].bmv_length - 1LL));
 
311
                        if (map[i + 1].bmv_oflags & BMV_OF_PREALLOC)
 
312
                                flg = 1;
 
313
                        if (map[i + 1].bmv_block == -1) {
 
314
                                foff_w = max(foff_w, strlen(rbuf));
 
315
                                tot_w = max(tot_w,
 
316
                                        numlen(map[i+1].bmv_length));
 
317
                        } else {
 
318
                                snprintf(bbuf, sizeof(bbuf), "%lld..%lld",
 
319
                                        (long long) map[i + 1].bmv_block,
 
320
                                        (long long)(map[i + 1].bmv_block +
 
321
                                                map[i + 1].bmv_length - 1LL));
 
322
                                agno = map[i + 1].bmv_block / bbperag;
 
323
                                agoff = map[i + 1].bmv_block - (agno * bbperag);
 
324
                                snprintf(abuf, sizeof(abuf), "(%lld..%lld)",
 
325
                                        (long long)agoff,  (long long)
 
326
                                        (agoff + map[i + 1].bmv_length - 1LL));
 
327
                                foff_w = max(foff_w, strlen(rbuf));
 
328
                                boff_w = max(boff_w, strlen(bbuf));
 
329
                                aoff_w = max(aoff_w, strlen(abuf));
 
330
                                tot_w = max(tot_w,
 
331
                                        numlen(map[i+1].bmv_length));
 
332
                        }
 
333
                }
 
334
                agno_w = max(MINAG_WIDTH, numlen(fsgeo.agcount));
 
335
                printf("%4s: %-*s %-*s %*s %-*s %*s%s\n",
 
336
                        _("EXT"),
 
337
                        foff_w, _("FILE-OFFSET"),
 
338
                        boff_w, _("BLOCK-RANGE"),
 
339
                        agno_w, _("AG"),
 
340
                        aoff_w, _("AG-OFFSET"),
 
341
                        tot_w, _("TOTAL"),
 
342
                        flg ? _(" FLAGS") : "");
 
343
                for (i = 0; i < map->bmv_entries; i++) {
 
344
                        flg = FLG_NULL;
 
345
                        if (map[i + 1].bmv_oflags & BMV_OF_PREALLOC) {
 
346
                                flg |= FLG_PRE;
 
347
                        }
 
348
                        /*
 
349
                         * If striping enabled, determine if extent starts/ends
 
350
                         * on a stripe unit boundary.
 
351
                         */
 
352
                        if (sunit) {
 
353
                                if (map[i + 1].bmv_block  % sunit != 0) {
 
354
                                        flg |= FLG_BSU;
 
355
                                }
 
356
                                if (((map[i + 1].bmv_block +
 
357
                                      map[i + 1].bmv_length ) % sunit ) != 0) {
 
358
                                        flg |= FLG_ESU;
 
359
                                }
 
360
                                if (map[i + 1].bmv_block % swidth != 0) {
 
361
                                        flg |= FLG_BSW;
 
362
                                }
 
363
                                if (((map[i + 1].bmv_block +
 
364
                                      map[i + 1].bmv_length ) % swidth ) != 0) {
 
365
                                        flg |= FLG_ESW;
 
366
                                }
 
367
                        }
 
368
                        snprintf(rbuf, sizeof(rbuf), "[%lld..%lld]:",
 
369
                                (long long) map[i + 1].bmv_offset,
 
370
                                (long long)(map[i + 1].bmv_offset +
 
371
                                map[i + 1].bmv_length - 1LL));
 
372
                        if (map[i + 1].bmv_block == -1) {
 
373
                                printf("%4d: %-*s %-*s %*s %-*s %*lld\n",
 
374
                                        i,
 
375
                                        foff_w, rbuf,
 
376
                                        boff_w, _("hole"),
 
377
                                        agno_w, "",
 
378
                                        aoff_w, "",
 
379
                                        tot_w, (long long)map[i+1].bmv_length);
 
380
                        } else {
 
381
                                snprintf(bbuf, sizeof(bbuf), "%lld..%lld",
 
382
                                        (long long) map[i + 1].bmv_block,
 
383
                                        (long long)(map[i + 1].bmv_block +
 
384
                                                map[i + 1].bmv_length - 1LL));
 
385
                                agno = map[i + 1].bmv_block / bbperag;
 
386
                                agoff = map[i + 1].bmv_block - (agno * bbperag);
 
387
                                snprintf(abuf, sizeof(abuf), "(%lld..%lld)",
 
388
                                        (long long)agoff,  (long long)
 
389
                                        (agoff + map[i + 1].bmv_length - 1LL));
 
390
                                printf("%4d: %-*s %-*s %*d %-*s %*lld",
 
391
                                        i,
 
392
                                        foff_w, rbuf,
 
393
                                        boff_w, bbuf,
 
394
                                        agno_w, agno,
 
395
                                        aoff_w, abuf,
 
396
                                        tot_w, (long long)map[i+1].bmv_length);
 
397
                                if (flg == FLG_NULL) {
 
398
                                        printf("\n");
 
399
                                } else {
 
400
                                        printf(" %-*.*o\n", NFLG, NFLG, flg);
 
401
                                }
 
402
                        }
 
403
                }
 
404
                if (flg && vflag > 1) {
 
405
                        printf(_(" FLAG Values:\n"));
 
406
                        printf(_("    %*.*o Unwritten preallocated extent\n"),
 
407
                                NFLG+1, NFLG+1, FLG_PRE);
 
408
                        printf(_("    %*.*o Doesn't begin on stripe unit\n"),
 
409
                                NFLG+1, NFLG+1, FLG_BSU);
 
410
                        printf(_("    %*.*o Doesn't end   on stripe unit\n"),
 
411
                                NFLG+1, NFLG+1, FLG_ESU);
 
412
                        printf(_("    %*.*o Doesn't begin on stripe width\n"),
 
413
                                NFLG+1, NFLG+1, FLG_BSW);
 
414
                        printf(_("    %*.*o Doesn't end   on stripe width\n"),
 
415
                                NFLG+1, NFLG+1, FLG_ESW);
 
416
                }
 
417
        }
 
418
        free(map);
 
419
        return 0;
 
420
}
 
421
 
 
422
void
 
423
bmap_init(void)
 
424
{
 
425
        bmap_cmd.name = _("bmap");
 
426
        bmap_cmd.cfunc = bmap_f;
 
427
        bmap_cmd.argmin = 0;
 
428
        bmap_cmd.argmax = -1;
 
429
        bmap_cmd.flags = CMD_NOMAP_OK;
 
430
        bmap_cmd.args = _("[-adlpv] [-n nx]");
 
431
        bmap_cmd.oneline = _("print block mapping for an XFS file");
 
432
        bmap_cmd.help = bmap_help;
 
433
 
 
434
        add_command(&bmap_cmd);
 
435
}