1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2018-2024 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <djwong@kernel.org>
10 #include <sys/statvfs.h>
12 #include "libfrog/paths.h"
13 #include "libfrog/workqueue.h"
14 #include "xfs_scrub.h"
22 /* Phase 4: Repair filesystem. */
24 struct repair_list_schedule
{
25 struct action_list
*repair_list
;
27 /* Action items that we could not resolve and want to try again. */
28 struct action_list requeue_list
;
32 /* Workers use this to signal the scheduler when all work is done. */
35 /* Number of workers that are still running. */
38 /* Or should we all abort? */
41 /* Did we make any progress this round? */
45 /* Try to repair as many things on our list as we can. */
52 struct repair_list_schedule
*rls
= priv
;
53 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
55 pthread_mutex_lock(&rls
->lock
);
56 while (!rls
->aborted
) {
57 struct action_item
*aitem
;
58 enum tryrepair_outcome outcome
;
61 aitem
= action_list_pop(rls
->repair_list
);
65 pthread_mutex_unlock(&rls
->lock
);
66 ret
= action_item_try_repair(ctx
, aitem
, &outcome
);
67 pthread_mutex_lock(&rls
->lock
);
78 * Partial progress. Make a note of that and requeue
79 * this item for the next round.
81 rls
->made_progress
= true;
82 action_list_add(&rls
->requeue_list
, aitem
);
86 * No progress. Requeue this item for a later round,
87 * which could happen if something else makes progress.
89 action_list_add(&rls
->requeue_list
, aitem
);
93 * All repairs for this item completed. Free the item,
94 * and remember that progress was made.
96 rls
->made_progress
= true;
103 if (rls
->workers
== 0)
104 pthread_cond_broadcast(&rls
->done
);
105 pthread_mutex_unlock(&rls
->lock
);
109 * Schedule repair list workers. Returns 1 if we made progress, 0 if we
110 * did not, or -1 if we need to abort everything.
113 repair_list_schedule(
114 struct scrub_ctx
*ctx
,
115 struct workqueue
*wq
,
116 struct action_list
*repair_list
)
118 struct repair_list_schedule rls
= {
119 .lock
= PTHREAD_MUTEX_INITIALIZER
,
120 .done
= PTHREAD_COND_INITIALIZER
,
121 .repair_list
= repair_list
,
124 unsigned int nr_workers
= scrub_nproc(ctx
);
125 bool made_any_progress
= false;
128 if (action_list_empty(repair_list
))
131 action_list_init(&rls
.requeue_list
);
134 * Use the workers to run through the entire repair list once. Requeue
135 * anything that did not make progress, and keep trying as long as the
136 * workers made any kind of progress.
139 rls
.made_progress
= false;
141 /* Start all the worker threads. */
142 for (i
= 0; i
< nr_workers
; i
++) {
143 pthread_mutex_lock(&rls
.lock
);
145 pthread_mutex_unlock(&rls
.lock
);
147 ret
= -workqueue_add(wq
, repair_list_worker
, 0, &rls
);
149 str_liberror(ctx
, ret
,
150 _("queueing repair list worker"));
151 pthread_mutex_lock(&rls
.lock
);
153 pthread_mutex_unlock(&rls
.lock
);
158 /* Wait for all worker functions to return. */
159 pthread_mutex_lock(&rls
.lock
);
160 while (rls
.workers
> 0)
161 pthread_cond_wait(&rls
.done
, &rls
.lock
);
162 pthread_mutex_unlock(&rls
.lock
);
164 action_list_merge(repair_list
, &rls
.requeue_list
);
166 if (ret
|| rls
.aborted
)
168 if (rls
.made_progress
)
169 made_any_progress
= true;
170 } while (rls
.made_progress
&& !action_list_empty(repair_list
));
172 if (made_any_progress
)
177 /* Process both repair lists. */
180 struct scrub_ctx
*ctx
)
186 ret
= -workqueue_create(&wq
, (struct xfs_mount
*)ctx
,
187 scrub_nproc_workqueue(ctx
));
189 str_liberror(ctx
, ret
, _("creating repair workqueue"));
194 * Try to fix everything on the space metadata repair list and then the
195 * file repair list until we stop making progress. These repairs can
196 * be threaded, if the user desires.
201 ret
= repair_list_schedule(ctx
, &wq
, ctx
->fs_repair_list
);
207 ret
= repair_list_schedule(ctx
, &wq
, ctx
->file_repair_list
);
212 } while (fixed_anything
> 0);
214 ret
= -workqueue_terminate(&wq
);
216 str_liberror(ctx
, ret
, _("finishing repair work"));
217 workqueue_destroy(&wq
);
223 * Combine both repair lists and repair everything serially. This is
224 * the last chance to fix things.
226 action_list_merge(ctx
->fs_repair_list
, ctx
->file_repair_list
);
227 return action_list_process(ctx
, ctx
->fs_repair_list
, XRM_FINAL_WARNING
);
230 /* Fix everything that needs fixing. */
233 struct scrub_ctx
*ctx
)
235 struct xfs_fsop_geom fsgeom
;
236 struct scrub_item sri
;
239 if (action_list_empty(ctx
->fs_repair_list
) &&
240 action_list_empty(ctx
->file_repair_list
))
243 if (ctx
->mode
== SCRUB_MODE_PREEN
&& ctx
->corruptions_found
) {
244 str_info(ctx
, ctx
->mntpoint
,
245 _("Corruptions found; will not optimize. Re-run without -p.\n"));
250 * Check the resource usage counters early. Normally we do this during
251 * phase 7, but some of the cross-referencing requires fairly accurate
252 * summary counters. Check and try to repair them now to minimize the
253 * chance that repairs of primary metadata fail due to secondary
254 * metadata. If repairs fails, we'll come back during phase 7.
256 scrub_item_init_fs(&sri
);
257 scrub_item_schedule(&sri
, XFS_SCRUB_TYPE_FSCOUNTERS
);
260 * Repair possibly bad quota counts before starting other repairs,
261 * because wildly incorrect quota counts can cause shutdowns.
262 * Quotacheck scans all inodes, so we only want to do it if we know
265 ret
= xfrog_geometry(ctx
->mnt
.fd
, &fsgeom
);
269 if (fsgeom
.sick
& XFS_FSOP_GEOM_SICK_QUOTACHECK
)
270 scrub_item_schedule(&sri
, XFS_SCRUB_TYPE_QUOTACHECK
);
272 /* Check and repair counters before starting on the rest. */
273 ret
= scrub_item_check(ctx
, &sri
);
276 ret
= repair_item_corruption(ctx
, &sri
);
280 return repair_everything(ctx
);
283 /* Estimate how much work we're going to do. */
286 struct scrub_ctx
*ctx
,
288 unsigned int *nr_threads
,
291 unsigned long long need_fixing
;
293 /* Everything on the repair lis. */
294 need_fixing
= action_list_length(ctx
->fs_repair_list
) +
295 action_list_length(ctx
->file_repair_list
);
297 *items
= need_fixing
;
298 *nr_threads
= scrub_nproc(ctx
) + 1;