]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
7e36bc0f DW |
2 | /* |
3 | * Copyright (C) 2018 Oracle. All Rights Reserved. | |
7e36bc0f | 4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> |
7e36bc0f | 5 | */ |
a440f877 | 6 | #include "xfs.h" |
7e36bc0f | 7 | #include <stdint.h> |
7e36bc0f DW |
8 | #include <dirent.h> |
9 | #include <sys/types.h> | |
7e36bc0f | 10 | #include <sys/statvfs.h> |
7e36bc0f | 11 | #include "list.h" |
42b4c8e8 | 12 | #include "libfrog/paths.h" |
56598728 | 13 | #include "libfrog/workqueue.h" |
7e36bc0f DW |
14 | #include "xfs_scrub.h" |
15 | #include "common.h" | |
ed60d210 | 16 | #include "progress.h" |
7e36bc0f | 17 | #include "scrub.h" |
ee310b0c | 18 | #include "repair.h" |
7e36bc0f DW |
19 | #include "vfs.h" |
20 | ||
21 | /* Phase 4: Repair filesystem. */ | |
22 | ||
ee310b0c DW |
23 | /* Fix all the problems in our per-AG list. */ |
24 | static void | |
596a30ba | 25 | repair_ag( |
ee310b0c DW |
26 | struct workqueue *wq, |
27 | xfs_agnumber_t agno, | |
28 | void *priv) | |
29 | { | |
30 | struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; | |
596a30ba | 31 | bool *aborted = priv; |
83d2c80b | 32 | struct action_list *alist; |
ee310b0c DW |
33 | size_t unfixed; |
34 | size_t new_unfixed; | |
35 | unsigned int flags = 0; | |
83d2c80b | 36 | int ret; |
ee310b0c DW |
37 | |
38 | alist = &ctx->action_lists[agno]; | |
83d2c80b | 39 | unfixed = action_list_length(alist); |
ee310b0c DW |
40 | |
41 | /* Repair anything broken until we fail to make progress. */ | |
42 | do { | |
83d2c80b DW |
43 | ret = action_list_process(ctx, ctx->mnt.fd, alist, flags); |
44 | if (ret) { | |
596a30ba | 45 | *aborted = true; |
ee310b0c DW |
46 | return; |
47 | } | |
83d2c80b | 48 | new_unfixed = action_list_length(alist); |
ee310b0c DW |
49 | if (new_unfixed == unfixed) |
50 | break; | |
51 | unfixed = new_unfixed; | |
596a30ba DW |
52 | if (*aborted) |
53 | return; | |
54 | } while (unfixed > 0); | |
ee310b0c DW |
55 | |
56 | /* Try once more, but this time complain if we can't fix things. */ | |
06e49f3e | 57 | flags |= ALP_COMPLAIN_IF_UNFIXED; |
83d2c80b DW |
58 | ret = action_list_process(ctx, ctx->mnt.fd, alist, flags); |
59 | if (ret) | |
596a30ba | 60 | *aborted = true; |
ee310b0c DW |
61 | } |
62 | ||
7e36bc0f | 63 | /* Process all the action items. */ |
596a30ba DW |
64 | static int |
65 | repair_everything( | |
7e36bc0f DW |
66 | struct scrub_ctx *ctx) |
67 | { | |
ee310b0c DW |
68 | struct workqueue wq; |
69 | xfs_agnumber_t agno; | |
596a30ba | 70 | bool aborted = false; |
ee310b0c DW |
71 | int ret; |
72 | ||
73 | ret = workqueue_create(&wq, (struct xfs_mount *)ctx, | |
74 | scrub_nproc_workqueue(ctx)); | |
75 | if (ret) { | |
9d57cbfc | 76 | str_liberror(ctx, ret, _("creating repair workqueue")); |
596a30ba | 77 | return ret; |
ee310b0c | 78 | } |
596a30ba DW |
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")); | |
ee310b0c | 86 | break; |
596a30ba | 87 | } |
ee310b0c | 88 | } |
71296cf8 DW |
89 | |
90 | ret = workqueue_terminate(&wq); | |
596a30ba | 91 | if (ret) |
71296cf8 | 92 | str_liberror(ctx, ret, _("finishing repair work")); |
ee310b0c | 93 | workqueue_destroy(&wq); |
7e36bc0f | 94 | |
596a30ba DW |
95 | if (aborted) |
96 | return ECANCELED; | |
97 | ||
7e36bc0f | 98 | pthread_mutex_lock(&ctx->lock); |
596a30ba | 99 | if (ctx->corruptions_found == 0 && ctx->unfixable_errors == 0 && |
49e05cb0 | 100 | want_fstrim) { |
7e36bc0f | 101 | fstrim(ctx); |
ed60d210 DW |
102 | progress_add(1); |
103 | } | |
7e36bc0f DW |
104 | pthread_mutex_unlock(&ctx->lock); |
105 | ||
596a30ba | 106 | return 0; |
7e36bc0f DW |
107 | } |
108 | ||
109 | /* Fix everything that needs fixing. */ | |
596a30ba DW |
110 | int |
111 | phase4_func( | |
d22f2471 | 112 | struct scrub_ctx *ctx) |
7e36bc0f | 113 | { |
d22f2471 | 114 | int ret; |
cbaf1c9d DW |
115 | |
116 | /* | |
117 | * Check the summary counters early. Normally we do this during phase | |
118 | * seven, but some of the cross-referencing requires fairly-accurate | |
119 | * counters, so counter repairs have to be put on the list now so that | |
120 | * they get fixed before we stop retrying unfixed metadata repairs. | |
121 | */ | |
d22f2471 DW |
122 | ret = xfs_scrub_fs_summary(ctx, &ctx->action_lists[0]); |
123 | if (ret) | |
596a30ba | 124 | return ret; |
cbaf1c9d | 125 | |
596a30ba | 126 | return repair_everything(ctx); |
7e36bc0f DW |
127 | } |
128 | ||
ed60d210 | 129 | bool |
596a30ba DW |
130 | xfs_repair_fs( |
131 | struct scrub_ctx *ctx) | |
132 | { | |
133 | return phase4_func(ctx) == 0; | |
134 | } | |
135 | ||
136 | /* Estimate how much work we're going to do. */ | |
137 | int | |
138 | phase4_estimate( | |
ed60d210 DW |
139 | struct scrub_ctx *ctx, |
140 | uint64_t *items, | |
141 | unsigned int *nr_threads, | |
142 | int *rshift) | |
143 | { | |
ee310b0c DW |
144 | xfs_agnumber_t agno; |
145 | size_t need_fixing = 0; | |
146 | ||
3f9efb2e | 147 | for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) |
83d2c80b | 148 | need_fixing += action_list_length(&ctx->action_lists[agno]); |
ee310b0c DW |
149 | need_fixing++; |
150 | *items = need_fixing; | |
151 | *nr_threads = scrub_nproc(ctx) + 1; | |
ed60d210 | 152 | *rshift = 0; |
596a30ba DW |
153 | return 0; |
154 | } | |
155 | ||
156 | bool | |
157 | xfs_estimate_repair_work( | |
158 | struct scrub_ctx *ctx, | |
159 | uint64_t *items, | |
160 | unsigned int *nr_threads, | |
161 | int *rshift) | |
162 | { | |
163 | return phase4_estimate(ctx, items, nr_threads, rshift) == 0; | |
ed60d210 | 164 | } |