]>
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" | |
9 | #include "path.h" | |
10 | #include "io.h" | |
11 | #include "input.h" | |
12 | ||
13 | static cmdinfo_t fsmap_cmd; | |
14 | static dev_t xfs_data_dev; | |
15 | ||
16 | static void | |
17 | fsmap_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 | |
43 | static const char * | |
44 | special_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 | ||
76 | static void | |
77 | dump_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 | ||
109 | static void | |
110 | dump_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 */ | |
160 | static void | |
161 | dump_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 | ||
347 | static void | |
348 | dump_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 | ||
367 | int | |
368 | fsmap_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 | ||
564 | void | |
565 | fsmap_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 | } |