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