xref: /OK3568_Linux_fs/kernel/fs/xfs/scrub/inode.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_inode.h"
15*4882a593Smuzhiyun #include "xfs_ialloc.h"
16*4882a593Smuzhiyun #include "xfs_da_format.h"
17*4882a593Smuzhiyun #include "xfs_reflink.h"
18*4882a593Smuzhiyun #include "xfs_rmap.h"
19*4882a593Smuzhiyun #include "xfs_bmap_util.h"
20*4882a593Smuzhiyun #include "scrub/scrub.h"
21*4882a593Smuzhiyun #include "scrub/common.h"
22*4882a593Smuzhiyun #include "scrub/btree.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun  * Grab total control of the inode metadata.  It doesn't matter here if
26*4882a593Smuzhiyun  * the file data is still changing; exclusive access to the metadata is
27*4882a593Smuzhiyun  * the goal.
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun int
xchk_setup_inode(struct xfs_scrub * sc,struct xfs_inode * ip)30*4882a593Smuzhiyun xchk_setup_inode(
31*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
32*4882a593Smuzhiyun 	struct xfs_inode	*ip)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	int			error;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	/*
37*4882a593Smuzhiyun 	 * Try to get the inode.  If the verifiers fail, we try again
38*4882a593Smuzhiyun 	 * in raw mode.
39*4882a593Smuzhiyun 	 */
40*4882a593Smuzhiyun 	error = xchk_get_inode(sc, ip);
41*4882a593Smuzhiyun 	switch (error) {
42*4882a593Smuzhiyun 	case 0:
43*4882a593Smuzhiyun 		break;
44*4882a593Smuzhiyun 	case -EFSCORRUPTED:
45*4882a593Smuzhiyun 	case -EFSBADCRC:
46*4882a593Smuzhiyun 		return xchk_trans_alloc(sc, 0);
47*4882a593Smuzhiyun 	default:
48*4882a593Smuzhiyun 		return error;
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	/* Got the inode, lock it and we're ready to go. */
52*4882a593Smuzhiyun 	sc->ilock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
53*4882a593Smuzhiyun 	xfs_ilock(sc->ip, sc->ilock_flags);
54*4882a593Smuzhiyun 	error = xchk_trans_alloc(sc, 0);
55*4882a593Smuzhiyun 	if (error)
56*4882a593Smuzhiyun 		goto out;
57*4882a593Smuzhiyun 	sc->ilock_flags |= XFS_ILOCK_EXCL;
58*4882a593Smuzhiyun 	xfs_ilock(sc->ip, XFS_ILOCK_EXCL);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun out:
61*4882a593Smuzhiyun 	/* scrub teardown will unlock and release the inode for us */
62*4882a593Smuzhiyun 	return error;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* Inode core */
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun /* Validate di_extsize hint. */
68*4882a593Smuzhiyun STATIC void
xchk_inode_extsize(struct xfs_scrub * sc,struct xfs_dinode * dip,xfs_ino_t ino,uint16_t mode,uint16_t flags)69*4882a593Smuzhiyun xchk_inode_extsize(
70*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
71*4882a593Smuzhiyun 	struct xfs_dinode	*dip,
72*4882a593Smuzhiyun 	xfs_ino_t		ino,
73*4882a593Smuzhiyun 	uint16_t		mode,
74*4882a593Smuzhiyun 	uint16_t		flags)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	xfs_failaddr_t		fa;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	fa = xfs_inode_validate_extsize(sc->mp, be32_to_cpu(dip->di_extsize),
79*4882a593Smuzhiyun 			mode, flags);
80*4882a593Smuzhiyun 	if (fa)
81*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /*
85*4882a593Smuzhiyun  * Validate di_cowextsize hint.
86*4882a593Smuzhiyun  *
87*4882a593Smuzhiyun  * The rules are documented at xfs_ioctl_setattr_check_cowextsize().
88*4882a593Smuzhiyun  * These functions must be kept in sync with each other.
89*4882a593Smuzhiyun  */
90*4882a593Smuzhiyun STATIC void
xchk_inode_cowextsize(struct xfs_scrub * sc,struct xfs_dinode * dip,xfs_ino_t ino,uint16_t mode,uint16_t flags,uint64_t flags2)91*4882a593Smuzhiyun xchk_inode_cowextsize(
92*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
93*4882a593Smuzhiyun 	struct xfs_dinode	*dip,
94*4882a593Smuzhiyun 	xfs_ino_t		ino,
95*4882a593Smuzhiyun 	uint16_t		mode,
96*4882a593Smuzhiyun 	uint16_t		flags,
97*4882a593Smuzhiyun 	uint64_t		flags2)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	xfs_failaddr_t		fa;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	fa = xfs_inode_validate_cowextsize(sc->mp,
102*4882a593Smuzhiyun 			be32_to_cpu(dip->di_cowextsize), mode, flags,
103*4882a593Smuzhiyun 			flags2);
104*4882a593Smuzhiyun 	if (fa)
105*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /* Make sure the di_flags make sense for the inode. */
109*4882a593Smuzhiyun STATIC void
xchk_inode_flags(struct xfs_scrub * sc,struct xfs_dinode * dip,xfs_ino_t ino,uint16_t mode,uint16_t flags)110*4882a593Smuzhiyun xchk_inode_flags(
111*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
112*4882a593Smuzhiyun 	struct xfs_dinode	*dip,
113*4882a593Smuzhiyun 	xfs_ino_t		ino,
114*4882a593Smuzhiyun 	uint16_t		mode,
115*4882a593Smuzhiyun 	uint16_t		flags)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	struct xfs_mount	*mp = sc->mp;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/* di_flags are all taken, last bit cannot be used */
120*4882a593Smuzhiyun 	if (flags & ~XFS_DIFLAG_ANY)
121*4882a593Smuzhiyun 		goto bad;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	/* rt flags require rt device */
124*4882a593Smuzhiyun 	if ((flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)
125*4882a593Smuzhiyun 		goto bad;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	/* new rt bitmap flag only valid for rbmino */
128*4882a593Smuzhiyun 	if ((flags & XFS_DIFLAG_NEWRTBM) && ino != mp->m_sb.sb_rbmino)
129*4882a593Smuzhiyun 		goto bad;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/* directory-only flags */
132*4882a593Smuzhiyun 	if ((flags & (XFS_DIFLAG_RTINHERIT |
133*4882a593Smuzhiyun 		     XFS_DIFLAG_EXTSZINHERIT |
134*4882a593Smuzhiyun 		     XFS_DIFLAG_PROJINHERIT |
135*4882a593Smuzhiyun 		     XFS_DIFLAG_NOSYMLINKS)) &&
136*4882a593Smuzhiyun 	    !S_ISDIR(mode))
137*4882a593Smuzhiyun 		goto bad;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	/* file-only flags */
140*4882a593Smuzhiyun 	if ((flags & (XFS_DIFLAG_REALTIME | FS_XFLAG_EXTSIZE)) &&
141*4882a593Smuzhiyun 	    !S_ISREG(mode))
142*4882a593Smuzhiyun 		goto bad;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/* filestreams and rt make no sense */
145*4882a593Smuzhiyun 	if ((flags & XFS_DIFLAG_FILESTREAM) && (flags & XFS_DIFLAG_REALTIME))
146*4882a593Smuzhiyun 		goto bad;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return;
149*4882a593Smuzhiyun bad:
150*4882a593Smuzhiyun 	xchk_ino_set_corrupt(sc, ino);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun /* Make sure the di_flags2 make sense for the inode. */
154*4882a593Smuzhiyun STATIC void
xchk_inode_flags2(struct xfs_scrub * sc,struct xfs_dinode * dip,xfs_ino_t ino,uint16_t mode,uint16_t flags,uint64_t flags2)155*4882a593Smuzhiyun xchk_inode_flags2(
156*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
157*4882a593Smuzhiyun 	struct xfs_dinode	*dip,
158*4882a593Smuzhiyun 	xfs_ino_t		ino,
159*4882a593Smuzhiyun 	uint16_t		mode,
160*4882a593Smuzhiyun 	uint16_t		flags,
161*4882a593Smuzhiyun 	uint64_t		flags2)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	struct xfs_mount	*mp = sc->mp;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* Unknown di_flags2 could be from a future kernel */
166*4882a593Smuzhiyun 	if (flags2 & ~XFS_DIFLAG2_ANY)
167*4882a593Smuzhiyun 		xchk_ino_set_warning(sc, ino);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	/* reflink flag requires reflink feature */
170*4882a593Smuzhiyun 	if ((flags2 & XFS_DIFLAG2_REFLINK) &&
171*4882a593Smuzhiyun 	    !xfs_sb_version_hasreflink(&mp->m_sb))
172*4882a593Smuzhiyun 		goto bad;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	/* cowextsize flag is checked w.r.t. mode separately */
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/* file/dir-only flags */
177*4882a593Smuzhiyun 	if ((flags2 & XFS_DIFLAG2_DAX) && !(S_ISREG(mode) || S_ISDIR(mode)))
178*4882a593Smuzhiyun 		goto bad;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	/* file-only flags */
181*4882a593Smuzhiyun 	if ((flags2 & XFS_DIFLAG2_REFLINK) && !S_ISREG(mode))
182*4882a593Smuzhiyun 		goto bad;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	/* realtime and reflink make no sense, currently */
185*4882a593Smuzhiyun 	if ((flags & XFS_DIFLAG_REALTIME) && (flags2 & XFS_DIFLAG2_REFLINK))
186*4882a593Smuzhiyun 		goto bad;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	/* dax and reflink make no sense, currently */
189*4882a593Smuzhiyun 	if ((flags2 & XFS_DIFLAG2_DAX) && (flags2 & XFS_DIFLAG2_REFLINK))
190*4882a593Smuzhiyun 		goto bad;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	/* no bigtime iflag without the bigtime feature */
193*4882a593Smuzhiyun 	if (xfs_dinode_has_bigtime(dip) &&
194*4882a593Smuzhiyun 	    !xfs_sb_version_hasbigtime(&mp->m_sb))
195*4882a593Smuzhiyun 		goto bad;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return;
198*4882a593Smuzhiyun bad:
199*4882a593Smuzhiyun 	xchk_ino_set_corrupt(sc, ino);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun static inline void
xchk_dinode_nsec(struct xfs_scrub * sc,xfs_ino_t ino,struct xfs_dinode * dip,const xfs_timestamp_t ts)203*4882a593Smuzhiyun xchk_dinode_nsec(
204*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
205*4882a593Smuzhiyun 	xfs_ino_t		ino,
206*4882a593Smuzhiyun 	struct xfs_dinode	*dip,
207*4882a593Smuzhiyun 	const xfs_timestamp_t	ts)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	struct timespec64	tv;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	tv = xfs_inode_from_disk_ts(dip, ts);
212*4882a593Smuzhiyun 	if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
213*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun /* Scrub all the ondisk inode fields. */
217*4882a593Smuzhiyun STATIC void
xchk_dinode(struct xfs_scrub * sc,struct xfs_dinode * dip,xfs_ino_t ino)218*4882a593Smuzhiyun xchk_dinode(
219*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
220*4882a593Smuzhiyun 	struct xfs_dinode	*dip,
221*4882a593Smuzhiyun 	xfs_ino_t		ino)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	struct xfs_mount	*mp = sc->mp;
224*4882a593Smuzhiyun 	size_t			fork_recs;
225*4882a593Smuzhiyun 	unsigned long long	isize;
226*4882a593Smuzhiyun 	uint64_t		flags2;
227*4882a593Smuzhiyun 	uint32_t		nextents;
228*4882a593Smuzhiyun 	uint16_t		flags;
229*4882a593Smuzhiyun 	uint16_t		mode;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	flags = be16_to_cpu(dip->di_flags);
232*4882a593Smuzhiyun 	if (dip->di_version >= 3)
233*4882a593Smuzhiyun 		flags2 = be64_to_cpu(dip->di_flags2);
234*4882a593Smuzhiyun 	else
235*4882a593Smuzhiyun 		flags2 = 0;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/* di_mode */
238*4882a593Smuzhiyun 	mode = be16_to_cpu(dip->di_mode);
239*4882a593Smuzhiyun 	switch (mode & S_IFMT) {
240*4882a593Smuzhiyun 	case S_IFLNK:
241*4882a593Smuzhiyun 	case S_IFREG:
242*4882a593Smuzhiyun 	case S_IFDIR:
243*4882a593Smuzhiyun 	case S_IFCHR:
244*4882a593Smuzhiyun 	case S_IFBLK:
245*4882a593Smuzhiyun 	case S_IFIFO:
246*4882a593Smuzhiyun 	case S_IFSOCK:
247*4882a593Smuzhiyun 		/* mode is recognized */
248*4882a593Smuzhiyun 		break;
249*4882a593Smuzhiyun 	default:
250*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
251*4882a593Smuzhiyun 		break;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* v1/v2 fields */
255*4882a593Smuzhiyun 	switch (dip->di_version) {
256*4882a593Smuzhiyun 	case 1:
257*4882a593Smuzhiyun 		/*
258*4882a593Smuzhiyun 		 * We autoconvert v1 inodes into v2 inodes on writeout,
259*4882a593Smuzhiyun 		 * so just mark this inode for preening.
260*4882a593Smuzhiyun 		 */
261*4882a593Smuzhiyun 		xchk_ino_set_preen(sc, ino);
262*4882a593Smuzhiyun 		break;
263*4882a593Smuzhiyun 	case 2:
264*4882a593Smuzhiyun 	case 3:
265*4882a593Smuzhiyun 		if (dip->di_onlink != 0)
266*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 		if (dip->di_mode == 0 && sc->ip)
269*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 		if (dip->di_projid_hi != 0 &&
272*4882a593Smuzhiyun 		    !xfs_sb_version_hasprojid32bit(&mp->m_sb))
273*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
274*4882a593Smuzhiyun 		break;
275*4882a593Smuzhiyun 	default:
276*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
277*4882a593Smuzhiyun 		return;
278*4882a593Smuzhiyun 	}
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/*
281*4882a593Smuzhiyun 	 * di_uid/di_gid -- -1 isn't invalid, but there's no way that
282*4882a593Smuzhiyun 	 * userspace could have created that.
283*4882a593Smuzhiyun 	 */
284*4882a593Smuzhiyun 	if (dip->di_uid == cpu_to_be32(-1U) ||
285*4882a593Smuzhiyun 	    dip->di_gid == cpu_to_be32(-1U))
286*4882a593Smuzhiyun 		xchk_ino_set_warning(sc, ino);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* di_format */
289*4882a593Smuzhiyun 	switch (dip->di_format) {
290*4882a593Smuzhiyun 	case XFS_DINODE_FMT_DEV:
291*4882a593Smuzhiyun 		if (!S_ISCHR(mode) && !S_ISBLK(mode) &&
292*4882a593Smuzhiyun 		    !S_ISFIFO(mode) && !S_ISSOCK(mode))
293*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
294*4882a593Smuzhiyun 		break;
295*4882a593Smuzhiyun 	case XFS_DINODE_FMT_LOCAL:
296*4882a593Smuzhiyun 		if (!S_ISDIR(mode) && !S_ISLNK(mode))
297*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
298*4882a593Smuzhiyun 		break;
299*4882a593Smuzhiyun 	case XFS_DINODE_FMT_EXTENTS:
300*4882a593Smuzhiyun 		if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
301*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
302*4882a593Smuzhiyun 		break;
303*4882a593Smuzhiyun 	case XFS_DINODE_FMT_BTREE:
304*4882a593Smuzhiyun 		if (!S_ISREG(mode) && !S_ISDIR(mode))
305*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
306*4882a593Smuzhiyun 		break;
307*4882a593Smuzhiyun 	case XFS_DINODE_FMT_UUID:
308*4882a593Smuzhiyun 	default:
309*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
310*4882a593Smuzhiyun 		break;
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	/* di_[amc]time.nsec */
314*4882a593Smuzhiyun 	xchk_dinode_nsec(sc, ino, dip, dip->di_atime);
315*4882a593Smuzhiyun 	xchk_dinode_nsec(sc, ino, dip, dip->di_mtime);
316*4882a593Smuzhiyun 	xchk_dinode_nsec(sc, ino, dip, dip->di_ctime);
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	/*
319*4882a593Smuzhiyun 	 * di_size.  xfs_dinode_verify checks for things that screw up
320*4882a593Smuzhiyun 	 * the VFS such as the upper bit being set and zero-length
321*4882a593Smuzhiyun 	 * symlinks/directories, but we can do more here.
322*4882a593Smuzhiyun 	 */
323*4882a593Smuzhiyun 	isize = be64_to_cpu(dip->di_size);
324*4882a593Smuzhiyun 	if (isize & (1ULL << 63))
325*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	/* Devices, fifos, and sockets must have zero size */
328*4882a593Smuzhiyun 	if (!S_ISDIR(mode) && !S_ISREG(mode) && !S_ISLNK(mode) && isize != 0)
329*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	/* Directories can't be larger than the data section size (32G) */
332*4882a593Smuzhiyun 	if (S_ISDIR(mode) && (isize == 0 || isize >= XFS_DIR2_SPACE_SIZE))
333*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	/* Symlinks can't be larger than SYMLINK_MAXLEN */
336*4882a593Smuzhiyun 	if (S_ISLNK(mode) && (isize == 0 || isize >= XFS_SYMLINK_MAXLEN))
337*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	/*
340*4882a593Smuzhiyun 	 * Warn if the running kernel can't handle the kinds of offsets
341*4882a593Smuzhiyun 	 * needed to deal with the file size.  In other words, if the
342*4882a593Smuzhiyun 	 * pagecache can't cache all the blocks in this file due to
343*4882a593Smuzhiyun 	 * overly large offsets, flag the inode for admin review.
344*4882a593Smuzhiyun 	 */
345*4882a593Smuzhiyun 	if (isize >= mp->m_super->s_maxbytes)
346*4882a593Smuzhiyun 		xchk_ino_set_warning(sc, ino);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* di_nblocks */
349*4882a593Smuzhiyun 	if (flags2 & XFS_DIFLAG2_REFLINK) {
350*4882a593Smuzhiyun 		; /* nblocks can exceed dblocks */
351*4882a593Smuzhiyun 	} else if (flags & XFS_DIFLAG_REALTIME) {
352*4882a593Smuzhiyun 		/*
353*4882a593Smuzhiyun 		 * nblocks is the sum of data extents (in the rtdev),
354*4882a593Smuzhiyun 		 * attr extents (in the datadev), and both forks' bmbt
355*4882a593Smuzhiyun 		 * blocks (in the datadev).  This clumsy check is the
356*4882a593Smuzhiyun 		 * best we can do without cross-referencing with the
357*4882a593Smuzhiyun 		 * inode forks.
358*4882a593Smuzhiyun 		 */
359*4882a593Smuzhiyun 		if (be64_to_cpu(dip->di_nblocks) >=
360*4882a593Smuzhiyun 		    mp->m_sb.sb_dblocks + mp->m_sb.sb_rblocks)
361*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
362*4882a593Smuzhiyun 	} else {
363*4882a593Smuzhiyun 		if (be64_to_cpu(dip->di_nblocks) >= mp->m_sb.sb_dblocks)
364*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	xchk_inode_flags(sc, dip, ino, mode, flags);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	xchk_inode_extsize(sc, dip, ino, mode, flags);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	/* di_nextents */
372*4882a593Smuzhiyun 	nextents = be32_to_cpu(dip->di_nextents);
373*4882a593Smuzhiyun 	fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
374*4882a593Smuzhiyun 	switch (dip->di_format) {
375*4882a593Smuzhiyun 	case XFS_DINODE_FMT_EXTENTS:
376*4882a593Smuzhiyun 		if (nextents > fork_recs)
377*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
378*4882a593Smuzhiyun 		break;
379*4882a593Smuzhiyun 	case XFS_DINODE_FMT_BTREE:
380*4882a593Smuzhiyun 		if (nextents <= fork_recs)
381*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
382*4882a593Smuzhiyun 		break;
383*4882a593Smuzhiyun 	default:
384*4882a593Smuzhiyun 		if (nextents != 0)
385*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
386*4882a593Smuzhiyun 		break;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	/* di_forkoff */
390*4882a593Smuzhiyun 	if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
391*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
392*4882a593Smuzhiyun 	if (dip->di_anextents != 0 && dip->di_forkoff == 0)
393*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
394*4882a593Smuzhiyun 	if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
395*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	/* di_aformat */
398*4882a593Smuzhiyun 	if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
399*4882a593Smuzhiyun 	    dip->di_aformat != XFS_DINODE_FMT_EXTENTS &&
400*4882a593Smuzhiyun 	    dip->di_aformat != XFS_DINODE_FMT_BTREE)
401*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	/* di_anextents */
404*4882a593Smuzhiyun 	nextents = be16_to_cpu(dip->di_anextents);
405*4882a593Smuzhiyun 	fork_recs =  XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
406*4882a593Smuzhiyun 	switch (dip->di_aformat) {
407*4882a593Smuzhiyun 	case XFS_DINODE_FMT_EXTENTS:
408*4882a593Smuzhiyun 		if (nextents > fork_recs)
409*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
410*4882a593Smuzhiyun 		break;
411*4882a593Smuzhiyun 	case XFS_DINODE_FMT_BTREE:
412*4882a593Smuzhiyun 		if (nextents <= fork_recs)
413*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
414*4882a593Smuzhiyun 		break;
415*4882a593Smuzhiyun 	default:
416*4882a593Smuzhiyun 		if (nextents != 0)
417*4882a593Smuzhiyun 			xchk_ino_set_corrupt(sc, ino);
418*4882a593Smuzhiyun 	}
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	if (dip->di_version >= 3) {
421*4882a593Smuzhiyun 		xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
422*4882a593Smuzhiyun 		xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
423*4882a593Smuzhiyun 		xchk_inode_cowextsize(sc, dip, ino, mode, flags,
424*4882a593Smuzhiyun 				flags2);
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun /*
429*4882a593Smuzhiyun  * Make sure the finobt doesn't think this inode is free.
430*4882a593Smuzhiyun  * We don't have to check the inobt ourselves because we got the inode via
431*4882a593Smuzhiyun  * IGET_UNTRUSTED, which checks the inobt for us.
432*4882a593Smuzhiyun  */
433*4882a593Smuzhiyun static void
xchk_inode_xref_finobt(struct xfs_scrub * sc,xfs_ino_t ino)434*4882a593Smuzhiyun xchk_inode_xref_finobt(
435*4882a593Smuzhiyun 	struct xfs_scrub		*sc,
436*4882a593Smuzhiyun 	xfs_ino_t			ino)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	struct xfs_inobt_rec_incore	rec;
439*4882a593Smuzhiyun 	xfs_agino_t			agino;
440*4882a593Smuzhiyun 	int				has_record;
441*4882a593Smuzhiyun 	int				error;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	if (!sc->sa.fino_cur || xchk_skip_xref(sc->sm))
444*4882a593Smuzhiyun 		return;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	agino = XFS_INO_TO_AGINO(sc->mp, ino);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	/*
449*4882a593Smuzhiyun 	 * Try to get the finobt record.  If we can't get it, then we're
450*4882a593Smuzhiyun 	 * in good shape.
451*4882a593Smuzhiyun 	 */
452*4882a593Smuzhiyun 	error = xfs_inobt_lookup(sc->sa.fino_cur, agino, XFS_LOOKUP_LE,
453*4882a593Smuzhiyun 			&has_record);
454*4882a593Smuzhiyun 	if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
455*4882a593Smuzhiyun 	    !has_record)
456*4882a593Smuzhiyun 		return;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	error = xfs_inobt_get_rec(sc->sa.fino_cur, &rec, &has_record);
459*4882a593Smuzhiyun 	if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
460*4882a593Smuzhiyun 	    !has_record)
461*4882a593Smuzhiyun 		return;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	/*
464*4882a593Smuzhiyun 	 * Otherwise, make sure this record either doesn't cover this inode,
465*4882a593Smuzhiyun 	 * or that it does but it's marked present.
466*4882a593Smuzhiyun 	 */
467*4882a593Smuzhiyun 	if (rec.ir_startino > agino ||
468*4882a593Smuzhiyun 	    rec.ir_startino + XFS_INODES_PER_CHUNK <= agino)
469*4882a593Smuzhiyun 		return;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	if (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))
472*4882a593Smuzhiyun 		xchk_btree_xref_set_corrupt(sc, sc->sa.fino_cur, 0);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun /* Cross reference the inode fields with the forks. */
476*4882a593Smuzhiyun STATIC void
xchk_inode_xref_bmap(struct xfs_scrub * sc,struct xfs_dinode * dip)477*4882a593Smuzhiyun xchk_inode_xref_bmap(
478*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
479*4882a593Smuzhiyun 	struct xfs_dinode	*dip)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun 	xfs_extnum_t		nextents;
482*4882a593Smuzhiyun 	xfs_filblks_t		count;
483*4882a593Smuzhiyun 	xfs_filblks_t		acount;
484*4882a593Smuzhiyun 	int			error;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (xchk_skip_xref(sc->sm))
487*4882a593Smuzhiyun 		return;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	/* Walk all the extents to check nextents/naextents/nblocks. */
490*4882a593Smuzhiyun 	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_DATA_FORK,
491*4882a593Smuzhiyun 			&nextents, &count);
492*4882a593Smuzhiyun 	if (!xchk_should_check_xref(sc, &error, NULL))
493*4882a593Smuzhiyun 		return;
494*4882a593Smuzhiyun 	if (nextents < be32_to_cpu(dip->di_nextents))
495*4882a593Smuzhiyun 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
498*4882a593Smuzhiyun 			&nextents, &acount);
499*4882a593Smuzhiyun 	if (!xchk_should_check_xref(sc, &error, NULL))
500*4882a593Smuzhiyun 		return;
501*4882a593Smuzhiyun 	if (nextents != be16_to_cpu(dip->di_anextents))
502*4882a593Smuzhiyun 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	/* Check nblocks against the inode. */
505*4882a593Smuzhiyun 	if (count + acount != be64_to_cpu(dip->di_nblocks))
506*4882a593Smuzhiyun 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun /* Cross-reference with the other btrees. */
510*4882a593Smuzhiyun STATIC void
xchk_inode_xref(struct xfs_scrub * sc,xfs_ino_t ino,struct xfs_dinode * dip)511*4882a593Smuzhiyun xchk_inode_xref(
512*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
513*4882a593Smuzhiyun 	xfs_ino_t		ino,
514*4882a593Smuzhiyun 	struct xfs_dinode	*dip)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun 	xfs_agnumber_t		agno;
517*4882a593Smuzhiyun 	xfs_agblock_t		agbno;
518*4882a593Smuzhiyun 	int			error;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
521*4882a593Smuzhiyun 		return;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	agno = XFS_INO_TO_AGNO(sc->mp, ino);
524*4882a593Smuzhiyun 	agbno = XFS_INO_TO_AGBNO(sc->mp, ino);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	error = xchk_ag_init(sc, agno, &sc->sa);
527*4882a593Smuzhiyun 	if (!xchk_xref_process_error(sc, agno, agbno, &error))
528*4882a593Smuzhiyun 		return;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	xchk_xref_is_used_space(sc, agbno, 1);
531*4882a593Smuzhiyun 	xchk_inode_xref_finobt(sc, ino);
532*4882a593Smuzhiyun 	xchk_xref_is_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_INODES);
533*4882a593Smuzhiyun 	xchk_xref_is_not_shared(sc, agbno, 1);
534*4882a593Smuzhiyun 	xchk_inode_xref_bmap(sc, dip);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	xchk_ag_free(sc, &sc->sa);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun /*
540*4882a593Smuzhiyun  * If the reflink iflag disagrees with a scan for shared data fork extents,
541*4882a593Smuzhiyun  * either flag an error (shared extents w/ no flag) or a preen (flag set w/o
542*4882a593Smuzhiyun  * any shared extents).  We already checked for reflink iflag set on a non
543*4882a593Smuzhiyun  * reflink filesystem.
544*4882a593Smuzhiyun  */
545*4882a593Smuzhiyun static void
xchk_inode_check_reflink_iflag(struct xfs_scrub * sc,xfs_ino_t ino)546*4882a593Smuzhiyun xchk_inode_check_reflink_iflag(
547*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
548*4882a593Smuzhiyun 	xfs_ino_t		ino)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun 	struct xfs_mount	*mp = sc->mp;
551*4882a593Smuzhiyun 	bool			has_shared;
552*4882a593Smuzhiyun 	int			error;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	if (!xfs_sb_version_hasreflink(&mp->m_sb))
555*4882a593Smuzhiyun 		return;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	error = xfs_reflink_inode_has_shared_extents(sc->tp, sc->ip,
558*4882a593Smuzhiyun 			&has_shared);
559*4882a593Smuzhiyun 	if (!xchk_xref_process_error(sc, XFS_INO_TO_AGNO(mp, ino),
560*4882a593Smuzhiyun 			XFS_INO_TO_AGBNO(mp, ino), &error))
561*4882a593Smuzhiyun 		return;
562*4882a593Smuzhiyun 	if (xfs_is_reflink_inode(sc->ip) && !has_shared)
563*4882a593Smuzhiyun 		xchk_ino_set_preen(sc, ino);
564*4882a593Smuzhiyun 	else if (!xfs_is_reflink_inode(sc->ip) && has_shared)
565*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, ino);
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun /* Scrub an inode. */
569*4882a593Smuzhiyun int
xchk_inode(struct xfs_scrub * sc)570*4882a593Smuzhiyun xchk_inode(
571*4882a593Smuzhiyun 	struct xfs_scrub	*sc)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	struct xfs_dinode	di;
574*4882a593Smuzhiyun 	int			error = 0;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	/*
577*4882a593Smuzhiyun 	 * If sc->ip is NULL, that means that the setup function called
578*4882a593Smuzhiyun 	 * xfs_iget to look up the inode.  xfs_iget returned a EFSCORRUPTED
579*4882a593Smuzhiyun 	 * and a NULL inode, so flag the corruption error and return.
580*4882a593Smuzhiyun 	 */
581*4882a593Smuzhiyun 	if (!sc->ip) {
582*4882a593Smuzhiyun 		xchk_ino_set_corrupt(sc, sc->sm->sm_ino);
583*4882a593Smuzhiyun 		return 0;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	/* Scrub the inode core. */
587*4882a593Smuzhiyun 	xfs_inode_to_disk(sc->ip, &di, 0);
588*4882a593Smuzhiyun 	xchk_dinode(sc, &di, sc->ip->i_ino);
589*4882a593Smuzhiyun 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
590*4882a593Smuzhiyun 		goto out;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	/*
593*4882a593Smuzhiyun 	 * Look for discrepancies between file's data blocks and the reflink
594*4882a593Smuzhiyun 	 * iflag.  We already checked the iflag against the file mode when
595*4882a593Smuzhiyun 	 * we scrubbed the dinode.
596*4882a593Smuzhiyun 	 */
597*4882a593Smuzhiyun 	if (S_ISREG(VFS_I(sc->ip)->i_mode))
598*4882a593Smuzhiyun 		xchk_inode_check_reflink_iflag(sc, sc->ip->i_ino);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	xchk_inode_xref(sc, sc->ip->i_ino, &di);
601*4882a593Smuzhiyun out:
602*4882a593Smuzhiyun 	return error;
603*4882a593Smuzhiyun }
604