1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2017 Oracle. All Rights Reserved.
4*4882a593Smuzhiyun * Author: Darrick J. Wong <darrick.wong@oracle.com>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #include "xfs.h"
7*4882a593Smuzhiyun #include "xfs_fs.h"
8*4882a593Smuzhiyun #include "xfs_shared.h"
9*4882a593Smuzhiyun #include "xfs_format.h"
10*4882a593Smuzhiyun #include "xfs_trans_resv.h"
11*4882a593Smuzhiyun #include "xfs_mount.h"
12*4882a593Smuzhiyun #include "xfs_btree.h"
13*4882a593Smuzhiyun #include "xfs_log_format.h"
14*4882a593Smuzhiyun #include "xfs_trans.h"
15*4882a593Smuzhiyun #include "xfs_sb.h"
16*4882a593Smuzhiyun #include "xfs_inode.h"
17*4882a593Smuzhiyun #include "xfs_icache.h"
18*4882a593Smuzhiyun #include "xfs_alloc.h"
19*4882a593Smuzhiyun #include "xfs_alloc_btree.h"
20*4882a593Smuzhiyun #include "xfs_ialloc.h"
21*4882a593Smuzhiyun #include "xfs_ialloc_btree.h"
22*4882a593Smuzhiyun #include "xfs_refcount_btree.h"
23*4882a593Smuzhiyun #include "xfs_rmap.h"
24*4882a593Smuzhiyun #include "xfs_rmap_btree.h"
25*4882a593Smuzhiyun #include "xfs_log.h"
26*4882a593Smuzhiyun #include "xfs_trans_priv.h"
27*4882a593Smuzhiyun #include "xfs_attr.h"
28*4882a593Smuzhiyun #include "xfs_reflink.h"
29*4882a593Smuzhiyun #include "scrub/scrub.h"
30*4882a593Smuzhiyun #include "scrub/common.h"
31*4882a593Smuzhiyun #include "scrub/trace.h"
32*4882a593Smuzhiyun #include "scrub/repair.h"
33*4882a593Smuzhiyun #include "scrub/health.h"
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* Common code for the metadata scrubbers. */
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun * Handling operational errors.
39*4882a593Smuzhiyun *
40*4882a593Smuzhiyun * The *_process_error() family of functions are used to process error return
41*4882a593Smuzhiyun * codes from functions called as part of a scrub operation.
42*4882a593Smuzhiyun *
43*4882a593Smuzhiyun * If there's no error, we return true to tell the caller that it's ok
44*4882a593Smuzhiyun * to move on to the next check in its list.
45*4882a593Smuzhiyun *
46*4882a593Smuzhiyun * For non-verifier errors (e.g. ENOMEM) we return false to tell the
47*4882a593Smuzhiyun * caller that something bad happened, and we preserve *error so that
48*4882a593Smuzhiyun * the caller can return the *error up the stack to userspace.
49*4882a593Smuzhiyun *
50*4882a593Smuzhiyun * Verifier errors (EFSBADCRC/EFSCORRUPTED) are recorded by setting
51*4882a593Smuzhiyun * OFLAG_CORRUPT in sm_flags and the *error is cleared. In other words,
52*4882a593Smuzhiyun * we track verifier errors (and failed scrub checks) via OFLAG_CORRUPT,
53*4882a593Smuzhiyun * not via return codes. We return false to tell the caller that
54*4882a593Smuzhiyun * something bad happened. Since the error has been cleared, the caller
55*4882a593Smuzhiyun * will (presumably) return that zero and scrubbing will move on to
56*4882a593Smuzhiyun * whatever's next.
57*4882a593Smuzhiyun *
58*4882a593Smuzhiyun * ftrace can be used to record the precise metadata location and the
59*4882a593Smuzhiyun * approximate code location of the failed operation.
60*4882a593Smuzhiyun */
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* Check for operational errors. */
63*4882a593Smuzhiyun static bool
__xchk_process_error(struct xfs_scrub * sc,xfs_agnumber_t agno,xfs_agblock_t bno,int * error,__u32 errflag,void * ret_ip)64*4882a593Smuzhiyun __xchk_process_error(
65*4882a593Smuzhiyun struct xfs_scrub *sc,
66*4882a593Smuzhiyun xfs_agnumber_t agno,
67*4882a593Smuzhiyun xfs_agblock_t bno,
68*4882a593Smuzhiyun int *error,
69*4882a593Smuzhiyun __u32 errflag,
70*4882a593Smuzhiyun void *ret_ip)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun switch (*error) {
73*4882a593Smuzhiyun case 0:
74*4882a593Smuzhiyun return true;
75*4882a593Smuzhiyun case -EDEADLOCK:
76*4882a593Smuzhiyun /* Used to restart an op with deadlock avoidance. */
77*4882a593Smuzhiyun trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
78*4882a593Smuzhiyun break;
79*4882a593Smuzhiyun case -EFSBADCRC:
80*4882a593Smuzhiyun case -EFSCORRUPTED:
81*4882a593Smuzhiyun /* Note the badness but don't abort. */
82*4882a593Smuzhiyun sc->sm->sm_flags |= errflag;
83*4882a593Smuzhiyun *error = 0;
84*4882a593Smuzhiyun /* fall through */
85*4882a593Smuzhiyun default:
86*4882a593Smuzhiyun trace_xchk_op_error(sc, agno, bno, *error,
87*4882a593Smuzhiyun ret_ip);
88*4882a593Smuzhiyun break;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun return false;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun bool
xchk_process_error(struct xfs_scrub * sc,xfs_agnumber_t agno,xfs_agblock_t bno,int * error)94*4882a593Smuzhiyun xchk_process_error(
95*4882a593Smuzhiyun struct xfs_scrub *sc,
96*4882a593Smuzhiyun xfs_agnumber_t agno,
97*4882a593Smuzhiyun xfs_agblock_t bno,
98*4882a593Smuzhiyun int *error)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun return __xchk_process_error(sc, agno, bno, error,
101*4882a593Smuzhiyun XFS_SCRUB_OFLAG_CORRUPT, __return_address);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun bool
xchk_xref_process_error(struct xfs_scrub * sc,xfs_agnumber_t agno,xfs_agblock_t bno,int * error)105*4882a593Smuzhiyun xchk_xref_process_error(
106*4882a593Smuzhiyun struct xfs_scrub *sc,
107*4882a593Smuzhiyun xfs_agnumber_t agno,
108*4882a593Smuzhiyun xfs_agblock_t bno,
109*4882a593Smuzhiyun int *error)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun return __xchk_process_error(sc, agno, bno, error,
112*4882a593Smuzhiyun XFS_SCRUB_OFLAG_XFAIL, __return_address);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* Check for operational errors for a file offset. */
116*4882a593Smuzhiyun static bool
__xchk_fblock_process_error(struct xfs_scrub * sc,int whichfork,xfs_fileoff_t offset,int * error,__u32 errflag,void * ret_ip)117*4882a593Smuzhiyun __xchk_fblock_process_error(
118*4882a593Smuzhiyun struct xfs_scrub *sc,
119*4882a593Smuzhiyun int whichfork,
120*4882a593Smuzhiyun xfs_fileoff_t offset,
121*4882a593Smuzhiyun int *error,
122*4882a593Smuzhiyun __u32 errflag,
123*4882a593Smuzhiyun void *ret_ip)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun switch (*error) {
126*4882a593Smuzhiyun case 0:
127*4882a593Smuzhiyun return true;
128*4882a593Smuzhiyun case -EDEADLOCK:
129*4882a593Smuzhiyun /* Used to restart an op with deadlock avoidance. */
130*4882a593Smuzhiyun trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
131*4882a593Smuzhiyun break;
132*4882a593Smuzhiyun case -EFSBADCRC:
133*4882a593Smuzhiyun case -EFSCORRUPTED:
134*4882a593Smuzhiyun /* Note the badness but don't abort. */
135*4882a593Smuzhiyun sc->sm->sm_flags |= errflag;
136*4882a593Smuzhiyun *error = 0;
137*4882a593Smuzhiyun /* fall through */
138*4882a593Smuzhiyun default:
139*4882a593Smuzhiyun trace_xchk_file_op_error(sc, whichfork, offset, *error,
140*4882a593Smuzhiyun ret_ip);
141*4882a593Smuzhiyun break;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun return false;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun bool
xchk_fblock_process_error(struct xfs_scrub * sc,int whichfork,xfs_fileoff_t offset,int * error)147*4882a593Smuzhiyun xchk_fblock_process_error(
148*4882a593Smuzhiyun struct xfs_scrub *sc,
149*4882a593Smuzhiyun int whichfork,
150*4882a593Smuzhiyun xfs_fileoff_t offset,
151*4882a593Smuzhiyun int *error)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun return __xchk_fblock_process_error(sc, whichfork, offset, error,
154*4882a593Smuzhiyun XFS_SCRUB_OFLAG_CORRUPT, __return_address);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun bool
xchk_fblock_xref_process_error(struct xfs_scrub * sc,int whichfork,xfs_fileoff_t offset,int * error)158*4882a593Smuzhiyun xchk_fblock_xref_process_error(
159*4882a593Smuzhiyun struct xfs_scrub *sc,
160*4882a593Smuzhiyun int whichfork,
161*4882a593Smuzhiyun xfs_fileoff_t offset,
162*4882a593Smuzhiyun int *error)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun return __xchk_fblock_process_error(sc, whichfork, offset, error,
165*4882a593Smuzhiyun XFS_SCRUB_OFLAG_XFAIL, __return_address);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /*
169*4882a593Smuzhiyun * Handling scrub corruption/optimization/warning checks.
170*4882a593Smuzhiyun *
171*4882a593Smuzhiyun * The *_set_{corrupt,preen,warning}() family of functions are used to
172*4882a593Smuzhiyun * record the presence of metadata that is incorrect (corrupt), could be
173*4882a593Smuzhiyun * optimized somehow (preen), or should be flagged for administrative
174*4882a593Smuzhiyun * review but is not incorrect (warn).
175*4882a593Smuzhiyun *
176*4882a593Smuzhiyun * ftrace can be used to record the precise metadata location and
177*4882a593Smuzhiyun * approximate code location of the failed check.
178*4882a593Smuzhiyun */
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* Record a block which could be optimized. */
181*4882a593Smuzhiyun void
xchk_block_set_preen(struct xfs_scrub * sc,struct xfs_buf * bp)182*4882a593Smuzhiyun xchk_block_set_preen(
183*4882a593Smuzhiyun struct xfs_scrub *sc,
184*4882a593Smuzhiyun struct xfs_buf *bp)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_PREEN;
187*4882a593Smuzhiyun trace_xchk_block_preen(sc, bp->b_bn, __return_address);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun * Record an inode which could be optimized. The trace data will
192*4882a593Smuzhiyun * include the block given by bp if bp is given; otherwise it will use
193*4882a593Smuzhiyun * the block location of the inode record itself.
194*4882a593Smuzhiyun */
195*4882a593Smuzhiyun void
xchk_ino_set_preen(struct xfs_scrub * sc,xfs_ino_t ino)196*4882a593Smuzhiyun xchk_ino_set_preen(
197*4882a593Smuzhiyun struct xfs_scrub *sc,
198*4882a593Smuzhiyun xfs_ino_t ino)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_PREEN;
201*4882a593Smuzhiyun trace_xchk_ino_preen(sc, ino, __return_address);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /* Record something being wrong with the filesystem primary superblock. */
205*4882a593Smuzhiyun void
xchk_set_corrupt(struct xfs_scrub * sc)206*4882a593Smuzhiyun xchk_set_corrupt(
207*4882a593Smuzhiyun struct xfs_scrub *sc)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
210*4882a593Smuzhiyun trace_xchk_fs_error(sc, 0, __return_address);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* Record a corrupt block. */
214*4882a593Smuzhiyun void
xchk_block_set_corrupt(struct xfs_scrub * sc,struct xfs_buf * bp)215*4882a593Smuzhiyun xchk_block_set_corrupt(
216*4882a593Smuzhiyun struct xfs_scrub *sc,
217*4882a593Smuzhiyun struct xfs_buf *bp)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
220*4882a593Smuzhiyun trace_xchk_block_error(sc, bp->b_bn, __return_address);
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* Record a corruption while cross-referencing. */
224*4882a593Smuzhiyun void
xchk_block_xref_set_corrupt(struct xfs_scrub * sc,struct xfs_buf * bp)225*4882a593Smuzhiyun xchk_block_xref_set_corrupt(
226*4882a593Smuzhiyun struct xfs_scrub *sc,
227*4882a593Smuzhiyun struct xfs_buf *bp)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XCORRUPT;
230*4882a593Smuzhiyun trace_xchk_block_error(sc, bp->b_bn, __return_address);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /*
234*4882a593Smuzhiyun * Record a corrupt inode. The trace data will include the block given
235*4882a593Smuzhiyun * by bp if bp is given; otherwise it will use the block location of the
236*4882a593Smuzhiyun * inode record itself.
237*4882a593Smuzhiyun */
238*4882a593Smuzhiyun void
xchk_ino_set_corrupt(struct xfs_scrub * sc,xfs_ino_t ino)239*4882a593Smuzhiyun xchk_ino_set_corrupt(
240*4882a593Smuzhiyun struct xfs_scrub *sc,
241*4882a593Smuzhiyun xfs_ino_t ino)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
244*4882a593Smuzhiyun trace_xchk_ino_error(sc, ino, __return_address);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /* Record a corruption while cross-referencing with an inode. */
248*4882a593Smuzhiyun void
xchk_ino_xref_set_corrupt(struct xfs_scrub * sc,xfs_ino_t ino)249*4882a593Smuzhiyun xchk_ino_xref_set_corrupt(
250*4882a593Smuzhiyun struct xfs_scrub *sc,
251*4882a593Smuzhiyun xfs_ino_t ino)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XCORRUPT;
254*4882a593Smuzhiyun trace_xchk_ino_error(sc, ino, __return_address);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* Record corruption in a block indexed by a file fork. */
258*4882a593Smuzhiyun void
xchk_fblock_set_corrupt(struct xfs_scrub * sc,int whichfork,xfs_fileoff_t offset)259*4882a593Smuzhiyun xchk_fblock_set_corrupt(
260*4882a593Smuzhiyun struct xfs_scrub *sc,
261*4882a593Smuzhiyun int whichfork,
262*4882a593Smuzhiyun xfs_fileoff_t offset)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
265*4882a593Smuzhiyun trace_xchk_fblock_error(sc, whichfork, offset, __return_address);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* Record a corruption while cross-referencing a fork block. */
269*4882a593Smuzhiyun void
xchk_fblock_xref_set_corrupt(struct xfs_scrub * sc,int whichfork,xfs_fileoff_t offset)270*4882a593Smuzhiyun xchk_fblock_xref_set_corrupt(
271*4882a593Smuzhiyun struct xfs_scrub *sc,
272*4882a593Smuzhiyun int whichfork,
273*4882a593Smuzhiyun xfs_fileoff_t offset)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XCORRUPT;
276*4882a593Smuzhiyun trace_xchk_fblock_error(sc, whichfork, offset, __return_address);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /*
280*4882a593Smuzhiyun * Warn about inodes that need administrative review but is not
281*4882a593Smuzhiyun * incorrect.
282*4882a593Smuzhiyun */
283*4882a593Smuzhiyun void
xchk_ino_set_warning(struct xfs_scrub * sc,xfs_ino_t ino)284*4882a593Smuzhiyun xchk_ino_set_warning(
285*4882a593Smuzhiyun struct xfs_scrub *sc,
286*4882a593Smuzhiyun xfs_ino_t ino)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_WARNING;
289*4882a593Smuzhiyun trace_xchk_ino_warning(sc, ino, __return_address);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun /* Warn about a block indexed by a file fork that needs review. */
293*4882a593Smuzhiyun void
xchk_fblock_set_warning(struct xfs_scrub * sc,int whichfork,xfs_fileoff_t offset)294*4882a593Smuzhiyun xchk_fblock_set_warning(
295*4882a593Smuzhiyun struct xfs_scrub *sc,
296*4882a593Smuzhiyun int whichfork,
297*4882a593Smuzhiyun xfs_fileoff_t offset)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_WARNING;
300*4882a593Smuzhiyun trace_xchk_fblock_warning(sc, whichfork, offset, __return_address);
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /* Signal an incomplete scrub. */
304*4882a593Smuzhiyun void
xchk_set_incomplete(struct xfs_scrub * sc)305*4882a593Smuzhiyun xchk_set_incomplete(
306*4882a593Smuzhiyun struct xfs_scrub *sc)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_INCOMPLETE;
309*4882a593Smuzhiyun trace_xchk_incomplete(sc, __return_address);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /*
313*4882a593Smuzhiyun * rmap scrubbing -- compute the number of blocks with a given owner,
314*4882a593Smuzhiyun * at least according to the reverse mapping data.
315*4882a593Smuzhiyun */
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun struct xchk_rmap_ownedby_info {
318*4882a593Smuzhiyun const struct xfs_owner_info *oinfo;
319*4882a593Smuzhiyun xfs_filblks_t *blocks;
320*4882a593Smuzhiyun };
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun STATIC int
xchk_count_rmap_ownedby_irec(struct xfs_btree_cur * cur,struct xfs_rmap_irec * rec,void * priv)323*4882a593Smuzhiyun xchk_count_rmap_ownedby_irec(
324*4882a593Smuzhiyun struct xfs_btree_cur *cur,
325*4882a593Smuzhiyun struct xfs_rmap_irec *rec,
326*4882a593Smuzhiyun void *priv)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun struct xchk_rmap_ownedby_info *sroi = priv;
329*4882a593Smuzhiyun bool irec_attr;
330*4882a593Smuzhiyun bool oinfo_attr;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun irec_attr = rec->rm_flags & XFS_RMAP_ATTR_FORK;
333*4882a593Smuzhiyun oinfo_attr = sroi->oinfo->oi_flags & XFS_OWNER_INFO_ATTR_FORK;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if (rec->rm_owner != sroi->oinfo->oi_owner)
336*4882a593Smuzhiyun return 0;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) || irec_attr == oinfo_attr)
339*4882a593Smuzhiyun (*sroi->blocks) += rec->rm_blockcount;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun return 0;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun /*
345*4882a593Smuzhiyun * Calculate the number of blocks the rmap thinks are owned by something.
346*4882a593Smuzhiyun * The caller should pass us an rmapbt cursor.
347*4882a593Smuzhiyun */
348*4882a593Smuzhiyun int
xchk_count_rmap_ownedby_ag(struct xfs_scrub * sc,struct xfs_btree_cur * cur,const struct xfs_owner_info * oinfo,xfs_filblks_t * blocks)349*4882a593Smuzhiyun xchk_count_rmap_ownedby_ag(
350*4882a593Smuzhiyun struct xfs_scrub *sc,
351*4882a593Smuzhiyun struct xfs_btree_cur *cur,
352*4882a593Smuzhiyun const struct xfs_owner_info *oinfo,
353*4882a593Smuzhiyun xfs_filblks_t *blocks)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun struct xchk_rmap_ownedby_info sroi = {
356*4882a593Smuzhiyun .oinfo = oinfo,
357*4882a593Smuzhiyun .blocks = blocks,
358*4882a593Smuzhiyun };
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun *blocks = 0;
361*4882a593Smuzhiyun return xfs_rmap_query_all(cur, xchk_count_rmap_ownedby_irec,
362*4882a593Smuzhiyun &sroi);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /*
366*4882a593Smuzhiyun * AG scrubbing
367*4882a593Smuzhiyun *
368*4882a593Smuzhiyun * These helpers facilitate locking an allocation group's header
369*4882a593Smuzhiyun * buffers, setting up cursors for all btrees that are present, and
370*4882a593Smuzhiyun * cleaning everything up once we're through.
371*4882a593Smuzhiyun */
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun /* Decide if we want to return an AG header read failure. */
374*4882a593Smuzhiyun static inline bool
want_ag_read_header_failure(struct xfs_scrub * sc,unsigned int type)375*4882a593Smuzhiyun want_ag_read_header_failure(
376*4882a593Smuzhiyun struct xfs_scrub *sc,
377*4882a593Smuzhiyun unsigned int type)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun /* Return all AG header read failures when scanning btrees. */
380*4882a593Smuzhiyun if (sc->sm->sm_type != XFS_SCRUB_TYPE_AGF &&
381*4882a593Smuzhiyun sc->sm->sm_type != XFS_SCRUB_TYPE_AGFL &&
382*4882a593Smuzhiyun sc->sm->sm_type != XFS_SCRUB_TYPE_AGI)
383*4882a593Smuzhiyun return true;
384*4882a593Smuzhiyun /*
385*4882a593Smuzhiyun * If we're scanning a given type of AG header, we only want to
386*4882a593Smuzhiyun * see read failures from that specific header. We'd like the
387*4882a593Smuzhiyun * other headers to cross-check them, but this isn't required.
388*4882a593Smuzhiyun */
389*4882a593Smuzhiyun if (sc->sm->sm_type == type)
390*4882a593Smuzhiyun return true;
391*4882a593Smuzhiyun return false;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun /*
395*4882a593Smuzhiyun * Grab all the headers for an AG.
396*4882a593Smuzhiyun *
397*4882a593Smuzhiyun * The headers should be released by xchk_ag_free, but as a fail
398*4882a593Smuzhiyun * safe we attach all the buffers we grab to the scrub transaction so
399*4882a593Smuzhiyun * they'll all be freed when we cancel it.
400*4882a593Smuzhiyun */
401*4882a593Smuzhiyun int
xchk_ag_read_headers(struct xfs_scrub * sc,xfs_agnumber_t agno,struct xfs_buf ** agi,struct xfs_buf ** agf,struct xfs_buf ** agfl)402*4882a593Smuzhiyun xchk_ag_read_headers(
403*4882a593Smuzhiyun struct xfs_scrub *sc,
404*4882a593Smuzhiyun xfs_agnumber_t agno,
405*4882a593Smuzhiyun struct xfs_buf **agi,
406*4882a593Smuzhiyun struct xfs_buf **agf,
407*4882a593Smuzhiyun struct xfs_buf **agfl)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun struct xfs_mount *mp = sc->mp;
410*4882a593Smuzhiyun int error;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun error = xfs_ialloc_read_agi(mp, sc->tp, agno, agi);
413*4882a593Smuzhiyun if (error && want_ag_read_header_failure(sc, XFS_SCRUB_TYPE_AGI))
414*4882a593Smuzhiyun goto out;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun error = xfs_alloc_read_agf(mp, sc->tp, agno, 0, agf);
417*4882a593Smuzhiyun if (error && want_ag_read_header_failure(sc, XFS_SCRUB_TYPE_AGF))
418*4882a593Smuzhiyun goto out;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun error = xfs_alloc_read_agfl(mp, sc->tp, agno, agfl);
421*4882a593Smuzhiyun if (error && want_ag_read_header_failure(sc, XFS_SCRUB_TYPE_AGFL))
422*4882a593Smuzhiyun goto out;
423*4882a593Smuzhiyun error = 0;
424*4882a593Smuzhiyun out:
425*4882a593Smuzhiyun return error;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /* Release all the AG btree cursors. */
429*4882a593Smuzhiyun void
xchk_ag_btcur_free(struct xchk_ag * sa)430*4882a593Smuzhiyun xchk_ag_btcur_free(
431*4882a593Smuzhiyun struct xchk_ag *sa)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun if (sa->refc_cur)
434*4882a593Smuzhiyun xfs_btree_del_cursor(sa->refc_cur, XFS_BTREE_ERROR);
435*4882a593Smuzhiyun if (sa->rmap_cur)
436*4882a593Smuzhiyun xfs_btree_del_cursor(sa->rmap_cur, XFS_BTREE_ERROR);
437*4882a593Smuzhiyun if (sa->fino_cur)
438*4882a593Smuzhiyun xfs_btree_del_cursor(sa->fino_cur, XFS_BTREE_ERROR);
439*4882a593Smuzhiyun if (sa->ino_cur)
440*4882a593Smuzhiyun xfs_btree_del_cursor(sa->ino_cur, XFS_BTREE_ERROR);
441*4882a593Smuzhiyun if (sa->cnt_cur)
442*4882a593Smuzhiyun xfs_btree_del_cursor(sa->cnt_cur, XFS_BTREE_ERROR);
443*4882a593Smuzhiyun if (sa->bno_cur)
444*4882a593Smuzhiyun xfs_btree_del_cursor(sa->bno_cur, XFS_BTREE_ERROR);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun sa->refc_cur = NULL;
447*4882a593Smuzhiyun sa->rmap_cur = NULL;
448*4882a593Smuzhiyun sa->fino_cur = NULL;
449*4882a593Smuzhiyun sa->ino_cur = NULL;
450*4882a593Smuzhiyun sa->bno_cur = NULL;
451*4882a593Smuzhiyun sa->cnt_cur = NULL;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /* Initialize all the btree cursors for an AG. */
455*4882a593Smuzhiyun int
xchk_ag_btcur_init(struct xfs_scrub * sc,struct xchk_ag * sa)456*4882a593Smuzhiyun xchk_ag_btcur_init(
457*4882a593Smuzhiyun struct xfs_scrub *sc,
458*4882a593Smuzhiyun struct xchk_ag *sa)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun struct xfs_mount *mp = sc->mp;
461*4882a593Smuzhiyun xfs_agnumber_t agno = sa->agno;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun xchk_perag_get(sc->mp, sa);
464*4882a593Smuzhiyun if (sa->agf_bp &&
465*4882a593Smuzhiyun xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
466*4882a593Smuzhiyun /* Set up a bnobt cursor for cross-referencing. */
467*4882a593Smuzhiyun sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
468*4882a593Smuzhiyun agno, XFS_BTNUM_BNO);
469*4882a593Smuzhiyun if (!sa->bno_cur)
470*4882a593Smuzhiyun goto err;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun if (sa->agf_bp &&
474*4882a593Smuzhiyun xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
475*4882a593Smuzhiyun /* Set up a cntbt cursor for cross-referencing. */
476*4882a593Smuzhiyun sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
477*4882a593Smuzhiyun agno, XFS_BTNUM_CNT);
478*4882a593Smuzhiyun if (!sa->cnt_cur)
479*4882a593Smuzhiyun goto err;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun /* Set up a inobt cursor for cross-referencing. */
483*4882a593Smuzhiyun if (sa->agi_bp &&
484*4882a593Smuzhiyun xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
485*4882a593Smuzhiyun sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
486*4882a593Smuzhiyun agno, XFS_BTNUM_INO);
487*4882a593Smuzhiyun if (!sa->ino_cur)
488*4882a593Smuzhiyun goto err;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun /* Set up a finobt cursor for cross-referencing. */
492*4882a593Smuzhiyun if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
493*4882a593Smuzhiyun xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
494*4882a593Smuzhiyun sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
495*4882a593Smuzhiyun agno, XFS_BTNUM_FINO);
496*4882a593Smuzhiyun if (!sa->fino_cur)
497*4882a593Smuzhiyun goto err;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun /* Set up a rmapbt cursor for cross-referencing. */
501*4882a593Smuzhiyun if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
502*4882a593Smuzhiyun xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
503*4882a593Smuzhiyun sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
504*4882a593Smuzhiyun agno);
505*4882a593Smuzhiyun if (!sa->rmap_cur)
506*4882a593Smuzhiyun goto err;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun /* Set up a refcountbt cursor for cross-referencing. */
510*4882a593Smuzhiyun if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
511*4882a593Smuzhiyun xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
512*4882a593Smuzhiyun sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
513*4882a593Smuzhiyun sa->agf_bp, agno);
514*4882a593Smuzhiyun if (!sa->refc_cur)
515*4882a593Smuzhiyun goto err;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun return 0;
519*4882a593Smuzhiyun err:
520*4882a593Smuzhiyun return -ENOMEM;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun /* Release the AG header context and btree cursors. */
524*4882a593Smuzhiyun void
xchk_ag_free(struct xfs_scrub * sc,struct xchk_ag * sa)525*4882a593Smuzhiyun xchk_ag_free(
526*4882a593Smuzhiyun struct xfs_scrub *sc,
527*4882a593Smuzhiyun struct xchk_ag *sa)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun xchk_ag_btcur_free(sa);
530*4882a593Smuzhiyun if (sa->agfl_bp) {
531*4882a593Smuzhiyun xfs_trans_brelse(sc->tp, sa->agfl_bp);
532*4882a593Smuzhiyun sa->agfl_bp = NULL;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun if (sa->agf_bp) {
535*4882a593Smuzhiyun xfs_trans_brelse(sc->tp, sa->agf_bp);
536*4882a593Smuzhiyun sa->agf_bp = NULL;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun if (sa->agi_bp) {
539*4882a593Smuzhiyun xfs_trans_brelse(sc->tp, sa->agi_bp);
540*4882a593Smuzhiyun sa->agi_bp = NULL;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun if (sa->pag) {
543*4882a593Smuzhiyun xfs_perag_put(sa->pag);
544*4882a593Smuzhiyun sa->pag = NULL;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun sa->agno = NULLAGNUMBER;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun /*
550*4882a593Smuzhiyun * For scrub, grab the AGI and the AGF headers, in that order. Locking
551*4882a593Smuzhiyun * order requires us to get the AGI before the AGF. We use the
552*4882a593Smuzhiyun * transaction to avoid deadlocking on crosslinked metadata buffers;
553*4882a593Smuzhiyun * either the caller passes one in (bmap scrub) or we have to create a
554*4882a593Smuzhiyun * transaction ourselves.
555*4882a593Smuzhiyun */
556*4882a593Smuzhiyun int
xchk_ag_init(struct xfs_scrub * sc,xfs_agnumber_t agno,struct xchk_ag * sa)557*4882a593Smuzhiyun xchk_ag_init(
558*4882a593Smuzhiyun struct xfs_scrub *sc,
559*4882a593Smuzhiyun xfs_agnumber_t agno,
560*4882a593Smuzhiyun struct xchk_ag *sa)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun int error;
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun sa->agno = agno;
565*4882a593Smuzhiyun error = xchk_ag_read_headers(sc, agno, &sa->agi_bp,
566*4882a593Smuzhiyun &sa->agf_bp, &sa->agfl_bp);
567*4882a593Smuzhiyun if (error)
568*4882a593Smuzhiyun return error;
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun return xchk_ag_btcur_init(sc, sa);
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun /*
574*4882a593Smuzhiyun * Grab the per-ag structure if we haven't already gotten it. Teardown of the
575*4882a593Smuzhiyun * xchk_ag will release it for us.
576*4882a593Smuzhiyun */
577*4882a593Smuzhiyun void
xchk_perag_get(struct xfs_mount * mp,struct xchk_ag * sa)578*4882a593Smuzhiyun xchk_perag_get(
579*4882a593Smuzhiyun struct xfs_mount *mp,
580*4882a593Smuzhiyun struct xchk_ag *sa)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun if (!sa->pag)
583*4882a593Smuzhiyun sa->pag = xfs_perag_get(mp, sa->agno);
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun /* Per-scrubber setup functions */
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun /*
589*4882a593Smuzhiyun * Grab an empty transaction so that we can re-grab locked buffers if
590*4882a593Smuzhiyun * one of our btrees turns out to be cyclic.
591*4882a593Smuzhiyun *
592*4882a593Smuzhiyun * If we're going to repair something, we need to ask for the largest possible
593*4882a593Smuzhiyun * log reservation so that we can handle the worst case scenario for metadata
594*4882a593Smuzhiyun * updates while rebuilding a metadata item. We also need to reserve as many
595*4882a593Smuzhiyun * blocks in the head transaction as we think we're going to need to rebuild
596*4882a593Smuzhiyun * the metadata object.
597*4882a593Smuzhiyun */
598*4882a593Smuzhiyun int
xchk_trans_alloc(struct xfs_scrub * sc,uint resblks)599*4882a593Smuzhiyun xchk_trans_alloc(
600*4882a593Smuzhiyun struct xfs_scrub *sc,
601*4882a593Smuzhiyun uint resblks)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)
604*4882a593Smuzhiyun return xfs_trans_alloc(sc->mp, &M_RES(sc->mp)->tr_itruncate,
605*4882a593Smuzhiyun resblks, 0, 0, &sc->tp);
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun return xfs_trans_alloc_empty(sc->mp, &sc->tp);
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun /* Set us up with a transaction and an empty context. */
611*4882a593Smuzhiyun int
xchk_setup_fs(struct xfs_scrub * sc,struct xfs_inode * ip)612*4882a593Smuzhiyun xchk_setup_fs(
613*4882a593Smuzhiyun struct xfs_scrub *sc,
614*4882a593Smuzhiyun struct xfs_inode *ip)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun uint resblks;
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun resblks = xrep_calc_ag_resblks(sc);
619*4882a593Smuzhiyun return xchk_trans_alloc(sc, resblks);
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun /* Set us up with AG headers and btree cursors. */
623*4882a593Smuzhiyun int
xchk_setup_ag_btree(struct xfs_scrub * sc,struct xfs_inode * ip,bool force_log)624*4882a593Smuzhiyun xchk_setup_ag_btree(
625*4882a593Smuzhiyun struct xfs_scrub *sc,
626*4882a593Smuzhiyun struct xfs_inode *ip,
627*4882a593Smuzhiyun bool force_log)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun struct xfs_mount *mp = sc->mp;
630*4882a593Smuzhiyun int error;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun /*
633*4882a593Smuzhiyun * If the caller asks us to checkpont the log, do so. This
634*4882a593Smuzhiyun * expensive operation should be performed infrequently and only
635*4882a593Smuzhiyun * as a last resort. Any caller that sets force_log should
636*4882a593Smuzhiyun * document why they need to do so.
637*4882a593Smuzhiyun */
638*4882a593Smuzhiyun if (force_log) {
639*4882a593Smuzhiyun error = xchk_checkpoint_log(mp);
640*4882a593Smuzhiyun if (error)
641*4882a593Smuzhiyun return error;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun error = xchk_setup_fs(sc, ip);
645*4882a593Smuzhiyun if (error)
646*4882a593Smuzhiyun return error;
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun return xchk_ag_init(sc, sc->sm->sm_agno, &sc->sa);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun /* Push everything out of the log onto disk. */
652*4882a593Smuzhiyun int
xchk_checkpoint_log(struct xfs_mount * mp)653*4882a593Smuzhiyun xchk_checkpoint_log(
654*4882a593Smuzhiyun struct xfs_mount *mp)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun int error;
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun error = xfs_log_force(mp, XFS_LOG_SYNC);
659*4882a593Smuzhiyun if (error)
660*4882a593Smuzhiyun return error;
661*4882a593Smuzhiyun xfs_ail_push_all_sync(mp->m_ail);
662*4882a593Smuzhiyun return 0;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun /*
666*4882a593Smuzhiyun * Given an inode and the scrub control structure, grab either the
667*4882a593Smuzhiyun * inode referenced in the control structure or the inode passed in.
668*4882a593Smuzhiyun * The inode is not locked.
669*4882a593Smuzhiyun */
670*4882a593Smuzhiyun int
xchk_get_inode(struct xfs_scrub * sc,struct xfs_inode * ip_in)671*4882a593Smuzhiyun xchk_get_inode(
672*4882a593Smuzhiyun struct xfs_scrub *sc,
673*4882a593Smuzhiyun struct xfs_inode *ip_in)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun struct xfs_imap imap;
676*4882a593Smuzhiyun struct xfs_mount *mp = sc->mp;
677*4882a593Smuzhiyun struct xfs_inode *ip = NULL;
678*4882a593Smuzhiyun int error;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun /* We want to scan the inode we already had opened. */
681*4882a593Smuzhiyun if (sc->sm->sm_ino == 0 || sc->sm->sm_ino == ip_in->i_ino) {
682*4882a593Smuzhiyun sc->ip = ip_in;
683*4882a593Smuzhiyun return 0;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun /* Look up the inode, see if the generation number matches. */
687*4882a593Smuzhiyun if (xfs_internal_inum(mp, sc->sm->sm_ino))
688*4882a593Smuzhiyun return -ENOENT;
689*4882a593Smuzhiyun error = xfs_iget(mp, NULL, sc->sm->sm_ino,
690*4882a593Smuzhiyun XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE, 0, &ip);
691*4882a593Smuzhiyun switch (error) {
692*4882a593Smuzhiyun case -ENOENT:
693*4882a593Smuzhiyun /* Inode doesn't exist, just bail out. */
694*4882a593Smuzhiyun return error;
695*4882a593Smuzhiyun case 0:
696*4882a593Smuzhiyun /* Got an inode, continue. */
697*4882a593Smuzhiyun break;
698*4882a593Smuzhiyun case -EINVAL:
699*4882a593Smuzhiyun /*
700*4882a593Smuzhiyun * -EINVAL with IGET_UNTRUSTED could mean one of several
701*4882a593Smuzhiyun * things: userspace gave us an inode number that doesn't
702*4882a593Smuzhiyun * correspond to fs space, or doesn't have an inobt entry;
703*4882a593Smuzhiyun * or it could simply mean that the inode buffer failed the
704*4882a593Smuzhiyun * read verifiers.
705*4882a593Smuzhiyun *
706*4882a593Smuzhiyun * Try just the inode mapping lookup -- if it succeeds, then
707*4882a593Smuzhiyun * the inode buffer verifier failed and something needs fixing.
708*4882a593Smuzhiyun * Otherwise, we really couldn't find it so tell userspace
709*4882a593Smuzhiyun * that it no longer exists.
710*4882a593Smuzhiyun */
711*4882a593Smuzhiyun error = xfs_imap(sc->mp, sc->tp, sc->sm->sm_ino, &imap,
712*4882a593Smuzhiyun XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE);
713*4882a593Smuzhiyun if (error)
714*4882a593Smuzhiyun return -ENOENT;
715*4882a593Smuzhiyun error = -EFSCORRUPTED;
716*4882a593Smuzhiyun /* fall through */
717*4882a593Smuzhiyun default:
718*4882a593Smuzhiyun trace_xchk_op_error(sc,
719*4882a593Smuzhiyun XFS_INO_TO_AGNO(mp, sc->sm->sm_ino),
720*4882a593Smuzhiyun XFS_INO_TO_AGBNO(mp, sc->sm->sm_ino),
721*4882a593Smuzhiyun error, __return_address);
722*4882a593Smuzhiyun return error;
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun if (VFS_I(ip)->i_generation != sc->sm->sm_gen) {
725*4882a593Smuzhiyun xfs_irele(ip);
726*4882a593Smuzhiyun return -ENOENT;
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun sc->ip = ip;
730*4882a593Smuzhiyun return 0;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun /* Set us up to scrub a file's contents. */
734*4882a593Smuzhiyun int
xchk_setup_inode_contents(struct xfs_scrub * sc,struct xfs_inode * ip,unsigned int resblks)735*4882a593Smuzhiyun xchk_setup_inode_contents(
736*4882a593Smuzhiyun struct xfs_scrub *sc,
737*4882a593Smuzhiyun struct xfs_inode *ip,
738*4882a593Smuzhiyun unsigned int resblks)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun int error;
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun error = xchk_get_inode(sc, ip);
743*4882a593Smuzhiyun if (error)
744*4882a593Smuzhiyun return error;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun /* Got the inode, lock it and we're ready to go. */
747*4882a593Smuzhiyun sc->ilock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
748*4882a593Smuzhiyun xfs_ilock(sc->ip, sc->ilock_flags);
749*4882a593Smuzhiyun error = xchk_trans_alloc(sc, resblks);
750*4882a593Smuzhiyun if (error)
751*4882a593Smuzhiyun goto out;
752*4882a593Smuzhiyun sc->ilock_flags |= XFS_ILOCK_EXCL;
753*4882a593Smuzhiyun xfs_ilock(sc->ip, XFS_ILOCK_EXCL);
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun out:
756*4882a593Smuzhiyun /* scrub teardown will unlock and release the inode for us */
757*4882a593Smuzhiyun return error;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun /*
761*4882a593Smuzhiyun * Predicate that decides if we need to evaluate the cross-reference check.
762*4882a593Smuzhiyun * If there was an error accessing the cross-reference btree, just delete
763*4882a593Smuzhiyun * the cursor and skip the check.
764*4882a593Smuzhiyun */
765*4882a593Smuzhiyun bool
xchk_should_check_xref(struct xfs_scrub * sc,int * error,struct xfs_btree_cur ** curpp)766*4882a593Smuzhiyun xchk_should_check_xref(
767*4882a593Smuzhiyun struct xfs_scrub *sc,
768*4882a593Smuzhiyun int *error,
769*4882a593Smuzhiyun struct xfs_btree_cur **curpp)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun /* No point in xref if we already know we're corrupt. */
772*4882a593Smuzhiyun if (xchk_skip_xref(sc->sm))
773*4882a593Smuzhiyun return false;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun if (*error == 0)
776*4882a593Smuzhiyun return true;
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun if (curpp) {
779*4882a593Smuzhiyun /* If we've already given up on xref, just bail out. */
780*4882a593Smuzhiyun if (!*curpp)
781*4882a593Smuzhiyun return false;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun /* xref error, delete cursor and bail out. */
784*4882a593Smuzhiyun xfs_btree_del_cursor(*curpp, XFS_BTREE_ERROR);
785*4882a593Smuzhiyun *curpp = NULL;
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XFAIL;
789*4882a593Smuzhiyun trace_xchk_xref_error(sc, *error, __return_address);
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun /*
792*4882a593Smuzhiyun * Errors encountered during cross-referencing with another
793*4882a593Smuzhiyun * data structure should not cause this scrubber to abort.
794*4882a593Smuzhiyun */
795*4882a593Smuzhiyun *error = 0;
796*4882a593Smuzhiyun return false;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun /* Run the structure verifiers on in-memory buffers to detect bad memory. */
800*4882a593Smuzhiyun void
xchk_buffer_recheck(struct xfs_scrub * sc,struct xfs_buf * bp)801*4882a593Smuzhiyun xchk_buffer_recheck(
802*4882a593Smuzhiyun struct xfs_scrub *sc,
803*4882a593Smuzhiyun struct xfs_buf *bp)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun xfs_failaddr_t fa;
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun if (bp->b_ops == NULL) {
808*4882a593Smuzhiyun xchk_block_set_corrupt(sc, bp);
809*4882a593Smuzhiyun return;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun if (bp->b_ops->verify_struct == NULL) {
812*4882a593Smuzhiyun xchk_set_incomplete(sc);
813*4882a593Smuzhiyun return;
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun fa = bp->b_ops->verify_struct(bp);
816*4882a593Smuzhiyun if (!fa)
817*4882a593Smuzhiyun return;
818*4882a593Smuzhiyun sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
819*4882a593Smuzhiyun trace_xchk_block_error(sc, bp->b_bn, fa);
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun /*
823*4882a593Smuzhiyun * Scrub the attr/data forks of a metadata inode. The metadata inode must be
824*4882a593Smuzhiyun * pointed to by sc->ip and the ILOCK must be held.
825*4882a593Smuzhiyun */
826*4882a593Smuzhiyun int
xchk_metadata_inode_forks(struct xfs_scrub * sc)827*4882a593Smuzhiyun xchk_metadata_inode_forks(
828*4882a593Smuzhiyun struct xfs_scrub *sc)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun __u32 smtype;
831*4882a593Smuzhiyun bool shared;
832*4882a593Smuzhiyun int error;
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
835*4882a593Smuzhiyun return 0;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun /* Metadata inodes don't live on the rt device. */
838*4882a593Smuzhiyun if (sc->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
839*4882a593Smuzhiyun xchk_ino_set_corrupt(sc, sc->ip->i_ino);
840*4882a593Smuzhiyun return 0;
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun /* They should never participate in reflink. */
844*4882a593Smuzhiyun if (xfs_is_reflink_inode(sc->ip)) {
845*4882a593Smuzhiyun xchk_ino_set_corrupt(sc, sc->ip->i_ino);
846*4882a593Smuzhiyun return 0;
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun /* They also should never have extended attributes. */
850*4882a593Smuzhiyun if (xfs_inode_hasattr(sc->ip)) {
851*4882a593Smuzhiyun xchk_ino_set_corrupt(sc, sc->ip->i_ino);
852*4882a593Smuzhiyun return 0;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun /* Invoke the data fork scrubber. */
856*4882a593Smuzhiyun smtype = sc->sm->sm_type;
857*4882a593Smuzhiyun sc->sm->sm_type = XFS_SCRUB_TYPE_BMBTD;
858*4882a593Smuzhiyun error = xchk_bmap_data(sc);
859*4882a593Smuzhiyun sc->sm->sm_type = smtype;
860*4882a593Smuzhiyun if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
861*4882a593Smuzhiyun return error;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun /* Look for incorrect shared blocks. */
864*4882a593Smuzhiyun if (xfs_sb_version_hasreflink(&sc->mp->m_sb)) {
865*4882a593Smuzhiyun error = xfs_reflink_inode_has_shared_extents(sc->tp, sc->ip,
866*4882a593Smuzhiyun &shared);
867*4882a593Smuzhiyun if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0,
868*4882a593Smuzhiyun &error))
869*4882a593Smuzhiyun return error;
870*4882a593Smuzhiyun if (shared)
871*4882a593Smuzhiyun xchk_ino_set_corrupt(sc, sc->ip->i_ino);
872*4882a593Smuzhiyun }
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun return error;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun /*
878*4882a593Smuzhiyun * Try to lock an inode in violation of the usual locking order rules. For
879*4882a593Smuzhiyun * example, trying to get the IOLOCK while in transaction context, or just
880*4882a593Smuzhiyun * plain breaking AG-order or inode-order inode locking rules. Either way,
881*4882a593Smuzhiyun * the only way to avoid an ABBA deadlock is to use trylock and back off if
882*4882a593Smuzhiyun * we can't.
883*4882a593Smuzhiyun */
884*4882a593Smuzhiyun int
xchk_ilock_inverted(struct xfs_inode * ip,uint lock_mode)885*4882a593Smuzhiyun xchk_ilock_inverted(
886*4882a593Smuzhiyun struct xfs_inode *ip,
887*4882a593Smuzhiyun uint lock_mode)
888*4882a593Smuzhiyun {
889*4882a593Smuzhiyun int i;
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun for (i = 0; i < 20; i++) {
892*4882a593Smuzhiyun if (xfs_ilock_nowait(ip, lock_mode))
893*4882a593Smuzhiyun return 0;
894*4882a593Smuzhiyun delay(1);
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun return -EDEADLOCK;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun /* Pause background reaping of resources. */
900*4882a593Smuzhiyun void
xchk_stop_reaping(struct xfs_scrub * sc)901*4882a593Smuzhiyun xchk_stop_reaping(
902*4882a593Smuzhiyun struct xfs_scrub *sc)
903*4882a593Smuzhiyun {
904*4882a593Smuzhiyun sc->flags |= XCHK_REAPING_DISABLED;
905*4882a593Smuzhiyun xfs_stop_block_reaping(sc->mp);
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun /* Restart background reaping of resources. */
909*4882a593Smuzhiyun void
xchk_start_reaping(struct xfs_scrub * sc)910*4882a593Smuzhiyun xchk_start_reaping(
911*4882a593Smuzhiyun struct xfs_scrub *sc)
912*4882a593Smuzhiyun {
913*4882a593Smuzhiyun xfs_start_block_reaping(sc->mp);
914*4882a593Smuzhiyun sc->flags &= ~XCHK_REAPING_DISABLED;
915*4882a593Smuzhiyun }
916