]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/spacemap.c
xfs_scrub: reclassify runtime errors
[thirdparty/xfsprogs-dev.git] / scrub / spacemap.c
1 /*
2 * Copyright (C) 2018 Oracle. All Rights Reserved.
3 *
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <pthread.h>
25 #include <sys/statvfs.h>
26 #include "workqueue.h"
27 #include "xfs.h"
28 #include "xfs_fs.h"
29 #include "path.h"
30 #include "xfs_scrub.h"
31 #include "common.h"
32 #include "spacemap.h"
33
34 /*
35 * Filesystem space map iterators.
36 *
37 * Logically, we call GETFSMAP to fetch a set of space map records and
38 * call a function to iterate over the records. However, that's not
39 * what actually happens -- the work is split into separate items, with
40 * each AG, the realtime device, and the log device getting their own
41 * work items. For an XFS with a realtime device and an external log,
42 * this means that we can have up to ($agcount + 2) threads running at
43 * once.
44 *
45 * This comes into play if we want to have per-workitem memory. Maybe.
46 * XXX: do we really need all that ?
47 */
48
49 #define FSMAP_NR 65536
50
51 /* Iterate all the fs block mappings between the two keys. */
52 bool
53 xfs_iterate_fsmap(
54 struct scrub_ctx *ctx,
55 const char *descr,
56 struct fsmap *keys,
57 xfs_fsmap_iter_fn fn,
58 void *arg)
59 {
60 struct fsmap_head *head;
61 struct fsmap *p;
62 bool moveon = true;
63 int i;
64 int error;
65
66 head = malloc(fsmap_sizeof(FSMAP_NR));
67 if (!head) {
68 str_errno(ctx, descr);
69 return false;
70 }
71
72 memset(head, 0, sizeof(*head));
73 memcpy(head->fmh_keys, keys, sizeof(struct fsmap) * 2);
74 head->fmh_count = FSMAP_NR;
75
76 while ((error = ioctl(ctx->mnt_fd, FS_IOC_GETFSMAP, head)) == 0) {
77 for (i = 0, p = head->fmh_recs;
78 i < head->fmh_entries;
79 i++, p++) {
80 moveon = fn(ctx, descr, p, arg);
81 if (!moveon)
82 goto out;
83 if (xfs_scrub_excessive_errors(ctx)) {
84 moveon = false;
85 goto out;
86 }
87 }
88
89 if (head->fmh_entries == 0)
90 break;
91 p = &head->fmh_recs[head->fmh_entries - 1];
92 if (p->fmr_flags & FMR_OF_LAST)
93 break;
94 fsmap_advance(head);
95 }
96
97 if (error) {
98 str_errno(ctx, descr);
99 moveon = false;
100 }
101 out:
102 free(head);
103 return moveon;
104 }
105
106 /* GETFSMAP wrappers routines. */
107 struct xfs_scan_blocks {
108 xfs_fsmap_iter_fn fn;
109 void *arg;
110 bool moveon;
111 };
112
113 /* Iterate all the reverse mappings of an AG. */
114 static void
115 xfs_scan_ag_blocks(
116 struct workqueue *wq,
117 xfs_agnumber_t agno,
118 void *arg)
119 {
120 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
121 struct xfs_scan_blocks *sbx = arg;
122 char descr[DESCR_BUFSZ];
123 struct fsmap keys[2];
124 off64_t bperag;
125 bool moveon;
126
127 bperag = (off64_t)ctx->geo.agblocks *
128 (off64_t)ctx->geo.blocksize;
129
130 snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u fsmap"),
131 major(ctx->fsinfo.fs_datadev),
132 minor(ctx->fsinfo.fs_datadev),
133 agno);
134
135 memset(keys, 0, sizeof(struct fsmap) * 2);
136 keys->fmr_device = ctx->fsinfo.fs_datadev;
137 keys->fmr_physical = agno * bperag;
138 (keys + 1)->fmr_device = ctx->fsinfo.fs_datadev;
139 (keys + 1)->fmr_physical = ((agno + 1) * bperag) - 1;
140 (keys + 1)->fmr_owner = ULLONG_MAX;
141 (keys + 1)->fmr_offset = ULLONG_MAX;
142 (keys + 1)->fmr_flags = UINT_MAX;
143
144 moveon = xfs_iterate_fsmap(ctx, descr, keys, sbx->fn, sbx->arg);
145 if (!moveon)
146 sbx->moveon = false;
147 }
148
149 /* Iterate all the reverse mappings of a standalone device. */
150 static void
151 xfs_scan_dev_blocks(
152 struct scrub_ctx *ctx,
153 int idx,
154 dev_t dev,
155 struct xfs_scan_blocks *sbx)
156 {
157 struct fsmap keys[2];
158 char descr[DESCR_BUFSZ];
159 bool moveon;
160
161 snprintf(descr, DESCR_BUFSZ, _("dev %d:%d fsmap"),
162 major(dev), minor(dev));
163
164 memset(keys, 0, sizeof(struct fsmap) * 2);
165 keys->fmr_device = dev;
166 (keys + 1)->fmr_device = dev;
167 (keys + 1)->fmr_physical = ULLONG_MAX;
168 (keys + 1)->fmr_owner = ULLONG_MAX;
169 (keys + 1)->fmr_offset = ULLONG_MAX;
170 (keys + 1)->fmr_flags = UINT_MAX;
171
172 moveon = xfs_iterate_fsmap(ctx, descr, keys, sbx->fn, sbx->arg);
173 if (!moveon)
174 sbx->moveon = false;
175 }
176
177 /* Iterate all the reverse mappings of the realtime device. */
178 static void
179 xfs_scan_rt_blocks(
180 struct workqueue *wq,
181 xfs_agnumber_t agno,
182 void *arg)
183 {
184 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
185
186 xfs_scan_dev_blocks(ctx, agno, ctx->fsinfo.fs_rtdev, arg);
187 }
188
189 /* Iterate all the reverse mappings of the log device. */
190 static void
191 xfs_scan_log_blocks(
192 struct workqueue *wq,
193 xfs_agnumber_t agno,
194 void *arg)
195 {
196 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
197
198 xfs_scan_dev_blocks(ctx, agno, ctx->fsinfo.fs_logdev, arg);
199 }
200
201 /* Scan all the blocks in a filesystem. */
202 bool
203 xfs_scan_all_spacemaps(
204 struct scrub_ctx *ctx,
205 xfs_fsmap_iter_fn fn,
206 void *arg)
207 {
208 struct workqueue wq;
209 struct xfs_scan_blocks sbx;
210 xfs_agnumber_t agno;
211 int ret;
212
213 sbx.moveon = true;
214 sbx.fn = fn;
215 sbx.arg = arg;
216
217 ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
218 scrub_nproc_workqueue(ctx));
219 if (ret) {
220 str_info(ctx, ctx->mntpoint, _("Could not create workqueue."));
221 return false;
222 }
223 if (ctx->fsinfo.fs_rt) {
224 ret = workqueue_add(&wq, xfs_scan_rt_blocks,
225 ctx->geo.agcount + 1, &sbx);
226 if (ret) {
227 sbx.moveon = false;
228 str_info(ctx, ctx->mntpoint,
229 _("Could not queue rtdev fsmap work."));
230 goto out;
231 }
232 }
233 if (ctx->fsinfo.fs_log) {
234 ret = workqueue_add(&wq, xfs_scan_log_blocks,
235 ctx->geo.agcount + 2, &sbx);
236 if (ret) {
237 sbx.moveon = false;
238 str_info(ctx, ctx->mntpoint,
239 _("Could not queue logdev fsmap work."));
240 goto out;
241 }
242 }
243 for (agno = 0; agno < ctx->geo.agcount; agno++) {
244 ret = workqueue_add(&wq, xfs_scan_ag_blocks, agno, &sbx);
245 if (ret) {
246 sbx.moveon = false;
247 str_info(ctx, ctx->mntpoint,
248 _("Could not queue AG %u fsmap work."), agno);
249 break;
250 }
251 }
252 out:
253 workqueue_destroy(&wq);
254
255 return sbx.moveon;
256 }