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