]>
Commit | Line | Data |
---|---|---|
813c67c7 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 as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it would be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write the Free Software Foundation, | |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
19 | ||
20 | #include <sys/uio.h> | |
21 | #include <xfs/xfs.h> | |
22 | #include "command.h" | |
23 | #include "input.h" | |
24 | #include "init.h" | |
25 | #include "path.h" | |
26 | #include "io.h" | |
27 | ||
28 | static struct cmdinfo scrub_cmd; | |
29 | ||
30 | /* Type info and names for the scrub types. */ | |
31 | enum scrub_type { | |
32 | ST_NONE, /* disabled */ | |
33 | ST_PERAG, /* per-AG metadata */ | |
34 | ST_FS, /* per-FS metadata */ | |
35 | ST_INODE, /* per-inode metadata */ | |
36 | }; | |
37 | ||
38 | struct scrub_descr { | |
39 | const char *name; | |
40 | enum scrub_type type; | |
41 | }; | |
42 | ||
43 | static const struct scrub_descr scrubbers[XFS_SCRUB_TYPE_NR] = { | |
44 | [XFS_SCRUB_TYPE_PROBE] = {"probe", ST_NONE}, | |
45 | [XFS_SCRUB_TYPE_SB] = {"sb", ST_PERAG}, | |
46 | [XFS_SCRUB_TYPE_AGF] = {"agf", ST_PERAG}, | |
47 | [XFS_SCRUB_TYPE_AGFL] = {"agfl", ST_PERAG}, | |
48 | [XFS_SCRUB_TYPE_AGI] = {"agi", ST_PERAG}, | |
49 | [XFS_SCRUB_TYPE_BNOBT] = {"bnobt", ST_PERAG}, | |
50 | [XFS_SCRUB_TYPE_CNTBT] = {"cntbt", ST_PERAG}, | |
51 | [XFS_SCRUB_TYPE_INOBT] = {"inobt", ST_PERAG}, | |
52 | [XFS_SCRUB_TYPE_FINOBT] = {"finobt", ST_PERAG}, | |
53 | [XFS_SCRUB_TYPE_RMAPBT] = {"rmapbt", ST_PERAG}, | |
54 | [XFS_SCRUB_TYPE_REFCNTBT] = {"refcountbt", ST_PERAG}, | |
55 | [XFS_SCRUB_TYPE_INODE] = {"inode", ST_INODE}, | |
56 | [XFS_SCRUB_TYPE_BMBTD] = {"bmapbtd", ST_INODE}, | |
57 | [XFS_SCRUB_TYPE_BMBTA] = {"bmapbta", ST_INODE}, | |
58 | [XFS_SCRUB_TYPE_BMBTC] = {"bmapbtc", ST_INODE}, | |
59 | [XFS_SCRUB_TYPE_DIR] = {"directory", ST_INODE}, | |
60 | [XFS_SCRUB_TYPE_XATTR] = {"xattr", ST_INODE}, | |
61 | [XFS_SCRUB_TYPE_SYMLINK] = {"symlink", ST_INODE}, | |
62 | [XFS_SCRUB_TYPE_PARENT] = {"parent", ST_INODE}, | |
63 | [XFS_SCRUB_TYPE_RTBITMAP] = {"rtbitmap", ST_FS}, | |
64 | [XFS_SCRUB_TYPE_RTSUM] = {"rtsummary", ST_FS}, | |
65 | [XFS_SCRUB_TYPE_UQUOTA] = {"usrquota", ST_FS}, | |
66 | [XFS_SCRUB_TYPE_GQUOTA] = {"grpquota", ST_FS}, | |
67 | [XFS_SCRUB_TYPE_PQUOTA] = {"prjquota", ST_FS}, | |
68 | }; | |
69 | ||
70 | static void | |
71 | scrub_help(void) | |
72 | { | |
73 | const struct scrub_descr *d; | |
74 | int i; | |
75 | ||
76 | printf(_( | |
77 | "\n" | |
78 | " Scrubs a piece of XFS filesystem metadata. The first argument is the type\n" | |
79 | " of metadata to examine. Allocation group metadata types take one AG number\n" | |
80 | " as the second parameter. Inode metadata types act on the currently open file\n" | |
81 | " or (optionally) take an inode number and generation number to act upon as\n" | |
82 | " the second and third parameters.\n" | |
83 | "\n" | |
84 | " Example:\n" | |
85 | " 'scrub inobt 3' - scrub the inode btree in AG 3.\n" | |
86 | " 'scrub bmapbtd 128 13525' - scrubs the extent map of inode 128 gen 13525.\n" | |
87 | "\n" | |
88 | " Known metadata scrub types are:")); | |
89 | for (i = 0, d = scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) | |
90 | printf(" %s", d->name); | |
91 | printf("\n"); | |
92 | } | |
93 | ||
94 | static void | |
95 | scrub_ioctl( | |
96 | int fd, | |
97 | int type, | |
98 | uint64_t control, | |
99 | uint32_t control2) | |
100 | { | |
101 | struct xfs_scrub_metadata meta; | |
102 | const struct scrub_descr *sc; | |
103 | int error; | |
104 | ||
105 | sc = &scrubbers[type]; | |
106 | memset(&meta, 0, sizeof(meta)); | |
107 | meta.sm_type = type; | |
108 | switch (sc->type) { | |
109 | case ST_PERAG: | |
110 | meta.sm_agno = control; | |
111 | break; | |
112 | case ST_INODE: | |
113 | meta.sm_ino = control; | |
114 | meta.sm_gen = control2; | |
115 | break; | |
116 | case ST_NONE: | |
117 | case ST_FS: | |
118 | /* no control parameters */ | |
119 | break; | |
120 | } | |
121 | meta.sm_flags = 0; | |
122 | ||
123 | error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta); | |
124 | if (error) | |
125 | perror("scrub"); | |
126 | if (meta.sm_flags & XFS_SCRUB_OFLAG_CORRUPT) | |
127 | printf(_("Corruption detected.\n")); | |
128 | if (meta.sm_flags & XFS_SCRUB_OFLAG_PREEN) | |
129 | printf(_("Optimization possible.\n")); | |
130 | if (meta.sm_flags & XFS_SCRUB_OFLAG_XFAIL) | |
131 | printf(_("Cross-referencing failed.\n")); | |
132 | if (meta.sm_flags & XFS_SCRUB_OFLAG_XCORRUPT) | |
133 | printf(_("Corruption detected during cross-referencing.\n")); | |
134 | if (meta.sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) | |
135 | printf(_("Scan was not complete.\n")); | |
136 | } | |
137 | ||
138 | static int | |
139 | parse_args( | |
140 | int argc, | |
141 | char **argv, | |
142 | struct cmdinfo *cmdinfo, | |
143 | void (*fn)(int, int, uint64_t, uint32_t)) | |
144 | { | |
145 | char *p; | |
146 | int type = -1; | |
147 | int i, c; | |
148 | uint64_t control = 0; | |
149 | uint32_t control2 = 0; | |
150 | const struct scrub_descr *d = NULL; | |
151 | ||
152 | while ((c = getopt(argc, argv, "")) != EOF) { | |
153 | switch (c) { | |
154 | default: | |
155 | return command_usage(cmdinfo); | |
156 | } | |
157 | } | |
158 | if (optind > argc - 1) | |
159 | return command_usage(cmdinfo); | |
160 | ||
161 | for (i = 0, d = scrubbers; i < XFS_SCRUB_TYPE_NR; i++, d++) { | |
162 | if (strcmp(d->name, argv[optind]) == 0) { | |
163 | type = i; | |
164 | break; | |
165 | } | |
166 | } | |
167 | optind++; | |
168 | ||
169 | if (type < 0) { | |
170 | printf(_("Unknown type '%s'.\n"), argv[optind]); | |
171 | return command_usage(cmdinfo); | |
172 | } | |
173 | ||
174 | switch (d->type) { | |
175 | case ST_INODE: | |
176 | if (optind == argc) { | |
177 | control = 0; | |
178 | control2 = 0; | |
179 | } else if (optind == argc - 2) { | |
180 | control = strtoull(argv[optind], &p, 0); | |
181 | if (*p != '\0') { | |
182 | fprintf(stderr, | |
183 | _("Bad inode number '%s'.\n"), | |
184 | argv[optind]); | |
185 | return 0; | |
186 | } | |
187 | control2 = strtoul(argv[optind + 1], &p, 0); | |
188 | if (*p != '\0') { | |
189 | fprintf(stderr, | |
190 | _("Bad generation number '%s'.\n"), | |
191 | argv[optind + 1]); | |
192 | return 0; | |
193 | } | |
194 | } else { | |
195 | fprintf(stderr, | |
196 | _("Must specify inode number and generation.\n")); | |
197 | return 0; | |
198 | } | |
199 | break; | |
200 | case ST_PERAG: | |
201 | if (optind != argc - 1) { | |
202 | fprintf(stderr, | |
203 | _("Must specify one AG number.\n")); | |
204 | return 0; | |
205 | } | |
206 | control = strtoul(argv[optind], &p, 0); | |
207 | if (*p != '\0') { | |
208 | fprintf(stderr, | |
209 | _("Bad AG number '%s'.\n"), argv[optind]); | |
210 | return 0; | |
211 | } | |
212 | break; | |
213 | case ST_FS: | |
214 | case ST_NONE: | |
215 | if (optind != argc) { | |
216 | fprintf(stderr, | |
217 | _("No parameters allowed.\n")); | |
218 | return 0; | |
219 | } | |
220 | break; | |
221 | default: | |
222 | ASSERT(0); | |
223 | break; | |
224 | } | |
225 | fn(file->fd, type, control, control2); | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
230 | static int | |
231 | scrub_f( | |
232 | int argc, | |
233 | char **argv) | |
234 | { | |
235 | return parse_args(argc, argv, &scrub_cmd, scrub_ioctl); | |
236 | } | |
237 | ||
238 | void | |
239 | scrub_init(void) | |
240 | { | |
241 | scrub_cmd.name = "scrub"; | |
242 | scrub_cmd.altname = "sc"; | |
243 | scrub_cmd.cfunc = scrub_f; | |
244 | scrub_cmd.argmin = 1; | |
245 | scrub_cmd.argmax = -1; | |
246 | scrub_cmd.flags = CMD_NOMAP_OK; | |
247 | scrub_cmd.args = _("type [agno|ino gen]"); | |
248 | scrub_cmd.oneline = _("scrubs filesystem metadata"); | |
249 | scrub_cmd.help = scrub_help; | |
250 | ||
251 | add_command(&scrub_cmd); | |
252 | } |