]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/fsmap.c
xfsprogs: document environment variables
[thirdparty/xfsprogs-dev.git] / io / fsmap.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0+
3fcab549
DW
2/*
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
3fcab549 4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
3fcab549
DW
5 */
6#include "platform_defs.h"
7#include "command.h"
8#include "init.h"
9#include "path.h"
10#include "io.h"
11#include "input.h"
12
13static cmdinfo_t fsmap_cmd;
14static dev_t xfs_data_dev;
15
16static void
17fsmap_help(void)
18{
19 printf(_(
20"\n"
21" Prints the block mapping for the filesystem hosting the current file"
22"\n"
23" fsmap prints the map of disk blocks used by the whole filesystem.\n"
24" When possible, owner and offset information will be included in the\n"
25" space report.\n"
26"\n"
27" By default, each line of the listing takes the following form:\n"
28" extent: major:minor [startblock..endblock]: owner startoffset..endoffset length\n"
29" The owner field is either an inode number or a special value.\n"
30" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
31" -d -- query only the data device (default).\n"
32" -l -- query only the log device.\n"
33" -r -- query only the realtime device.\n"
34" -n -- query n extents at a time.\n"
35" -m -- output machine-readable format.\n"
36" -v -- Verbose information, show AG and offsets. Show flags legend on 2nd -v\n"
2fc6b167
DW
37"\n"
38"The optional start and end arguments require one of -d, -l, or -r to be set.\n"
3fcab549
DW
39"\n"));
40}
41
42#define OWNER_BUF_SZ 32
43static const char *
44special_owner(
45 int64_t owner,
46 char *buf)
47{
48 switch (owner) {
49 case XFS_FMR_OWN_FREE:
50 return _("free space");
51 case XFS_FMR_OWN_UNKNOWN:
52 return _("unknown");
53 case XFS_FMR_OWN_FS:
54 return _("static fs metadata");
55 case XFS_FMR_OWN_LOG:
56 return _("journalling log");
57 case XFS_FMR_OWN_AG:
58 return _("per-AG metadata");
59 case XFS_FMR_OWN_INOBT:
60 return _("inode btree");
61 case XFS_FMR_OWN_INODES:
62 return _("inodes");
63 case XFS_FMR_OWN_REFC:
64 return _("refcount btree");
65 case XFS_FMR_OWN_COW:
66 return _("cow reservation");
67 case XFS_FMR_OWN_DEFECTIVE:
68 return _("defective");
69 default:
70 snprintf(buf, OWNER_BUF_SZ, _("special %u:%u"),
71 FMR_OWNER_TYPE(owner), FMR_OWNER_CODE(owner));
72 return buf;
73 }
74}
75
76static void
77dump_map(
78 unsigned long long *nr,
79 struct fsmap_head *head)
80{
81 unsigned long long i;
82 struct fsmap *p;
83 char owner[OWNER_BUF_SZ];
84 char *fork;
85
86 for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
87 printf("\t%llu: %u:%u [%lld..%lld]: ", i + (*nr),
88 major(p->fmr_device), minor(p->fmr_device),
89 (long long)BTOBBT(p->fmr_physical),
90 (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
91 fork = (p->fmr_flags & FMR_OF_ATTR_FORK) ? _("attr") : _("data");
92 if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
93 printf("%s", special_owner(p->fmr_owner, owner));
94 else if (p->fmr_flags & FMR_OF_EXTENT_MAP)
95 printf(_("inode %lld %s extent map"),
96 (long long) p->fmr_owner, fork);
97 else
98 printf(_("inode %lld %s %lld..%lld"),
99 (long long)p->fmr_owner, fork,
100 (long long)BTOBBT(p->fmr_offset),
101 (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
102 printf(_(" %lld\n"),
103 (long long)BTOBBT(p->fmr_length));
104 }
105
106 (*nr) += head->fmh_entries;
107}
108
109static void
110dump_map_machine(
111 unsigned long long *nr,
112 struct fsmap_head *head)
113{
114 unsigned long long i;
115 struct fsmap *p;
116 char *fork;
117
118 printf(_("EXT,MAJOR,MINOR,PSTART,PEND,OWNER,OSTART,OEND,LENGTH\n"));
119 for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
120 printf("%llu,%u,%u,%lld,%lld,", i + (*nr),
121 major(p->fmr_device), minor(p->fmr_device),
122 (long long)BTOBBT(p->fmr_physical),
123 (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
124 fork = (p->fmr_flags & FMR_OF_ATTR_FORK) ? "attr" : "data";
125 if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
126 printf("special_%u:%u,,,", FMR_OWNER_TYPE(p->fmr_owner),
127 FMR_OWNER_CODE(p->fmr_owner));
128 else if (p->fmr_flags & FMR_OF_EXTENT_MAP)
129 printf(_("inode_%lld_%s_bmbt,,,"),
130 (long long) p->fmr_owner, fork);
131 else
132 printf(_("inode_%lld_%s,%lld,%lld,"),
133 (long long)p->fmr_owner, fork,
134 (long long)BTOBBT(p->fmr_offset),
135 (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
136 printf("%lld\n",
137 (long long)BTOBBT(p->fmr_length));
138 }
139
140 (*nr) += head->fmh_entries;
141}
142
143/*
144 * Verbose mode displays:
145 * extent: major:minor [startblock..endblock]: startoffset..endoffset \
146 * ag# (agoffset..agendoffset) totalbbs flags
147 */
148#define MINRANGE_WIDTH 16
149#define MINAG_WIDTH 2
150#define MINTOT_WIDTH 5
151#define NFLG 7 /* count of flags */
152#define FLG_NULL 00000000 /* Null flag */
153#define FLG_ATTR_FORK 01000000 /* attribute fork */
154#define FLG_SHARED 00100000 /* shared extent */
155#define FLG_PRE 00010000 /* Unwritten extent */
156#define FLG_BSU 00001000 /* Not on begin of stripe unit */
157#define FLG_ESU 00000100 /* Not on end of stripe unit */
158#define FLG_BSW 00000010 /* Not on begin of stripe width */
159#define FLG_ESW 00000001 /* Not on end of stripe width */
160static void
161dump_map_verbose(
162 unsigned long long *nr,
163 struct fsmap_head *head,
164 bool *dumped_flags,
165 struct xfs_fsop_geom *fsgeo)
166{
167 unsigned long long i;
168 struct fsmap *p;
169 int agno;
170 off64_t agoff, bperag;
171 int foff_w, boff_w, aoff_w, tot_w, agno_w, own_w;
172 int nr_w, dev_w;
41198ef1
DC
173 char rbuf[40], bbuf[40], abuf[40], obuf[40];
174 char nbuf[40], dbuf[40], gbuf[40];
3fcab549
DW
175 char owner[OWNER_BUF_SZ];
176 int sunit, swidth;
177 int flg = 0;
178
179 foff_w = boff_w = aoff_w = own_w = MINRANGE_WIDTH;
180 dev_w = 3;
181 nr_w = 4;
182 tot_w = MINTOT_WIDTH;
183 bperag = (off64_t)fsgeo->agblocks *
184 (off64_t)fsgeo->blocksize;
185 sunit = (fsgeo->sunit * fsgeo->blocksize);
186 swidth = (fsgeo->swidth * fsgeo->blocksize);
187
188 /*
189 * Go through the extents and figure out the width
190 * needed for all columns.
191 */
192 for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
193 if (p->fmr_flags & FMR_OF_PREALLOC ||
194 p->fmr_flags & FMR_OF_ATTR_FORK ||
195 p->fmr_flags & FMR_OF_SHARED)
196 flg = 1;
197 if (sunit &&
198 (p->fmr_physical % sunit != 0 ||
199 ((p->fmr_physical + p->fmr_length) % sunit) != 0 ||
200 p->fmr_physical % swidth != 0 ||
201 ((p->fmr_physical + p->fmr_length) % swidth) != 0))
202 flg = 1;
203 if (flg)
204 *dumped_flags = true;
205 snprintf(nbuf, sizeof(nbuf), "%llu", (*nr) + i);
206 nr_w = max(nr_w, strlen(nbuf));
207 if (head->fmh_oflags & FMH_OF_DEV_T)
208 snprintf(dbuf, sizeof(dbuf), "%u:%u",
209 major(p->fmr_device),
210 minor(p->fmr_device));
211 else
212 snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device);
213 dev_w = max(dev_w, strlen(dbuf));
214 snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:",
215 (long long)BTOBBT(p->fmr_physical),
216 (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
217 boff_w = max(boff_w, strlen(bbuf));
218 if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
219 own_w = max(own_w, strlen(
220 special_owner(p->fmr_owner, owner)));
221 else {
222 snprintf(obuf, sizeof(obuf), "%lld",
223 (long long)p->fmr_owner);
224 own_w = max(own_w, strlen(obuf));
225 }
226 if (p->fmr_flags & FMR_OF_EXTENT_MAP)
227 foff_w = max(foff_w, strlen(_("extent_map")));
228 else if (p->fmr_flags & FMR_OF_SPECIAL_OWNER)
229 ;
230 else {
231 snprintf(rbuf, sizeof(rbuf), "%lld..%lld",
232 (long long)BTOBBT(p->fmr_offset),
233 (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
234 foff_w = max(foff_w, strlen(rbuf));
235 }
236 if (p->fmr_device == xfs_data_dev) {
237 agno = p->fmr_physical / bperag;
238 agoff = p->fmr_physical - (agno * bperag);
239 snprintf(abuf, sizeof(abuf),
240 "(%lld..%lld)",
241 (long long)BTOBBT(agoff),
242 (long long)BTOBBT(agoff + p->fmr_length - 1));
243 } else
244 abuf[0] = 0;
245 aoff_w = max(aoff_w, strlen(abuf));
246 tot_w = max(tot_w,
247 numlen(BTOBBT(p->fmr_length), 10));
248 }
249 agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount, 10));
250 if (*nr == 0)
251 printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n",
252 nr_w, _("EXT"),
253 dev_w, _("DEV"),
254 boff_w, _("BLOCK-RANGE"),
255 own_w, _("OWNER"),
256 foff_w, _("FILE-OFFSET"),
257 agno_w, _("AG"),
258 aoff_w, _("AG-OFFSET"),
259 tot_w, _("TOTAL"),
260 flg ? _(" FLAGS") : "");
261 for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
262 flg = FLG_NULL;
263 if (p->fmr_flags & FMR_OF_PREALLOC)
264 flg |= FLG_PRE;
265 if (p->fmr_flags & FMR_OF_ATTR_FORK)
266 flg |= FLG_ATTR_FORK;
267 if (p->fmr_flags & FMR_OF_SHARED)
268 flg |= FLG_SHARED;
269 /*
270 * If striping enabled, determine if extent starts/ends
271 * on a stripe unit boundary.
272 */
273 if (sunit) {
274 if (p->fmr_physical % sunit != 0)
275 flg |= FLG_BSU;
276 if (((p->fmr_physical +
277 p->fmr_length ) % sunit ) != 0)
278 flg |= FLG_ESU;
279 if (p->fmr_physical % swidth != 0)
280 flg |= FLG_BSW;
281 if (((p->fmr_physical +
282 p->fmr_length ) % swidth ) != 0)
283 flg |= FLG_ESW;
284 }
285 if (head->fmh_oflags & FMH_OF_DEV_T)
286 snprintf(dbuf, sizeof(dbuf), "%u:%u",
287 major(p->fmr_device),
288 minor(p->fmr_device));
289 else
290 snprintf(dbuf, sizeof(dbuf), "0x%x", p->fmr_device);
291 snprintf(bbuf, sizeof(bbuf), "[%lld..%lld]:",
292 (long long)BTOBBT(p->fmr_physical),
293 (long long)BTOBBT(p->fmr_physical + p->fmr_length - 1));
294 if (p->fmr_flags & FMR_OF_SPECIAL_OWNER) {
295 snprintf(obuf, sizeof(obuf), "%s",
296 special_owner(p->fmr_owner, owner));
297 snprintf(rbuf, sizeof(rbuf), " ");
298 } else {
299 snprintf(obuf, sizeof(obuf), "%lld",
300 (long long)p->fmr_owner);
301 snprintf(rbuf, sizeof(rbuf), "%lld..%lld",
302 (long long)BTOBBT(p->fmr_offset),
303 (long long)BTOBBT(p->fmr_offset + p->fmr_length - 1));
304 }
305 if (p->fmr_device == xfs_data_dev) {
306 agno = p->fmr_physical / bperag;
307 agoff = p->fmr_physical - (agno * bperag);
308 snprintf(abuf, sizeof(abuf),
309 "(%lld..%lld)",
310 (long long)BTOBBT(agoff),
311 (long long)BTOBBT(agoff + p->fmr_length - 1));
312 snprintf(gbuf, sizeof(gbuf),
313 "%lld",
314 (long long)agno);
315 } else {
316 abuf[0] = 0;
317 gbuf[0] = 0;
318 }
319 if (p->fmr_flags & FMR_OF_EXTENT_MAP)
320 printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n",
321 nr_w, (*nr) + i,
322 dev_w, dbuf,
323 boff_w, bbuf,
324 own_w, obuf,
325 foff_w, _("extent map"),
326 agno_w, gbuf,
327 aoff_w, abuf,
328 tot_w, (long long)BTOBBT(p->fmr_length));
329 else {
330 printf("%*llu: %-*s %-*s %-*s %-*s", nr_w, (*nr) + i,
331 dev_w, dbuf, boff_w, bbuf, own_w, obuf,
332 foff_w, rbuf);
333 printf(" %-*s %-*s", agno_w, gbuf,
334 aoff_w, abuf);
335 printf(" %*lld", tot_w,
336 (long long)BTOBBT(p->fmr_length));
337 if (flg == FLG_NULL)
338 printf("\n");
339 else
340 printf(" %-*.*o\n", NFLG, NFLG, flg);
341 }
342 }
343
344 (*nr) += head->fmh_entries;
345}
346
347static void
348dump_verbose_key(void)
349{
350 printf(_(" FLAG Values:\n"));
351 printf(_(" %*.*o Attribute fork\n"),
352 NFLG+1, NFLG+1, FLG_ATTR_FORK);
353 printf(_(" %*.*o Shared extent\n"),
354 NFLG+1, NFLG+1, FLG_SHARED);
355 printf(_(" %*.*o Unwritten preallocated extent\n"),
356 NFLG+1, NFLG+1, FLG_PRE);
357 printf(_(" %*.*o Doesn't begin on stripe unit\n"),
358 NFLG+1, NFLG+1, FLG_BSU);
359 printf(_(" %*.*o Doesn't end on stripe unit\n"),
360 NFLG+1, NFLG+1, FLG_ESU);
361 printf(_(" %*.*o Doesn't begin on stripe width\n"),
362 NFLG+1, NFLG+1, FLG_BSW);
363 printf(_(" %*.*o Doesn't end on stripe width\n"),
364 NFLG+1, NFLG+1, FLG_ESW);
365}
366
367int
368fsmap_f(
369 int argc,
370 char **argv)
371{
372 struct fsmap *p;
373 struct fsmap_head *nhead;
374 struct fsmap_head *head;
375 struct fsmap *l, *h;
376 struct xfs_fsop_geom fsgeo;
377 long long start = 0;
378 long long end = -1;
379 int nmap_size;
380 int map_size;
381 int nflag = 0;
382 int vflag = 0;
383 int mflag = 0;
384 int i = 0;
385 int c;
386 unsigned long long nr = 0;
387 size_t fsblocksize, fssectsize;
388 struct fs_path *fs;
389 static bool tab_init;
390 bool dumped_flags = false;
391 int dflag, lflag, rflag;
392
393 init_cvtnum(&fsblocksize, &fssectsize);
394
395 dflag = lflag = rflag = 0;
396 while ((c = getopt(argc, argv, "dlmn:rv")) != EOF) {
397 switch (c) {
398 case 'd': /* data device */
399 dflag = 1;
400 break;
401 case 'l': /* log device */
402 lflag = 1;
403 break;
404 case 'm': /* machine readable format */
405 mflag++;
406 break;
407 case 'n': /* number of extents specified */
408 nflag = cvt_u32(optarg, 10);
409 if (errno)
410 return command_usage(&fsmap_cmd);
411 break;
412 case 'r': /* rt device */
413 rflag = 1;
414 break;
415 case 'v': /* Verbose output */
416 vflag++;
417 break;
418 default:
419 return command_usage(&fsmap_cmd);
420 }
421 }
422
423 if ((dflag + lflag + rflag > 1) || (mflag > 0 && vflag > 0) ||
424 (argc > optind && dflag + lflag + rflag == 0))
425 return command_usage(&fsmap_cmd);
426
427 if (argc > optind) {
428 start = cvtnum(fsblocksize, fssectsize, argv[optind]);
429 if (start < 0) {
430 fprintf(stderr,
431 _("Bad rmap start_bblock %s.\n"),
432 argv[optind]);
433 return 0;
434 }
435 start <<= BBSHIFT;
436 }
437
438 if (argc > optind + 1) {
439 end = cvtnum(fsblocksize, fssectsize, argv[optind + 1]);
440 if (end < 0) {
441 fprintf(stderr,
442 _("Bad rmap end_bblock %s.\n"),
443 argv[optind + 1]);
444 return 0;
445 }
446 end <<= BBSHIFT;
447 }
448
449 if (vflag) {
450 c = ioctl(file->fd, XFS_IOC_FSGEOMETRY, &fsgeo);
451 if (c < 0) {
452 fprintf(stderr,
453 _("%s: can't get geometry [\"%s\"]: %s\n"),
454 progname, file->name, strerror(errno));
455 exitcode = 1;
456 return 0;
457 }
458 }
459
460 map_size = nflag ? nflag : 131072 / sizeof(struct fsmap);
461 head = malloc(fsmap_sizeof(map_size));
462 if (head == NULL) {
463 fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"),
464 progname, fsmap_sizeof(map_size));
465 exitcode = 1;
466 return 0;
467 }
468
469 memset(head, 0, sizeof(*head));
470 l = head->fmh_keys;
471 h = head->fmh_keys + 1;
472 if (dflag) {
473 l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
474 } else if (lflag) {
475 l->fmr_device = h->fmr_device = file->fs_path.fs_logdev;
476 } else if (rflag) {
477 l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
478 } else {
479 l->fmr_device = 0;
480 h->fmr_device = UINT_MAX;
481 }
482 l->fmr_physical = start;
483 h->fmr_physical = end;
484 h->fmr_owner = ULLONG_MAX;
485 h->fmr_flags = UINT_MAX;
486 h->fmr_offset = ULLONG_MAX;
487
488 /* Count mappings */
489 if (!nflag) {
490 head->fmh_count = 0;
491 i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
492 if (i < 0) {
493 fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
494 " iflags=0x%x [\"%s\"]: %s\n"),
495 progname, head->fmh_iflags, file->name,
496 strerror(errno));
497 free(head);
498 exitcode = 1;
499 return 0;
500 }
501 if (head->fmh_entries > map_size + 2) {
502 map_size = 11ULL * head->fmh_entries / 10;
503 nmap_size = map_size > (1 << 24) ? (1 << 24) : map_size;
504 nhead = realloc(head, fsmap_sizeof(nmap_size));
505 if (nhead == NULL) {
506 fprintf(stderr,
507 _("%s: cannot realloc %zu bytes\n"),
508 progname, fsmap_sizeof(nmap_size));
509 } else {
510 head = nhead;
511 map_size = nmap_size;
512 }
513 }
514 }
515
516 /*
517 * If this is an XFS filesystem, remember the data device.
518 * (We report AG number/block for data device extents on XFS).
519 */
520 if (!tab_init) {
521 fs_table_initialise(0, NULL, 0, NULL);
522 tab_init = true;
523 }
524 fs = fs_table_lookup(file->name, FS_MOUNT_POINT);
525 xfs_data_dev = fs ? fs->fs_datadev : 0;
526
527 head->fmh_count = map_size;
528 do {
529 /* Get some extents */
530 i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
531 if (i < 0) {
532 fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
533 " iflags=0x%x [\"%s\"]: %s\n"),
534 progname, head->fmh_iflags, file->name,
535 strerror(errno));
536 free(head);
537 exitcode = 1;
538 return 0;
539 }
540
541 if (head->fmh_entries == 0)
542 break;
543
544 if (vflag)
545 dump_map_verbose(&nr, head, &dumped_flags, &fsgeo);
546 else if (mflag)
547 dump_map_machine(&nr, head);
548 else
549 dump_map(&nr, head);
550
551 p = &head->fmh_recs[head->fmh_entries - 1];
552 if (p->fmr_flags & FMR_OF_LAST)
553 break;
554 fsmap_advance(head);
555 } while (true);
556
557 if (dumped_flags)
558 dump_verbose_key();
559
560 free(head);
561 return 0;
562}
563
564void
565fsmap_init(void)
566{
567 fsmap_cmd.name = "fsmap";
568 fsmap_cmd.cfunc = fsmap_f;
569 fsmap_cmd.argmin = 0;
570 fsmap_cmd.argmax = -1;
571 fsmap_cmd.flags = CMD_NOMAP_OK | CMD_FLAG_FOREIGN_OK;
572 fsmap_cmd.args = _("[-d|-l|-r] [-m|-v] [-n nx] [start] [end]");
573 fsmap_cmd.oneline = _("print filesystem mapping for a range of blocks");
574 fsmap_cmd.help = fsmap_help;
575
576 add_command(&fsmap_cmd);
577}