]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - scrub/inodes.c
libfrog: fix workqueue error communication problems
[thirdparty/xfsprogs-dev.git] / scrub / inodes.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0+
372d4ba9
DW
2/*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
372d4ba9 4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
372d4ba9 5 */
a440f877 6#include "xfs.h"
372d4ba9
DW
7#include <stdint.h>
8#include <stdlib.h>
9#include <pthread.h>
10#include <sys/statvfs.h>
11#include "platform_defs.h"
372d4ba9
DW
12#include "xfs_arch.h"
13#include "xfs_format.h"
14#include "handle.h"
42b4c8e8 15#include "libfrog/paths.h"
56598728 16#include "libfrog/workqueue.h"
372d4ba9
DW
17#include "xfs_scrub.h"
18#include "common.h"
19#include "inodes.h"
fee68490 20#include "libfrog/fsgeom.h"
f31b5e12 21#include "libfrog/bulkstat.h"
372d4ba9
DW
22
23/*
24 * Iterate a range of inodes.
25 *
26 * This is a little more involved than repeatedly asking BULKSTAT for a
27 * buffer's worth of stat data for some number of inodes. We want to scan as
28 * many of the inodes that the inobt thinks there are, including the ones that
29 * are broken, but if we ask for n inodes starting at x, it'll skip the bad
30 * ones and fill from beyond the range (x + n).
31 *
32 * Therefore, we ask INUMBERS to return one inobt chunk's worth of inode
33 * bitmap information. Then we try to BULKSTAT only the inodes that were
34 * present in that chunk, and compare what we got against what INUMBERS said
35 * was there. If there's a mismatch, we know that we have an inode that fails
36 * the verifiers but we can inject the bulkstat information to force the scrub
37 * code to deal with the broken inodes.
38 *
39 * If the iteration function returns ESTALE, that means that the inode has
40 * been deleted and possibly recreated since the BULKSTAT call. We wil
41 * refresh the stat information and try again up to 30 times before reporting
42 * the staleness as an error.
43 */
44
45/*
46 * Did we get exactly the inodes we expected? If not, load them one at a
47 * time (or fake it) into the bulkstat data.
48 */
49static void
50xfs_iterate_inodes_range_check(
51 struct scrub_ctx *ctx,
b94a69ac 52 struct xfs_inumbers *inumbers,
4cca629d 53 struct xfs_bulkstat *bstat)
372d4ba9 54{
4cca629d 55 struct xfs_bulkstat *bs;
372d4ba9
DW
56 int i;
57 int error;
58
372d4ba9 59 for (i = 0, bs = bstat; i < XFS_INODES_PER_CHUNK; i++) {
b94a69ac 60 if (!(inumbers->xi_allocmask & (1ULL << i)))
372d4ba9 61 continue;
b94a69ac 62 if (bs->bs_ino == inumbers->xi_startino + i) {
372d4ba9
DW
63 bs++;
64 continue;
65 }
66
67 /* Load the one inode. */
f31b5e12 68 error = xfrog_bulkstat_single(&ctx->mnt,
b94a69ac
DW
69 inumbers->xi_startino + i, 0, bs);
70 if (error || bs->bs_ino != inumbers->xi_startino + i) {
4cca629d 71 memset(bs, 0, sizeof(struct xfs_bulkstat));
b94a69ac 72 bs->bs_ino = inumbers->xi_startino + i;
372d4ba9
DW
73 bs->bs_blksize = ctx->mnt_sv.f_frsize;
74 }
75 bs++;
76 }
77}
78
79/*
80 * Call into the filesystem for inode/bulkstat information and call our
81 * iterator function. We'll try to fill the bulkstat information in batches,
82 * but we also can detect iget failures.
83 */
84static bool
23ea9841 85xfs_iterate_inodes_ag(
372d4ba9
DW
86 struct scrub_ctx *ctx,
87 const char *descr,
88 void *fshandle,
23ea9841 89 uint32_t agno,
372d4ba9
DW
90 xfs_inode_iter_fn fn,
91 void *arg)
92{
372d4ba9 93 struct xfs_handle handle;
b94a69ac 94 struct xfs_inumbers_req *ireq;
4cca629d 95 struct xfs_bulkstat_req *breq;
372d4ba9 96 char idescr[DESCR_BUFSZ];
4cca629d 97 struct xfs_bulkstat *bs;
b94a69ac 98 struct xfs_inumbers *inumbers;
372d4ba9
DW
99 bool moveon = true;
100 int i;
101 int error;
102 int stale_count = 0;
103
372d4ba9
DW
104 memcpy(&handle.ha_fsid, fshandle, sizeof(handle.ha_fsid));
105 handle.ha_fid.fid_len = sizeof(xfs_fid_t) -
106 sizeof(handle.ha_fid.fid_len);
107 handle.ha_fid.fid_pad = 0;
108
4cca629d
DW
109 breq = xfrog_bulkstat_alloc_req(XFS_INODES_PER_CHUNK, 0);
110 if (!breq) {
111 str_info(ctx, descr, _("Insufficient memory; giving up."));
112 return false;
113 }
114
23ea9841 115 ireq = xfrog_inumbers_alloc_req(1, 0);
b94a69ac
DW
116 if (!ireq) {
117 str_info(ctx, descr, _("Insufficient memory; giving up."));
118 free(breq);
119 return false;
120 }
121 inumbers = &ireq->inumbers[0];
23ea9841 122 xfrog_inumbers_set_ag(ireq, agno);
b94a69ac 123
372d4ba9 124 /* Find the inode chunk & alloc mask */
b94a69ac
DW
125 error = xfrog_inumbers(&ctx->mnt, ireq);
126 while (!error && ireq->hdr.ocount > 0) {
300661d3
DW
127 /*
128 * We can have totally empty inode chunks on filesystems where
129 * there are more than 64 inodes per block. Skip these.
130 */
b94a69ac 131 if (inumbers->xi_alloccount == 0)
300661d3 132 goto igrp_retry;
4cca629d 133
b94a69ac
DW
134 breq->hdr.ino = inumbers->xi_startino;
135 breq->hdr.icount = inumbers->xi_alloccount;
4cca629d 136 error = xfrog_bulkstat(&ctx->mnt, breq);
f31b5e12
DW
137 if (error) {
138 char errbuf[DESCR_BUFSZ];
139
140 str_info(ctx, descr, "%s", strerror_r(error,
141 errbuf, DESCR_BUFSZ));
142 }
372d4ba9 143
b94a69ac 144 xfs_iterate_inodes_range_check(ctx, inumbers, breq->bulkstat);
372d4ba9
DW
145
146 /* Iterate all the inodes. */
4cca629d 147 for (i = 0, bs = breq->bulkstat;
b94a69ac 148 i < inumbers->xi_alloccount;
4cca629d 149 i++, bs++) {
372d4ba9
DW
150 handle.ha_fid.fid_ino = bs->bs_ino;
151 handle.ha_fid.fid_gen = bs->bs_gen;
152 error = fn(ctx, &handle, bs, arg);
153 switch (error) {
154 case 0:
155 break;
156 case ESTALE:
157 stale_count++;
158 if (stale_count < 30) {
b94a69ac 159 ireq->hdr.ino = inumbers->xi_startino;
372d4ba9
DW
160 goto igrp_retry;
161 }
162 snprintf(idescr, DESCR_BUFSZ, "inode %"PRIu64,
163 (uint64_t)bs->bs_ino);
bb5dbd06
DW
164 str_info(ctx, idescr,
165_("Changed too many times during scan; giving up."));
372d4ba9
DW
166 break;
167 case XFS_ITERATE_INODES_ABORT:
168 error = 0;
169 /* fall thru */
170 default:
171 moveon = false;
172 errno = error;
173 goto err;
174 }
175 if (xfs_scrub_excessive_errors(ctx)) {
176 moveon = false;
177 goto out;
178 }
179 }
180
181 stale_count = 0;
182igrp_retry:
b94a69ac 183 error = xfrog_inumbers(&ctx->mnt, ireq);
372d4ba9
DW
184 }
185
186err:
187 if (error) {
621f3374 188 str_liberror(ctx, error, descr);
372d4ba9
DW
189 moveon = false;
190 }
191out:
b94a69ac 192 free(ireq);
4cca629d 193 free(breq);
372d4ba9
DW
194 return moveon;
195}
196
197/* BULKSTAT wrapper routines. */
198struct xfs_scan_inodes {
199 xfs_inode_iter_fn fn;
200 void *arg;
201 bool moveon;
202};
203
204/* Scan all the inodes in an AG. */
205static void
206xfs_scan_ag_inodes(
207 struct workqueue *wq,
208 xfs_agnumber_t agno,
209 void *arg)
210{
211 struct xfs_scan_inodes *si = arg;
212 struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx;
213 char descr[DESCR_BUFSZ];
372d4ba9
DW
214 bool moveon;
215
216 snprintf(descr, DESCR_BUFSZ, _("dev %d:%d AG %u inodes"),
217 major(ctx->fsinfo.fs_datadev),
218 minor(ctx->fsinfo.fs_datadev),
219 agno);
220
23ea9841
DW
221 moveon = xfs_iterate_inodes_ag(ctx, descr, ctx->fshandle, agno,
222 si->fn, si->arg);
372d4ba9
DW
223 if (!moveon)
224 si->moveon = false;
225}
226
227/* Scan all the inodes in a filesystem. */
228bool
229xfs_scan_all_inodes(
230 struct scrub_ctx *ctx,
231 xfs_inode_iter_fn fn,
232 void *arg)
233{
234 struct xfs_scan_inodes si;
235 xfs_agnumber_t agno;
236 struct workqueue wq;
237 int ret;
238
239 si.moveon = true;
240 si.fn = fn;
241 si.arg = arg;
242
243 ret = workqueue_create(&wq, (struct xfs_mount *)ctx,
244 scrub_nproc_workqueue(ctx));
245 if (ret) {
9d57cbfc 246 str_liberror(ctx, ret, _("creating bulkstat workqueue"));
372d4ba9
DW
247 return false;
248 }
249
3f9efb2e 250 for (agno = 0; agno < ctx->mnt.fsgeom.agcount; agno++) {
372d4ba9
DW
251 ret = workqueue_add(&wq, xfs_scan_ag_inodes, agno, &si);
252 if (ret) {
253 si.moveon = false;
9d57cbfc 254 str_liberror(ctx, ret, _("queueing bulkstat work"));
372d4ba9
DW
255 break;
256 }
257 }
258
259 workqueue_destroy(&wq);
260
261 return si.moveon;
262}
263
264/*
265 * Open a file by handle, or return a negative error code.
266 */
267int
268xfs_open_handle(
269 struct xfs_handle *handle)
270{
271 return open_by_fshandle(handle, sizeof(*handle),
272 O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY);
273}