]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - scrub/spacemap.c
libfrog: convert workqueue.c functions to negative error codes
[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
7a2eef2b
DW
34/*
35 * Iterate all the fs block mappings between the two keys. Returns 0 or a
36 * positive error number.
37 */
38int
39scrub_iterate_fsmap(
bc94c5d6 40 struct scrub_ctx *ctx,
bc94c5d6 41 struct fsmap *keys,
7a2eef2b 42 scrub_fsmap_iter_fn fn,
bc94c5d6
DW
43 void *arg)
44{
45 struct fsmap_head *head;
46 struct fsmap *p;
bc94c5d6
DW
47 int i;
48 int error;
49
50 head = malloc(fsmap_sizeof(FSMAP_NR));
7a2eef2b
DW
51 if (!head)
52 return errno;
bc94c5d6
DW
53
54 memset(head, 0, sizeof(*head));
55 memcpy(head->fmh_keys, keys, sizeof(struct fsmap) * 2);
56 head->fmh_count = FSMAP_NR;
57
3f9efb2e 58 while ((error = ioctl(ctx->mnt.fd, FS_IOC_GETFSMAP, head)) == 0) {
bc94c5d6
DW
59 for (i = 0, p = head->fmh_recs;
60 i < head->fmh_entries;
61 i++, p++) {
7a2eef2b
DW
62 error = fn(ctx, p, arg);
63 if (error)
bc94c5d6 64 goto out;
7a2eef2b 65 if (xfs_scrub_excessive_errors(ctx))
bc94c5d6 66 goto out;
bc94c5d6
DW
67 }
68
69 if (head->fmh_entries == 0)
70 break;
71 p = &head->fmh_recs[head->fmh_entries - 1];
72 if (p->fmr_flags & FMR_OF_LAST)
73 break;
74 fsmap_advance(head);
75 }
7a2eef2b
DW
76 if (error)
77 error = errno;
bc94c5d6
DW
78out:
79 free(head);
7a2eef2b 80 return error;
bc94c5d6
DW
81}
82
83/* GETFSMAP wrappers routines. */
7a2eef2b
DW
84struct scan_blocks {
85 scrub_fsmap_iter_fn fn;
bc94c5d6 86 void *arg;
7a2eef2b 87 bool aborted;
bc94c5d6
DW
88};
89
90/* Iterate all the reverse mappings of an AG. */
91static void
7a2eef2b 92scan_ag_rmaps(
bc94c5d6
DW
93 struct workqueue *wq,
94 xfs_agnumber_t agno,
95 void *arg)
96{
97 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
7a2eef2b 98 struct scan_blocks *sbx = arg;
bc94c5d6
DW
99 struct fsmap keys[2];
100 off64_t bperag;
7a2eef2b 101 int ret;
bc94c5d6 102
3f9efb2e
DW
103 bperag = (off64_t)ctx->mnt.fsgeom.agblocks *
104 (off64_t)ctx->mnt.fsgeom.blocksize;
bc94c5d6 105
bc94c5d6
DW
106 memset(keys, 0, sizeof(struct fsmap) * 2);
107 keys->fmr_device = ctx->fsinfo.fs_datadev;
108 keys->fmr_physical = agno * bperag;
109 (keys + 1)->fmr_device = ctx->fsinfo.fs_datadev;
110 (keys + 1)->fmr_physical = ((agno + 1) * bperag) - 1;
111 (keys + 1)->fmr_owner = ULLONG_MAX;
112 (keys + 1)->fmr_offset = ULLONG_MAX;
113 (keys + 1)->fmr_flags = UINT_MAX;
114
7a2eef2b
DW
115 if (sbx->aborted)
116 return;
117
118 ret = scrub_iterate_fsmap(ctx, keys, sbx->fn, sbx->arg);
119 if (ret) {
120 char descr[DESCR_BUFSZ];
121
122 snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u fsmap"),
123 major(ctx->fsinfo.fs_datadev),
124 minor(ctx->fsinfo.fs_datadev),
125 agno);
126 str_liberror(ctx, ret, descr);
127 sbx->aborted = true;
128 }
bc94c5d6
DW
129}
130
131/* Iterate all the reverse mappings of a standalone device. */
132static void
7a2eef2b 133scan_dev_rmaps(
bc94c5d6
DW
134 struct scrub_ctx *ctx,
135 int idx,
136 dev_t dev,
7a2eef2b 137 struct scan_blocks *sbx)
bc94c5d6
DW
138{
139 struct fsmap keys[2];
7a2eef2b 140 int ret;
bc94c5d6
DW
141
142 memset(keys, 0, sizeof(struct fsmap) * 2);
143 keys->fmr_device = dev;
144 (keys + 1)->fmr_device = dev;
145 (keys + 1)->fmr_physical = ULLONG_MAX;
146 (keys + 1)->fmr_owner = ULLONG_MAX;
147 (keys + 1)->fmr_offset = ULLONG_MAX;
148 (keys + 1)->fmr_flags = UINT_MAX;
149
7a2eef2b
DW
150 if (sbx->aborted)
151 return;
152
153 ret = scrub_iterate_fsmap(ctx, keys, sbx->fn, sbx->arg);
154 if (ret) {
155 char descr[DESCR_BUFSZ];
156
157 snprintf(descr, DESCR_BUFSZ, _("dev %d:%d fsmap"),
158 major(dev), minor(dev));
159 str_liberror(ctx, ret, descr);
160 sbx->aborted = true;
161 }
bc94c5d6
DW
162}
163
164/* Iterate all the reverse mappings of the realtime device. */
165static void
7a2eef2b 166scan_rt_rmaps(
bc94c5d6
DW
167 struct workqueue *wq,
168 xfs_agnumber_t agno,
169 void *arg)
170{
171 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
172
7a2eef2b 173 scan_dev_rmaps(ctx, agno, ctx->fsinfo.fs_rtdev, arg);
bc94c5d6
DW
174}
175
176/* Iterate all the reverse mappings of the log device. */
177static void
7a2eef2b 178scan_log_rmaps(
bc94c5d6
DW
179 struct workqueue *wq,
180 xfs_agnumber_t agno,
181 void *arg)
182{
183 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
184
7a2eef2b 185 scan_dev_rmaps(ctx, agno, ctx->fsinfo.fs_logdev, arg);
bc94c5d6
DW
186}
187
7a2eef2b
DW
188/*
189 * Scan all the blocks in a filesystem. If errors occur, this function will
190 * log them and return nonzero.
191 */
192int
193scrub_scan_all_spacemaps(
bc94c5d6 194 struct scrub_ctx *ctx,
7a2eef2b 195 scrub_fsmap_iter_fn fn,
bc94c5d6
DW
196 void *arg)
197{
198 struct workqueue wq;
7a2eef2b
DW
199 struct scan_blocks sbx = {
200 .fn = fn,
201 .arg = arg,
202 };
bc94c5d6
DW
203 xfs_agnumber_t agno;
204 int ret;
205
baed134d 206 ret = -workqueue_create(&wq, (struct xfs_mount *)ctx,
bc94c5d6
DW
207 scrub_nproc_workqueue(ctx));
208 if (ret) {
9d57cbfc 209 str_liberror(ctx, ret, _("creating fsmap workqueue"));
7a2eef2b 210 return ret;
bc94c5d6
DW
211 }
212 if (ctx->fsinfo.fs_rt) {
baed134d 213 ret = -workqueue_add(&wq, scan_rt_rmaps,
3f9efb2e 214 ctx->mnt.fsgeom.agcount + 1, &sbx);
bc94c5d6 215 if (ret) {
7a2eef2b 216 sbx.aborted = true;
9d57cbfc 217 str_liberror(ctx, ret, _("queueing rtdev fsmap work"));
bc94c5d6
DW
218 goto out;
219 }
220 }
221 if (ctx->fsinfo.fs_log) {
baed134d 222 ret = -workqueue_add(&wq, scan_log_rmaps,
3f9efb2e 223 ctx->mnt.fsgeom.agcount + 2, &sbx);
bc94c5d6 224 if (ret) {
7a2eef2b 225 sbx.aborted = true;
9d57cbfc 226 str_liberror(ctx, ret, _("queueing logdev fsmap work"));
bc94c5d6
DW
227 goto out;
228 }
229 }
3f9efb2e 230 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
baed134d 231 ret = -workqueue_add(&wq, scan_ag_rmaps, agno, &sbx);
bc94c5d6 232 if (ret) {
7a2eef2b 233 sbx.aborted = true;
9d57cbfc 234 str_liberror(ctx, ret, _("queueing per-AG fsmap work"));
bc94c5d6
DW
235 break;
236 }
237 }
238out:
baed134d 239 ret = -workqueue_terminate(&wq);
71296cf8 240 if (ret) {
7a2eef2b 241 sbx.aborted = true;
71296cf8
DW
242 str_liberror(ctx, ret, _("finishing fsmap work"));
243 }
bc94c5d6
DW
244 workqueue_destroy(&wq);
245
7a2eef2b
DW
246 if (!ret && sbx.aborted)
247 ret = -1;
248
249 return ret;
bc94c5d6 250}