]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/phase4.c
xfsprogs: Release v6.7.0
[thirdparty/xfsprogs-dev.git] / scrub / phase4.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2018-2024 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <djwong@kernel.org>
5 */
6 #include "xfs.h"
7 #include <stdint.h>
8 #include <dirent.h>
9 #include <sys/types.h>
10 #include <sys/statvfs.h>
11 #include "list.h"
12 #include "libfrog/paths.h"
13 #include "libfrog/workqueue.h"
14 #include "xfs_scrub.h"
15 #include "common.h"
16 #include "progress.h"
17 #include "scrub.h"
18 #include "repair.h"
19 #include "vfs.h"
20
21 /* Phase 4: Repair filesystem. */
22
23 /* Fix all the problems in our per-AG list. */
24 static void
25 repair_ag(
26 struct workqueue *wq,
27 xfs_agnumber_t agno,
28 void *priv)
29 {
30 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
31 bool *aborted = priv;
32 struct action_list *alist;
33 unsigned long long unfixed;
34 unsigned long long new_unfixed;
35 unsigned int flags = 0;
36 int ret;
37
38 alist = &ctx->action_lists[agno];
39 unfixed = action_list_length(alist);
40
41 /* Repair anything broken until we fail to make progress. */
42 do {
43 ret = action_list_process(ctx, -1, alist, flags);
44 if (ret) {
45 *aborted = true;
46 return;
47 }
48 new_unfixed = action_list_length(alist);
49 if (new_unfixed == unfixed)
50 break;
51 unfixed = new_unfixed;
52 if (*aborted)
53 return;
54 } while (unfixed > 0);
55
56 /* Try once more, but this time complain if we can't fix things. */
57 flags |= ALP_COMPLAIN_IF_UNFIXED;
58 ret = action_list_process(ctx, -1, alist, flags);
59 if (ret)
60 *aborted = true;
61 }
62
63 /* Process all the action items. */
64 static int
65 repair_everything(
66 struct scrub_ctx *ctx)
67 {
68 struct workqueue wq;
69 xfs_agnumber_t agno;
70 bool aborted = false;
71 int ret;
72
73 ret = -workqueue_create(&wq, (struct xfs_mount *)ctx,
74 scrub_nproc_workqueue(ctx));
75 if (ret) {
76 str_liberror(ctx, ret, _("creating repair workqueue"));
77 return ret;
78 }
79 for (agno = 0; !aborted && agno < ctx->mnt.fsgeom.agcount; agno++) {
80 if (action_list_length(&ctx->action_lists[agno]) == 0)
81 continue;
82
83 ret = -workqueue_add(&wq, repair_ag, agno, &aborted);
84 if (ret) {
85 str_liberror(ctx, ret, _("queueing repair work"));
86 break;
87 }
88 }
89
90 ret = -workqueue_terminate(&wq);
91 if (ret)
92 str_liberror(ctx, ret, _("finishing repair work"));
93 workqueue_destroy(&wq);
94
95 if (aborted)
96 return ECANCELED;
97
98 return 0;
99 }
100
101 /* Decide if we have any repair work to do. */
102 static inline bool
103 have_action_items(
104 struct scrub_ctx *ctx)
105 {
106 xfs_agnumber_t agno;
107
108 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
109 if (action_list_length(&ctx->action_lists[agno]) > 0)
110 return true;
111 }
112
113 return false;
114 }
115
116 /* Trim the unused areas of the filesystem if the caller asked us to. */
117 static void
118 trim_filesystem(
119 struct scrub_ctx *ctx)
120 {
121 if (want_fstrim)
122 fstrim(ctx);
123 progress_add(1);
124 }
125
126 /* Fix everything that needs fixing. */
127 int
128 phase4_func(
129 struct scrub_ctx *ctx)
130 {
131 int ret;
132
133 if (!have_action_items(ctx))
134 goto maybe_trim;
135
136 /*
137 * Check the summary counters early. Normally we do this during phase
138 * seven, but some of the cross-referencing requires fairly-accurate
139 * counters, so counter repairs have to be put on the list now so that
140 * they get fixed before we stop retrying unfixed metadata repairs.
141 */
142 ret = scrub_fs_summary(ctx, &ctx->action_lists[0]);
143 if (ret)
144 return ret;
145
146 ret = repair_everything(ctx);
147 if (ret)
148 return ret;
149
150 /*
151 * If errors remain on the filesystem, do not trim anything. We don't
152 * have any threads running, so it's ok to skip the ctx lock here.
153 */
154 if (ctx->corruptions_found || ctx->unfixable_errors != 0)
155 return 0;
156
157 maybe_trim:
158 trim_filesystem(ctx);
159 return 0;
160 }
161
162 /* Estimate how much work we're going to do. */
163 int
164 phase4_estimate(
165 struct scrub_ctx *ctx,
166 uint64_t *items,
167 unsigned int *nr_threads,
168 int *rshift)
169 {
170 xfs_agnumber_t agno;
171 unsigned long long need_fixing = 0;
172
173 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++)
174 need_fixing += action_list_length(&ctx->action_lists[agno]);
175 need_fixing++;
176 *items = need_fixing;
177 *nr_threads = scrub_nproc(ctx) + 1;
178 *rshift = 0;
179 return 0;
180 }