2
* Copyright (c) 2000-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>
38
static cmdinfo_t bmap_cmd;
45
" prints the block mapping for an XFS file's data or attribute forks"
48
" 'bmap -vp' - tabular format verbose map, including unwritten extents\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"
72
for (len = 0, tmp = val; tmp > 0; tmp = tmp/10)
74
return (len == 0 ? 1 : len);
84
struct xfs_fsop_geom fsgeo;
92
int bmv_iflags = 0; /* flags for XFS_IOC_GETBMAPX */
96
while ((c = getopt(argc, argv, "adln:pv")) != EOF) {
98
case 'a': /* Attribute fork. */
99
bmv_iflags |= BMV_IF_ATTRFORK;
102
case 'l': /* list number of blocks with each extent */
105
case 'n': /* number of extents specified */
106
nflag = atoi(optarg);
109
/* do not recall possibly offline DMAPI files */
110
bmv_iflags |= BMV_IF_NO_DMAPI_READ;
113
/* report unwritten preallocated blocks */
114
bmv_iflags |= BMV_IF_PREALLOC;
116
case 'v': /* Verbose output */
120
return command_usage(&bmap_cmd);
124
bmv_iflags &= ~(BMV_IF_PREALLOC|BMV_IF_NO_DMAPI_READ);
127
c = xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo);
130
_("%s: can't get geometry [\"%s\"]: %s\n"),
131
progname, file->name, strerror(errno));
135
c = xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx);
138
_("%s: cannot read attrs on \"%s\": %s\n"),
139
progname, file->name, strerror(errno));
144
if (fsx.fsx_xflags == XFS_XFLAG_REALTIME) {
146
* ag info not applicable to rt, continue
153
map_size = nflag ? nflag+1 : 32; /* initial guess - 256 */
154
map = malloc(map_size*sizeof(*map));
156
fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
157
progname, (int)(map_size * sizeof(*map)));
163
/* Try the xfsctl(XFS_IOC_GETBMAPX) for the number of extents specified
164
* by nflag, or the initial guess number of extents (256).
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.
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.
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).
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.
190
do { /* loop a miximum of two times */
192
bzero(map, sizeof(*map)); /* zero header */
194
map->bmv_length = -1;
195
map->bmv_count = map_size;
196
map->bmv_iflags = bmv_iflags;
198
i = xfsctl(file->name, file->fd, XFS_IOC_GETBMAPX, map);
201
&& !aflag && filesize() == 0) {
204
fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETBMAPX)"
205
" iflags=0x%x [\"%s\"]: %s\n"),
206
progname, map->bmv_iflags, file->name,
215
if (map->bmv_entries < map->bmv_count-1)
217
/* Get number of extents from xfsctl XFS_IOC_FSGETXATTR[A]
220
i = xfsctl(file->name, file->fd, aflag ?
221
XFS_IOC_FSGETXATTRA : XFS_IOC_FSGETXATTR, &fsx);
223
fprintf(stderr, "%s: xfsctl(XFS_IOC_FSGETXATTR%s) "
224
"[\"%s\"]: %s\n", progname, aflag ? "A" : "",
225
file->name, strerror(errno));
230
if (fsx.fsx_nextents >= map_size-1) {
231
map_size = 2*(fsx.fsx_nextents+1);
232
map = realloc(map, map_size*sizeof(*map));
235
_("%s: cannot realloc %d bytes\n"),
236
progname, (int)(map_size*sizeof(*map)));
241
} while (++loop < 2);
243
if (map->bmv_entries <= 0) {
244
printf(_("%s: no extents\n"), file->name);
249
printf("%s:\n", file->name);
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)
260
(long long) map[i + 1].bmv_block,
261
(long long)(map[i + 1].bmv_block +
262
map[i + 1].bmv_length - 1LL));
266
printf(_(" %lld blocks\n"),
267
(long long)map[i+1].bmv_length);
273
* Verbose mode displays:
274
* extent: [startoffset..endoffset]: startblock..endblock \
275
* ag# (agoffset..agendoffset) totalbbs
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 */
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];
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;
303
* Go through the extents and figure out the width
304
* needed for all columns.
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)
313
if (map[i + 1].bmv_block == -1) {
314
foff_w = max(foff_w, strlen(rbuf));
316
numlen(map[i+1].bmv_length));
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));
331
numlen(map[i+1].bmv_length));
334
agno_w = max(MINAG_WIDTH, numlen(fsgeo.agcount));
335
printf("%4s: %-*s %-*s %*s %-*s %*s%s\n",
337
foff_w, _("FILE-OFFSET"),
338
boff_w, _("BLOCK-RANGE"),
340
aoff_w, _("AG-OFFSET"),
342
flg ? _(" FLAGS") : "");
343
for (i = 0; i < map->bmv_entries; i++) {
345
if (map[i + 1].bmv_oflags & BMV_OF_PREALLOC) {
349
* If striping enabled, determine if extent starts/ends
350
* on a stripe unit boundary.
353
if (map[i + 1].bmv_block % sunit != 0) {
356
if (((map[i + 1].bmv_block +
357
map[i + 1].bmv_length ) % sunit ) != 0) {
360
if (map[i + 1].bmv_block % swidth != 0) {
363
if (((map[i + 1].bmv_block +
364
map[i + 1].bmv_length ) % swidth ) != 0) {
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",
379
tot_w, (long long)map[i+1].bmv_length);
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",
396
tot_w, (long long)map[i+1].bmv_length);
397
if (flg == FLG_NULL) {
400
printf(" %-*.*o\n", NFLG, NFLG, flg);
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);
425
bmap_cmd.name = _("bmap");
426
bmap_cmd.cfunc = bmap_f;
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;
434
add_command(&bmap_cmd);