]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/inodes.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 "platform_defs.h"
13 #include "xfs_format.h"
15 #include "libfrog/paths.h"
16 #include "libfrog/workqueue.h"
17 #include "xfs_scrub.h"
20 #include "libfrog/fsgeom.h"
21 #include "libfrog/bulkstat.h"
24 * Iterate a range of inodes.
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).
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.
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.
46 * Run bulkstat on an entire inode allocation group, then check that we got
47 * exactly the inodes we expected. If not, load them one at a time (or fake
48 * it) into the bulkstat data.
51 bulkstat_for_inumbers(
52 struct scrub_ctx
*ctx
,
54 const struct xfs_inumbers
*inumbers
,
55 struct xfs_bulkstat_req
*breq
)
57 struct xfs_bulkstat
*bstat
= breq
->bulkstat
;
58 struct xfs_bulkstat
*bs
;
62 /* First we try regular bulkstat, for speed. */
63 breq
->hdr
.ino
= inumbers
->xi_startino
;
64 breq
->hdr
.icount
= inumbers
->xi_alloccount
;
65 error
= -xfrog_bulkstat(&ctx
->mnt
, breq
);
67 char errbuf
[DESCR_BUFSZ
];
69 str_info(ctx
, descr
, "%s",
70 strerror_r(error
, errbuf
, DESCR_BUFSZ
));
74 * Check each of the stats we got back to make sure we got the inodes
77 for (i
= 0, bs
= bstat
; i
< XFS_INODES_PER_CHUNK
; i
++) {
78 if (!(inumbers
->xi_allocmask
& (1ULL << i
)))
80 if (bs
->bs_ino
== inumbers
->xi_startino
+ i
) {
85 /* Load the one inode. */
86 error
= -xfrog_bulkstat_single(&ctx
->mnt
,
87 inumbers
->xi_startino
+ i
, 0, bs
);
88 if (error
|| bs
->bs_ino
!= inumbers
->xi_startino
+ i
) {
89 memset(bs
, 0, sizeof(struct xfs_bulkstat
));
90 bs
->bs_ino
= inumbers
->xi_startino
+ i
;
91 bs
->bs_blksize
= ctx
->mnt_sv
.f_frsize
;
97 /* BULKSTAT wrapper routines. */
99 scrub_inode_iter_fn fn
;
105 * Call into the filesystem for inode/bulkstat information and call our
106 * iterator function. We'll try to fill the bulkstat information in batches,
107 * but we also can detect iget failures.
111 struct workqueue
*wq
,
115 struct xfs_handle handle
;
116 char descr
[DESCR_BUFSZ
];
117 struct xfs_inumbers_req
*ireq
;
118 struct xfs_bulkstat_req
*breq
;
119 struct scan_inodes
*si
= arg
;
120 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
121 struct xfs_bulkstat
*bs
;
122 struct xfs_inumbers
*inumbers
;
127 snprintf(descr
, DESCR_BUFSZ
, _("dev %d:%d AG %u inodes"),
128 major(ctx
->fsinfo
.fs_datadev
),
129 minor(ctx
->fsinfo
.fs_datadev
),
132 memcpy(&handle
.ha_fsid
, ctx
->fshandle
, sizeof(handle
.ha_fsid
));
133 handle
.ha_fid
.fid_len
= sizeof(xfs_fid_t
) -
134 sizeof(handle
.ha_fid
.fid_len
);
135 handle
.ha_fid
.fid_pad
= 0;
137 error
= -xfrog_bulkstat_alloc_req(XFS_INODES_PER_CHUNK
, 0, &breq
);
139 str_liberror(ctx
, error
, descr
);
144 error
= -xfrog_inumbers_alloc_req(1, 0, &ireq
);
146 str_liberror(ctx
, error
, descr
);
151 inumbers
= &ireq
->inumbers
[0];
152 xfrog_inumbers_set_ag(ireq
, agno
);
154 /* Find the inode chunk & alloc mask */
155 error
= -xfrog_inumbers(&ctx
->mnt
, ireq
);
156 while (!error
&& !si
->aborted
&& ireq
->hdr
.ocount
> 0) {
158 * We can have totally empty inode chunks on filesystems where
159 * there are more than 64 inodes per block. Skip these.
161 if (inumbers
->xi_alloccount
== 0)
164 bulkstat_for_inumbers(ctx
, descr
, inumbers
, breq
);
166 /* Iterate all the inodes. */
167 for (i
= 0, bs
= breq
->bulkstat
;
168 !si
->aborted
&& i
< inumbers
->xi_alloccount
;
170 handle
.ha_fid
.fid_ino
= bs
->bs_ino
;
171 handle
.ha_fid
.fid_gen
= bs
->bs_gen
;
172 error
= si
->fn(ctx
, &handle
, bs
, si
->arg
);
177 char idescr
[DESCR_BUFSZ
];
180 if (stale_count
< 30) {
181 ireq
->hdr
.ino
= inumbers
->xi_startino
;
184 scrub_render_ino_descr(ctx
, idescr
, DESCR_BUFSZ
,
185 bs
->bs_ino
, bs
->bs_gen
, NULL
);
186 str_info(ctx
, idescr
,
187 _("Changed too many times during scan; giving up."));
196 if (xfs_scrub_excessive_errors(ctx
)) {
204 error
= -xfrog_inumbers(&ctx
->mnt
, ireq
);
209 str_liberror(ctx
, error
, descr
);
218 * Scan all the inodes in a filesystem. On error, this function will log
219 * an error message and return -1.
222 scrub_scan_all_inodes(
223 struct scrub_ctx
*ctx
,
224 scrub_inode_iter_fn fn
,
227 struct scan_inodes si
= {
235 ret
= -workqueue_create(&wq
, (struct xfs_mount
*)ctx
,
236 scrub_nproc_workqueue(ctx
));
238 str_liberror(ctx
, ret
, _("creating bulkstat workqueue"));
242 for (agno
= 0; agno
< ctx
->mnt
.fsgeom
.agcount
; agno
++) {
243 ret
= -workqueue_add(&wq
, scan_ag_inodes
, agno
, &si
);
246 str_liberror(ctx
, ret
, _("queueing bulkstat work"));
251 ret
= -workqueue_terminate(&wq
);
254 str_liberror(ctx
, ret
, _("finishing bulkstat work"));
256 workqueue_destroy(&wq
);
258 return si
.aborted
? -1 : 0;
261 /* Open a file by handle, returning either the fd or -1 on error. */
264 struct xfs_handle
*handle
)
266 return open_by_fshandle(handle
, sizeof(*handle
),
267 O_RDONLY
| O_NOATIME
| O_NOFOLLOW
| O_NOCTTY
);