blob: 76fbc7ca4cec46ea8327cc00c0352bda314aa2e1 [file] [log] [blame]
Dave Chinner0b61f8a2018-06-05 19:42:14 -07001// SPDX-License-Identifier: GPL-2.0+
Darrick J. Wong80e4e122017-10-17 21:37:42 -07002/*
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
Darrick J. Wong80e4e122017-10-17 21:37:42 -07004 * Author: Darrick J. Wong <darrick.wong@oracle.com>
Darrick J. Wong80e4e122017-10-17 21:37:42 -07005 */
6#include "xfs.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_trans_resv.h"
11#include "xfs_mount.h"
Darrick J. Wong80e4e122017-10-17 21:37:42 -070012#include "xfs_btree.h"
Darrick J. Wong80e4e122017-10-17 21:37:42 -070013#include "xfs_log_format.h"
Darrick J. Wong80e4e122017-10-17 21:37:42 -070014#include "xfs_inode.h"
Darrick J. Wong80e4e122017-10-17 21:37:42 -070015#include "xfs_ialloc.h"
16#include "xfs_da_format.h"
17#include "xfs_reflink.h"
Darrick J. Wongd8526572018-01-16 18:53:08 -080018#include "xfs_rmap.h"
Darrick J. Wong561f6482018-01-16 18:53:10 -080019#include "xfs_bmap_util.h"
Darrick J. Wong80e4e122017-10-17 21:37:42 -070020#include "scrub/scrub.h"
21#include "scrub/common.h"
Darrick J. Wong2e6f2752018-01-16 18:53:07 -080022#include "scrub/btree.h"
Darrick J. Wong80e4e122017-10-17 21:37:42 -070023
24/*
25 * Grab total control of the inode metadata. It doesn't matter here if
26 * the file data is still changing; exclusive access to the metadata is
27 * the goal.
28 */
29int
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070030xchk_setup_inode(
Darrick J. Wong026f57e2021-04-07 17:59:39 -070031 struct xfs_scrub *sc)
Darrick J. Wong80e4e122017-10-17 21:37:42 -070032{
Darrick J. Wong032d91f2018-07-19 12:29:12 -070033 int error;
Darrick J. Wong80e4e122017-10-17 21:37:42 -070034
35 /*
36 * Try to get the inode. If the verifiers fail, we try again
37 * in raw mode.
38 */
Darrick J. Wong026f57e2021-04-07 17:59:39 -070039 error = xchk_get_inode(sc);
Darrick J. Wong80e4e122017-10-17 21:37:42 -070040 switch (error) {
41 case 0:
42 break;
43 case -EFSCORRUPTED:
44 case -EFSBADCRC:
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070045 return xchk_trans_alloc(sc, 0);
Darrick J. Wong80e4e122017-10-17 21:37:42 -070046 default:
47 return error;
48 }
49
50 /* Got the inode, lock it and we're ready to go. */
51 sc->ilock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
52 xfs_ilock(sc->ip, sc->ilock_flags);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070053 error = xchk_trans_alloc(sc, 0);
Darrick J. Wong80e4e122017-10-17 21:37:42 -070054 if (error)
55 goto out;
56 sc->ilock_flags |= XFS_ILOCK_EXCL;
57 xfs_ilock(sc->ip, XFS_ILOCK_EXCL);
58
59out:
60 /* scrub teardown will unlock and release the inode for us */
61 return error;
62}
63
64/* Inode core */
65
Darrick J. Wong8bb82bc2018-03-23 10:06:55 -070066/* Validate di_extsize hint. */
Darrick J. Wong80e4e122017-10-17 21:37:42 -070067STATIC void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070068xchk_inode_extsize(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -070069 struct xfs_scrub *sc,
Darrick J. Wong032d91f2018-07-19 12:29:12 -070070 struct xfs_dinode *dip,
71 xfs_ino_t ino,
72 uint16_t mode,
73 uint16_t flags)
Darrick J. Wong80e4e122017-10-17 21:37:42 -070074{
Darrick J. Wong032d91f2018-07-19 12:29:12 -070075 xfs_failaddr_t fa;
Darrick J. Wongb102a462021-07-14 09:03:41 -070076 uint32_t value = be32_to_cpu(dip->di_extsize);
Darrick J. Wong80e4e122017-10-17 21:37:42 -070077
Darrick J. Wongb102a462021-07-14 09:03:41 -070078 fa = xfs_inode_validate_extsize(sc->mp, value, mode, flags);
Darrick J. Wong8bb82bc2018-03-23 10:06:55 -070079 if (fa)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -070080 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wongb102a462021-07-14 09:03:41 -070081
82 /*
83 * XFS allows a sysadmin to change the rt extent size when adding a rt
84 * section to a filesystem after formatting. If there are any
85 * directories with extszinherit and rtinherit set, the hint could
86 * become misaligned with the new rextsize. The verifier doesn't check
87 * this, because we allow rtinherit directories even without an rt
88 * device. Flag this as an administrative warning since we will clean
89 * this up eventually.
90 */
91 if ((flags & XFS_DIFLAG_RTINHERIT) &&
92 (flags & XFS_DIFLAG_EXTSZINHERIT) &&
93 value % sc->mp->m_sb.sb_rextsize > 0)
94 xchk_ino_set_warning(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -070095}
96
97/*
98 * Validate di_cowextsize hint.
99 *
100 * The rules are documented at xfs_ioctl_setattr_check_cowextsize().
101 * These functions must be kept in sync with each other.
102 */
103STATIC void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700104xchk_inode_cowextsize(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -0700105 struct xfs_scrub *sc,
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700106 struct xfs_dinode *dip,
107 xfs_ino_t ino,
108 uint16_t mode,
109 uint16_t flags,
110 uint64_t flags2)
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700111{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700112 xfs_failaddr_t fa;
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700113
Darrick J. Wong8bb82bc2018-03-23 10:06:55 -0700114 fa = xfs_inode_validate_cowextsize(sc->mp,
115 be32_to_cpu(dip->di_cowextsize), mode, flags,
116 flags2);
117 if (fa)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700118 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700119}
120
121/* Make sure the di_flags make sense for the inode. */
122STATIC void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700123xchk_inode_flags(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -0700124 struct xfs_scrub *sc,
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700125 struct xfs_dinode *dip,
126 xfs_ino_t ino,
127 uint16_t mode,
128 uint16_t flags)
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700129{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700130 struct xfs_mount *mp = sc->mp;
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700131
Eric Sandeenf369a132018-09-29 13:49:00 +1000132 /* di_flags are all taken, last bit cannot be used */
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700133 if (flags & ~XFS_DIFLAG_ANY)
134 goto bad;
135
136 /* rt flags require rt device */
Darrick J. Wongc1f6b1a2020-11-02 17:14:07 -0800137 if ((flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700138 goto bad;
139
140 /* new rt bitmap flag only valid for rbmino */
141 if ((flags & XFS_DIFLAG_NEWRTBM) && ino != mp->m_sb.sb_rbmino)
142 goto bad;
143
144 /* directory-only flags */
145 if ((flags & (XFS_DIFLAG_RTINHERIT |
146 XFS_DIFLAG_EXTSZINHERIT |
147 XFS_DIFLAG_PROJINHERIT |
148 XFS_DIFLAG_NOSYMLINKS)) &&
149 !S_ISDIR(mode))
150 goto bad;
151
152 /* file-only flags */
153 if ((flags & (XFS_DIFLAG_REALTIME | FS_XFLAG_EXTSIZE)) &&
154 !S_ISREG(mode))
155 goto bad;
156
157 /* filestreams and rt make no sense */
158 if ((flags & XFS_DIFLAG_FILESTREAM) && (flags & XFS_DIFLAG_REALTIME))
159 goto bad;
160
161 return;
162bad:
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700163 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700164}
165
166/* Make sure the di_flags2 make sense for the inode. */
167STATIC void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700168xchk_inode_flags2(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -0700169 struct xfs_scrub *sc,
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700170 struct xfs_dinode *dip,
171 xfs_ino_t ino,
172 uint16_t mode,
173 uint16_t flags,
174 uint64_t flags2)
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700175{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700176 struct xfs_mount *mp = sc->mp;
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700177
Eric Sandeenf369a132018-09-29 13:49:00 +1000178 /* Unknown di_flags2 could be from a future kernel */
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700179 if (flags2 & ~XFS_DIFLAG2_ANY)
Eric Sandeenf369a132018-09-29 13:49:00 +1000180 xchk_ino_set_warning(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700181
182 /* reflink flag requires reflink feature */
183 if ((flags2 & XFS_DIFLAG2_REFLINK) &&
184 !xfs_sb_version_hasreflink(&mp->m_sb))
185 goto bad;
186
187 /* cowextsize flag is checked w.r.t. mode separately */
188
189 /* file/dir-only flags */
190 if ((flags2 & XFS_DIFLAG2_DAX) && !(S_ISREG(mode) || S_ISDIR(mode)))
191 goto bad;
192
193 /* file-only flags */
194 if ((flags2 & XFS_DIFLAG2_REFLINK) && !S_ISREG(mode))
195 goto bad;
196
197 /* realtime and reflink make no sense, currently */
198 if ((flags & XFS_DIFLAG_REALTIME) && (flags2 & XFS_DIFLAG2_REFLINK))
199 goto bad;
200
Darrick J. Wongf93e54362020-08-17 09:59:07 -0700201 /* no bigtime iflag without the bigtime feature */
202 if (xfs_dinode_has_bigtime(dip) &&
203 !xfs_sb_version_hasbigtime(&mp->m_sb))
204 goto bad;
205
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700206 return;
207bad:
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700208 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700209}
210
Darrick J. Wong5a0bb062020-08-24 15:15:46 -0700211static inline void
212xchk_dinode_nsec(
213 struct xfs_scrub *sc,
214 xfs_ino_t ino,
Darrick J. Wongf93e54362020-08-17 09:59:07 -0700215 struct xfs_dinode *dip,
Darrick J. Wong5a0bb062020-08-24 15:15:46 -0700216 const xfs_timestamp_t ts)
217{
218 struct timespec64 tv;
219
Darrick J. Wongf93e54362020-08-17 09:59:07 -0700220 tv = xfs_inode_from_disk_ts(dip, ts);
Darrick J. Wong5a0bb062020-08-24 15:15:46 -0700221 if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
222 xchk_ino_set_corrupt(sc, ino);
223}
224
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700225/* Scrub all the ondisk inode fields. */
226STATIC void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700227xchk_dinode(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -0700228 struct xfs_scrub *sc,
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700229 struct xfs_dinode *dip,
230 xfs_ino_t ino)
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700231{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700232 struct xfs_mount *mp = sc->mp;
233 size_t fork_recs;
234 unsigned long long isize;
235 uint64_t flags2;
236 uint32_t nextents;
237 uint16_t flags;
238 uint16_t mode;
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700239
240 flags = be16_to_cpu(dip->di_flags);
241 if (dip->di_version >= 3)
242 flags2 = be64_to_cpu(dip->di_flags2);
243 else
244 flags2 = 0;
245
246 /* di_mode */
247 mode = be16_to_cpu(dip->di_mode);
Darrick J. Wong3b42d382017-11-27 21:40:19 -0800248 switch (mode & S_IFMT) {
249 case S_IFLNK:
250 case S_IFREG:
251 case S_IFDIR:
252 case S_IFCHR:
253 case S_IFBLK:
254 case S_IFIFO:
255 case S_IFSOCK:
256 /* mode is recognized */
257 break;
258 default:
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700259 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong3b42d382017-11-27 21:40:19 -0800260 break;
261 }
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700262
263 /* v1/v2 fields */
264 switch (dip->di_version) {
265 case 1:
266 /*
267 * We autoconvert v1 inodes into v2 inodes on writeout,
268 * so just mark this inode for preening.
269 */
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700270 xchk_ino_set_preen(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700271 break;
272 case 2:
273 case 3:
274 if (dip->di_onlink != 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700275 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700276
277 if (dip->di_mode == 0 && sc->ip)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700278 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700279
280 if (dip->di_projid_hi != 0 &&
281 !xfs_sb_version_hasprojid32bit(&mp->m_sb))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700282 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700283 break;
284 default:
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700285 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700286 return;
287 }
288
289 /*
290 * di_uid/di_gid -- -1 isn't invalid, but there's no way that
291 * userspace could have created that.
292 */
293 if (dip->di_uid == cpu_to_be32(-1U) ||
294 dip->di_gid == cpu_to_be32(-1U))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700295 xchk_ino_set_warning(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700296
297 /* di_format */
298 switch (dip->di_format) {
299 case XFS_DINODE_FMT_DEV:
300 if (!S_ISCHR(mode) && !S_ISBLK(mode) &&
301 !S_ISFIFO(mode) && !S_ISSOCK(mode))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700302 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700303 break;
304 case XFS_DINODE_FMT_LOCAL:
305 if (!S_ISDIR(mode) && !S_ISLNK(mode))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700306 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700307 break;
308 case XFS_DINODE_FMT_EXTENTS:
309 if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700310 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700311 break;
312 case XFS_DINODE_FMT_BTREE:
313 if (!S_ISREG(mode) && !S_ISDIR(mode))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700314 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700315 break;
316 case XFS_DINODE_FMT_UUID:
317 default:
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700318 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700319 break;
320 }
321
Darrick J. Wong29c1c122018-01-08 10:41:35 -0800322 /* di_[amc]time.nsec */
Darrick J. Wongf93e54362020-08-17 09:59:07 -0700323 xchk_dinode_nsec(sc, ino, dip, dip->di_atime);
324 xchk_dinode_nsec(sc, ino, dip, dip->di_mtime);
325 xchk_dinode_nsec(sc, ino, dip, dip->di_ctime);
Darrick J. Wong29c1c122018-01-08 10:41:35 -0800326
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700327 /*
328 * di_size. xfs_dinode_verify checks for things that screw up
329 * the VFS such as the upper bit being set and zero-length
330 * symlinks/directories, but we can do more here.
331 */
332 isize = be64_to_cpu(dip->di_size);
333 if (isize & (1ULL << 63))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700334 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700335
336 /* Devices, fifos, and sockets must have zero size */
337 if (!S_ISDIR(mode) && !S_ISREG(mode) && !S_ISLNK(mode) && isize != 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700338 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700339
340 /* Directories can't be larger than the data section size (32G) */
341 if (S_ISDIR(mode) && (isize == 0 || isize >= XFS_DIR2_SPACE_SIZE))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700342 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700343
344 /* Symlinks can't be larger than SYMLINK_MAXLEN */
345 if (S_ISLNK(mode) && (isize == 0 || isize >= XFS_SYMLINK_MAXLEN))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700346 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700347
348 /*
349 * Warn if the running kernel can't handle the kinds of offsets
350 * needed to deal with the file size. In other words, if the
351 * pagecache can't cache all the blocks in this file due to
352 * overly large offsets, flag the inode for admin review.
353 */
354 if (isize >= mp->m_super->s_maxbytes)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700355 xchk_ino_set_warning(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700356
357 /* di_nblocks */
358 if (flags2 & XFS_DIFLAG2_REFLINK) {
359 ; /* nblocks can exceed dblocks */
360 } else if (flags & XFS_DIFLAG_REALTIME) {
361 /*
362 * nblocks is the sum of data extents (in the rtdev),
363 * attr extents (in the datadev), and both forks' bmbt
364 * blocks (in the datadev). This clumsy check is the
365 * best we can do without cross-referencing with the
366 * inode forks.
367 */
368 if (be64_to_cpu(dip->di_nblocks) >=
369 mp->m_sb.sb_dblocks + mp->m_sb.sb_rblocks)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700370 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700371 } else {
372 if (be64_to_cpu(dip->di_nblocks) >= mp->m_sb.sb_dblocks)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700373 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700374 }
375
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700376 xchk_inode_flags(sc, dip, ino, mode, flags);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700377
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700378 xchk_inode_extsize(sc, dip, ino, mode, flags);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700379
380 /* di_nextents */
381 nextents = be32_to_cpu(dip->di_nextents);
382 fork_recs = XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
383 switch (dip->di_format) {
384 case XFS_DINODE_FMT_EXTENTS:
385 if (nextents > fork_recs)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700386 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700387 break;
388 case XFS_DINODE_FMT_BTREE:
389 if (nextents <= fork_recs)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700390 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700391 break;
392 default:
393 if (nextents != 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700394 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700395 break;
396 }
397
398 /* di_forkoff */
399 if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700400 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700401 if (dip->di_anextents != 0 && dip->di_forkoff == 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700402 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700403 if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700404 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700405
406 /* di_aformat */
407 if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
408 dip->di_aformat != XFS_DINODE_FMT_EXTENTS &&
409 dip->di_aformat != XFS_DINODE_FMT_BTREE)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700410 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700411
412 /* di_anextents */
413 nextents = be16_to_cpu(dip->di_anextents);
414 fork_recs = XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
415 switch (dip->di_aformat) {
416 case XFS_DINODE_FMT_EXTENTS:
417 if (nextents > fork_recs)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700418 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700419 break;
420 case XFS_DINODE_FMT_BTREE:
421 if (nextents <= fork_recs)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700422 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700423 break;
424 default:
425 if (nextents != 0)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700426 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700427 }
428
429 if (dip->di_version >= 3) {
Darrick J. Wongf93e54362020-08-17 09:59:07 -0700430 xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700431 xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
432 xchk_inode_cowextsize(sc, dip, ino, mode, flags,
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700433 flags2);
434 }
435}
436
Darrick J. Wong2e6f2752018-01-16 18:53:07 -0800437/*
438 * Make sure the finobt doesn't think this inode is free.
439 * We don't have to check the inobt ourselves because we got the inode via
440 * IGET_UNTRUSTED, which checks the inobt for us.
441 */
442static void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700443xchk_inode_xref_finobt(
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700444 struct xfs_scrub *sc,
Darrick J. Wong2e6f2752018-01-16 18:53:07 -0800445 xfs_ino_t ino)
446{
447 struct xfs_inobt_rec_incore rec;
448 xfs_agino_t agino;
449 int has_record;
450 int error;
451
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700452 if (!sc->sa.fino_cur || xchk_skip_xref(sc->sm))
Darrick J. Wong2e6f2752018-01-16 18:53:07 -0800453 return;
454
455 agino = XFS_INO_TO_AGINO(sc->mp, ino);
456
457 /*
458 * Try to get the finobt record. If we can't get it, then we're
459 * in good shape.
460 */
461 error = xfs_inobt_lookup(sc->sa.fino_cur, agino, XFS_LOOKUP_LE,
462 &has_record);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700463 if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
Darrick J. Wong2e6f2752018-01-16 18:53:07 -0800464 !has_record)
465 return;
466
467 error = xfs_inobt_get_rec(sc->sa.fino_cur, &rec, &has_record);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700468 if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
Darrick J. Wong2e6f2752018-01-16 18:53:07 -0800469 !has_record)
470 return;
471
472 /*
473 * Otherwise, make sure this record either doesn't cover this inode,
474 * or that it does but it's marked present.
475 */
476 if (rec.ir_startino > agino ||
477 rec.ir_startino + XFS_INODES_PER_CHUNK <= agino)
478 return;
479
480 if (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700481 xchk_btree_xref_set_corrupt(sc, sc->sa.fino_cur, 0);
Darrick J. Wong2e6f2752018-01-16 18:53:07 -0800482}
483
Darrick J. Wong561f6482018-01-16 18:53:10 -0800484/* Cross reference the inode fields with the forks. */
485STATIC void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700486xchk_inode_xref_bmap(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -0700487 struct xfs_scrub *sc,
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700488 struct xfs_dinode *dip)
Darrick J. Wong561f6482018-01-16 18:53:10 -0800489{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700490 xfs_extnum_t nextents;
491 xfs_filblks_t count;
492 xfs_filblks_t acount;
493 int error;
Darrick J. Wong561f6482018-01-16 18:53:10 -0800494
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700495 if (xchk_skip_xref(sc->sm))
Darrick J. Wong8389f3ff2018-05-14 06:34:31 -0700496 return;
497
Darrick J. Wong561f6482018-01-16 18:53:10 -0800498 /* Walk all the extents to check nextents/naextents/nblocks. */
499 error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_DATA_FORK,
500 &nextents, &count);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700501 if (!xchk_should_check_xref(sc, &error, NULL))
Darrick J. Wong561f6482018-01-16 18:53:10 -0800502 return;
503 if (nextents < be32_to_cpu(dip->di_nextents))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700504 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
Darrick J. Wong561f6482018-01-16 18:53:10 -0800505
506 error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
507 &nextents, &acount);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700508 if (!xchk_should_check_xref(sc, &error, NULL))
Darrick J. Wong561f6482018-01-16 18:53:10 -0800509 return;
510 if (nextents != be16_to_cpu(dip->di_anextents))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700511 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
Darrick J. Wong561f6482018-01-16 18:53:10 -0800512
513 /* Check nblocks against the inode. */
514 if (count + acount != be64_to_cpu(dip->di_nblocks))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700515 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
Darrick J. Wong561f6482018-01-16 18:53:10 -0800516}
517
Darrick J. Wong166d7642018-01-16 18:53:05 -0800518/* Cross-reference with the other btrees. */
519STATIC void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700520xchk_inode_xref(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -0700521 struct xfs_scrub *sc,
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700522 xfs_ino_t ino,
523 struct xfs_dinode *dip)
Darrick J. Wong166d7642018-01-16 18:53:05 -0800524{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700525 xfs_agnumber_t agno;
526 xfs_agblock_t agbno;
527 int error;
Darrick J. Wong52dc4b42018-01-16 18:53:06 -0800528
Darrick J. Wong166d7642018-01-16 18:53:05 -0800529 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
530 return;
Darrick J. Wong52dc4b42018-01-16 18:53:06 -0800531
532 agno = XFS_INO_TO_AGNO(sc->mp, ino);
533 agbno = XFS_INO_TO_AGBNO(sc->mp, ino);
534
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700535 error = xchk_ag_init(sc, agno, &sc->sa);
536 if (!xchk_xref_process_error(sc, agno, agbno, &error))
Darrick J. Wong52dc4b42018-01-16 18:53:06 -0800537 return;
538
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700539 xchk_xref_is_used_space(sc, agbno, 1);
540 xchk_inode_xref_finobt(sc, ino);
Darrick J. Wong7280fed2018-12-12 08:46:23 -0800541 xchk_xref_is_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_INODES);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700542 xchk_xref_is_not_shared(sc, agbno, 1);
543 xchk_inode_xref_bmap(sc, dip);
Darrick J. Wong52dc4b42018-01-16 18:53:06 -0800544
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700545 xchk_ag_free(sc, &sc->sa);
Darrick J. Wong166d7642018-01-16 18:53:05 -0800546}
547
Darrick J. Wongf6d5fc22018-01-16 18:53:09 -0800548/*
549 * If the reflink iflag disagrees with a scan for shared data fork extents,
550 * either flag an error (shared extents w/ no flag) or a preen (flag set w/o
551 * any shared extents). We already checked for reflink iflag set on a non
552 * reflink filesystem.
553 */
554static void
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700555xchk_inode_check_reflink_iflag(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -0700556 struct xfs_scrub *sc,
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700557 xfs_ino_t ino)
Darrick J. Wongf6d5fc22018-01-16 18:53:09 -0800558{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700559 struct xfs_mount *mp = sc->mp;
560 bool has_shared;
561 int error;
Darrick J. Wongf6d5fc22018-01-16 18:53:09 -0800562
563 if (!xfs_sb_version_hasreflink(&mp->m_sb))
564 return;
565
566 error = xfs_reflink_inode_has_shared_extents(sc->tp, sc->ip,
567 &has_shared);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700568 if (!xchk_xref_process_error(sc, XFS_INO_TO_AGNO(mp, ino),
Darrick J. Wongf6d5fc22018-01-16 18:53:09 -0800569 XFS_INO_TO_AGBNO(mp, ino), &error))
570 return;
571 if (xfs_is_reflink_inode(sc->ip) && !has_shared)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700572 xchk_ino_set_preen(sc, ino);
Darrick J. Wongf6d5fc22018-01-16 18:53:09 -0800573 else if (!xfs_is_reflink_inode(sc->ip) && has_shared)
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700574 xchk_ino_set_corrupt(sc, ino);
Darrick J. Wongf6d5fc22018-01-16 18:53:09 -0800575}
576
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700577/* Scrub an inode. */
578int
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700579xchk_inode(
Darrick J. Wong1d8a7482018-07-19 12:29:12 -0700580 struct xfs_scrub *sc)
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700581{
Darrick J. Wong032d91f2018-07-19 12:29:12 -0700582 struct xfs_dinode di;
583 int error = 0;
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700584
Darrick J. Wongd0018ad2018-03-23 10:06:54 -0700585 /*
586 * If sc->ip is NULL, that means that the setup function called
587 * xfs_iget to look up the inode. xfs_iget returned a EFSCORRUPTED
588 * and a NULL inode, so flag the corruption error and return.
589 */
590 if (!sc->ip) {
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700591 xchk_ino_set_corrupt(sc, sc->sm->sm_ino);
Darrick J. Wongd0018ad2018-03-23 10:06:54 -0700592 return 0;
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700593 }
594
Darrick J. Wongd0018ad2018-03-23 10:06:54 -0700595 /* Scrub the inode core. */
596 xfs_inode_to_disk(sc->ip, &di, 0);
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700597 xchk_dinode(sc, &di, sc->ip->i_ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700598 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
599 goto out;
600
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700601 /*
Darrick J. Wongf6d5fc22018-01-16 18:53:09 -0800602 * Look for discrepancies between file's data blocks and the reflink
603 * iflag. We already checked the iflag against the file mode when
604 * we scrubbed the dinode.
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700605 */
Darrick J. Wongf6d5fc22018-01-16 18:53:09 -0800606 if (S_ISREG(VFS_I(sc->ip)->i_mode))
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700607 xchk_inode_check_reflink_iflag(sc, sc->ip->i_ino);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700608
Darrick J. Wongc517b3a2018-07-19 12:29:11 -0700609 xchk_inode_xref(sc, sc->ip->i_ino, &di);
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700610out:
Darrick J. Wong80e4e122017-10-17 21:37:42 -0700611 return error;
612}