]>
Commit | Line | Data |
---|---|---|
3c8276c4 DW |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2019 Oracle. All Rights Reserved. | |
4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> | |
5 | */ | |
6 | #include "xfs.h" | |
7 | #include "platform_defs.h" | |
8 | #include "command.h" | |
9 | #include "init.h" | |
9fc3ef62 | 10 | #include "libfrog/logging.h" |
3c8276c4 DW |
11 | #include "libfrog/fsgeom.h" |
12 | #include "libfrog/bulkstat.h" | |
13 | #include "libfrog/paths.h" | |
14 | #include "io.h" | |
15 | #include "input.h" | |
16 | ||
17 | static void | |
18 | dump_bulkstat_time( | |
19 | const char *tag, | |
20 | uint64_t sec, | |
21 | uint32_t nsec) | |
22 | { | |
23 | printf("\t%s = %"PRIu64".%"PRIu32"\n", tag, sec, nsec); | |
24 | } | |
25 | ||
26 | static void | |
27 | dump_bulkstat( | |
28 | struct xfs_bulkstat *bstat) | |
29 | { | |
30 | printf("bs_ino = %"PRIu64"\n", bstat->bs_ino); | |
31 | printf("\tbs_size = %"PRIu64"\n", bstat->bs_size); | |
32 | ||
33 | printf("\tbs_blocks = %"PRIu64"\n", bstat->bs_blocks); | |
34 | printf("\tbs_xflags = 0x%"PRIx64"\n", bstat->bs_xflags); | |
35 | ||
36 | dump_bulkstat_time("bs_atime", bstat->bs_atime, bstat->bs_atime_nsec); | |
37 | dump_bulkstat_time("bs_ctime", bstat->bs_ctime, bstat->bs_ctime_nsec); | |
38 | dump_bulkstat_time("bs_mtime", bstat->bs_mtime, bstat->bs_mtime_nsec); | |
39 | dump_bulkstat_time("bs_btime", bstat->bs_btime, bstat->bs_btime_nsec); | |
40 | ||
41 | printf("\tbs_gen = 0x%"PRIx32"\n", bstat->bs_gen); | |
42 | printf("\tbs_uid = %"PRIu32"\n", bstat->bs_uid); | |
43 | printf("\tbs_gid = %"PRIu32"\n", bstat->bs_gid); | |
44 | printf("\tbs_projectid = %"PRIu32"\n", bstat->bs_projectid); | |
45 | ||
46 | printf("\tbs_blksize = %"PRIu32"\n", bstat->bs_blksize); | |
47 | printf("\tbs_rdev = %"PRIu32"\n", bstat->bs_rdev); | |
48 | printf("\tbs_cowextsize_blks = %"PRIu32"\n", bstat->bs_cowextsize_blks); | |
49 | printf("\tbs_extsize_blks = %"PRIu32"\n", bstat->bs_extsize_blks); | |
50 | ||
51 | printf("\tbs_nlink = %"PRIu32"\n", bstat->bs_nlink); | |
52 | printf("\tbs_extents = %"PRIu32"\n", bstat->bs_extents); | |
53 | printf("\tbs_aextents = %"PRIu32"\n", bstat->bs_aextents); | |
54 | printf("\tbs_version = %"PRIu16"\n", bstat->bs_version); | |
55 | printf("\tbs_forkoff = %"PRIu16"\n", bstat->bs_forkoff); | |
56 | ||
57 | printf("\tbs_sick = 0x%"PRIx16"\n", bstat->bs_sick); | |
58 | printf("\tbs_checked = 0x%"PRIx16"\n", bstat->bs_checked); | |
59 | printf("\tbs_mode = 0%"PRIo16"\n", bstat->bs_mode); | |
ac87307e | 60 | printf("\tbs_extents64 = %"PRIu64"\n", bstat->bs_extents64); |
3c8276c4 DW |
61 | }; |
62 | ||
63 | static void | |
64 | bulkstat_help(void) | |
65 | { | |
66 | printf(_( | |
67 | "Bulk-queries the filesystem for inode stat information and prints it.\n" | |
68 | "\n" | |
69 | " -a <agno> Only iterate this AG.\n" | |
70 | " -d Print debugging output.\n" | |
7f6791f7 | 71 | " -q Be quiet, no output.\n" |
3c8276c4 DW |
72 | " -e <ino> Stop after this inode.\n" |
73 | " -n <nr> Ask for this many results at once.\n" | |
74 | " -s <ino> Inode to start with.\n" | |
75 | " -v <ver> Use this version of the ioctl (1 or 5).\n")); | |
76 | } | |
77 | ||
78 | static void | |
79 | set_xfd_flags( | |
80 | struct xfs_fd *xfd, | |
81 | uint32_t ver) | |
82 | { | |
83 | switch (ver) { | |
84 | case 1: | |
85 | xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V1; | |
86 | break; | |
87 | case 5: | |
88 | xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V5; | |
89 | break; | |
90 | default: | |
91 | break; | |
92 | } | |
93 | } | |
94 | ||
95 | static int | |
96 | bulkstat_f( | |
97 | int argc, | |
98 | char **argv) | |
99 | { | |
100 | struct xfs_fd xfd = XFS_FD_INIT(file->fd); | |
101 | struct xfs_bulkstat_req *breq; | |
102 | uint64_t startino = 0; | |
103 | uint64_t endino = -1ULL; | |
104 | uint32_t batch_size = 4096; | |
105 | uint32_t agno = 0; | |
106 | uint32_t ver = 0; | |
107 | bool has_agno = false; | |
108 | bool debug = false; | |
7f6791f7 | 109 | bool quiet = false; |
3c8276c4 DW |
110 | unsigned int i; |
111 | int c; | |
112 | int ret; | |
113 | ||
7f6791f7 | 114 | while ((c = getopt(argc, argv, "a:de:n:qs:v:")) != -1) { |
3c8276c4 DW |
115 | switch (c) { |
116 | case 'a': | |
117 | agno = cvt_u32(optarg, 10); | |
118 | if (errno) { | |
119 | perror(optarg); | |
120 | return 1; | |
121 | } | |
122 | has_agno = true; | |
123 | break; | |
124 | case 'd': | |
125 | debug = true; | |
126 | break; | |
127 | case 'e': | |
128 | endino = cvt_u64(optarg, 10); | |
129 | if (errno) { | |
130 | perror(optarg); | |
131 | return 1; | |
132 | } | |
133 | break; | |
134 | case 'n': | |
135 | batch_size = cvt_u32(optarg, 10); | |
136 | if (errno) { | |
137 | perror(optarg); | |
138 | return 1; | |
139 | } | |
140 | break; | |
7f6791f7 DC |
141 | case 'q': |
142 | quiet = true; | |
143 | break; | |
3c8276c4 DW |
144 | case 's': |
145 | startino = cvt_u64(optarg, 10); | |
146 | if (errno) { | |
147 | perror(optarg); | |
148 | return 1; | |
149 | } | |
150 | break; | |
151 | case 'v': | |
152 | ver = cvt_u32(optarg, 10); | |
153 | if (errno) { | |
154 | perror(optarg); | |
155 | return 1; | |
156 | } | |
157 | if (ver != 1 && ver != 5) { | |
158 | fprintf(stderr, "version must be 1 or 5.\n"); | |
159 | return 1; | |
160 | } | |
161 | break; | |
162 | default: | |
163 | bulkstat_help(); | |
164 | return 0; | |
165 | } | |
166 | } | |
167 | if (optind != argc) { | |
168 | bulkstat_help(); | |
169 | return 0; | |
170 | } | |
171 | ||
03d96c64 | 172 | ret = -xfd_prepare_geometry(&xfd); |
3c8276c4 | 173 | if (ret) { |
9fc3ef62 | 174 | xfrog_perror(ret, "xfd_prepare_geometry"); |
3c8276c4 DW |
175 | exitcode = 1; |
176 | return 0; | |
177 | } | |
178 | ||
e6542132 DW |
179 | ret = -xfrog_bulkstat_alloc_req(batch_size, startino, &breq); |
180 | if (ret) { | |
181 | xfrog_perror(ret, "alloc bulkreq"); | |
3c8276c4 DW |
182 | exitcode = 1; |
183 | return 0; | |
184 | } | |
185 | ||
186 | if (has_agno) | |
187 | xfrog_bulkstat_set_ag(breq, agno); | |
188 | ||
189 | set_xfd_flags(&xfd, ver); | |
190 | ||
e6542132 | 191 | while ((ret = -xfrog_bulkstat(&xfd, breq)) == 0) { |
3c8276c4 DW |
192 | if (debug) |
193 | printf( | |
194 | _("bulkstat: startino=%lld flags=0x%x agno=%u ret=%d icount=%u ocount=%u\n"), | |
195 | (long long)breq->hdr.ino, | |
196 | (unsigned int)breq->hdr.flags, | |
197 | (unsigned int)breq->hdr.agno, | |
198 | ret, | |
199 | (unsigned int)breq->hdr.icount, | |
200 | (unsigned int)breq->hdr.ocount); | |
201 | if (breq->hdr.ocount == 0) | |
202 | break; | |
203 | ||
204 | for (i = 0; i < breq->hdr.ocount; i++) { | |
205 | if (breq->bulkstat[i].bs_ino > endino) | |
206 | break; | |
7f6791f7 DC |
207 | if (quiet) |
208 | continue; | |
3c8276c4 DW |
209 | dump_bulkstat(&breq->bulkstat[i]); |
210 | } | |
211 | } | |
212 | if (ret) { | |
9fc3ef62 | 213 | xfrog_perror(ret, "xfrog_bulkstat"); |
3c8276c4 DW |
214 | exitcode = 1; |
215 | } | |
216 | ||
217 | free(breq); | |
218 | return 0; | |
219 | } | |
220 | ||
221 | static void | |
222 | bulkstat_single_help(void) | |
223 | { | |
224 | printf(_( | |
225 | "Queries the filesystem for a single inode's stat information and prints it.\n" | |
226 | "If a given inode is not allocated, information about the next allocated \n" | |
227 | "inode will be printed instead.\n" | |
228 | "\n" | |
229 | " -v (ver) Use this version of the ioctl (1 or 5).\n" | |
230 | " -d Print debugging information.\n" | |
231 | "\n" | |
232 | "Pass in inode numbers or a special inode name:\n" | |
233 | " root Root directory.\n")); | |
234 | } | |
235 | ||
236 | struct single_map { | |
237 | const char *tag; | |
238 | uint64_t code; | |
239 | }; | |
240 | ||
241 | struct single_map tags[] = { | |
242 | {"root", XFS_BULK_IREQ_SPECIAL_ROOT}, | |
243 | {NULL, 0}, | |
244 | }; | |
245 | ||
246 | static int | |
247 | bulkstat_single_f( | |
248 | int argc, | |
249 | char **argv) | |
250 | { | |
251 | struct xfs_fd xfd = XFS_FD_INIT(file->fd); | |
252 | struct xfs_bulkstat bulkstat; | |
253 | unsigned long ver = 0; | |
254 | unsigned int i; | |
255 | bool debug = false; | |
256 | int c; | |
257 | int ret; | |
258 | ||
259 | while ((c = getopt(argc, argv, "dv:")) != -1) { | |
260 | switch (c) { | |
261 | case 'd': | |
262 | debug = true; | |
263 | break; | |
264 | case 'v': | |
265 | errno = 0; | |
266 | ver = strtoull(optarg, NULL, 10); | |
267 | if (errno) { | |
268 | perror(optarg); | |
269 | return 1; | |
270 | } | |
271 | if (ver != 1 && ver != 5) { | |
272 | fprintf(stderr, "version must be 1 or 5.\n"); | |
273 | return 1; | |
274 | } | |
275 | break; | |
276 | default: | |
277 | bulkstat_single_help(); | |
278 | return 0; | |
279 | } | |
280 | } | |
281 | ||
03d96c64 | 282 | ret = -xfd_prepare_geometry(&xfd); |
3c8276c4 | 283 | if (ret) { |
9fc3ef62 | 284 | xfrog_perror(ret, "xfd_prepare_geometry"); |
3c8276c4 DW |
285 | exitcode = 1; |
286 | return 0; | |
287 | } | |
288 | ||
289 | set_xfd_flags(&xfd, ver); | |
290 | ||
291 | for (i = optind; i < argc; i++) { | |
292 | struct single_map *sm = tags; | |
293 | uint64_t ino; | |
294 | unsigned int flags = 0; | |
295 | ||
296 | /* Try to look up our tag... */ | |
297 | for (sm = tags; sm->tag; sm++) { | |
298 | if (!strcmp(argv[i], sm->tag)) { | |
299 | ino = sm->code; | |
300 | flags |= XFS_BULK_IREQ_SPECIAL; | |
301 | break; | |
302 | } | |
303 | } | |
304 | ||
305 | /* ...or else it's an inode number. */ | |
306 | if (sm->tag == NULL) { | |
307 | errno = 0; | |
308 | ino = strtoull(argv[i], NULL, 10); | |
309 | if (errno) { | |
310 | perror(argv[i]); | |
311 | exitcode = 1; | |
312 | return 0; | |
313 | } | |
314 | } | |
315 | ||
e6542132 | 316 | ret = -xfrog_bulkstat_single(&xfd, ino, flags, &bulkstat); |
3c8276c4 | 317 | if (ret) { |
9fc3ef62 | 318 | xfrog_perror(ret, "xfrog_bulkstat_single"); |
3c8276c4 DW |
319 | continue; |
320 | } | |
321 | ||
322 | if (debug) | |
323 | printf( | |
324 | _("bulkstat_single: startino=%"PRIu64" flags=0x%"PRIx32" ret=%d\n"), | |
325 | ino, flags, ret); | |
326 | ||
327 | dump_bulkstat(&bulkstat); | |
328 | } | |
329 | ||
330 | return 0; | |
331 | } | |
332 | ||
333 | static void | |
334 | dump_inumbers( | |
335 | struct xfs_inumbers *inumbers) | |
336 | { | |
337 | printf("xi_startino = %"PRIu64"\n", inumbers->xi_startino); | |
338 | printf("\txi_allocmask = 0x%"PRIx64"\n", inumbers->xi_allocmask); | |
339 | printf("\txi_alloccount = %"PRIu8"\n", inumbers->xi_alloccount); | |
340 | printf("\txi_version = %"PRIu8"\n", inumbers->xi_version); | |
341 | } | |
342 | ||
343 | static void | |
344 | inumbers_help(void) | |
345 | { | |
346 | printf(_( | |
347 | "Queries the filesystem for inode group information and prints it.\n" | |
348 | "\n" | |
349 | " -a <agno> Only iterate this AG.\n" | |
350 | " -d Print debugging output.\n" | |
351 | " -e <ino> Stop after this inode.\n" | |
352 | " -n <nr> Ask for this many results at once.\n" | |
353 | " -s <ino> Inode to start with.\n" | |
354 | " -v <ver> Use this version of the ioctl (1 or 5).\n")); | |
355 | } | |
356 | ||
357 | static int | |
358 | inumbers_f( | |
359 | int argc, | |
360 | char **argv) | |
361 | { | |
362 | struct xfs_fd xfd = XFS_FD_INIT(file->fd); | |
363 | struct xfs_inumbers_req *ireq; | |
364 | uint64_t startino = 0; | |
365 | uint64_t endino = -1ULL; | |
366 | uint32_t batch_size = 4096; | |
367 | uint32_t agno = 0; | |
368 | uint32_t ver = 0; | |
369 | bool has_agno = false; | |
370 | bool debug = false; | |
371 | unsigned int i; | |
372 | int c; | |
373 | int ret; | |
374 | ||
375 | while ((c = getopt(argc, argv, "a:de:n:s:v:")) != -1) { | |
376 | switch (c) { | |
377 | case 'a': | |
378 | agno = cvt_u32(optarg, 10); | |
379 | if (errno) { | |
380 | perror(optarg); | |
381 | return 1; | |
382 | } | |
383 | has_agno = true; | |
384 | break; | |
385 | case 'd': | |
386 | debug = true; | |
387 | break; | |
388 | case 'e': | |
389 | endino = cvt_u64(optarg, 10); | |
390 | if (errno) { | |
391 | perror(optarg); | |
392 | return 1; | |
393 | } | |
394 | break; | |
395 | case 'n': | |
396 | batch_size = cvt_u32(optarg, 10); | |
397 | if (errno) { | |
398 | perror(optarg); | |
399 | return 1; | |
400 | } | |
401 | break; | |
402 | case 's': | |
403 | startino = cvt_u64(optarg, 10); | |
404 | if (errno) { | |
405 | perror(optarg); | |
406 | return 1; | |
407 | } | |
408 | break; | |
409 | case 'v': | |
410 | ver = cvt_u32(optarg, 10); | |
411 | if (errno) { | |
412 | perror(optarg); | |
413 | return 1; | |
414 | } | |
415 | if (ver != 1 && ver != 5) { | |
416 | fprintf(stderr, "version must be 1 or 5.\n"); | |
417 | return 1; | |
418 | } | |
419 | break; | |
420 | default: | |
421 | bulkstat_help(); | |
422 | return 0; | |
423 | } | |
424 | } | |
425 | if (optind != argc) { | |
426 | bulkstat_help(); | |
427 | return 0; | |
428 | } | |
429 | ||
03d96c64 | 430 | ret = -xfd_prepare_geometry(&xfd); |
3c8276c4 | 431 | if (ret) { |
9fc3ef62 | 432 | xfrog_perror(ret, "xfd_prepare_geometry"); |
3c8276c4 DW |
433 | exitcode = 1; |
434 | return 0; | |
435 | } | |
436 | ||
e6542132 DW |
437 | ret = -xfrog_inumbers_alloc_req(batch_size, startino, &ireq); |
438 | if (ret) { | |
439 | xfrog_perror(ret, "alloc inumbersreq"); | |
3c8276c4 DW |
440 | exitcode = 1; |
441 | return 0; | |
442 | } | |
443 | ||
444 | if (has_agno) | |
445 | xfrog_inumbers_set_ag(ireq, agno); | |
446 | ||
447 | set_xfd_flags(&xfd, ver); | |
448 | ||
e6542132 | 449 | while ((ret = -xfrog_inumbers(&xfd, ireq)) == 0) { |
3c8276c4 DW |
450 | if (debug) |
451 | printf( | |
452 | _("bulkstat: startino=%"PRIu64" flags=0x%"PRIx32" agno=%"PRIu32" ret=%d icount=%"PRIu32" ocount=%"PRIu32"\n"), | |
453 | ireq->hdr.ino, | |
454 | ireq->hdr.flags, | |
455 | ireq->hdr.agno, | |
456 | ret, | |
457 | ireq->hdr.icount, | |
458 | ireq->hdr.ocount); | |
459 | if (ireq->hdr.ocount == 0) | |
460 | break; | |
461 | ||
462 | for (i = 0; i < ireq->hdr.ocount; i++) { | |
463 | if (ireq->inumbers[i].xi_startino > endino) | |
464 | break; | |
465 | dump_inumbers(&ireq->inumbers[i]); | |
466 | } | |
467 | } | |
468 | if (ret) { | |
9fc3ef62 | 469 | xfrog_perror(ret, "xfrog_inumbers"); |
3c8276c4 DW |
470 | exitcode = 1; |
471 | } | |
472 | ||
473 | free(ireq); | |
474 | return 0; | |
475 | } | |
476 | ||
477 | static cmdinfo_t bulkstat_cmd = { | |
478 | .name = "bulkstat", | |
479 | .cfunc = bulkstat_f, | |
480 | .argmin = 0, | |
481 | .argmax = -1, | |
482 | .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT, | |
483 | .help = bulkstat_help, | |
484 | }; | |
485 | ||
486 | static cmdinfo_t bulkstat_single_cmd = { | |
487 | .name = "bulkstat_single", | |
488 | .cfunc = bulkstat_single_f, | |
489 | .argmin = 1, | |
490 | .argmax = -1, | |
491 | .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT, | |
492 | .help = bulkstat_single_help, | |
493 | }; | |
494 | ||
495 | static cmdinfo_t inumbers_cmd = { | |
496 | .name = "inumbers", | |
497 | .cfunc = inumbers_f, | |
498 | .argmin = 0, | |
499 | .argmax = -1, | |
500 | .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT, | |
501 | .help = inumbers_help, | |
502 | }; | |
503 | ||
504 | void | |
505 | bulkstat_init(void) | |
506 | { | |
507 | bulkstat_cmd.args = | |
508 | _("[-a agno] [-d] [-e endino] [-n batchsize] [-s startino] [-v version]"); | |
509 | bulkstat_cmd.oneline = _("Bulk stat of inodes in a filesystem"); | |
510 | ||
511 | bulkstat_single_cmd.args = _("[-d] [-v version] inum..."); | |
512 | bulkstat_single_cmd.oneline = _("Stat one inode in a filesystem"); | |
513 | ||
514 | inumbers_cmd.args = | |
515 | _("[-a agno] [-d] [-e endino] [-n batchsize] [-s startino] [-v version]"); | |
516 | inumbers_cmd.oneline = _("Query inode groups in a filesystem"); | |
517 | ||
518 | add_command(&bulkstat_cmd); | |
519 | add_command(&bulkstat_single_cmd); | |
520 | add_command(&inumbers_cmd); | |
521 | } |