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