]>
Commit | Line | Data |
---|---|---|
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" | |
42b4c8e8 | 9 | #include "libfrog/paths.h" |
3fcab549 DW |
10 | #include "io.h" |
11 | #include "input.h" | |
fee68490 | 12 | #include "libfrog/fsgeom.h" |
3fcab549 DW |
13 | |
14 | static cmdinfo_t fsmap_cmd; | |
15 | static dev_t xfs_data_dev; | |
16 | ||
17 | static void | |
18 | fsmap_help(void) | |
19 | { | |
20 | printf(_( | |
21 | "\n" | |
22 | " Prints the block mapping for the filesystem hosting the current file" | |
23 | "\n" | |
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" | |
26 | " space report.\n" | |
27 | "\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" | |
2fc6b167 DW |
38 | "\n" |
39 | "The optional start and end arguments require one of -d, -l, or -r to be set.\n" | |
3fcab549 DW |
40 | "\n")); |
41 | } | |
42 | ||
43 | #define OWNER_BUF_SZ 32 | |
44 | static const char * | |
45 | special_owner( | |
46 | int64_t owner, | |
47 | char *buf) | |
48 | { | |
49 | switch (owner) { | |
50 | case XFS_FMR_OWN_FREE: | |
51 | return _("free space"); | |
52 | case XFS_FMR_OWN_UNKNOWN: | |
53 | return _("unknown"); | |
54 | case XFS_FMR_OWN_FS: | |
55 | return _("static fs metadata"); | |
56 | case XFS_FMR_OWN_LOG: | |
57 | return _("journalling log"); | |
58 | case XFS_FMR_OWN_AG: | |
59 | return _("per-AG metadata"); | |
60 | case XFS_FMR_OWN_INOBT: | |
61 | return _("inode btree"); | |
62 | case XFS_FMR_OWN_INODES: | |
63 | return _("inodes"); | |
64 | case XFS_FMR_OWN_REFC: | |
65 | return _("refcount btree"); | |
66 | case XFS_FMR_OWN_COW: | |
67 | return _("cow reservation"); | |
68 | case XFS_FMR_OWN_DEFECTIVE: | |
69 | return _("defective"); | |
70 | default: | |
71 | snprintf(buf, OWNER_BUF_SZ, _("special %u:%u"), | |
72 | FMR_OWNER_TYPE(owner), FMR_OWNER_CODE(owner)); | |
73 | return buf; | |
74 | } | |
75 | } | |
76 | ||
77 | static void | |
78 | dump_map( | |
79 | unsigned long long *nr, | |
80 | struct fsmap_head *head) | |
81 | { | |
82 | unsigned long long i; | |
83 | struct fsmap *p; | |
84 | char owner[OWNER_BUF_SZ]; | |
85 | char *fork; | |
86 | ||
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); | |
98 | else | |
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)); | |
103 | printf(_(" %lld\n"), | |
104 | (long long)BTOBBT(p->fmr_length)); | |
105 | } | |
106 | ||
107 | (*nr) += head->fmh_entries; | |
108 | } | |
109 | ||
110 | static void | |
111 | dump_map_machine( | |
112 | unsigned long long *nr, | |
113 | struct fsmap_head *head) | |
114 | { | |
115 | unsigned long long i; | |
116 | struct fsmap *p; | |
117 | char *fork; | |
118 | ||
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); | |
132 | else | |
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)); | |
137 | printf("%lld\n", | |
138 | (long long)BTOBBT(p->fmr_length)); | |
139 | } | |
140 | ||
141 | (*nr) += head->fmh_entries; | |
142 | } | |
143 | ||
144 | /* | |
145 | * Verbose mode displays: | |
146 | * extent: major:minor [startblock..endblock]: startoffset..endoffset \ | |
147 | * ag# (agoffset..agendoffset) totalbbs flags | |
148 | */ | |
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 */ | |
161 | static void | |
162 | dump_map_verbose( | |
163 | unsigned long long *nr, | |
164 | struct fsmap_head *head, | |
165 | bool *dumped_flags, | |
166 | struct xfs_fsop_geom *fsgeo) | |
167 | { | |
168 | unsigned long long i; | |
169 | struct fsmap *p; | |
170 | int agno; | |
171 | off64_t agoff, bperag; | |
172 | int foff_w, boff_w, aoff_w, tot_w, agno_w, own_w; | |
173 | int nr_w, dev_w; | |
41198ef1 DC |
174 | char rbuf[40], bbuf[40], abuf[40], obuf[40]; |
175 | char nbuf[40], dbuf[40], gbuf[40]; | |
3fcab549 DW |
176 | char owner[OWNER_BUF_SZ]; |
177 | int sunit, swidth; | |
178 | int flg = 0; | |
179 | ||
180 | foff_w = boff_w = aoff_w = own_w = MINRANGE_WIDTH; | |
181 | dev_w = 3; | |
182 | nr_w = 4; | |
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); | |
188 | ||
189 | /* | |
190 | * Go through the extents and figure out the width | |
191 | * needed for all columns. | |
192 | */ | |
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) | |
197 | flg = 1; | |
198 | if (sunit && | |
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)) | |
203 | flg = 1; | |
204 | if (flg) | |
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)); | |
212 | else | |
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))); | |
222 | else { | |
223 | snprintf(obuf, sizeof(obuf), "%lld", | |
224 | (long long)p->fmr_owner); | |
225 | own_w = max(own_w, strlen(obuf)); | |
226 | } | |
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) | |
230 | ; | |
231 | else { | |
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)); | |
236 | } | |
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), | |
241 | "(%lld..%lld)", | |
242 | (long long)BTOBBT(agoff), | |
243 | (long long)BTOBBT(agoff + p->fmr_length - 1)); | |
244 | } else | |
245 | abuf[0] = 0; | |
246 | aoff_w = max(aoff_w, strlen(abuf)); | |
247 | tot_w = max(tot_w, | |
248 | numlen(BTOBBT(p->fmr_length), 10)); | |
249 | } | |
250 | agno_w = max(MINAG_WIDTH, numlen(fsgeo->agcount, 10)); | |
251 | if (*nr == 0) | |
252 | printf("%*s: %-*s %-*s %-*s %-*s %*s %-*s %*s%s\n", | |
253 | nr_w, _("EXT"), | |
254 | dev_w, _("DEV"), | |
255 | boff_w, _("BLOCK-RANGE"), | |
256 | own_w, _("OWNER"), | |
257 | foff_w, _("FILE-OFFSET"), | |
258 | agno_w, _("AG"), | |
259 | aoff_w, _("AG-OFFSET"), | |
260 | tot_w, _("TOTAL"), | |
261 | flg ? _(" FLAGS") : ""); | |
262 | for (i = 0, p = head->fmh_recs; i < head->fmh_entries; i++, p++) { | |
263 | flg = FLG_NULL; | |
264 | if (p->fmr_flags & FMR_OF_PREALLOC) | |
265 | flg |= FLG_PRE; | |
266 | if (p->fmr_flags & FMR_OF_ATTR_FORK) | |
267 | flg |= FLG_ATTR_FORK; | |
268 | if (p->fmr_flags & FMR_OF_SHARED) | |
269 | flg |= FLG_SHARED; | |
270 | /* | |
271 | * If striping enabled, determine if extent starts/ends | |
272 | * on a stripe unit boundary. | |
273 | */ | |
274 | if (sunit) { | |
275 | if (p->fmr_physical % sunit != 0) | |
276 | flg |= FLG_BSU; | |
277 | if (((p->fmr_physical + | |
278 | p->fmr_length ) % sunit ) != 0) | |
279 | flg |= FLG_ESU; | |
280 | if (p->fmr_physical % swidth != 0) | |
281 | flg |= FLG_BSW; | |
282 | if (((p->fmr_physical + | |
283 | p->fmr_length ) % swidth ) != 0) | |
284 | flg |= FLG_ESW; | |
285 | } | |
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)); | |
290 | else | |
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), " "); | |
299 | } else { | |
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)); | |
305 | } | |
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), | |
310 | "(%lld..%lld)", | |
311 | (long long)BTOBBT(agoff), | |
312 | (long long)BTOBBT(agoff + p->fmr_length - 1)); | |
313 | snprintf(gbuf, sizeof(gbuf), | |
314 | "%lld", | |
315 | (long long)agno); | |
316 | } else { | |
317 | abuf[0] = 0; | |
318 | gbuf[0] = 0; | |
319 | } | |
320 | if (p->fmr_flags & FMR_OF_EXTENT_MAP) | |
321 | printf("%*llu: %-*s %-*s %-*s %-*s %-*s %-*s %*lld\n", | |
322 | nr_w, (*nr) + i, | |
323 | dev_w, dbuf, | |
324 | boff_w, bbuf, | |
325 | own_w, obuf, | |
326 | foff_w, _("extent map"), | |
327 | agno_w, gbuf, | |
328 | aoff_w, abuf, | |
329 | tot_w, (long long)BTOBBT(p->fmr_length)); | |
330 | else { | |
331 | printf("%*llu: %-*s %-*s %-*s %-*s", nr_w, (*nr) + i, | |
332 | dev_w, dbuf, boff_w, bbuf, own_w, obuf, | |
333 | foff_w, rbuf); | |
334 | printf(" %-*s %-*s", agno_w, gbuf, | |
335 | aoff_w, abuf); | |
336 | printf(" %*lld", tot_w, | |
337 | (long long)BTOBBT(p->fmr_length)); | |
338 | if (flg == FLG_NULL) | |
339 | printf("\n"); | |
340 | else | |
341 | printf(" %-*.*o\n", NFLG, NFLG, flg); | |
342 | } | |
343 | } | |
344 | ||
345 | (*nr) += head->fmh_entries; | |
346 | } | |
347 | ||
348 | static void | |
349 | dump_verbose_key(void) | |
350 | { | |
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); | |
366 | } | |
367 | ||
00ff2b10 | 368 | static int |
3fcab549 DW |
369 | fsmap_f( |
370 | int argc, | |
371 | char **argv) | |
372 | { | |
373 | struct fsmap *p; | |
374 | struct fsmap_head *nhead; | |
375 | struct fsmap_head *head; | |
376 | struct fsmap *l, *h; | |
377 | struct xfs_fsop_geom fsgeo; | |
378 | long long start = 0; | |
379 | long long end = -1; | |
380 | int nmap_size; | |
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 | return command_usage(&fsmap_cmd); | |
421 | } | |
422 | } | |
423 | ||
424 | if ((dflag + lflag + rflag > 1) || (mflag > 0 && vflag > 0) || | |
425 | (argc > optind && dflag + lflag + rflag == 0)) | |
426 | return command_usage(&fsmap_cmd); | |
427 | ||
428 | if (argc > optind) { | |
429 | start = cvtnum(fsblocksize, fssectsize, argv[optind]); | |
430 | if (start < 0) { | |
431 | fprintf(stderr, | |
432 | _("Bad rmap start_bblock %s.\n"), | |
433 | argv[optind]); | |
434 | return 0; | |
435 | } | |
436 | start <<= BBSHIFT; | |
437 | } | |
438 | ||
439 | if (argc > optind + 1) { | |
440 | end = cvtnum(fsblocksize, fssectsize, argv[optind + 1]); | |
441 | if (end < 0) { | |
442 | fprintf(stderr, | |
443 | _("Bad rmap end_bblock %s.\n"), | |
444 | argv[optind + 1]); | |
445 | return 0; | |
446 | } | |
447 | end <<= BBSHIFT; | |
448 | } | |
449 | ||
450 | if (vflag) { | |
03d96c64 | 451 | c = -xfrog_geometry(file->fd, &fsgeo); |
9612817d | 452 | if (c) { |
3fcab549 DW |
453 | fprintf(stderr, |
454 | _("%s: can't get geometry [\"%s\"]: %s\n"), | |
03d96c64 | 455 | progname, file->name, strerror(c)); |
3fcab549 DW |
456 | exitcode = 1; |
457 | return 0; | |
458 | } | |
459 | } | |
460 | ||
461 | map_size = nflag ? nflag : 131072 / sizeof(struct fsmap); | |
462 | head = malloc(fsmap_sizeof(map_size)); | |
463 | if (head == NULL) { | |
464 | fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"), | |
465 | progname, fsmap_sizeof(map_size)); | |
466 | exitcode = 1; | |
467 | return 0; | |
468 | } | |
469 | ||
470 | memset(head, 0, sizeof(*head)); | |
471 | l = head->fmh_keys; | |
472 | h = head->fmh_keys + 1; | |
473 | if (dflag) { | |
474 | l->fmr_device = h->fmr_device = file->fs_path.fs_datadev; | |
475 | } else if (lflag) { | |
476 | l->fmr_device = h->fmr_device = file->fs_path.fs_logdev; | |
477 | } else if (rflag) { | |
478 | l->fmr_device = h->fmr_device = file->fs_path.fs_rtdev; | |
479 | } else { | |
480 | l->fmr_device = 0; | |
481 | h->fmr_device = UINT_MAX; | |
482 | } | |
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; | |
488 | ||
489 | /* Count mappings */ | |
490 | if (!nflag) { | |
491 | head->fmh_count = 0; | |
492 | i = ioctl(file->fd, FS_IOC_GETFSMAP, head); | |
493 | if (i < 0) { | |
494 | fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)" | |
495 | " iflags=0x%x [\"%s\"]: %s\n"), | |
496 | progname, head->fmh_iflags, file->name, | |
497 | strerror(errno)); | |
498 | free(head); | |
499 | exitcode = 1; | |
500 | return 0; | |
501 | } | |
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)); | |
506 | if (nhead == NULL) { | |
507 | fprintf(stderr, | |
508 | _("%s: cannot realloc %zu bytes\n"), | |
509 | progname, fsmap_sizeof(nmap_size)); | |
510 | } else { | |
511 | head = nhead; | |
512 | map_size = nmap_size; | |
513 | } | |
514 | } | |
515 | } | |
516 | ||
517 | /* | |
518 | * If this is an XFS filesystem, remember the data device. | |
519 | * (We report AG number/block for data device extents on XFS). | |
520 | */ | |
521 | if (!tab_init) { | |
522 | fs_table_initialise(0, NULL, 0, NULL); | |
523 | tab_init = true; | |
524 | } | |
525 | fs = fs_table_lookup(file->name, FS_MOUNT_POINT); | |
526 | xfs_data_dev = fs ? fs->fs_datadev : 0; | |
527 | ||
528 | head->fmh_count = map_size; | |
529 | do { | |
530 | /* Get some extents */ | |
531 | i = ioctl(file->fd, FS_IOC_GETFSMAP, head); | |
532 | if (i < 0) { | |
533 | fprintf(stderr, _("%s: xfsctl(XFS_IOC_GETFSMAP)" | |
534 | " iflags=0x%x [\"%s\"]: %s\n"), | |
535 | progname, head->fmh_iflags, file->name, | |
536 | strerror(errno)); | |
537 | free(head); | |
538 | exitcode = 1; | |
539 | return 0; | |
540 | } | |
541 | ||
542 | if (head->fmh_entries == 0) | |
543 | break; | |
544 | ||
545 | if (vflag) | |
546 | dump_map_verbose(&nr, head, &dumped_flags, &fsgeo); | |
547 | else if (mflag) | |
548 | dump_map_machine(&nr, head); | |
549 | else | |
550 | dump_map(&nr, head); | |
551 | ||
552 | p = &head->fmh_recs[head->fmh_entries - 1]; | |
553 | if (p->fmr_flags & FMR_OF_LAST) | |
554 | break; | |
555 | fsmap_advance(head); | |
556 | } while (true); | |
557 | ||
558 | if (dumped_flags) | |
559 | dump_verbose_key(); | |
560 | ||
561 | free(head); | |
562 | return 0; | |
563 | } | |
564 | ||
565 | void | |
566 | fsmap_init(void) | |
567 | { | |
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; | |
576 | ||
577 | add_command(&fsmap_cmd); | |
578 | } |