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