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