]>
Commit | Line | Data |
---|---|---|
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 | ||
27 | static cmdinfo_t fsmap_cmd; | |
28 | static dev_t xfs_data_dev; | |
29 | ||
30 | static void | |
31 | fsmap_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 | |
57 | static const char * | |
58 | special_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 | ||
90 | static void | |
91 | dump_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 | ||
123 | static void | |
124 | dump_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 */ | |
174 | static void | |
175 | dump_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 | ||
361 | static void | |
362 | dump_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 | ||
381 | int | |
382 | fsmap_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 | ||
578 | void | |
579 | fsmap_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 | } |