]>
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"
7 #include <linux/fsmap.h>
10 #include "libfrog/paths.h"
13 #include "libfrog/fsgeom.h"
15 static cmdinfo_t fsmap_cmd
;
16 static dev_t xfs_data_dev
;
23 " Prints the block mapping for the filesystem hosting the current file"
25 " fsmap prints the map of disk blocks used by the whole filesystem.\n"
26 " When possible, owner and offset information will be included in the\n"
29 " By default, each line of the listing takes the following form:\n"
30 " extent: major:minor [startblock..endblock]: owner startoffset..endoffset length\n"
31 " The owner field is either an inode number or a special value.\n"
32 " All the file offsets and disk blocks are in units of 512-byte blocks.\n"
33 " -d -- query only the data device (default).\n"
34 " -l -- query only the log device.\n"
35 " -r -- query only the realtime device.\n"
36 " -n -- query n extents at a time.\n"
37 " -m -- output machine-readable format.\n"
38 " -v -- Verbose information, show AG and offsets. Show flags legend on 2nd -v\n"
40 "The optional start and end arguments require one of -d, -l, or -r to be set.\n"
44 #define OWNER_BUF_SZ 32
51 case XFS_FMR_OWN_FREE
:
52 return _("free space");
53 case XFS_FMR_OWN_UNKNOWN
:
56 return _("static fs metadata");
58 return _("journalling log");
60 return _("per-AG metadata");
61 case XFS_FMR_OWN_INOBT
:
62 return _("inode btree");
63 case XFS_FMR_OWN_INODES
:
65 case XFS_FMR_OWN_REFC
:
66 return _("refcount btree");
68 return _("cow reservation");
69 case XFS_FMR_OWN_DEFECTIVE
:
70 return _("defective");
72 snprintf(buf
, OWNER_BUF_SZ
, _("special %u:%u"),
73 FMR_OWNER_TYPE(owner
), FMR_OWNER_CODE(owner
));
80 unsigned long long *nr
,
81 struct fsmap_head
*head
)
85 char owner
[OWNER_BUF_SZ
];
88 for (i
= 0, p
= head
->fmh_recs
; i
< head
->fmh_entries
; i
++, p
++) {
89 printf("\t%llu: %u:%u [%lld..%lld]: ", i
+ (*nr
),
90 major(p
->fmr_device
), minor(p
->fmr_device
),
91 (long long)BTOBBT(p
->fmr_physical
),
92 (long long)BTOBBT(p
->fmr_physical
+ p
->fmr_length
- 1));
93 fork
= (p
->fmr_flags
& FMR_OF_ATTR_FORK
) ? _("attr") : _("data");
94 if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
)
95 printf("%s", special_owner(p
->fmr_owner
, owner
));
96 else if (p
->fmr_flags
& FMR_OF_EXTENT_MAP
)
97 printf(_("inode %lld %s extent map"),
98 (long long) p
->fmr_owner
, fork
);
100 printf(_("inode %lld %s %lld..%lld"),
101 (long long)p
->fmr_owner
, fork
,
102 (long long)BTOBBT(p
->fmr_offset
),
103 (long long)BTOBBT(p
->fmr_offset
+ p
->fmr_length
- 1));
105 (long long)BTOBBT(p
->fmr_length
));
108 (*nr
) += head
->fmh_entries
;
113 unsigned long long *nr
,
114 struct fsmap_head
*head
)
116 unsigned long long i
;
121 printf(_("EXT,MAJOR,MINOR,PSTART,PEND,OWNER,OSTART,OEND,LENGTH\n"));
122 for (i
= 0, p
= head
->fmh_recs
; i
< head
->fmh_entries
; i
++, p
++) {
123 printf("%llu,%u,%u,%lld,%lld,", i
+ (*nr
),
124 major(p
->fmr_device
), minor(p
->fmr_device
),
125 (long long)BTOBBT(p
->fmr_physical
),
126 (long long)BTOBBT(p
->fmr_physical
+ p
->fmr_length
- 1));
127 fork
= (p
->fmr_flags
& FMR_OF_ATTR_FORK
) ? "attr" : "data";
128 if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
)
129 printf("special_%u:%u,,,", FMR_OWNER_TYPE(p
->fmr_owner
),
130 FMR_OWNER_CODE(p
->fmr_owner
));
131 else if (p
->fmr_flags
& FMR_OF_EXTENT_MAP
)
132 printf(_("inode_%lld_%s_bmbt,,,"),
133 (long long) p
->fmr_owner
, fork
);
135 printf(_("inode_%lld_%s,%lld,%lld,"),
136 (long long)p
->fmr_owner
, fork
,
137 (long long)BTOBBT(p
->fmr_offset
),
138 (long long)BTOBBT(p
->fmr_offset
+ p
->fmr_length
- 1));
140 (long long)BTOBBT(p
->fmr_length
));
143 (*nr
) += head
->fmh_entries
;
147 * Verbose mode displays:
148 * extent: major:minor [startblock..endblock]: startoffset..endoffset \
149 * ag# (agoffset..agendoffset) totalbbs flags
151 #define MINRANGE_WIDTH 16
152 #define MINAG_WIDTH 2
153 #define MINTOT_WIDTH 5
154 #define NFLG 7 /* count of flags */
155 #define FLG_NULL 00000000 /* Null flag */
156 #define FLG_ATTR_FORK 01000000 /* attribute fork */
157 #define FLG_SHARED 00100000 /* shared extent */
158 #define FLG_PRE 00010000 /* Unwritten extent */
159 #define FLG_BSU 00001000 /* Not on begin of stripe unit */
160 #define FLG_ESU 00000100 /* Not on end of stripe unit */
161 #define FLG_BSW 00000010 /* Not on begin of stripe width */
162 #define FLG_ESW 00000001 /* Not on end of stripe width */
165 unsigned long long *nr
,
166 struct fsmap_head
*head
,
168 struct xfs_fsop_geom
*fsgeo
)
170 unsigned long long i
;
173 off64_t agoff
, bperag
;
174 int foff_w
, boff_w
, aoff_w
, tot_w
, agno_w
, own_w
;
176 char rbuf
[40], bbuf
[40], abuf
[40], obuf
[40];
177 char nbuf
[40], dbuf
[40], gbuf
[40];
178 char owner
[OWNER_BUF_SZ
];
182 foff_w
= boff_w
= aoff_w
= own_w
= MINRANGE_WIDTH
;
185 tot_w
= MINTOT_WIDTH
;
186 bperag
= (off64_t
)fsgeo
->agblocks
*
187 (off64_t
)fsgeo
->blocksize
;
188 sunit
= (fsgeo
->sunit
* fsgeo
->blocksize
);
189 swidth
= (fsgeo
->swidth
* fsgeo
->blocksize
);
192 * Go through the extents and figure out the width
193 * needed for all columns.
195 for (i
= 0, p
= head
->fmh_recs
; i
< head
->fmh_entries
; i
++, p
++) {
196 if (p
->fmr_flags
& FMR_OF_PREALLOC
||
197 p
->fmr_flags
& FMR_OF_ATTR_FORK
||
198 p
->fmr_flags
& FMR_OF_SHARED
)
200 if (sunit
&& p
->fmr_device
== xfs_data_dev
&&
201 (p
->fmr_physical
% sunit
!= 0 ||
202 ((p
->fmr_physical
+ p
->fmr_length
) % sunit
) != 0 ||
203 p
->fmr_physical
% swidth
!= 0 ||
204 ((p
->fmr_physical
+ p
->fmr_length
) % swidth
) != 0))
207 *dumped_flags
= true;
208 snprintf(nbuf
, sizeof(nbuf
), "%llu", (*nr
) + i
);
209 nr_w
= max(nr_w
, strlen(nbuf
));
210 if (head
->fmh_oflags
& FMH_OF_DEV_T
)
211 snprintf(dbuf
, sizeof(dbuf
), "%u:%u",
212 major(p
->fmr_device
),
213 minor(p
->fmr_device
));
215 snprintf(dbuf
, sizeof(dbuf
), "0x%x", p
->fmr_device
);
216 dev_w
= max(dev_w
, strlen(dbuf
));
217 snprintf(bbuf
, sizeof(bbuf
), "[%lld..%lld]:",
218 (long long)BTOBBT(p
->fmr_physical
),
219 (long long)BTOBBT(p
->fmr_physical
+ p
->fmr_length
- 1));
220 boff_w
= max(boff_w
, strlen(bbuf
));
221 if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
)
222 own_w
= max(own_w
, strlen(
223 special_owner(p
->fmr_owner
, owner
)));
225 snprintf(obuf
, sizeof(obuf
), "%lld",
226 (long long)p
->fmr_owner
);
227 own_w
= max(own_w
, strlen(obuf
));
229 if (p
->fmr_flags
& FMR_OF_EXTENT_MAP
)
230 foff_w
= max(foff_w
, strlen(_("extent_map")));
231 else if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
)
234 snprintf(rbuf
, sizeof(rbuf
), "%lld..%lld",
235 (long long)BTOBBT(p
->fmr_offset
),
236 (long long)BTOBBT(p
->fmr_offset
+ p
->fmr_length
- 1));
237 foff_w
= max(foff_w
, strlen(rbuf
));
239 if (p
->fmr_device
== xfs_data_dev
) {
240 agno
= p
->fmr_physical
/ bperag
;
241 agoff
= p
->fmr_physical
- (agno
* bperag
);
242 snprintf(abuf
, sizeof(abuf
),
244 (long long)BTOBBT(agoff
),
245 (long long)BTOBBT(agoff
+ p
->fmr_length
- 1));
248 aoff_w
= max(aoff_w
, strlen(abuf
));
250 numlen(BTOBBT(p
->fmr_length
), 10));
252 agno_w
= max(MINAG_WIDTH
, numlen(fsgeo
->agcount
, 10));
254 printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n",
257 boff_w
, _("BLOCK-RANGE"),
259 foff_w
, _("FILE-OFFSET"),
261 aoff_w
, _("AG-OFFSET"),
263 flg
? _(" FLAGS") : "");
264 for (i
= 0, p
= head
->fmh_recs
; i
< head
->fmh_entries
; i
++, p
++) {
266 if (p
->fmr_flags
& FMR_OF_PREALLOC
)
268 if (p
->fmr_flags
& FMR_OF_ATTR_FORK
)
269 flg
|= FLG_ATTR_FORK
;
270 if (p
->fmr_flags
& FMR_OF_SHARED
)
273 * If striping enabled, determine if extent starts/ends
274 * on a stripe unit boundary.
276 if (sunit
&& p
->fmr_device
== xfs_data_dev
) {
277 if (p
->fmr_physical
% sunit
!= 0)
279 if (((p
->fmr_physical
+
280 p
->fmr_length
) % sunit
) != 0)
282 if (p
->fmr_physical
% swidth
!= 0)
284 if (((p
->fmr_physical
+
285 p
->fmr_length
) % swidth
) != 0)
288 if (head
->fmh_oflags
& FMH_OF_DEV_T
)
289 snprintf(dbuf
, sizeof(dbuf
), "%u:%u",
290 major(p
->fmr_device
),
291 minor(p
->fmr_device
));
293 snprintf(dbuf
, sizeof(dbuf
), "0x%x", p
->fmr_device
);
294 snprintf(bbuf
, sizeof(bbuf
), "[%lld..%lld]:",
295 (long long)BTOBBT(p
->fmr_physical
),
296 (long long)BTOBBT(p
->fmr_physical
+ p
->fmr_length
- 1));
297 if (p
->fmr_flags
& FMR_OF_SPECIAL_OWNER
) {
298 snprintf(obuf
, sizeof(obuf
), "%s",
299 special_owner(p
->fmr_owner
, owner
));
300 snprintf(rbuf
, sizeof(rbuf
), " ");
302 snprintf(obuf
, sizeof(obuf
), "%lld",
303 (long long)p
->fmr_owner
);
304 snprintf(rbuf
, sizeof(rbuf
), "%lld..%lld",
305 (long long)BTOBBT(p
->fmr_offset
),
306 (long long)BTOBBT(p
->fmr_offset
+ p
->fmr_length
- 1));
308 if (p
->fmr_device
== xfs_data_dev
) {
309 agno
= p
->fmr_physical
/ bperag
;
310 agoff
= p
->fmr_physical
- (agno
* bperag
);
311 snprintf(abuf
, sizeof(abuf
),
313 (long long)BTOBBT(agoff
),
314 (long long)BTOBBT(agoff
+ p
->fmr_length
- 1));
315 snprintf(gbuf
, sizeof(gbuf
),
322 if (p
->fmr_flags
& FMR_OF_EXTENT_MAP
)
323 printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n",
328 foff_w
, _("extent map"),
331 tot_w
, (long long)BTOBBT(p
->fmr_length
));
333 printf("%*llu: %-*s %-*s %-*s %-*s", nr_w
, (*nr
) + i
,
334 dev_w
, dbuf
, boff_w
, bbuf
, own_w
, obuf
,
336 printf(" %-*s %-*s", agno_w
, gbuf
,
338 printf(" %*lld", tot_w
,
339 (long long)BTOBBT(p
->fmr_length
));
343 printf(" %-*.*o\n", NFLG
, NFLG
, flg
);
347 (*nr
) += head
->fmh_entries
;
351 dump_verbose_key(void)
353 printf(_(" FLAG Values:\n"));
354 printf(_(" %*.*o Attribute fork\n"),
355 NFLG
+1, NFLG
+1, FLG_ATTR_FORK
);
356 printf(_(" %*.*o Shared extent\n"),
357 NFLG
+1, NFLG
+1, FLG_SHARED
);
358 printf(_(" %*.*o Unwritten preallocated extent\n"),
359 NFLG
+1, NFLG
+1, FLG_PRE
);
360 printf(_(" %*.*o Doesn't begin on stripe unit\n"),
361 NFLG
+1, NFLG
+1, FLG_BSU
);
362 printf(_(" %*.*o Doesn't end on stripe unit\n"),
363 NFLG
+1, NFLG
+1, FLG_ESU
);
364 printf(_(" %*.*o Doesn't begin on stripe width\n"),
365 NFLG
+1, NFLG
+1, FLG_BSW
);
366 printf(_(" %*.*o Doesn't end on stripe width\n"),
367 NFLG
+1, NFLG
+1, FLG_ESW
);
376 struct fsmap_head
*head
;
378 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 */
421 return command_usage(&fsmap_cmd
);
425 if ((dflag
+ lflag
+ rflag
> 1) || (mflag
> 0 && vflag
> 0) ||
426 (argc
> optind
&& dflag
+ lflag
+ rflag
== 0)) {
428 return command_usage(&fsmap_cmd
);
432 start
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
435 _("Bad rmap start_bblock %s.\n"),
443 if (argc
> optind
+ 1) {
444 end
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
+ 1]);
447 _("Bad rmap end_bblock %s.\n"),
456 c
= -xfrog_geometry(file
->fd
, &fsgeo
);
459 _("%s: can't get geometry [\"%s\"]: %s\n"),
460 progname
, file
->name
, strerror(c
));
466 map_size
= nflag
? nflag
: 131072 / sizeof(struct fsmap
);
467 head
= malloc(fsmap_sizeof(map_size
));
469 fprintf(stderr
, _("%s: malloc of %zu bytes failed.\n"),
470 progname
, fsmap_sizeof(map_size
));
475 memset(head
, 0, sizeof(*head
));
477 h
= head
->fmh_keys
+ 1;
479 l
->fmr_device
= h
->fmr_device
= file
->fs_path
.fs_datadev
;
481 l
->fmr_device
= h
->fmr_device
= file
->fs_path
.fs_logdev
;
483 l
->fmr_device
= h
->fmr_device
= file
->fs_path
.fs_rtdev
;
486 h
->fmr_device
= UINT_MAX
;
488 l
->fmr_physical
= start
;
489 h
->fmr_physical
= end
;
490 h
->fmr_owner
= ULLONG_MAX
;
491 h
->fmr_flags
= UINT_MAX
;
492 h
->fmr_offset
= ULLONG_MAX
;
495 * If this is an XFS filesystem, remember the data device.
496 * (We report AG number/block for data device extents on XFS).
499 fs_table_initialise(0, NULL
, 0, NULL
);
502 fs
= fs_table_lookup(file
->name
, FS_MOUNT_POINT
);
503 xfs_data_dev
= fs
? fs
->fs_datadev
: 0;
505 head
->fmh_count
= map_size
;
507 /* Get some extents */
508 i
= ioctl(file
->fd
, FS_IOC_GETFSMAP
, head
);
510 fprintf(stderr
, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
511 " iflags=0x%x [\"%s\"]: %s\n"),
512 progname
, head
->fmh_iflags
, file
->name
,
519 if (head
->fmh_entries
== 0)
523 dump_map_verbose(&nr
, head
, &dumped_flags
, &fsgeo
);
525 dump_map_machine(&nr
, head
);
529 p
= &head
->fmh_recs
[head
->fmh_entries
- 1];
530 if (p
->fmr_flags
& FMR_OF_LAST
)
545 fsmap_cmd
.name
= "fsmap";
546 fsmap_cmd
.cfunc
= fsmap_f
;
547 fsmap_cmd
.argmin
= 0;
548 fsmap_cmd
.argmax
= -1;
549 fsmap_cmd
.flags
= CMD_NOMAP_OK
| CMD_FLAG_FOREIGN_OK
;
550 fsmap_cmd
.args
= _("[-d|-l|-r] [-m|-v] [-n nx] [start] [end]");
551 fsmap_cmd
.oneline
= _("print filesystem mapping for a range of blocks");
552 fsmap_cmd
.help
= fsmap_help
;
554 add_command(&fsmap_cmd
);