1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
10 #include <sys/statvfs.h>
12 #include "libfrog/paths.h"
13 #include "xfs_scrub.h"
20 * Prioritize action items in order of how long we can wait.
21 * 0 = do it now, 10000 = do it later.
23 * To minimize the amount of repair work, we want to prioritize metadata
24 * objects by perceived corruptness. If CORRUPT is set, the fields are
25 * just plain bad; try fixing that first. Otherwise if XCORRUPT is set,
26 * the fields could be bad, but the xref data could also be bad; we'll
27 * try fixing that next. Finally, if XFAIL is set, some other metadata
28 * structure failed validation during xref, so we'll recheck this
29 * metadata last since it was probably fine.
31 * For metadata that lie in the critical path of checking other metadata
32 * (superblock, AG{F,I,FL}, inobt) we scrub and fix those things before
33 * we even get to handling their dependencies, so things should progress
37 /* Sort action items in severity order. */
40 struct action_item
*aitem
,
43 if (aitem
->flags
& XFS_SCRUB_OFLAG_CORRUPT
)
45 else if (aitem
->flags
& XFS_SCRUB_OFLAG_XCORRUPT
)
47 else if (aitem
->flags
& XFS_SCRUB_OFLAG_XFAIL
)
49 else if (aitem
->flags
& XFS_SCRUB_OFLAG_PREEN
)
54 /* Sort the repair items in dependency order. */
56 xfs_action_item_priority(
57 struct action_item
*aitem
)
59 switch (aitem
->type
) {
60 case XFS_SCRUB_TYPE_SB
:
61 case XFS_SCRUB_TYPE_AGF
:
62 case XFS_SCRUB_TYPE_AGFL
:
63 case XFS_SCRUB_TYPE_AGI
:
64 case XFS_SCRUB_TYPE_BNOBT
:
65 case XFS_SCRUB_TYPE_CNTBT
:
66 case XFS_SCRUB_TYPE_INOBT
:
67 case XFS_SCRUB_TYPE_FINOBT
:
68 case XFS_SCRUB_TYPE_REFCNTBT
:
69 case XFS_SCRUB_TYPE_RMAPBT
:
70 case XFS_SCRUB_TYPE_INODE
:
71 case XFS_SCRUB_TYPE_BMBTD
:
72 case XFS_SCRUB_TYPE_BMBTA
:
73 case XFS_SCRUB_TYPE_BMBTC
:
74 return PRIO(aitem
, aitem
->type
- 1);
75 case XFS_SCRUB_TYPE_DIR
:
76 case XFS_SCRUB_TYPE_XATTR
:
77 case XFS_SCRUB_TYPE_SYMLINK
:
78 case XFS_SCRUB_TYPE_PARENT
:
79 return PRIO(aitem
, XFS_SCRUB_TYPE_DIR
);
80 case XFS_SCRUB_TYPE_RTBITMAP
:
81 case XFS_SCRUB_TYPE_RTSUM
:
82 return PRIO(aitem
, XFS_SCRUB_TYPE_RTBITMAP
);
83 case XFS_SCRUB_TYPE_UQUOTA
:
84 case XFS_SCRUB_TYPE_GQUOTA
:
85 case XFS_SCRUB_TYPE_PQUOTA
:
86 return PRIO(aitem
, XFS_SCRUB_TYPE_UQUOTA
);
87 case XFS_SCRUB_TYPE_FSCOUNTERS
:
88 /* This should always go after AG headers no matter what. */
89 return PRIO(aitem
, INT_MAX
);
94 /* Make sure that btrees get repaired before headers. */
96 xfs_action_item_compare(
101 struct action_item
*ra
;
102 struct action_item
*rb
;
104 ra
= container_of(a
, struct action_item
, list
);
105 rb
= container_of(b
, struct action_item
, list
);
107 return xfs_action_item_priority(ra
) - xfs_action_item_priority(rb
);
111 * Figure out which AG metadata must be fixed before we can move on
115 action_list_find_mustfix(
116 struct action_list
*alist
,
117 struct action_list
*immediate_alist
,
118 unsigned long long *broken_primaries
,
119 unsigned long long *broken_secondaries
)
121 struct action_item
*n
;
122 struct action_item
*aitem
;
124 list_for_each_entry_safe(aitem
, n
, &alist
->list
, list
) {
125 if (!(aitem
->flags
& XFS_SCRUB_OFLAG_CORRUPT
))
127 switch (aitem
->type
) {
128 case XFS_SCRUB_TYPE_RMAPBT
:
129 (*broken_secondaries
)++;
131 case XFS_SCRUB_TYPE_FINOBT
:
132 case XFS_SCRUB_TYPE_INOBT
:
134 list_move_tail(&aitem
->list
, &immediate_alist
->list
);
135 immediate_alist
->nr
++;
137 case XFS_SCRUB_TYPE_BNOBT
:
138 case XFS_SCRUB_TYPE_CNTBT
:
139 case XFS_SCRUB_TYPE_REFCNTBT
:
140 (*broken_primaries
)++;
150 * Allocate a certain number of repair lists for the scrub context. Returns
151 * zero or a positive error number.
156 struct action_list
**listsp
)
158 struct action_list
*lists
;
161 lists
= calloc(nr
, sizeof(struct action_list
));
165 for (agno
= 0; agno
< nr
; agno
++)
166 action_list_init(&lists
[agno
]);
172 /* Free the repair lists. */
175 struct action_list
**listsp
)
181 /* Initialize repair list */
184 struct action_list
*alist
)
186 INIT_LIST_HEAD(&alist
->list
);
188 alist
->sorted
= false;
191 /* Number of repairs in this list. */
194 struct action_list
*alist
)
199 /* Add to the list of repairs. */
202 struct action_list
*alist
,
203 struct action_item
*aitem
)
205 list_add_tail(&aitem
->list
, &alist
->list
);
207 alist
->sorted
= false;
210 /* Splice two repair lists. */
213 struct action_list
*dest
,
214 struct action_list
*src
)
219 list_splice_tail_init(&src
->list
, &dest
->list
);
222 dest
->sorted
= false;
225 /* Repair everything on this list. */
228 struct scrub_ctx
*ctx
,
230 struct action_list
*alist
,
231 unsigned int repair_flags
)
233 struct action_item
*aitem
;
234 struct action_item
*n
;
235 enum check_outcome fix
;
237 if (!alist
->sorted
) {
238 list_sort(NULL
, &alist
->list
, xfs_action_item_compare
);
239 alist
->sorted
= true;
242 list_for_each_entry_safe(aitem
, n
, &alist
->list
, list
) {
243 fix
= xfs_repair_metadata(ctx
, fd
, aitem
, repair_flags
);
246 if (!(repair_flags
& ALP_NOPROGRESS
))
249 list_del(&aitem
->list
);
261 if (xfs_scrub_excessive_errors(ctx
))
266 /* Defer all the repairs until phase 4. */
269 struct scrub_ctx
*ctx
,
271 struct action_list
*alist
)
273 ASSERT(agno
< ctx
->mnt
.fsgeom
.agcount
);
275 action_list_splice(&ctx
->action_lists
[agno
], alist
);
278 /* Run actions now and defer unfinished items for later. */
280 action_list_process_or_defer(
281 struct scrub_ctx
*ctx
,
283 struct action_list
*alist
)
287 ret
= action_list_process(ctx
, ctx
->mnt
.fd
, alist
,
288 ALP_REPAIR_ONLY
| ALP_NOPROGRESS
);
292 action_list_defer(ctx
, agno
, alist
);