]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/spacemap.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
10 #include <sys/statvfs.h>
11 #include "libfrog/workqueue.h"
12 #include "libfrog/paths.h"
13 #include "xfs_scrub.h"
18 * Filesystem space map iterators.
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
28 * This comes into play if we want to have per-workitem memory. Maybe.
29 * XXX: do we really need all that ?
32 #define FSMAP_NR 65536
35 * Iterate all the fs block mappings between the two keys. Returns 0 or a
36 * positive error number.
40 struct scrub_ctx
*ctx
,
42 scrub_fsmap_iter_fn fn
,
45 struct fsmap_head
*head
;
50 head
= malloc(fsmap_sizeof(FSMAP_NR
));
54 memset(head
, 0, sizeof(*head
));
55 memcpy(head
->fmh_keys
, keys
, sizeof(struct fsmap
) * 2);
56 head
->fmh_count
= FSMAP_NR
;
58 while ((error
= ioctl(ctx
->mnt
.fd
, FS_IOC_GETFSMAP
, head
)) == 0) {
59 for (i
= 0, p
= head
->fmh_recs
;
60 i
< head
->fmh_entries
;
62 error
= fn(ctx
, p
, arg
);
65 if (xfs_scrub_excessive_errors(ctx
))
69 if (head
->fmh_entries
== 0)
71 p
= &head
->fmh_recs
[head
->fmh_entries
- 1];
72 if (p
->fmr_flags
& FMR_OF_LAST
)
83 /* GETFSMAP wrappers routines. */
85 scrub_fsmap_iter_fn fn
;
90 /* Iterate all the reverse mappings of an AG. */
97 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
98 struct scan_blocks
*sbx
= arg
;
103 bperag
= (off64_t
)ctx
->mnt
.fsgeom
.agblocks
*
104 (off64_t
)ctx
->mnt
.fsgeom
.blocksize
;
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
;
118 ret
= scrub_iterate_fsmap(ctx
, keys
, sbx
->fn
, sbx
->arg
);
120 char descr
[DESCR_BUFSZ
];
122 snprintf(descr
, DESCR_BUFSZ
, _("dev %d:%d AG %u fsmap"),
123 major(ctx
->fsinfo
.fs_datadev
),
124 minor(ctx
->fsinfo
.fs_datadev
),
126 str_liberror(ctx
, ret
, descr
);
131 /* Iterate all the reverse mappings of a standalone device. */
134 struct scrub_ctx
*ctx
,
137 struct scan_blocks
*sbx
)
139 struct fsmap keys
[2];
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
;
153 ret
= scrub_iterate_fsmap(ctx
, keys
, sbx
->fn
, sbx
->arg
);
155 char descr
[DESCR_BUFSZ
];
157 snprintf(descr
, DESCR_BUFSZ
, _("dev %d:%d fsmap"),
158 major(dev
), minor(dev
));
159 str_liberror(ctx
, ret
, descr
);
164 /* Iterate all the reverse mappings of the realtime device. */
167 struct workqueue
*wq
,
171 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
173 scan_dev_rmaps(ctx
, agno
, ctx
->fsinfo
.fs_rtdev
, arg
);
176 /* Iterate all the reverse mappings of the log device. */
179 struct workqueue
*wq
,
183 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
185 scan_dev_rmaps(ctx
, agno
, ctx
->fsinfo
.fs_logdev
, arg
);
189 * Scan all the blocks in a filesystem. If errors occur, this function will
190 * log them and return nonzero.
193 scrub_scan_all_spacemaps(
194 struct scrub_ctx
*ctx
,
195 scrub_fsmap_iter_fn fn
,
199 struct scan_blocks sbx
= {
206 ret
= -workqueue_create(&wq
, (struct xfs_mount
*)ctx
,
207 scrub_nproc_workqueue(ctx
));
209 str_liberror(ctx
, ret
, _("creating fsmap workqueue"));
212 if (ctx
->fsinfo
.fs_rt
) {
213 ret
= -workqueue_add(&wq
, scan_rt_rmaps
,
214 ctx
->mnt
.fsgeom
.agcount
+ 1, &sbx
);
217 str_liberror(ctx
, ret
, _("queueing rtdev fsmap work"));
221 if (ctx
->fsinfo
.fs_log
) {
222 ret
= -workqueue_add(&wq
, scan_log_rmaps
,
223 ctx
->mnt
.fsgeom
.agcount
+ 2, &sbx
);
226 str_liberror(ctx
, ret
, _("queueing logdev fsmap work"));
230 for (agno
= 0; agno
< ctx
->mnt
.fsgeom
.agcount
; agno
++) {
231 ret
= -workqueue_add(&wq
, scan_ag_rmaps
, agno
, &sbx
);
234 str_liberror(ctx
, ret
, _("queueing per-AG fsmap work"));
239 ret
= -workqueue_terminate(&wq
);
242 str_liberror(ctx
, ret
, _("finishing fsmap work"));
244 workqueue_destroy(&wq
);
246 if (!ret
&& sbx
.aborted
)