xref: /OK3568_Linux_fs/kernel/fs/xfs/scrub/common.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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