]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
813c67c7 DW |
2 | /* |
3 | * Copyright (C) 2017 Oracle. All Rights Reserved. | |
813c67c7 | 4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> |
813c67c7 DW |
5 | */ |
6 | ||
7 | #include <sys/uio.h> | |
8 | #include <xfs/xfs.h> | |
9 | #include "command.h" | |
10 | #include "input.h" | |
11 | #include "init.h" | |
42b4c8e8 | 12 | #include "libfrog/paths.h" |
5ef3b66a DW |
13 | #include "libfrog/fsgeom.h" |
14 | #include "libfrog/scrub.h" | |
813c67c7 DW |
15 | #include "io.h" |
16 | ||
17 | static struct cmdinfo scrub_cmd; | |
bec810e8 | 18 | static struct cmdinfo repair_cmd; |
813c67c7 | 19 | |
813c67c7 DW |
20 | static void |
21 | scrub_help(void) | |
22 | { | |
5ef3b66a | 23 | const struct xfrog_scrub_descr *d; |
813c67c7 DW |
24 | int i; |
25 | ||
26 | printf(_( | |
27 | "\n" | |
28 | " Scrubs a piece of XFS filesystem metadata. The first argument is the type\n" | |
29 | " of metadata to examine. Allocation group metadata types take one AG number\n" | |
30 | " as the second parameter. Inode metadata types act on the currently open file\n" | |
31 | " or (optionally) take an inode number and generation number to act upon as\n" | |
32 | " the second and third parameters.\n" | |
33 | "\n" | |
34 | " Example:\n" | |
35 | " 'scrub inobt 3' - scrub the inode btree in AG 3.\n" | |
36 | " 'scrub bmapbtd 128 13525' - scrubs the extent map of inode 128 gen 13525.\n" | |
37 | "\n" | |
38 | " Known metadata scrub types are:")); | |
5ef3b66a | 39 | for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) |
813c67c7 DW |
40 | printf(" %s", d->name); |
41 | printf("\n"); | |
42 | } | |
43 | ||
99a0612b DW |
44 | static bool |
45 | parse_inode( | |
46 | int argc, | |
47 | char **argv, | |
48 | int optind, | |
49 | __u64 *ino, | |
50 | __u32 *gen) | |
51 | { | |
52 | char *p; | |
53 | unsigned long long control; | |
54 | unsigned long control2; | |
55 | ||
56 | if (optind == argc) { | |
57 | *ino = 0; | |
58 | *gen = 0; | |
59 | return true; | |
60 | } | |
61 | ||
62 | if (optind != argc - 2) { | |
63 | fprintf(stderr, | |
64 | _("Must specify inode number and generation.\n")); | |
65 | return false; | |
66 | } | |
67 | ||
68 | control = strtoull(argv[optind], &p, 0); | |
69 | if (*p != '\0') { | |
70 | fprintf(stderr, _("Bad inode number '%s'.\n"), | |
71 | argv[optind]); | |
72 | return false; | |
73 | } | |
74 | control2 = strtoul(argv[optind + 1], &p, 0); | |
75 | if (*p != '\0') { | |
76 | fprintf(stderr, _("Bad generation number '%s'.\n"), | |
77 | argv[optind + 1]); | |
78 | return false; | |
79 | } | |
80 | ||
81 | *ino = control; | |
82 | *gen = control2; | |
83 | return true; | |
84 | } | |
85 | ||
86 | static bool | |
87 | parse_agno( | |
88 | int argc, | |
89 | char **argv, | |
90 | int optind, | |
91 | __u32 *agno) | |
92 | { | |
93 | char *p; | |
94 | unsigned long control; | |
95 | ||
96 | if (optind != argc - 1) { | |
97 | fprintf(stderr, _("Must specify one AG number.\n")); | |
98 | return false; | |
99 | } | |
100 | ||
101 | control = strtoul(argv[optind], &p, 0); | |
102 | if (*p != '\0') { | |
103 | fprintf(stderr, _("Bad AG number '%s'.\n"), argv[optind]); | |
104 | return false; | |
105 | } | |
106 | ||
107 | *agno = control; | |
108 | return true; | |
109 | } | |
110 | ||
111 | static bool | |
112 | parse_none( | |
113 | int argc, | |
114 | int optind) | |
115 | { | |
116 | if (optind != argc) { | |
117 | fprintf(stderr, _("No parameters allowed.\n")); | |
118 | return false; | |
119 | } | |
120 | ||
121 | /* no control parameters */ | |
122 | return true; | |
123 | } | |
124 | ||
813c67c7 DW |
125 | static int |
126 | parse_args( | |
127 | int argc, | |
128 | char **argv, | |
4c91ffcf DW |
129 | const struct cmdinfo *cmdinfo, |
130 | struct xfs_scrub_metadata *meta) | |
813c67c7 | 131 | { |
813c67c7 DW |
132 | int type = -1; |
133 | int i, c; | |
9de9b740 | 134 | uint32_t flags = 0; |
5ef3b66a | 135 | const struct xfrog_scrub_descr *d = NULL; |
813c67c7 | 136 | |
4c91ffcf | 137 | memset(meta, 0, sizeof(struct xfs_scrub_metadata)); |
9de9b740 | 138 | while ((c = getopt(argc, argv, "R")) != EOF) { |
813c67c7 | 139 | switch (c) { |
9de9b740 DW |
140 | case 'R': |
141 | flags |= XFS_SCRUB_IFLAG_FORCE_REBUILD; | |
142 | break; | |
813c67c7 | 143 | default: |
1067f3cd | 144 | exitcode = 1; |
813c67c7 DW |
145 | return command_usage(cmdinfo); |
146 | } | |
147 | } | |
1067f3cd DW |
148 | if (optind > argc - 1) { |
149 | exitcode = 1; | |
813c67c7 | 150 | return command_usage(cmdinfo); |
1067f3cd | 151 | } |
813c67c7 | 152 | |
5ef3b66a | 153 | for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) { |
813c67c7 DW |
154 | if (strcmp(d->name, argv[optind]) == 0) { |
155 | type = i; | |
156 | break; | |
157 | } | |
158 | } | |
813c67c7 DW |
159 | if (type < 0) { |
160 | printf(_("Unknown type '%s'.\n"), argv[optind]); | |
1067f3cd | 161 | exitcode = 1; |
813c67c7 DW |
162 | return command_usage(cmdinfo); |
163 | } | |
7856ed05 | 164 | optind++; |
813c67c7 | 165 | |
4c91ffcf | 166 | meta->sm_type = type; |
9de9b740 | 167 | meta->sm_flags = flags; |
4c91ffcf | 168 | |
813c67c7 | 169 | switch (d->type) { |
5ef3b66a | 170 | case XFROG_SCRUB_TYPE_INODE: |
99a0612b DW |
171 | if (!parse_inode(argc, argv, optind, &meta->sm_ino, |
172 | &meta->sm_gen)) { | |
1067f3cd DW |
173 | exitcode = 1; |
174 | return command_usage(cmdinfo); | |
813c67c7 DW |
175 | } |
176 | break; | |
5ef3b66a DW |
177 | case XFROG_SCRUB_TYPE_AGHEADER: |
178 | case XFROG_SCRUB_TYPE_PERAG: | |
99a0612b | 179 | if (!parse_agno(argc, argv, optind, &meta->sm_agno)) { |
1067f3cd DW |
180 | exitcode = 1; |
181 | return command_usage(cmdinfo); | |
813c67c7 DW |
182 | } |
183 | break; | |
5ef3b66a DW |
184 | case XFROG_SCRUB_TYPE_FS: |
185 | case XFROG_SCRUB_TYPE_NONE: | |
99a0612b | 186 | if (!parse_none(argc, optind)) { |
1067f3cd DW |
187 | exitcode = 1; |
188 | return command_usage(cmdinfo); | |
813c67c7 DW |
189 | } |
190 | break; | |
191 | default: | |
192 | ASSERT(0); | |
193 | break; | |
194 | } | |
813c67c7 DW |
195 | return 0; |
196 | } | |
197 | ||
198 | static int | |
199 | scrub_f( | |
200 | int argc, | |
201 | char **argv) | |
202 | { | |
4c91ffcf DW |
203 | struct xfs_scrub_metadata meta; |
204 | int error; | |
205 | ||
206 | error = parse_args(argc, argv, &scrub_cmd, &meta); | |
207 | if (error) | |
208 | return error; | |
209 | ||
210 | error = ioctl(file->fd, XFS_IOC_SCRUB_METADATA, &meta); | |
211 | if (error) | |
212 | perror("scrub"); | |
213 | if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT) | |
214 | printf(_("Corruption detected.\n")); | |
215 | if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN) | |
216 | printf(_("Optimization possible.\n")); | |
217 | if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL) | |
218 | printf(_("Cross-referencing failed.\n")); | |
219 | if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT) | |
220 | printf(_("Corruption detected during cross-referencing.\n")); | |
221 | if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) | |
222 | printf(_("Scan was not complete.\n")); | |
223 | return 0; | |
813c67c7 DW |
224 | } |
225 | ||
226 | void | |
227 | scrub_init(void) | |
228 | { | |
229 | scrub_cmd.name = "scrub"; | |
230 | scrub_cmd.altname = "sc"; | |
231 | scrub_cmd.cfunc = scrub_f; | |
232 | scrub_cmd.argmin = 1; | |
233 | scrub_cmd.argmax = -1; | |
234 | scrub_cmd.flags = CMD_NOMAP_OK; | |
235 | scrub_cmd.args = _("type [agno|ino gen]"); | |
236 | scrub_cmd.oneline = _("scrubs filesystem metadata"); | |
237 | scrub_cmd.help = scrub_help; | |
238 | ||
239 | add_command(&scrub_cmd); | |
240 | } | |
bec810e8 DW |
241 | |
242 | static void | |
243 | repair_help(void) | |
244 | { | |
5ef3b66a | 245 | const struct xfrog_scrub_descr *d; |
bec810e8 DW |
246 | int i; |
247 | ||
248 | printf(_( | |
249 | "\n" | |
250 | " Repairs a piece of XFS filesystem metadata. The first argument is the type\n" | |
251 | " of metadata to examine. Allocation group metadata types take one AG number\n" | |
252 | " as the second parameter. Inode metadata types act on the currently open file\n" | |
253 | " or (optionally) take an inode number and generation number to act upon as\n" | |
254 | " the second and third parameters.\n" | |
255 | "\n" | |
9de9b740 DW |
256 | " Flags are -R to force rebuilding metadata.\n" |
257 | "\n" | |
bec810e8 DW |
258 | " Example:\n" |
259 | " 'repair inobt 3' - repairs the inode btree in AG 3.\n" | |
260 | " 'repair bmapbtd 128 13525' - repairs the extent map of inode 128 gen 13525.\n" | |
261 | "\n" | |
9de9b740 | 262 | " Known metadata repair types are:")); |
5ef3b66a | 263 | for (i = 0, d = xfrog_scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) |
bec810e8 DW |
264 | printf(" %s", d->name); |
265 | printf("\n"); | |
266 | } | |
267 | ||
4c91ffcf DW |
268 | static int |
269 | repair_f( | |
270 | int argc, | |
271 | char **argv) | |
bec810e8 DW |
272 | { |
273 | struct xfs_scrub_metadata meta; | |
bec810e8 DW |
274 | int error; |
275 | ||
4c91ffcf DW |
276 | error = parse_args(argc, argv, &repair_cmd, &meta); |
277 | if (error) | |
278 | return error; | |
279 | meta.sm_flags |= XFS_SCRUB_IFLAG_REPAIR; | |
bec810e8 | 280 | |
4c91ffcf | 281 | error = ioctl(file->fd, XFS_IOC_SCRUB_METADATA, &meta); |
bec810e8 | 282 | if (error) |
f1572219 | 283 | perror("repair"); |
bec810e8 DW |
284 | if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT) |
285 | printf(_("Corruption remains.\n")); | |
286 | if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN) | |
287 | printf(_("Optimization possible.\n")); | |
288 | if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL) | |
289 | printf(_("Cross-referencing failed.\n")); | |
290 | if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT) | |
291 | printf(_("Corruption still detected during cross-referencing.\n")); | |
292 | if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) | |
293 | printf(_("Repair was not complete.\n")); | |
294 | if (meta.sm_flags & XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED) | |
295 | printf(_("Metadata did not need repair or optimization.\n")); | |
4c91ffcf | 296 | return 0; |
bec810e8 DW |
297 | } |
298 | ||
299 | void | |
300 | repair_init(void) | |
301 | { | |
302 | if (!expert) | |
303 | return; | |
304 | repair_cmd.name = "repair"; | |
305 | repair_cmd.altname = "fix"; | |
306 | repair_cmd.cfunc = repair_f; | |
307 | repair_cmd.argmin = 1; | |
308 | repair_cmd.argmax = -1; | |
309 | repair_cmd.flags = CMD_NOMAP_OK; | |
310 | repair_cmd.args = _("type [agno|ino gen]"); | |
311 | repair_cmd.oneline = _("repairs filesystem metadata"); | |
312 | repair_cmd.help = repair_help; | |
313 | ||
314 | add_command(&repair_cmd); | |
315 | } |