]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - scrub/spacemap.c
libfrog: fix workqueue error communication problems
[thirdparty/xfsprogs-dev.git] / scrub / spacemap.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0+
bc94c5d6
DW
2/*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
bc94c5d6 4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
bc94c5d6 5 */
a440f877 6#include "xfs.h"
bc94c5d6
DW
7#include <stdint.h>
8#include <string.h>
9#include <pthread.h>
10#include <sys/statvfs.h>
56598728 11#include "libfrog/workqueue.h"
42b4c8e8 12#include "libfrog/paths.h"
bc94c5d6
DW
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. */
35bool
36xfs_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
3f9efb2e 59 while ((error = ioctl(ctx->mnt.fd, FS_IOC_GETFSMAP, head)) == 0) {
bc94c5d6
DW
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 }
84out:
85 free(head);
86 return moveon;
87}
88
89/* GETFSMAP wrappers routines. */
90struct 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. */
97static void
98xfs_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
3f9efb2e
DW
110 bperag = (off64_t)ctx->mnt.fsgeom.agblocks *
111 (off64_t)ctx->mnt.fsgeom.blocksize;
bc94c5d6
DW
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. */
133static void
134xfs_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. */
161static void
162xfs_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. */
173static void
174xfs_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. */
185bool
186xfs_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) {
9d57cbfc 203 str_liberror(ctx, ret, _("creating fsmap workqueue"));
bc94c5d6
DW
204 return false;
205 }
206 if (ctx->fsinfo.fs_rt) {
207 ret = workqueue_add(&wq, xfs_scan_rt_blocks,
3f9efb2e 208 ctx->mnt.fsgeom.agcount + 1, &sbx);
bc94c5d6
DW
209 if (ret) {
210 sbx.moveon = false;
9d57cbfc 211 str_liberror(ctx, ret, _("queueing rtdev fsmap work"));
bc94c5d6
DW
212 goto out;
213 }
214 }
215 if (ctx->fsinfo.fs_log) {
216 ret = workqueue_add(&wq, xfs_scan_log_blocks,
3f9efb2e 217 ctx->mnt.fsgeom.agcount + 2, &sbx);
bc94c5d6
DW
218 if (ret) {
219 sbx.moveon = false;
9d57cbfc 220 str_liberror(ctx, ret, _("queueing logdev fsmap work"));
bc94c5d6
DW
221 goto out;
222 }
223 }
3f9efb2e 224 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
bc94c5d6
DW
225 ret = workqueue_add(&wq, xfs_scan_ag_blocks, agno, &sbx);
226 if (ret) {
227 sbx.moveon = false;
9d57cbfc 228 str_liberror(ctx, ret, _("queueing per-AG fsmap work"));
bc94c5d6
DW
229 break;
230 }
231 }
232out:
233 workqueue_destroy(&wq);
234
235 return sbx.moveon;
236}