]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/fsmap.c
xfs: convert to new timestamp accessors
[thirdparty/xfsprogs-dev.git] / io / fsmap.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 */
6 #include "platform_defs.h"
7 #include <linux/fsmap.h>
8 #include "command.h"
9 #include "init.h"
10 #include "libfrog/paths.h"
11 #include "io.h"
12 #include "input.h"
13 #include "libfrog/fsgeom.h"
14
15 static cmdinfo_t fsmap_cmd;
16 static dev_t xfs_data_dev;
17
18 static void
19 fsmap_help(void)
20 {
21 printf(_(
22 "\n"
23 " Prints the block mapping for the filesystem hosting the current file"
24 "\n"
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"
27 " space report.\n"
28 "\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"
39 "\n"
40 "The optional start and end arguments require one of -d, -l, or -r to be set.\n"
41 "\n"));
42 }
43
44 #define OWNER_BUF_SZ 32
45 static const char *
46 special_owner(
47 int64_t owner,
48 char *buf)
49 {
50 switch (owner) {
51 case XFS_FMR_OWN_FREE:
52 return _("free space");
53 case XFS_FMR_OWN_UNKNOWN:
54 return _("unknown");
55 case XFS_FMR_OWN_FS:
56 return _("static fs metadata");
57 case XFS_FMR_OWN_LOG:
58 return _("journalling log");
59 case XFS_FMR_OWN_AG:
60 return _("per-AG metadata");
61 case XFS_FMR_OWN_INOBT:
62 return _("inode btree");
63 case XFS_FMR_OWN_INODES:
64 return _("inodes");
65 case XFS_FMR_OWN_REFC:
66 return _("refcount btree");
67 case XFS_FMR_OWN_COW:
68 return _("cow reservation");
69 case XFS_FMR_OWN_DEFECTIVE:
70 return _("defective");
71 default:
72 snprintf(buf, OWNER_BUF_SZ, _("special %u:%u"),
73 FMR_OWNER_TYPE(owner), FMR_OWNER_CODE(owner));
74 return buf;
75 }
76 }
77
78 static void
79 dump_map(
80 unsigned long long *nr,
81 struct fsmap_head *head)
82 {
83 unsigned long long i;
84 struct fsmap *p;
85 char owner[OWNER_BUF_SZ];
86 char *fork;
87
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);
99 else
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));
104 printf(_(" %lld\n"),
105 (long long)BTOBBT(p->fmr_length));
106 }
107
108 (*nr) += head->fmh_entries;
109 }
110
111 static void
112 dump_map_machine(
113 unsigned long long *nr,
114 struct fsmap_head *head)
115 {
116 unsigned long long i;
117 struct fsmap *p;
118 char *fork;
119
120 if (*nr == 0)
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);
134 else
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));
139 printf("%lld\n",
140 (long long)BTOBBT(p->fmr_length));
141 }
142
143 (*nr) += head->fmh_entries;
144 }
145
146 /*
147 * Verbose mode displays:
148 * extent: major:minor [startblock..endblock]: startoffset..endoffset \
149 * ag# (agoffset..agendoffset) totalbbs flags
150 */
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 */
163 static void
164 dump_map_verbose(
165 unsigned long long *nr,
166 struct fsmap_head *head,
167 bool *dumped_flags,
168 struct xfs_fsop_geom *fsgeo)
169 {
170 unsigned long long i;
171 struct fsmap *p;
172 int agno;
173 off64_t agoff, bperag;
174 int foff_w, boff_w, aoff_w, tot_w, agno_w, own_w;
175 int nr_w, dev_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];
179 int sunit, swidth;
180 int flg = 0;
181
182 foff_w = boff_w = aoff_w = own_w = MINRANGE_WIDTH;
183 dev_w = 3;
184 nr_w = 4;
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);
190
191 /*
192 * Go through the extents and figure out the width
193 * needed for all columns.
194 */
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)
199 flg = 1;
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))
205 flg = 1;
206 if (flg)
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));
214 else
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)));
224 else {
225 snprintf(obuf, sizeof(obuf), "%lld",
226 (long long)p->fmr_owner);
227 own_w = max(own_w, strlen(obuf));
228 }
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)
232 ;
233 else {
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));
238 }
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),
243 "(%lld..%lld)",
244 (long long)BTOBBT(agoff),
245 (long long)BTOBBT(agoff + p->fmr_length - 1));
246 } else
247 abuf[0] = 0;
248 aoff_w = max(aoff_w, strlen(abuf));
249 tot_w = max(tot_w,
250 numlen(BTOBBT(p->fmr_length), 10));
251 }
252 agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount, 10));
253 if (*nr == 0)
254 printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n",
255 nr_w, _("EXT"),
256 dev_w, _("DEV"),
257 boff_w, _("BLOCK-RANGE"),
258 own_w, _("OWNER"),
259 foff_w, _("FILE-OFFSET"),
260 agno_w, _("AG"),
261 aoff_w, _("AG-OFFSET"),
262 tot_w, _("TOTAL"),
263 flg ? _(" FLAGS") : "");
264 for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) {
265 flg = FLG_NULL;
266 if (p->fmr_flags & FMR_OF_PREALLOC)
267 flg |= FLG_PRE;
268 if (p->fmr_flags & FMR_OF_ATTR_FORK)
269 flg |= FLG_ATTR_FORK;
270 if (p->fmr_flags & FMR_OF_SHARED)
271 flg |= FLG_SHARED;
272 /*
273 * If striping enabled, determine if extent starts/ends
274 * on a stripe unit boundary.
275 */
276 if (sunit && p->fmr_device == xfs_data_dev) {
277 if (p->fmr_physical % sunit != 0)
278 flg |= FLG_BSU;
279 if (((p->fmr_physical +
280 p->fmr_length ) % sunit ) != 0)
281 flg |= FLG_ESU;
282 if (p->fmr_physical % swidth != 0)
283 flg |= FLG_BSW;
284 if (((p->fmr_physical +
285 p->fmr_length ) % swidth ) != 0)
286 flg |= FLG_ESW;
287 }
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));
292 else
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), " ");
301 } else {
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));
307 }
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),
312 "(%lld..%lld)",
313 (long long)BTOBBT(agoff),
314 (long long)BTOBBT(agoff + p->fmr_length - 1));
315 snprintf(gbuf, sizeof(gbuf),
316 "%lld",
317 (long long)agno);
318 } else {
319 abuf[0] = 0;
320 gbuf[0] = 0;
321 }
322 if (p->fmr_flags & FMR_OF_EXTENT_MAP)
323 printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n",
324 nr_w, (*nr) + i,
325 dev_w, dbuf,
326 boff_w, bbuf,
327 own_w, obuf,
328 foff_w, _("extent map"),
329 agno_w, gbuf,
330 aoff_w, abuf,
331 tot_w, (long long)BTOBBT(p->fmr_length));
332 else {
333 printf("%*llu: %-*s %-*s %-*s %-*s", nr_w, (*nr) + i,
334 dev_w, dbuf, boff_w, bbuf, own_w, obuf,
335 foff_w, rbuf);
336 printf(" %-*s %-*s", agno_w, gbuf,
337 aoff_w, abuf);
338 printf(" %*lld", tot_w,
339 (long long)BTOBBT(p->fmr_length));
340 if (flg == FLG_NULL)
341 printf("\n");
342 else
343 printf(" %-*.*o\n", NFLG, NFLG, flg);
344 }
345 }
346
347 (*nr) += head->fmh_entries;
348 }
349
350 static void
351 dump_verbose_key(void)
352 {
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);
368 }
369
370 static int
371 fsmap_f(
372 int argc,
373 char **argv)
374 {
375 struct fsmap *p;
376 struct fsmap_head *head;
377 struct fsmap *l, *h;
378 struct xfs_fsop_geom fsgeo;
379 long long start = 0;
380 long long end = -1;
381 int map_size;
382 int nflag = 0;
383 int vflag = 0;
384 int mflag = 0;
385 int i = 0;
386 int c;
387 unsigned long long nr = 0;
388 size_t fsblocksize, fssectsize;
389 struct fs_path *fs;
390 static bool tab_init;
391 bool dumped_flags = false;
392 int dflag, lflag, rflag;
393
394 init_cvtnum(&fsblocksize, &fssectsize);
395
396 dflag = lflag = rflag = 0;
397 while ((c = getopt(argc, argv, "dlmn:rv")) != EOF) {
398 switch (c) {
399 case 'd': /* data device */
400 dflag = 1;
401 break;
402 case 'l': /* log device */
403 lflag = 1;
404 break;
405 case 'm': /* machine readable format */
406 mflag++;
407 break;
408 case 'n': /* number of extents specified */
409 nflag = cvt_u32(optarg, 10);
410 if (errno)
411 return command_usage(&fsmap_cmd);
412 break;
413 case 'r': /* rt device */
414 rflag = 1;
415 break;
416 case 'v': /* Verbose output */
417 vflag++;
418 break;
419 default:
420 exitcode = 1;
421 return command_usage(&fsmap_cmd);
422 }
423 }
424
425 if ((dflag + lflag + rflag > 1) || (mflag > 0 && vflag > 0) ||
426 (argc > optind && dflag + lflag + rflag == 0)) {
427 exitcode = 1;
428 return command_usage(&fsmap_cmd);
429 }
430
431 if (argc > optind) {
432 start = cvtnum(fsblocksize, fssectsize, argv[optind]);
433 if (start < 0) {
434 fprintf(stderr,
435 _("Bad rmap start_bblock %s.\n"),
436 argv[optind]);
437 exitcode = 1;
438 return 0;
439 }
440 start <<= BBSHIFT;
441 }
442
443 if (argc > optind + 1) {
444 end = cvtnum(fsblocksize, fssectsize, argv[optind + 1]);
445 if (end < 0) {
446 fprintf(stderr,
447 _("Bad rmap end_bblock %s.\n"),
448 argv[optind + 1]);
449 exitcode = 1;
450 return 0;
451 }
452 end <<= BBSHIFT;
453 }
454
455 if (vflag) {
456 c = -xfrog_geometry(file->fd, &fsgeo);
457 if (c) {
458 fprintf(stderr,
459 _("%s: can't get geometry [\"%s\"]: %s\n"),
460 progname, file->name, strerror(c));
461 exitcode = 1;
462 return 0;
463 }
464 }
465
466 map_size = nflag ? nflag : 131072 / sizeof(struct fsmap);
467 head = malloc(fsmap_sizeof(map_size));
468 if (head == NULL) {
469 fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"),
470 progname, fsmap_sizeof(map_size));
471 exitcode = 1;
472 return 0;
473 }
474
475 memset(head, 0, sizeof(*head));
476 l = head->fmh_keys;
477 h = head->fmh_keys + 1;
478 if (dflag) {
479 l->fmr_device = h->fmr_device = file->fs_path.fs_datadev;
480 } else if (lflag) {
481 l->fmr_device = h->fmr_device = file->fs_path.fs_logdev;
482 } else if (rflag) {
483 l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev;
484 } else {
485 l->fmr_device = 0;
486 h->fmr_device = UINT_MAX;
487 }
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;
493
494 /*
495 * If this is an XFS filesystem, remember the data device.
496 * (We report AG number/block for data device extents on XFS).
497 */
498 if (!tab_init) {
499 fs_table_initialise(0, NULL, 0, NULL);
500 tab_init = true;
501 }
502 fs = fs_table_lookup(file->name, FS_MOUNT_POINT);
503 xfs_data_dev = fs ? fs->fs_datadev : 0;
504
505 head->fmh_count = map_size;
506 do {
507 /* Get some extents */
508 i = ioctl(file->fd, FS_IOC_GETFSMAP, head);
509 if (i < 0) {
510 fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)"
511 " iflags=0x%x [\"%s\"]: %s\n"),
512 progname, head->fmh_iflags, file->name,
513 strerror(errno));
514 free(head);
515 exitcode = 1;
516 return 0;
517 }
518
519 if (head->fmh_entries == 0)
520 break;
521
522 if (vflag)
523 dump_map_verbose(&nr, head, &dumped_flags, &fsgeo);
524 else if (mflag)
525 dump_map_machine(&nr, head);
526 else
527 dump_map(&nr, head);
528
529 p = &head->fmh_recs[head->fmh_entries - 1];
530 if (p->fmr_flags & FMR_OF_LAST)
531 break;
532 fsmap_advance(head);
533 } while (true);
534
535 if (dumped_flags)
536 dump_verbose_key();
537
538 free(head);
539 return 0;
540 }
541
542 void
543 fsmap_init(void)
544 {
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;
553
554 add_command(&fsmap_cmd);
555 }