]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/fsmap.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
6 #include "platform_defs.h"
9 #include "libfrog/paths.h"
12 #include "libfrog/fsgeom.h"
14 static cmdinfo_t fsmap_cmd
;
15 static dev_t xfs_data_dev
;
22 " Prints the block mapping for the filesystem hosting the current file"
24 " fsmap prints the map of disk blocks used by the whole filesystem.\n"
25 " When possible, owner and offset information will be included in the\n"
28 " By default, each line of the listing takes the following form:\n"
29 " extent: major:minor [startblock..endblock]: owner startoffset..endoffset length\n"
30 " The owner field is either an inode number or a special value.\n"
31 " All the file offsets and disk blocks are in units of 512-byte blocks.\n"
32 " -d -- query only the data device (default).\n"
33 " -l -- query only the log device.\n"
34 " -r -- query only the realtime device.\n"
35 " -n -- query n extents at a time.\n"
36 " -m -- output machine-readable format.\n"
37 " -v -- Verbose information, show AG and offsets. Show flags legend on 2nd -v\n"
39 "The optional start and end arguments require one of -d, -l, or -r to be set.\n"
43 #define OWNER_BUF_SZ 32
50 case XFS_FMR_OWN_FREE
:
51 return _("free space");
52 case XFS_FMR_OWN_UNKNOWN
:
55 return _("static fs metadata");
57 return _("journalling log");
59 return _("per-AG metadata");
60 case XFS_FMR_OWN_INOBT
:
61 return _("inode btree");
62 case XFS_FMR_OWN_INODES
:
64 case XFS_FMR_OWN_REFC
:
65 return _("refcount btree");
67 return _("cow reservation");
68 case XFS_FMR_OWN_DEFECTIVE
:
69 return _("defective");
71 snprintf(buf
, OWNER_BUF_SZ
, _("special %u:%u"),
72 FMR_OWNER_TYPE(owner
), FMR_OWNER_CODE(owner
));
79 unsigned long long *nr
,
80 struct fsmap_head
*head
)
84 char owner
[OWNER_BUF_SZ
];
87 for (i
= 0, p
= head
->fmh_recs
; i
< head
->fmh_entries
; i
++, p
++) {
88 printf("\t%llu: %u:%u [%lld..%lld]: ", i
+ (*nr
),
89 major(p
->fmr_device
), minor(p
->fmr_device
),
90 (long long)BTOBBT(p
->fmr_physical
),
91 (long long)BTOBBT(p
->fmr_physical
+ p
->fmr_length
- 1));
92 fork
= (p
->fmr_flags
& FMR_OF_ATTR_FORK
) ? _("attr") : _("data");
93 if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
)
94 printf("%s", special_owner(p
->fmr_owner
, owner
));
95 else if (p
->fmr_flags
& FMR_OF_EXTENT_MAP
)
96 printf(_("inode %lld %s extent map"),
97 (long long) p
->fmr_owner
, fork
);
99 printf(_("inode %lld %s %lld..%lld"),
100 (long long)p
->fmr_owner
, fork
,
101 (long long)BTOBBT(p
->fmr_offset
),
102 (long long)BTOBBT(p
->fmr_offset
+ p
->fmr_length
- 1));
104 (long long)BTOBBT(p
->fmr_length
));
107 (*nr
) += head
->fmh_entries
;
112 unsigned long long *nr
,
113 struct fsmap_head
*head
)
115 unsigned long long i
;
119 printf(_("EXT,MAJOR,MINOR,PSTART,PEND,OWNER,OSTART,OEND,LENGTH\n"));
120 for (i
= 0, p
= head
->fmh_recs
; i
< head
->fmh_entries
; i
++, p
++) {
121 printf("%llu,%u,%u,%lld,%lld,", i
+ (*nr
),
122 major(p
->fmr_device
), minor(p
->fmr_device
),
123 (long long)BTOBBT(p
->fmr_physical
),
124 (long long)BTOBBT(p
->fmr_physical
+ p
->fmr_length
- 1));
125 fork
= (p
->fmr_flags
& FMR_OF_ATTR_FORK
) ? "attr" : "data";
126 if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
)
127 printf("special_%u:%u,,,", FMR_OWNER_TYPE(p
->fmr_owner
),
128 FMR_OWNER_CODE(p
->fmr_owner
));
129 else if (p
->fmr_flags
& FMR_OF_EXTENT_MAP
)
130 printf(_("inode_%lld_%s_bmbt,,,"),
131 (long long) p
->fmr_owner
, fork
);
133 printf(_("inode_%lld_%s,%lld,%lld,"),
134 (long long)p
->fmr_owner
, fork
,
135 (long long)BTOBBT(p
->fmr_offset
),
136 (long long)BTOBBT(p
->fmr_offset
+ p
->fmr_length
- 1));
138 (long long)BTOBBT(p
->fmr_length
));
141 (*nr
) += head
->fmh_entries
;
145 * Verbose mode displays:
146 * extent: major:minor [startblock..endblock]: startoffset..endoffset \
147 * ag# (agoffset..agendoffset) totalbbs flags
149 #define MINRANGE_WIDTH 16
150 #define MINAG_WIDTH 2
151 #define MINTOT_WIDTH 5
152 #define NFLG 7 /* count of flags */
153 #define FLG_NULL 00000000 /* Null flag */
154 #define FLG_ATTR_FORK 01000000 /* attribute fork */
155 #define FLG_SHARED 00100000 /* shared extent */
156 #define FLG_PRE 00010000 /* Unwritten extent */
157 #define FLG_BSU 00001000 /* Not on begin of stripe unit */
158 #define FLG_ESU 00000100 /* Not on end of stripe unit */
159 #define FLG_BSW 00000010 /* Not on begin of stripe width */
160 #define FLG_ESW 00000001 /* Not on end of stripe width */
163 unsigned long long *nr
,
164 struct fsmap_head
*head
,
166 struct xfs_fsop_geom
*fsgeo
)
168 unsigned long long i
;
171 off64_t agoff
, bperag
;
172 int foff_w
, boff_w
, aoff_w
, tot_w
, agno_w
, own_w
;
174 char rbuf
[40], bbuf
[40], abuf
[40], obuf
[40];
175 char nbuf
[40], dbuf
[40], gbuf
[40];
176 char owner
[OWNER_BUF_SZ
];
180 foff_w
= boff_w
= aoff_w
= own_w
= MINRANGE_WIDTH
;
183 tot_w
= MINTOT_WIDTH
;
184 bperag
= (off64_t
)fsgeo
->agblocks
*
185 (off64_t
)fsgeo
->blocksize
;
186 sunit
= (fsgeo
->sunit
* fsgeo
->blocksize
);
187 swidth
= (fsgeo
->swidth
* fsgeo
->blocksize
);
190 * Go through the extents and figure out the width
191 * needed for all columns.
193 for (i
= 0, p
= head
->fmh_recs
; i
< head
->fmh_entries
; i
++, p
++) {
194 if (p
->fmr_flags
& FMR_OF_PREALLOC
||
195 p
->fmr_flags
& FMR_OF_ATTR_FORK
||
196 p
->fmr_flags
& FMR_OF_SHARED
)
199 (p
->fmr_physical
% sunit
!= 0 ||
200 ((p
->fmr_physical
+ p
->fmr_length
) % sunit
) != 0 ||
201 p
->fmr_physical
% swidth
!= 0 ||
202 ((p
->fmr_physical
+ p
->fmr_length
) % swidth
) != 0))
205 *dumped_flags
= true;
206 snprintf(nbuf
, sizeof(nbuf
), "%llu", (*nr
) + i
);
207 nr_w
= max(nr_w
, strlen(nbuf
));
208 if (head
->fmh_oflags
& FMH_OF_DEV_T
)
209 snprintf(dbuf
, sizeof(dbuf
), "%u:%u",
210 major(p
->fmr_device
),
211 minor(p
->fmr_device
));
213 snprintf(dbuf
, sizeof(dbuf
), "0x%x", p
->fmr_device
);
214 dev_w
= max(dev_w
, strlen(dbuf
));
215 snprintf(bbuf
, sizeof(bbuf
), "[%lld..%lld]:",
216 (long long)BTOBBT(p
->fmr_physical
),
217 (long long)BTOBBT(p
->fmr_physical
+ p
->fmr_length
- 1));
218 boff_w
= max(boff_w
, strlen(bbuf
));
219 if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
)
220 own_w
= max(own_w
, strlen(
221 special_owner(p
->fmr_owner
, owner
)));
223 snprintf(obuf
, sizeof(obuf
), "%lld",
224 (long long)p
->fmr_owner
);
225 own_w
= max(own_w
, strlen(obuf
));
227 if (p
->fmr_flags
& FMR_OF_EXTENT_MAP
)
228 foff_w
= max(foff_w
, strlen(_("extent_map")));
229 else if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
)
232 snprintf(rbuf
, sizeof(rbuf
), "%lld..%lld",
233 (long long)BTOBBT(p
->fmr_offset
),
234 (long long)BTOBBT(p
->fmr_offset
+ p
->fmr_length
- 1));
235 foff_w
= max(foff_w
, strlen(rbuf
));
237 if (p
->fmr_device
== xfs_data_dev
) {
238 agno
= p
->fmr_physical
/ bperag
;
239 agoff
= p
->fmr_physical
- (agno
* bperag
);
240 snprintf(abuf
, sizeof(abuf
),
242 (long long)BTOBBT(agoff
),
243 (long long)BTOBBT(agoff
+ p
->fmr_length
- 1));
246 aoff_w
= max(aoff_w
, strlen(abuf
));
248 numlen(BTOBBT(p
->fmr_length
), 10));
250 agno_w
= max(MINAG_WIDTH
, numlen(fsgeo
->agcount
, 10));
252 printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n",
255 boff_w
, _("BLOCK-RANGE"),
257 foff_w
, _("FILE-OFFSET"),
259 aoff_w
, _("AG-OFFSET"),
261 flg
? _(" FLAGS") : "");
262 for (i
= 0, p
= head
->fmh_recs
; i
< head
->fmh_entries
; i
++, p
++) {
264 if (p
->fmr_flags
& FMR_OF_PREALLOC
)
266 if (p
->fmr_flags
& FMR_OF_ATTR_FORK
)
267 flg
|= FLG_ATTR_FORK
;
268 if (p
->fmr_flags
& FMR_OF_SHARED
)
271 * If striping enabled, determine if extent starts/ends
272 * on a stripe unit boundary.
275 if (p
->fmr_physical
% sunit
!= 0)
277 if (((p
->fmr_physical
+
278 p
->fmr_length
) % sunit
) != 0)
280 if (p
->fmr_physical
% swidth
!= 0)
282 if (((p
->fmr_physical
+
283 p
->fmr_length
) % swidth
) != 0)
286 if (head
->fmh_oflags
& FMH_OF_DEV_T
)
287 snprintf(dbuf
, sizeof(dbuf
), "%u:%u",
288 major(p
->fmr_device
),
289 minor(p
->fmr_device
));
291 snprintf(dbuf
, sizeof(dbuf
), "0x%x", p
->fmr_device
);
292 snprintf(bbuf
, sizeof(bbuf
), "[%lld..%lld]:",
293 (long long)BTOBBT(p
->fmr_physical
),
294 (long long)BTOBBT(p
->fmr_physical
+ p
->fmr_length
- 1));
295 if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
) {
296 snprintf(obuf
, sizeof(obuf
), "%s",
297 special_owner(p
->fmr_owner
, owner
));
298 snprintf(rbuf
, sizeof(rbuf
), " ");
300 snprintf(obuf
, sizeof(obuf
), "%lld",
301 (long long)p
->fmr_owner
);
302 snprintf(rbuf
, sizeof(rbuf
), "%lld..%lld",
303 (long long)BTOBBT(p
->fmr_offset
),
304 (long long)BTOBBT(p
->fmr_offset
+ p
->fmr_length
- 1));
306 if (p
->fmr_device
== xfs_data_dev
) {
307 agno
= p
->fmr_physical
/ bperag
;
308 agoff
= p
->fmr_physical
- (agno
* bperag
);
309 snprintf(abuf
, sizeof(abuf
),
311 (long long)BTOBBT(agoff
),
312 (long long)BTOBBT(agoff
+ p
->fmr_length
- 1));
313 snprintf(gbuf
, sizeof(gbuf
),
320 if (p
->fmr_flags
& FMR_OF_EXTENT_MAP
)
321 printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n",
326 foff_w
, _("extent map"),
329 tot_w
, (long long)BTOBBT(p
->fmr_length
));
331 printf("%*llu: %-*s %-*s %-*s %-*s", nr_w
, (*nr
) + i
,
332 dev_w
, dbuf
, boff_w
, bbuf
, own_w
, obuf
,
334 printf(" %-*s %-*s", agno_w
, gbuf
,
336 printf(" %*lld", tot_w
,
337 (long long)BTOBBT(p
->fmr_length
));
341 printf(" %-*.*o\n", NFLG
, NFLG
, flg
);
345 (*nr
) += head
->fmh_entries
;
349 dump_verbose_key(void)
351 printf(_(" FLAG Values:\n"));
352 printf(_(" %*.*o Attribute fork\n"),
353 NFLG
+1, NFLG
+1, FLG_ATTR_FORK
);
354 printf(_(" %*.*o Shared extent\n"),
355 NFLG
+1, NFLG
+1, FLG_SHARED
);
356 printf(_(" %*.*o Unwritten preallocated extent\n"),
357 NFLG
+1, NFLG
+1, FLG_PRE
);
358 printf(_(" %*.*o Doesn't begin on stripe unit\n"),
359 NFLG
+1, NFLG
+1, FLG_BSU
);
360 printf(_(" %*.*o Doesn't end on stripe unit\n"),
361 NFLG
+1, NFLG
+1, FLG_ESU
);
362 printf(_(" %*.*o Doesn't begin on stripe width\n"),
363 NFLG
+1, NFLG
+1, FLG_BSW
);
364 printf(_(" %*.*o Doesn't end on stripe width\n"),
365 NFLG
+1, NFLG
+1, FLG_ESW
);
374 struct fsmap_head
*nhead
;
375 struct fsmap_head
*head
;
377 struct xfs_fsop_geom fsgeo
;
387 unsigned long long nr
= 0;
388 size_t fsblocksize
, fssectsize
;
390 static bool tab_init
;
391 bool dumped_flags
= false;
392 int dflag
, lflag
, rflag
;
394 init_cvtnum(&fsblocksize
, &fssectsize
);
396 dflag
= lflag
= rflag
= 0;
397 while ((c
= getopt(argc
, argv
, "dlmn:rv")) != EOF
) {
399 case 'd': /* data device */
402 case 'l': /* log device */
405 case 'm': /* machine readable format */
408 case 'n': /* number of extents specified */
409 nflag
= cvt_u32(optarg
, 10);
411 return command_usage(&fsmap_cmd
);
413 case 'r': /* rt device */
416 case 'v': /* Verbose output */
420 return command_usage(&fsmap_cmd
);
424 if ((dflag
+ lflag
+ rflag
> 1) || (mflag
> 0 && vflag
> 0) ||
425 (argc
> optind
&& dflag
+ lflag
+ rflag
== 0))
426 return command_usage(&fsmap_cmd
);
429 start
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
432 _("Bad rmap start_bblock %s.\n"),
439 if (argc
> optind
+ 1) {
440 end
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
+ 1]);
443 _("Bad rmap end_bblock %s.\n"),
451 c
= -xfrog_geometry(file
->fd
, &fsgeo
);
454 _("%s: can't get geometry [\"%s\"]: %s\n"),
455 progname
, file
->name
, strerror(c
));
461 map_size
= nflag
? nflag
: 131072 / sizeof(struct fsmap
);
462 head
= malloc(fsmap_sizeof(map_size
));
464 fprintf(stderr
, _("%s: malloc of %zu bytes failed.\n"),
465 progname
, fsmap_sizeof(map_size
));
470 memset(head
, 0, sizeof(*head
));
472 h
= head
->fmh_keys
+ 1;
474 l
->fmr_device
= h
->fmr_device
= file
->fs_path
.fs_datadev
;
476 l
->fmr_device
= h
->fmr_device
= file
->fs_path
.fs_logdev
;
478 l
->fmr_device
= h
->fmr_device
= file
->fs_path
.fs_rtdev
;
481 h
->fmr_device
= UINT_MAX
;
483 l
->fmr_physical
= start
;
484 h
->fmr_physical
= end
;
485 h
->fmr_owner
= ULLONG_MAX
;
486 h
->fmr_flags
= UINT_MAX
;
487 h
->fmr_offset
= ULLONG_MAX
;
492 i
= ioctl(file
->fd
, FS_IOC_GETFSMAP
, head
);
494 fprintf(stderr
, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
495 " iflags=0x%x [\"%s\"]: %s\n"),
496 progname
, head
->fmh_iflags
, file
->name
,
502 if (head
->fmh_entries
> map_size
+ 2) {
503 map_size
= 11ULL * head
->fmh_entries
/ 10;
504 nmap_size
= map_size
> (1 << 24) ? (1 << 24) : map_size
;
505 nhead
= realloc(head
, fsmap_sizeof(nmap_size
));
508 _("%s: cannot realloc %zu bytes\n"),
509 progname
, fsmap_sizeof(nmap_size
));
512 map_size
= nmap_size
;
518 * If this is an XFS filesystem, remember the data device.
519 * (We report AG number/block for data device extents on XFS).
522 fs_table_initialise(0, NULL
, 0, NULL
);
525 fs
= fs_table_lookup(file
->name
, FS_MOUNT_POINT
);
526 xfs_data_dev
= fs
? fs
->fs_datadev
: 0;
528 head
->fmh_count
= map_size
;
530 /* Get some extents */
531 i
= ioctl(file
->fd
, FS_IOC_GETFSMAP
, head
);
533 fprintf(stderr
, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
534 " iflags=0x%x [\"%s\"]: %s\n"),
535 progname
, head
->fmh_iflags
, file
->name
,
542 if (head
->fmh_entries
== 0)
546 dump_map_verbose(&nr
, head
, &dumped_flags
, &fsgeo
);
548 dump_map_machine(&nr
, head
);
552 p
= &head
->fmh_recs
[head
->fmh_entries
- 1];
553 if (p
->fmr_flags
& FMR_OF_LAST
)
568 fsmap_cmd
.name
= "fsmap";
569 fsmap_cmd
.cfunc
= fsmap_f
;
570 fsmap_cmd
.argmin
= 0;
571 fsmap_cmd
.argmax
= -1;
572 fsmap_cmd
.flags
= CMD_NOMAP_OK
| CMD_FLAG_FOREIGN_OK
;
573 fsmap_cmd
.args
= _("[-d|-l|-r] [-m|-v] [-n nx] [start] [end]");
574 fsmap_cmd
.oneline
= _("print filesystem mapping for a range of blocks");
575 fsmap_cmd
.help
= fsmap_help
;
577 add_command(&fsmap_cmd
);