]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/bmap.c
2 * Copyright (c) 2000-2003 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/
37 static cmdinfo_t bmap_cmd
;
42 printf("%s %s\n", bmap_cmd
.name
, bmap_cmd
.oneline
);
51 " prints the block mapping for an XFS file's data or attribute forks"
54 " 'bmap -vp' - tabular format verbose map, including unwritten extents\n"
56 " bmap prints the map of disk blocks used by the current file.\n"
57 " The map lists each extent used by the file, as well as regions in the\n"
58 " file that do not have any corresponding blocks (holes).\n"
59 " By default, each line of the listing takes the following form:\n"
60 " extent: [startoffset..endoffset]: startblock..endblock\n"
61 " Holes are marked by replacing the startblock..endblock with 'hole'.\n"
62 " All the file offsets and disk blocks are in units of 512-byte blocks.\n"
63 " -a -- prints the attribute fork map instead of the data fork.\n"
64 " -d -- suppresses a DMAPI read event, offline portions shown as holes.\n"
65 " -l -- also displays the length of each extent in 512-byte blocks.\n"
66 " Note: the bmap for non-regular files can be obtained provided the file\n"
67 " was opened appropriately (in particular, must be opened read-only).\n"
78 for (len
= 0, tmp
= val
; tmp
> 0; tmp
= tmp
/10)
80 return (len
== 0 ? 1 : len
);
90 struct xfs_fsop_geom_v1 fsgeo
;
98 int bmv_iflags
= 0; /* flags for XFS_IOC_GETBMAPX */
102 while ((c
= getopt(argc
, argv
, "adln:pv")) != EOF
) {
104 case 'a': /* Attribute fork. */
105 bmv_iflags
|= BMV_IF_ATTRFORK
;
108 case 'l': /* list number of blocks with each extent */
111 case 'n': /* number of extents specified */
112 nflag
= atoi(optarg
);
115 /* do not recall possibly offline DMAPI files */
116 bmv_iflags
|= BMV_IF_NO_DMAPI_READ
;
119 /* report unwritten preallocated blocks */
120 bmv_iflags
|= BMV_IF_PREALLOC
;
122 case 'v': /* Verbose output */
130 bmv_iflags
&= ~(BMV_IF_PREALLOC
|BMV_IF_NO_DMAPI_READ
);
133 if (xfsctl(fname
, fdesc
, XFS_IOC_FSGEOMETRY_V1
, &fsgeo
) < 0) {
135 _("%s: can't get geometry [\"%s\"]: %s\n"),
136 progname
, fname
, strerror(errno
));
140 if ((xfsctl(fname
, fdesc
, XFS_IOC_FSGETXATTR
, &fsx
)) < 0) {
142 _("%s: cannot read attrs on \"%s\": %s\n"),
143 progname
, fname
, strerror(errno
));
148 if (fsx
.fsx_xflags
== XFS_XFLAG_REALTIME
) {
150 * ag info not applicable to rt, continue
157 map_size
= nflag
? nflag
+1 : 32; /* initial guess - 256 */
158 map
= malloc(map_size
*sizeof(*map
));
160 fprintf(stderr
, _("%s: malloc of %d bytes failed.\n"),
161 progname
, (int)(map_size
* sizeof(*map
)));
167 /* Try the xfsctl(XFS_IOC_GETBMAPX) for the number of extents specified
168 * by nflag, or the initial guess number of extents (256).
170 * If there are more extents than we guessed, use xfsctl
171 * (XFS_IOC_FSGETXATTR[A]) to get the extent count, realloc some more
172 * space based on this count, and try again.
174 * If the initial FGETBMAPX attempt returns EINVAL, this may mean
175 * that we tried the FGETBMAPX on a zero length file. If we get
176 * EINVAL, check the length with fstat() and return "no extents"
177 * if the length == 0.
179 * Why not do the xfsctl(XFS_IOC_FSGETXATTR[A]) first? Two reasons:
180 * (1) The extent count may be wrong for a file with delayed
181 * allocation blocks. The XFS_IOC_GETBMAPX forces the real
182 * allocation and fixes up the extent count.
183 * (2) For XFS_IOC_GETBMAP[X] on a DMAPI file that has been moved
184 * offline by a DMAPI application (e.g., DMF) the
185 * XFS_IOC_FSGETXATTR only reflects the extents actually online.
186 * Doing XFS_IOC_GETBMAPX call first forces that data blocks online
187 * and then everything proceeds normally (see PV #545725).
189 * If you don't want this behavior on a DMAPI offline file,
190 * try the "-d" option which sets the BMV_IF_NO_DMAPI_READ
191 * iflag for XFS_IOC_GETBMAPX.
194 do { /* loop a miximum of two times */
196 bzero(map
, sizeof(*map
)); /* zero header */
198 map
->bmv_length
= -1;
199 map
->bmv_count
= map_size
;
200 map
->bmv_iflags
= bmv_iflags
;
202 i
= xfsctl(fname
, fdesc
, XFS_IOC_GETBMAPX
, map
);
205 && !aflag
&& filesize() == 0) {
208 fprintf(stderr
, _("%s: xfsctl(XFS_IOC_GETBMAPX)"
209 " iflags=0x%x [\"%s\"]: %s\n"),
210 progname
, map
->bmv_iflags
, fname
,
219 if (map
->bmv_entries
< map
->bmv_count
-1)
221 /* Get number of extents from xfsctl XFS_IOC_FSGETXATTR[A]
224 i
= xfsctl(fname
, fdesc
, aflag
?
225 XFS_IOC_FSGETXATTRA
: XFS_IOC_FSGETXATTR
, &fsx
);
227 fprintf(stderr
, "%s: xfsctl(XFS_IOC_FSGETXATTR%s) "
228 "[\"%s\"]: %s\n", progname
, aflag
? "A" : "",
229 fname
, strerror(errno
));
234 if (fsx
.fsx_nextents
>= map_size
-1) {
235 map_size
= 2*(fsx
.fsx_nextents
+1);
236 map
= realloc(map
, map_size
*sizeof(*map
));
239 _("%s: cannot realloc %d bytes\n"),
240 progname
, (int)(map_size
*sizeof(*map
)));
245 } while (++loop
< 2);
247 if (map
->bmv_entries
<= 0) {
248 printf(_("%s: no extents\n"), fname
);
253 printf("%s:\n", fname
);
255 for (i
= 0; i
< map
->bmv_entries
; i
++) {
256 printf("\t%d: [%lld..%lld]: ", i
,
257 (long long) map
[i
+ 1].bmv_offset
,
258 (long long)(map
[i
+ 1].bmv_offset
+
259 map
[i
+ 1].bmv_length
- 1LL));
260 if (map
[i
+ 1].bmv_block
== -1)
264 (long long) map
[i
+ 1].bmv_block
,
265 (long long)(map
[i
+ 1].bmv_block
+
266 map
[i
+ 1].bmv_length
- 1LL));
270 printf(_(" %lld blocks\n"),
271 (long long)map
[i
+1].bmv_length
);
277 * Verbose mode displays:
278 * extent: [startoffset..endoffset]: startblock..endblock \
279 * ag# (agoffset..agendoffset) totalbbs
281 #define MINRANGE_WIDTH 16
282 #define MINAG_WIDTH 2
283 #define MINTOT_WIDTH 5
284 #define max(a,b) (a > b ? a : b)
285 #define FLG_NULL 00000 /* Null flag */
286 #define FLG_BSU 01000 /* Not on begin of stripe unit */
287 #define FLG_ESU 00100 /* Not on end of stripe unit */
288 #define FLG_BSW 00010 /* Not on begin of stripe width */
289 #define FLG_ESW 00001 /* Not on end of stripe width */
291 off64_t agoff
, bbperag
;
292 int foff_w
, boff_w
, aoff_w
, tot_w
, agno_w
;
293 char rbuf
[32], bbuf
[32], abuf
[32];
296 foff_w
= boff_w
= aoff_w
= MINRANGE_WIDTH
;
297 tot_w
= MINTOT_WIDTH
;
298 bbperag
= (off64_t
)fsgeo
.agblocks
*
299 (off64_t
)fsgeo
.blocksize
/ BBSIZE
;
301 swidth
= fsgeo
.swidth
;
304 * Go through the extents and figure out the width
305 * needed for all columns.
307 for (i
= 0; i
< map
->bmv_entries
; i
++) {
308 snprintf(rbuf
, sizeof(rbuf
), "[%lld..%lld]:",
309 (long long) map
[i
+ 1].bmv_offset
,
310 (long long)(map
[i
+ 1].bmv_offset
+
311 map
[i
+ 1].bmv_length
- 1LL));
312 if (map
[i
+ 1].bmv_block
== -1) {
313 foff_w
= max(foff_w
, strlen(rbuf
));
315 numlen(map
[i
+1].bmv_length
));
317 snprintf(bbuf
, sizeof(bbuf
), "%lld..%lld",
318 (long long) map
[i
+ 1].bmv_block
,
319 (long long)(map
[i
+ 1].bmv_block
+
320 map
[i
+ 1].bmv_length
- 1LL));
321 agno
= map
[i
+ 1].bmv_block
/ bbperag
;
322 agoff
= map
[i
+ 1].bmv_block
- (agno
* bbperag
);
323 snprintf(abuf
, sizeof(abuf
), "(%lld..%lld)",
324 (long long)agoff
, (long long)
325 (agoff
+ map
[i
+ 1].bmv_length
- 1LL));
326 foff_w
= max(foff_w
, strlen(rbuf
));
327 boff_w
= max(boff_w
, strlen(bbuf
));
328 aoff_w
= max(aoff_w
, strlen(abuf
));
330 numlen(map
[i
+1].bmv_length
));
333 agno_w
= max(MINAG_WIDTH
, numlen(fsgeo
.agcount
));
334 printf("%4s: %-*s %-*s %*s %-*s %*s\n",
336 foff_w
, _("FILE-OFFSET"),
337 boff_w
, _("BLOCK-RANGE"),
339 aoff_w
, _("AG-OFFSET"),
341 for (i
= 0; i
< map
->bmv_entries
; i
++) {
344 if (map
[i
+ 1].bmv_block
% sunit
!= 0) {
347 if (((map
[i
+ 1].bmv_block
+
348 map
[i
+ 1].bmv_length
) % sunit
) != 0) {
351 if (map
[i
+ 1].bmv_block
% swidth
!= 0) {
354 if (((map
[i
+ 1].bmv_block
+
355 map
[i
+ 1].bmv_length
) % swidth
) != 0) {
359 snprintf(rbuf
, sizeof(rbuf
), "[%lld..%lld]:",
360 (long long) map
[i
+ 1].bmv_offset
,
361 (long long)(map
[i
+ 1].bmv_offset
+
362 map
[i
+ 1].bmv_length
- 1LL));
363 if (map
[i
+ 1].bmv_block
== -1) {
364 printf("%4d: %-*s %-*s %*s %-*s %*lld\n",
370 tot_w
, (long long)map
[i
+1].bmv_length
);
372 snprintf(bbuf
, sizeof(bbuf
), "%lld..%lld",
373 (long long) map
[i
+ 1].bmv_block
,
374 (long long)(map
[i
+ 1].bmv_block
+
375 map
[i
+ 1].bmv_length
- 1LL));
376 agno
= map
[i
+ 1].bmv_block
/ bbperag
;
377 agoff
= map
[i
+ 1].bmv_block
- (agno
* bbperag
);
378 snprintf(abuf
, sizeof(abuf
), "(%lld..%lld)",
379 (long long)agoff
, (long long)
380 (agoff
+ map
[i
+ 1].bmv_length
- 1LL));
381 printf("%4d: %-*s %-*s %*d %-*s %*lld",
387 tot_w
, (long long)map
[i
+1].bmv_length
);
388 if (flg
== FLG_NULL
) {
391 printf(" %-4.4o\n", flg
);
396 printf(_(" FLG Values:\n"));
397 printf(_(" %5.5o Doesn't begin on stripe unit\n"),
399 printf(_(" %5.5o Doesn't end on stripe unit\n"),
401 printf(_(" %5.5o Doesn't begin on stripe width\n"),
403 printf(_(" %5.5o Doesn't end on stripe width\n"),
414 bmap_cmd
.name
= _("bmap");
415 bmap_cmd
.cfunc
= bmap_f
;
417 bmap_cmd
.argmax
= -1;
418 bmap_cmd
.args
= _("[-adlpv] [-n nx]");
419 bmap_cmd
.oneline
= _("print block mapping for an XFS file");
420 bmap_cmd
.help
= bmap_help
;
422 add_command(&bmap_cmd
);