This source file includes following definitions.
- xchk_probe
- xchk_teardown
- xchk_experimental_warning
- xchk_validate_inputs
- xchk_postmortem
- xchk_postmortem
- xfs_scrub_metadata
1
2
3
4
5
6 #include "xfs.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_trans_resv.h"
11 #include "xfs_mount.h"
12 #include "xfs_log_format.h"
13 #include "xfs_trans.h"
14 #include "xfs_inode.h"
15 #include "xfs_quota.h"
16 #include "xfs_qm.h"
17 #include "xfs_errortag.h"
18 #include "xfs_error.h"
19 #include "scrub/scrub.h"
20 #include "scrub/common.h"
21 #include "scrub/trace.h"
22 #include "scrub/repair.h"
23 #include "scrub/health.h"
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 static int
134 xchk_probe(
135 struct xfs_scrub *sc)
136 {
137 int error = 0;
138
139 if (xchk_should_terminate(sc, &error))
140 return error;
141
142 return 0;
143 }
144
145
146
147
148 STATIC int
149 xchk_teardown(
150 struct xfs_scrub *sc,
151 struct xfs_inode *ip_in,
152 int error)
153 {
154 xchk_ag_free(sc, &sc->sa);
155 if (sc->tp) {
156 if (error == 0 && (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR))
157 error = xfs_trans_commit(sc->tp);
158 else
159 xfs_trans_cancel(sc->tp);
160 sc->tp = NULL;
161 }
162 if (sc->ip) {
163 if (sc->ilock_flags)
164 xfs_iunlock(sc->ip, sc->ilock_flags);
165 if (sc->ip != ip_in &&
166 !xfs_internal_inum(sc->mp, sc->ip->i_ino))
167 xfs_irele(sc->ip);
168 sc->ip = NULL;
169 }
170 if (sc->flags & XCHK_REAPING_DISABLED)
171 xchk_start_reaping(sc);
172 if (sc->flags & XCHK_HAS_QUOTAOFFLOCK) {
173 mutex_unlock(&sc->mp->m_quotainfo->qi_quotaofflock);
174 sc->flags &= ~XCHK_HAS_QUOTAOFFLOCK;
175 }
176 if (sc->buf) {
177 kmem_free(sc->buf);
178 sc->buf = NULL;
179 }
180 return error;
181 }
182
183
184
185 static const struct xchk_meta_ops meta_scrub_ops[] = {
186 [XFS_SCRUB_TYPE_PROBE] = {
187 .type = ST_NONE,
188 .setup = xchk_setup_fs,
189 .scrub = xchk_probe,
190 .repair = xrep_probe,
191 },
192 [XFS_SCRUB_TYPE_SB] = {
193 .type = ST_PERAG,
194 .setup = xchk_setup_fs,
195 .scrub = xchk_superblock,
196 .repair = xrep_superblock,
197 },
198 [XFS_SCRUB_TYPE_AGF] = {
199 .type = ST_PERAG,
200 .setup = xchk_setup_fs,
201 .scrub = xchk_agf,
202 .repair = xrep_agf,
203 },
204 [XFS_SCRUB_TYPE_AGFL]= {
205 .type = ST_PERAG,
206 .setup = xchk_setup_fs,
207 .scrub = xchk_agfl,
208 .repair = xrep_agfl,
209 },
210 [XFS_SCRUB_TYPE_AGI] = {
211 .type = ST_PERAG,
212 .setup = xchk_setup_fs,
213 .scrub = xchk_agi,
214 .repair = xrep_agi,
215 },
216 [XFS_SCRUB_TYPE_BNOBT] = {
217 .type = ST_PERAG,
218 .setup = xchk_setup_ag_allocbt,
219 .scrub = xchk_bnobt,
220 .repair = xrep_notsupported,
221 },
222 [XFS_SCRUB_TYPE_CNTBT] = {
223 .type = ST_PERAG,
224 .setup = xchk_setup_ag_allocbt,
225 .scrub = xchk_cntbt,
226 .repair = xrep_notsupported,
227 },
228 [XFS_SCRUB_TYPE_INOBT] = {
229 .type = ST_PERAG,
230 .setup = xchk_setup_ag_iallocbt,
231 .scrub = xchk_inobt,
232 .repair = xrep_notsupported,
233 },
234 [XFS_SCRUB_TYPE_FINOBT] = {
235 .type = ST_PERAG,
236 .setup = xchk_setup_ag_iallocbt,
237 .scrub = xchk_finobt,
238 .has = xfs_sb_version_hasfinobt,
239 .repair = xrep_notsupported,
240 },
241 [XFS_SCRUB_TYPE_RMAPBT] = {
242 .type = ST_PERAG,
243 .setup = xchk_setup_ag_rmapbt,
244 .scrub = xchk_rmapbt,
245 .has = xfs_sb_version_hasrmapbt,
246 .repair = xrep_notsupported,
247 },
248 [XFS_SCRUB_TYPE_REFCNTBT] = {
249 .type = ST_PERAG,
250 .setup = xchk_setup_ag_refcountbt,
251 .scrub = xchk_refcountbt,
252 .has = xfs_sb_version_hasreflink,
253 .repair = xrep_notsupported,
254 },
255 [XFS_SCRUB_TYPE_INODE] = {
256 .type = ST_INODE,
257 .setup = xchk_setup_inode,
258 .scrub = xchk_inode,
259 .repair = xrep_notsupported,
260 },
261 [XFS_SCRUB_TYPE_BMBTD] = {
262 .type = ST_INODE,
263 .setup = xchk_setup_inode_bmap,
264 .scrub = xchk_bmap_data,
265 .repair = xrep_notsupported,
266 },
267 [XFS_SCRUB_TYPE_BMBTA] = {
268 .type = ST_INODE,
269 .setup = xchk_setup_inode_bmap,
270 .scrub = xchk_bmap_attr,
271 .repair = xrep_notsupported,
272 },
273 [XFS_SCRUB_TYPE_BMBTC] = {
274 .type = ST_INODE,
275 .setup = xchk_setup_inode_bmap,
276 .scrub = xchk_bmap_cow,
277 .repair = xrep_notsupported,
278 },
279 [XFS_SCRUB_TYPE_DIR] = {
280 .type = ST_INODE,
281 .setup = xchk_setup_directory,
282 .scrub = xchk_directory,
283 .repair = xrep_notsupported,
284 },
285 [XFS_SCRUB_TYPE_XATTR] = {
286 .type = ST_INODE,
287 .setup = xchk_setup_xattr,
288 .scrub = xchk_xattr,
289 .repair = xrep_notsupported,
290 },
291 [XFS_SCRUB_TYPE_SYMLINK] = {
292 .type = ST_INODE,
293 .setup = xchk_setup_symlink,
294 .scrub = xchk_symlink,
295 .repair = xrep_notsupported,
296 },
297 [XFS_SCRUB_TYPE_PARENT] = {
298 .type = ST_INODE,
299 .setup = xchk_setup_parent,
300 .scrub = xchk_parent,
301 .repair = xrep_notsupported,
302 },
303 [XFS_SCRUB_TYPE_RTBITMAP] = {
304 .type = ST_FS,
305 .setup = xchk_setup_rt,
306 .scrub = xchk_rtbitmap,
307 .has = xfs_sb_version_hasrealtime,
308 .repair = xrep_notsupported,
309 },
310 [XFS_SCRUB_TYPE_RTSUM] = {
311 .type = ST_FS,
312 .setup = xchk_setup_rt,
313 .scrub = xchk_rtsummary,
314 .has = xfs_sb_version_hasrealtime,
315 .repair = xrep_notsupported,
316 },
317 [XFS_SCRUB_TYPE_UQUOTA] = {
318 .type = ST_FS,
319 .setup = xchk_setup_quota,
320 .scrub = xchk_quota,
321 .repair = xrep_notsupported,
322 },
323 [XFS_SCRUB_TYPE_GQUOTA] = {
324 .type = ST_FS,
325 .setup = xchk_setup_quota,
326 .scrub = xchk_quota,
327 .repair = xrep_notsupported,
328 },
329 [XFS_SCRUB_TYPE_PQUOTA] = {
330 .type = ST_FS,
331 .setup = xchk_setup_quota,
332 .scrub = xchk_quota,
333 .repair = xrep_notsupported,
334 },
335 [XFS_SCRUB_TYPE_FSCOUNTERS] = {
336 .type = ST_FS,
337 .setup = xchk_setup_fscounters,
338 .scrub = xchk_fscounters,
339 .repair = xrep_notsupported,
340 },
341 };
342
343
344 static inline void
345 xchk_experimental_warning(
346 struct xfs_mount *mp)
347 {
348 static struct ratelimit_state scrub_warning = RATELIMIT_STATE_INIT(
349 "xchk_warning", 86400 * HZ, 1);
350 ratelimit_set_flags(&scrub_warning, RATELIMIT_MSG_ON_RELEASE);
351
352 if (__ratelimit(&scrub_warning))
353 xfs_alert(mp,
354 "EXPERIMENTAL online scrub feature in use. Use at your own risk!");
355 }
356
357 static int
358 xchk_validate_inputs(
359 struct xfs_mount *mp,
360 struct xfs_scrub_metadata *sm)
361 {
362 int error;
363 const struct xchk_meta_ops *ops;
364
365 error = -EINVAL;
366
367 sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT;
368 if (sm->sm_flags & ~XFS_SCRUB_FLAGS_IN)
369 goto out;
370
371 if (memchr_inv(sm->sm_reserved, 0, sizeof(sm->sm_reserved)))
372 goto out;
373
374 error = -ENOENT;
375
376 if (sm->sm_type >= XFS_SCRUB_TYPE_NR)
377 goto out;
378 ops = &meta_scrub_ops[sm->sm_type];
379 if (ops->setup == NULL || ops->scrub == NULL)
380 goto out;
381
382 if (ops->has && !ops->has(&mp->m_sb))
383 goto out;
384
385 error = -EINVAL;
386
387 switch (ops->type) {
388 case ST_NONE:
389 case ST_FS:
390 if (sm->sm_ino || sm->sm_gen || sm->sm_agno)
391 goto out;
392 break;
393 case ST_PERAG:
394 if (sm->sm_ino || sm->sm_gen ||
395 sm->sm_agno >= mp->m_sb.sb_agcount)
396 goto out;
397 break;
398 case ST_INODE:
399 if (sm->sm_agno || (sm->sm_gen && !sm->sm_ino))
400 goto out;
401 break;
402 default:
403 goto out;
404 }
405
406
407
408
409
410
411
412 if (sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) {
413 error = -EOPNOTSUPP;
414 if (!xfs_sb_version_hascrc(&mp->m_sb))
415 goto out;
416
417 error = -EROFS;
418 if (mp->m_flags & XFS_MOUNT_RDONLY)
419 goto out;
420 }
421
422 error = 0;
423 out:
424 return error;
425 }
426
427 #ifdef CONFIG_XFS_ONLINE_REPAIR
428 static inline void xchk_postmortem(struct xfs_scrub *sc)
429 {
430
431
432
433
434
435 if ((sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) &&
436 (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
437 XFS_SCRUB_OFLAG_XCORRUPT)))
438 xrep_failure(sc->mp);
439 }
440 #else
441 static inline void xchk_postmortem(struct xfs_scrub *sc)
442 {
443
444
445
446
447 if (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
448 XFS_SCRUB_OFLAG_XCORRUPT))
449 xfs_alert_ratelimited(sc->mp,
450 "Corruption detected during scrub.");
451 }
452 #endif
453
454
455 int
456 xfs_scrub_metadata(
457 struct xfs_inode *ip,
458 struct xfs_scrub_metadata *sm)
459 {
460 struct xfs_scrub sc = {
461 .mp = ip->i_mount,
462 .sm = sm,
463 .sa = {
464 .agno = NULLAGNUMBER,
465 },
466 };
467 struct xfs_mount *mp = ip->i_mount;
468 int error = 0;
469
470 BUILD_BUG_ON(sizeof(meta_scrub_ops) !=
471 (sizeof(struct xchk_meta_ops) * XFS_SCRUB_TYPE_NR));
472
473 trace_xchk_start(ip, sm, error);
474
475
476 error = -ESHUTDOWN;
477 if (XFS_FORCED_SHUTDOWN(mp))
478 goto out;
479 error = -ENOTRECOVERABLE;
480 if (mp->m_flags & XFS_MOUNT_NORECOVERY)
481 goto out;
482
483 error = xchk_validate_inputs(mp, sm);
484 if (error)
485 goto out;
486
487 xchk_experimental_warning(mp);
488
489 sc.ops = &meta_scrub_ops[sm->sm_type];
490 sc.sick_mask = xchk_health_mask_for_scrub_type(sm->sm_type);
491 retry_op:
492
493 error = sc.ops->setup(&sc, ip);
494 if (error)
495 goto out_teardown;
496
497
498 error = sc.ops->scrub(&sc);
499 if (!(sc.flags & XCHK_TRY_HARDER) && error == -EDEADLOCK) {
500
501
502
503
504
505 error = xchk_teardown(&sc, ip, 0);
506 if (error)
507 goto out;
508 sc.flags |= XCHK_TRY_HARDER;
509 goto retry_op;
510 } else if (error)
511 goto out_teardown;
512
513 xchk_update_health(&sc);
514
515 if ((sc.sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) &&
516 !(sc.flags & XREP_ALREADY_FIXED)) {
517 bool needs_fix;
518
519
520 if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR))
521 sc.sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
522
523 needs_fix = (sc.sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
524 XFS_SCRUB_OFLAG_XCORRUPT |
525 XFS_SCRUB_OFLAG_PREEN));
526
527
528
529
530 if (!needs_fix) {
531 sc.sm->sm_flags |= XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED;
532 goto out_nofix;
533 }
534
535
536
537
538
539 error = xrep_attempt(ip, &sc);
540 if (error == -EAGAIN) {
541
542
543
544
545
546 error = xchk_teardown(&sc, ip, 0);
547 if (error) {
548 xrep_failure(mp);
549 goto out;
550 }
551 goto retry_op;
552 }
553 }
554
555 out_nofix:
556 xchk_postmortem(&sc);
557 out_teardown:
558 error = xchk_teardown(&sc, ip, error);
559 out:
560 trace_xchk_done(ip, sm, error);
561 if (error == -EFSCORRUPTED || error == -EFSBADCRC) {
562 sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
563 error = 0;
564 }
565 return error;
566 }