2 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
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.
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.
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.
24 #include <sys/statvfs.h>
25 #include "platform_defs.h"
27 #include "xfs_format.h"
30 #include "workqueue.h"
31 #include "xfs_scrub.h"
36 * Iterate a range of inodes.
38 * This is a little more involved than repeatedly asking BULKSTAT for a
39 * buffer's worth of stat data for some number of inodes. We want to scan as
40 * many of the inodes that the inobt thinks there are, including the ones that
41 * are broken, but if we ask for n inodes starting at x, it'll skip the bad
42 * ones and fill from beyond the range (x + n).
44 * Therefore, we ask INUMBERS to return one inobt chunk's worth of inode
45 * bitmap information. Then we try to BULKSTAT only the inodes that were
46 * present in that chunk, and compare what we got against what INUMBERS said
47 * was there. If there's a mismatch, we know that we have an inode that fails
48 * the verifiers but we can inject the bulkstat information to force the scrub
49 * code to deal with the broken inodes.
51 * If the iteration function returns ESTALE, that means that the inode has
52 * been deleted and possibly recreated since the BULKSTAT call. We wil
53 * refresh the stat information and try again up to 30 times before reporting
54 * the staleness as an error.
58 * Did we get exactly the inodes we expected? If not, load them one at a
59 * time (or fake it) into the bulkstat data.
62 xfs_iterate_inodes_range_check(
63 struct scrub_ctx
*ctx
,
64 struct xfs_inogrp
*inogrp
,
65 struct xfs_bstat
*bstat
)
67 struct xfs_fsop_bulkreq onereq
= {0};
74 onereq
.lastip
= &oneino
;
76 onereq
.ocount
= &onelen
;
78 for (i
= 0, bs
= bstat
; i
< XFS_INODES_PER_CHUNK
; i
++) {
79 if (!(inogrp
->xi_allocmask
& (1ULL << i
)))
81 if (bs
->bs_ino
== inogrp
->xi_startino
+ i
) {
86 /* Load the one inode. */
87 oneino
= inogrp
->xi_startino
+ i
;
89 error
= ioctl(ctx
->mnt_fd
, XFS_IOC_FSBULKSTAT_SINGLE
,
91 if (error
|| bs
->bs_ino
!= inogrp
->xi_startino
+ i
) {
92 memset(bs
, 0, sizeof(struct xfs_bstat
));
93 bs
->bs_ino
= inogrp
->xi_startino
+ i
;
94 bs
->bs_blksize
= ctx
->mnt_sv
.f_frsize
;
101 * Call into the filesystem for inode/bulkstat information and call our
102 * iterator function. We'll try to fill the bulkstat information in batches,
103 * but we also can detect iget failures.
106 xfs_iterate_inodes_range(
107 struct scrub_ctx
*ctx
,
112 xfs_inode_iter_fn fn
,
115 struct xfs_fsop_bulkreq igrpreq
= {0};
116 struct xfs_fsop_bulkreq bulkreq
= {0};
117 struct xfs_handle handle
;
118 struct xfs_inogrp inogrp
;
119 struct xfs_bstat bstat
[XFS_INODES_PER_CHUNK
];
120 char idescr
[DESCR_BUFSZ
];
121 char buf
[DESCR_BUFSZ
];
122 struct xfs_bstat
*bs
;
133 memset(bstat
, 0, XFS_INODES_PER_CHUNK
* sizeof(struct xfs_bstat
));
134 bulkreq
.lastip
= &ino
;
135 bulkreq
.icount
= XFS_INODES_PER_CHUNK
;
136 bulkreq
.ubuffer
= &bstat
;
137 bulkreq
.ocount
= &bulklen
;
139 igrpreq
.lastip
= &igrp_ino
;
141 igrpreq
.ubuffer
= &inogrp
;
142 igrpreq
.ocount
= &igrplen
;
144 memcpy(&handle
.ha_fsid
, fshandle
, sizeof(handle
.ha_fsid
));
145 handle
.ha_fid
.fid_len
= sizeof(xfs_fid_t
) -
146 sizeof(handle
.ha_fid
.fid_len
);
147 handle
.ha_fid
.fid_pad
= 0;
149 /* Find the inode chunk & alloc mask */
150 igrp_ino
= first_ino
;
151 error
= ioctl(ctx
->mnt_fd
, XFS_IOC_FSINUMBERS
, &igrpreq
);
152 while (!error
&& igrplen
) {
153 /* Load the inodes. */
154 ino
= inogrp
.xi_startino
- 1;
155 bulkreq
.icount
= inogrp
.xi_alloccount
;
156 error
= ioctl(ctx
->mnt_fd
, XFS_IOC_FSBULKSTAT
, &bulkreq
);
158 str_info(ctx
, descr
, "%s", strerror_r(errno
,
161 xfs_iterate_inodes_range_check(ctx
, &inogrp
, bstat
);
163 /* Iterate all the inodes. */
164 for (i
= 0, bs
= bstat
; i
< inogrp
.xi_alloccount
; i
++, bs
++) {
165 if (bs
->bs_ino
> last_ino
)
168 handle
.ha_fid
.fid_ino
= bs
->bs_ino
;
169 handle
.ha_fid
.fid_gen
= bs
->bs_gen
;
170 error
= fn(ctx
, &handle
, bs
, arg
);
176 if (stale_count
< 30) {
177 igrp_ino
= inogrp
.xi_startino
;
180 snprintf(idescr
, DESCR_BUFSZ
, "inode %"PRIu64
,
181 (uint64_t)bs
->bs_ino
);
182 str_info(ctx
, idescr
,
183 _("Changed too many times during scan; giving up."));
185 case XFS_ITERATE_INODES_ABORT
:
193 if (xfs_scrub_excessive_errors(ctx
)) {
201 error
= ioctl(ctx
->mnt_fd
, XFS_IOC_FSINUMBERS
, &igrpreq
);
206 str_errno(ctx
, descr
);
213 /* BULKSTAT wrapper routines. */
214 struct xfs_scan_inodes
{
215 xfs_inode_iter_fn fn
;
220 /* Scan all the inodes in an AG. */
223 struct workqueue
*wq
,
227 struct xfs_scan_inodes
*si
= arg
;
228 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
229 char descr
[DESCR_BUFSZ
];
231 uint64_t next_ag_ino
;
234 snprintf(descr
, DESCR_BUFSZ
, _("dev %d:%d AG %u inodes"),
235 major(ctx
->fsinfo
.fs_datadev
),
236 minor(ctx
->fsinfo
.fs_datadev
),
239 ag_ino
= (__u64
)agno
<< (ctx
->inopblog
+ ctx
->agblklog
);
240 next_ag_ino
= (__u64
)(agno
+ 1) << (ctx
->inopblog
+ ctx
->agblklog
);
242 moveon
= xfs_iterate_inodes_range(ctx
, descr
, ctx
->fshandle
, ag_ino
,
243 next_ag_ino
- 1, si
->fn
, si
->arg
);
248 /* Scan all the inodes in a filesystem. */
251 struct scrub_ctx
*ctx
,
252 xfs_inode_iter_fn fn
,
255 struct xfs_scan_inodes si
;
264 ret
= workqueue_create(&wq
, (struct xfs_mount
*)ctx
,
265 scrub_nproc_workqueue(ctx
));
267 str_info(ctx
, ctx
->mntpoint
, _("Could not create workqueue."));
271 for (agno
= 0; agno
< ctx
->geo
.agcount
; agno
++) {
272 ret
= workqueue_add(&wq
, xfs_scan_ag_inodes
, agno
, &si
);
275 str_info(ctx
, ctx
->mntpoint
,
276 _("Could not queue AG %u bulkstat work."), agno
);
281 workqueue_destroy(&wq
);
287 * Open a file by handle, or return a negative error code.
291 struct xfs_handle
*handle
)
293 return open_by_fshandle(handle
, sizeof(*handle
),
294 O_RDONLY
| O_NOATIME
| O_NOFOLLOW
| O_NOCTTY
);