]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/repair.c
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>
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
);
91 /* Make sure that btrees get repaired before headers. */
93 xfs_action_item_compare(
98 struct action_item
*ra
;
99 struct action_item
*rb
;
101 ra
= container_of(a
, struct action_item
, list
);
102 rb
= container_of(b
, struct action_item
, list
);
104 return xfs_action_item_priority(ra
) - xfs_action_item_priority(rb
);
108 * Figure out which AG metadata must be fixed before we can move on
112 xfs_action_list_find_mustfix(
113 struct xfs_action_list
*alist
,
114 struct xfs_action_list
*immediate_alist
,
115 unsigned long long *broken_primaries
,
116 unsigned long long *broken_secondaries
)
118 struct action_item
*n
;
119 struct action_item
*aitem
;
121 list_for_each_entry_safe(aitem
, n
, &alist
->list
, list
) {
122 if (!(aitem
->flags
& XFS_SCRUB_OFLAG_CORRUPT
))
124 switch (aitem
->type
) {
125 case XFS_SCRUB_TYPE_RMAPBT
:
126 (*broken_secondaries
)++;
128 case XFS_SCRUB_TYPE_FINOBT
:
129 case XFS_SCRUB_TYPE_INOBT
:
131 list_move_tail(&aitem
->list
, &immediate_alist
->list
);
132 immediate_alist
->nr
++;
134 case XFS_SCRUB_TYPE_BNOBT
:
135 case XFS_SCRUB_TYPE_CNTBT
:
136 case XFS_SCRUB_TYPE_REFCNTBT
:
137 (*broken_primaries
)++;
146 /* Allocate a certain number of repair lists for the scrub context. */
148 xfs_action_lists_alloc(
150 struct xfs_action_list
**listsp
)
152 struct xfs_action_list
*lists
;
155 lists
= calloc(nr
, sizeof(struct xfs_action_list
));
159 for (agno
= 0; agno
< nr
; agno
++)
160 xfs_action_list_init(&lists
[agno
]);
166 /* Free the repair lists. */
168 xfs_action_lists_free(
169 struct xfs_action_list
**listsp
)
175 /* Initialize repair list */
177 xfs_action_list_init(
178 struct xfs_action_list
*alist
)
180 INIT_LIST_HEAD(&alist
->list
);
182 alist
->sorted
= false;
185 /* Number of repairs in this list. */
187 xfs_action_list_length(
188 struct xfs_action_list
*alist
)
193 /* Add to the list of repairs. */
196 struct xfs_action_list
*alist
,
197 struct action_item
*aitem
)
199 list_add_tail(&aitem
->list
, &alist
->list
);
201 alist
->sorted
= false;
204 /* Splice two repair lists. */
206 xfs_action_list_splice(
207 struct xfs_action_list
*dest
,
208 struct xfs_action_list
*src
)
213 list_splice_tail_init(&src
->list
, &dest
->list
);
216 dest
->sorted
= false;
219 /* Repair everything on this list. */
221 xfs_action_list_process(
222 struct scrub_ctx
*ctx
,
224 struct xfs_action_list
*alist
,
225 unsigned int repair_flags
)
227 struct action_item
*aitem
;
228 struct action_item
*n
;
229 enum check_outcome fix
;
231 if (!alist
->sorted
) {
232 list_sort(NULL
, &alist
->list
, xfs_action_item_compare
);
233 alist
->sorted
= true;
236 list_for_each_entry_safe(aitem
, n
, &alist
->list
, list
) {
237 fix
= xfs_repair_metadata(ctx
, fd
, aitem
, repair_flags
);
240 if (!(repair_flags
& ALP_NOPROGRESS
))
243 list_del(&aitem
->list
);
255 return !xfs_scrub_excessive_errors(ctx
);
258 /* Defer all the repairs until phase 4. */
260 xfs_action_list_defer(
261 struct scrub_ctx
*ctx
,
263 struct xfs_action_list
*alist
)
265 ASSERT(agno
< ctx
->geo
.agcount
);
267 xfs_action_list_splice(&ctx
->action_lists
[agno
], alist
);
270 /* Run actions now and defer unfinished items for later. */
272 xfs_action_list_process_or_defer(
273 struct scrub_ctx
*ctx
,
275 struct xfs_action_list
*alist
)
279 moveon
= xfs_action_list_process(ctx
, ctx
->mnt_fd
, alist
,
280 ALP_REPAIR_ONLY
| ALP_NOPROGRESS
);
284 xfs_action_list_defer(ctx
, agno
, alist
);