Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2017-2023 Oracle. All Rights Reserved.
4 : * Author: Darrick J. Wong <djwong@kernel.org>
5 : */
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"
12 : #include "xfs_btree.h"
13 : #include "xfs_log_format.h"
14 : #include "xfs_trans.h"
15 : #include "xfs_ag.h"
16 : #include "xfs_inode.h"
17 : #include "xfs_ialloc.h"
18 : #include "xfs_icache.h"
19 : #include "xfs_da_format.h"
20 : #include "xfs_reflink.h"
21 : #include "xfs_rmap.h"
22 : #include "xfs_bmap_util.h"
23 : #include "scrub/scrub.h"
24 : #include "scrub/common.h"
25 : #include "scrub/btree.h"
26 : #include "scrub/trace.h"
27 :
28 : /* Prepare the attached inode for scrubbing. */
29 : static inline int
30 323988374 : xchk_prepare_iscrub(
31 : struct xfs_scrub *sc)
32 : {
33 323988374 : int error;
34 :
35 323988374 : sc->ilock_flags = XFS_IOLOCK_EXCL;
36 323988374 : xfs_ilock(sc->ip, sc->ilock_flags);
37 :
38 324002608 : error = xchk_trans_alloc(sc, 0);
39 324000679 : if (error)
40 : return error;
41 :
42 324002235 : sc->ilock_flags |= XFS_ILOCK_EXCL;
43 324002235 : xfs_ilock(sc->ip, XFS_ILOCK_EXCL);
44 324002235 : return 0;
45 : }
46 :
47 : /* Install this scrub-by-handle inode and prepare it for scrubbing. */
48 : static inline int
49 248633792 : xchk_install_handle_iscrub(
50 : struct xfs_scrub *sc,
51 : struct xfs_inode *ip)
52 : {
53 248633792 : int error;
54 :
55 248633792 : error = xchk_install_handle_inode(sc, ip);
56 248647664 : if (error)
57 : return error;
58 :
59 248537596 : return xchk_prepare_iscrub(sc);
60 : }
61 :
62 : /*
63 : * Grab total control of the inode metadata. In the best case, we grab the
64 : * incore inode and take all locks on it. If the incore inode cannot be
65 : * constructed due to corruption problems, lock the AGI so that we can single
66 : * step the loading process to fix everything that can go wrong.
67 : */
68 : int
69 325478462 : xchk_setup_inode(
70 : struct xfs_scrub *sc)
71 : {
72 325478462 : struct xfs_imap imap;
73 325478462 : struct xfs_inode *ip;
74 325478462 : struct xfs_mount *mp = sc->mp;
75 325478462 : struct xfs_inode *ip_in = XFS_I(file_inode(sc->file));
76 325478462 : struct xfs_buf *agi_bp;
77 325478462 : struct xfs_perag *pag;
78 325478462 : xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, sc->sm->sm_ino);
79 325478462 : int error;
80 :
81 325478462 : if (xchk_need_intent_drain(sc))
82 0 : xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
83 :
84 : /* We want to scan the opened inode, so lock it and exit. */
85 325478462 : if (sc->sm->sm_ino == 0 || sc->sm->sm_ino == ip_in->i_ino) {
86 75472929 : sc->ip = ip_in;
87 75472929 : return xchk_prepare_iscrub(sc);
88 : }
89 :
90 : /* Reject internal metadata files and obviously bad inode numbers. */
91 250005533 : if (xfs_internal_inum(mp, sc->sm->sm_ino))
92 : return -ENOENT;
93 249467353 : if (!xfs_verify_ino(sc->mp, sc->sm->sm_ino))
94 : return -ENOENT;
95 :
96 : /* Try a regular untrusted iget. */
97 249463018 : error = xchk_iget(sc, sc->sm->sm_ino, &ip);
98 249449521 : if (!error)
99 248627314 : return xchk_install_handle_iscrub(sc, ip);
100 822207 : if (error == -ENOENT)
101 : return error;
102 849 : if (error != -EFSCORRUPTED && error != -EFSBADCRC && error != -EINVAL)
103 0 : goto out_error;
104 :
105 : /*
106 : * EINVAL with IGET_UNTRUSTED probably means one of several things:
107 : * userspace gave us an inode number that doesn't correspond to fs
108 : * space; the inode btree lacks a record for this inode; or there is
109 : * a record, and it says this inode is free.
110 : *
111 : * EFSCORRUPTED/EFSBADCRC could mean that the inode was mappable, but
112 : * some other metadata corruption (e.g. inode forks) prevented
113 : * instantiation of the incore inode. Or it could mean the inobt is
114 : * corrupt.
115 : *
116 : * We want to look up this inode in the inobt directly to distinguish
117 : * three different scenarios: (1) the inobt says the inode is free,
118 : * in which case there's nothing to do; (2) the inobt is corrupt so we
119 : * should flag the corruption and exit to userspace to let it fix the
120 : * inobt; and (3) the inobt says the inode is allocated, but loading it
121 : * failed due to corruption.
122 : *
123 : * Allocate a transaction and grab the AGI to prevent inobt activity in
124 : * this AG. Retry the iget in case someone allocated a new inode after
125 : * the first iget failed.
126 : */
127 849 : error = xchk_trans_alloc(sc, 0);
128 849 : if (error)
129 0 : goto out_error;
130 :
131 849 : error = xchk_iget_agi(sc, sc->sm->sm_ino, &agi_bp, &ip);
132 849 : if (error == 0) {
133 : /* Actually got the incore inode, so install it and proceed. */
134 0 : xchk_trans_cancel(sc);
135 0 : return xchk_install_handle_iscrub(sc, ip);
136 : }
137 849 : if (error == -ENOENT)
138 0 : goto out_gone;
139 849 : if (error != -EFSCORRUPTED && error != -EFSBADCRC && error != -EINVAL)
140 0 : goto out_cancel;
141 :
142 : /* Ensure that we have protected against inode allocation/freeing. */
143 849 : if (agi_bp == NULL) {
144 0 : ASSERT(agi_bp != NULL);
145 0 : error = -ECANCELED;
146 0 : goto out_cancel;
147 : }
148 :
149 : /*
150 : * Untrusted iget failed a second time. Let's try an inobt lookup.
151 : * If the inobt doesn't think this is an allocated inode then we'll
152 : * return ENOENT to signal that the check can be skipped.
153 : *
154 : * If the lookup signals corruption, we'll mark this inode corrupt and
155 : * exit to userspace. There's little chance of fixing anything until
156 : * the inobt is straightened out, but there's nothing we can do here.
157 : *
158 : * If the lookup encounters a runtime error, exit to userspace.
159 : */
160 849 : pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, sc->sm->sm_ino));
161 849 : if (!pag) {
162 0 : error = -EFSCORRUPTED;
163 0 : goto out_cancel;
164 : }
165 :
166 849 : error = xfs_imap(pag, sc->tp, sc->sm->sm_ino, &imap,
167 : XFS_IGET_UNTRUSTED);
168 849 : xfs_perag_put(pag);
169 849 : if (error == -EINVAL || error == -ENOENT)
170 849 : goto out_gone;
171 0 : if (error)
172 0 : goto out_cancel;
173 :
174 : /*
175 : * The lookup succeeded. Chances are the ondisk inode is corrupt and
176 : * preventing iget from reading it. Retain the scrub transaction and
177 : * the AGI buffer to prevent anyone from allocating or freeing inodes.
178 : * This ensures that we preserve the inconsistency between the inobt
179 : * saying the inode is allocated and the icache being unable to load
180 : * the inode until we can flag the corruption in xchk_inode. The
181 : * scrub function has to note the corruption, since we're not really
182 : * supposed to do that from the setup function.
183 : */
184 : return 0;
185 :
186 0 : out_cancel:
187 0 : xchk_trans_cancel(sc);
188 0 : out_error:
189 0 : trace_xchk_op_error(sc, agno, XFS_INO_TO_AGBNO(mp, sc->sm->sm_ino),
190 : error, __return_address);
191 0 : return error;
192 849 : out_gone:
193 : /* The file is gone, so there's nothing to check. */
194 849 : xchk_trans_cancel(sc);
195 849 : return -ENOENT;
196 : }
197 :
198 : /* Inode core */
199 :
200 : /* Validate di_extsize hint. */
201 : STATIC void
202 324973973 : xchk_inode_extsize(
203 : struct xfs_scrub *sc,
204 : struct xfs_dinode *dip,
205 : xfs_ino_t ino,
206 : uint16_t mode,
207 : uint16_t flags)
208 : {
209 324973973 : xfs_failaddr_t fa;
210 324973973 : uint32_t value = be32_to_cpu(dip->di_extsize);
211 :
212 324973973 : fa = xfs_inode_validate_extsize(sc->mp, value, mode, flags);
213 324983316 : if (fa)
214 0 : xchk_ino_set_corrupt(sc, ino);
215 :
216 : /*
217 : * XFS allows a sysadmin to change the rt extent size when adding a rt
218 : * section to a filesystem after formatting. If there are any
219 : * directories with extszinherit and rtinherit set, the hint could
220 : * become misaligned with the new rextsize. The verifier doesn't check
221 : * this, because we allow rtinherit directories even without an rt
222 : * device. Flag this as an administrative warning since we will clean
223 : * this up eventually.
224 : */
225 324983316 : if ((flags & XFS_DIFLAG_RTINHERIT) &&
226 0 : (flags & XFS_DIFLAG_EXTSZINHERIT) &&
227 0 : value % sc->mp->m_sb.sb_rextsize > 0)
228 0 : xchk_ino_set_warning(sc, ino);
229 324983316 : }
230 :
231 : /*
232 : * Validate di_cowextsize hint.
233 : *
234 : * The rules are documented at xfs_ioctl_setattr_check_cowextsize().
235 : * These functions must be kept in sync with each other.
236 : */
237 : STATIC void
238 324972070 : xchk_inode_cowextsize(
239 : struct xfs_scrub *sc,
240 : struct xfs_dinode *dip,
241 : xfs_ino_t ino,
242 : uint16_t mode,
243 : uint16_t flags,
244 : uint64_t flags2)
245 : {
246 324972070 : xfs_failaddr_t fa;
247 :
248 324972070 : fa = xfs_inode_validate_cowextsize(sc->mp,
249 324972070 : be32_to_cpu(dip->di_cowextsize), mode, flags,
250 : flags2);
251 324968454 : if (fa)
252 0 : xchk_ino_set_corrupt(sc, ino);
253 324968454 : }
254 :
255 : /* Make sure the di_flags make sense for the inode. */
256 : STATIC void
257 324982446 : xchk_inode_flags(
258 : struct xfs_scrub *sc,
259 : struct xfs_dinode *dip,
260 : xfs_ino_t ino,
261 : uint16_t mode,
262 : uint16_t flags)
263 : {
264 324982446 : struct xfs_mount *mp = sc->mp;
265 :
266 : /* di_flags are all taken, last bit cannot be used */
267 324982446 : if (flags & ~XFS_DIFLAG_ANY)
268 0 : goto bad;
269 :
270 : /* rt flags require rt device */
271 324982446 : if ((flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)
272 0 : goto bad;
273 :
274 : /* new rt bitmap flag only valid for rbmino */
275 324982446 : if ((flags & XFS_DIFLAG_NEWRTBM) && ino != mp->m_sb.sb_rbmino)
276 0 : goto bad;
277 :
278 : /* directory-only flags */
279 324982446 : if ((flags & (XFS_DIFLAG_RTINHERIT |
280 : XFS_DIFLAG_EXTSZINHERIT |
281 : XFS_DIFLAG_PROJINHERIT |
282 42523445 : XFS_DIFLAG_NOSYMLINKS)) &&
283 : !S_ISDIR(mode))
284 0 : goto bad;
285 :
286 : /* file-only flags */
287 324982446 : if ((flags & (XFS_DIFLAG_REALTIME | FS_XFLAG_EXTSIZE)) &&
288 : !S_ISREG(mode))
289 0 : goto bad;
290 :
291 : /* filestreams and rt make no sense */
292 324982446 : if ((flags & XFS_DIFLAG_FILESTREAM) && (flags & XFS_DIFLAG_REALTIME))
293 0 : goto bad;
294 :
295 : return;
296 0 : bad:
297 0 : xchk_ino_set_corrupt(sc, ino);
298 : }
299 :
300 : /* Make sure the di_flags2 make sense for the inode. */
301 : STATIC void
302 324980317 : xchk_inode_flags2(
303 : struct xfs_scrub *sc,
304 : struct xfs_dinode *dip,
305 : xfs_ino_t ino,
306 : uint16_t mode,
307 : uint16_t flags,
308 : uint64_t flags2)
309 : {
310 324980317 : struct xfs_mount *mp = sc->mp;
311 :
312 : /* Unknown di_flags2 could be from a future kernel */
313 324980317 : if (flags2 & ~XFS_DIFLAG2_ANY)
314 0 : xchk_ino_set_warning(sc, ino);
315 :
316 : /* reflink flag requires reflink feature */
317 324980317 : if ((flags2 & XFS_DIFLAG2_REFLINK) &&
318 : !xfs_has_reflink(mp))
319 0 : goto bad;
320 :
321 : /* cowextsize flag is checked w.r.t. mode separately */
322 :
323 : /* file/dir-only flags */
324 324980317 : if ((flags2 & XFS_DIFLAG2_DAX) && !(S_ISREG(mode) || S_ISDIR(mode)))
325 0 : goto bad;
326 :
327 : /* file-only flags */
328 324980317 : if ((flags2 & XFS_DIFLAG2_REFLINK) && !S_ISREG(mode))
329 0 : goto bad;
330 :
331 : /* realtime and reflink make no sense, currently */
332 324980317 : if ((flags & XFS_DIFLAG_REALTIME) && (flags2 & XFS_DIFLAG2_REFLINK))
333 0 : goto bad;
334 :
335 : /* no bigtime iflag without the bigtime feature */
336 649960634 : if (xfs_dinode_has_bigtime(dip) && !xfs_has_bigtime(mp))
337 0 : goto bad;
338 :
339 : return;
340 0 : bad:
341 0 : xchk_ino_set_corrupt(sc, ino);
342 : }
343 :
344 : static inline void
345 1299816145 : xchk_dinode_nsec(
346 : struct xfs_scrub *sc,
347 : xfs_ino_t ino,
348 : struct xfs_dinode *dip,
349 : const xfs_timestamp_t ts)
350 : {
351 1299816145 : struct timespec64 tv;
352 :
353 1299816145 : tv = xfs_inode_from_disk_ts(dip, ts);
354 1299822472 : if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
355 0 : xchk_ino_set_corrupt(sc, ino);
356 1299822472 : }
357 :
358 : /* Scrub all the ondisk inode fields. */
359 : STATIC void
360 324984454 : xchk_dinode(
361 : struct xfs_scrub *sc,
362 : struct xfs_dinode *dip,
363 : xfs_ino_t ino)
364 : {
365 324984454 : struct xfs_mount *mp = sc->mp;
366 324984454 : size_t fork_recs;
367 324984454 : unsigned long long isize;
368 324984454 : uint64_t flags2;
369 324984454 : xfs_extnum_t nextents;
370 324984454 : xfs_extnum_t naextents;
371 324984454 : prid_t prid;
372 324984454 : uint16_t flags;
373 324984454 : uint16_t mode;
374 :
375 324984454 : flags = be16_to_cpu(dip->di_flags);
376 324984454 : if (dip->di_version >= 3)
377 324978331 : flags2 = be64_to_cpu(dip->di_flags2);
378 : else
379 : flags2 = 0;
380 :
381 : /* di_mode */
382 324984454 : mode = be16_to_cpu(dip->di_mode);
383 324984454 : switch (mode & S_IFMT) {
384 : case S_IFLNK:
385 : case S_IFREG:
386 : case S_IFDIR:
387 : case S_IFCHR:
388 : case S_IFBLK:
389 : case S_IFIFO:
390 : case S_IFSOCK:
391 : /* mode is recognized */
392 : break;
393 0 : default:
394 0 : xchk_ino_set_corrupt(sc, ino);
395 0 : break;
396 : }
397 :
398 : /* v1/v2 fields */
399 324984454 : switch (dip->di_version) {
400 0 : case 1:
401 : /*
402 : * We autoconvert v1 inodes into v2 inodes on writeout,
403 : * so just mark this inode for preening.
404 : */
405 0 : xchk_ino_set_preen(sc, ino);
406 0 : prid = 0;
407 0 : break;
408 324984454 : case 2:
409 : case 3:
410 324984454 : if (dip->di_onlink != 0)
411 0 : xchk_ino_set_corrupt(sc, ino);
412 :
413 324984454 : if (dip->di_mode == 0 && sc->ip)
414 0 : xchk_ino_set_corrupt(sc, ino);
415 :
416 324984454 : if (dip->di_projid_hi != 0 &&
417 : !xfs_has_projid32(mp))
418 0 : xchk_ino_set_corrupt(sc, ino);
419 :
420 324984454 : prid = be16_to_cpu(dip->di_projid_lo);
421 : break;
422 0 : default:
423 0 : xchk_ino_set_corrupt(sc, ino);
424 0 : return;
425 : }
426 :
427 324984454 : if (xfs_has_projid32(mp))
428 324985413 : prid |= (prid_t)be16_to_cpu(dip->di_projid_hi) << 16;
429 :
430 : /*
431 : * di_uid/di_gid -- -1 isn't invalid, but there's no way that
432 : * userspace could have created that.
433 : */
434 324984454 : if (dip->di_uid == cpu_to_be32(-1U) ||
435 324984454 : dip->di_gid == cpu_to_be32(-1U))
436 0 : xchk_ino_set_warning(sc, ino);
437 :
438 : /*
439 : * project id of -1 isn't supposed to be valid, but the kernel didn't
440 : * always validate that.
441 : */
442 324985708 : if (prid == -1U)
443 0 : xchk_ino_set_warning(sc, ino);
444 :
445 : /* di_format */
446 324985708 : switch (dip->di_format) {
447 110383938 : case XFS_DINODE_FMT_DEV:
448 110383938 : if (!S_ISCHR(mode) && !S_ISBLK(mode) &&
449 0 : !S_ISFIFO(mode) && !S_ISSOCK(mode))
450 0 : xchk_ino_set_corrupt(sc, ino);
451 : break;
452 92712777 : case XFS_DINODE_FMT_LOCAL:
453 92712777 : if (!S_ISDIR(mode) && !S_ISLNK(mode))
454 0 : xchk_ino_set_corrupt(sc, ino);
455 : break;
456 119453096 : case XFS_DINODE_FMT_EXTENTS:
457 119453096 : if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
458 0 : xchk_ino_set_corrupt(sc, ino);
459 : break;
460 2435897 : case XFS_DINODE_FMT_BTREE:
461 2435897 : if (!S_ISREG(mode) && !S_ISDIR(mode))
462 0 : xchk_ino_set_corrupt(sc, ino);
463 : break;
464 0 : case XFS_DINODE_FMT_UUID:
465 : default:
466 0 : xchk_ino_set_corrupt(sc, ino);
467 0 : break;
468 : }
469 :
470 : /* di_[amc]time.nsec */
471 324985708 : xchk_dinode_nsec(sc, ino, dip, dip->di_atime);
472 324985760 : xchk_dinode_nsec(sc, ino, dip, dip->di_mtime);
473 324989410 : xchk_dinode_nsec(sc, ino, dip, dip->di_ctime);
474 :
475 : /*
476 : * di_size. xfs_dinode_verify checks for things that screw up
477 : * the VFS such as the upper bit being set and zero-length
478 : * symlinks/directories, but we can do more here.
479 : */
480 324989552 : isize = be64_to_cpu(dip->di_size);
481 324989552 : if (isize & (1ULL << 63))
482 0 : xchk_ino_set_corrupt(sc, ino);
483 :
484 : /* Devices, fifos, and sockets must have zero size */
485 324989552 : if (!S_ISDIR(mode) && !S_ISREG(mode) && !S_ISLNK(mode) && isize != 0)
486 0 : xchk_ino_set_corrupt(sc, ino);
487 :
488 : /* Directories can't be larger than the data section size (32G) */
489 324989552 : if (S_ISDIR(mode) && (isize == 0 || isize >= XFS_DIR2_SPACE_SIZE))
490 0 : xchk_ino_set_corrupt(sc, ino);
491 :
492 : /* Symlinks can't be larger than SYMLINK_MAXLEN */
493 324989552 : if (S_ISLNK(mode) && (isize == 0 || isize >= XFS_SYMLINK_MAXLEN))
494 0 : xchk_ino_set_corrupt(sc, ino);
495 :
496 : /*
497 : * Warn if the running kernel can't handle the kinds of offsets
498 : * needed to deal with the file size. In other words, if the
499 : * pagecache can't cache all the blocks in this file due to
500 : * overly large offsets, flag the inode for admin review.
501 : */
502 324989552 : if (isize > mp->m_super->s_maxbytes)
503 0 : xchk_ino_set_warning(sc, ino);
504 :
505 : /* di_nblocks */
506 324989552 : if (flags2 & XFS_DIFLAG2_REFLINK) {
507 : ; /* nblocks can exceed dblocks */
508 319276969 : } else if (flags & XFS_DIFLAG_REALTIME) {
509 : /*
510 : * nblocks is the sum of data extents (in the rtdev),
511 : * attr extents (in the datadev), and both forks' bmbt
512 : * blocks (in the datadev). This clumsy check is the
513 : * best we can do without cross-referencing with the
514 : * inode forks.
515 : */
516 53326839 : if (be64_to_cpu(dip->di_nblocks) >=
517 53326839 : mp->m_sb.sb_dblocks + mp->m_sb.sb_rblocks)
518 0 : xchk_ino_set_corrupt(sc, ino);
519 : } else {
520 265950130 : if (be64_to_cpu(dip->di_nblocks) >= mp->m_sb.sb_dblocks)
521 0 : xchk_ino_set_corrupt(sc, ino);
522 : }
523 :
524 324989552 : xchk_inode_flags(sc, dip, ino, mode, flags);
525 :
526 324985226 : xchk_inode_extsize(sc, dip, ino, mode, flags);
527 :
528 324990874 : nextents = xfs_dfork_data_extents(dip);
529 324990874 : naextents = xfs_dfork_attr_extents(dip);
530 :
531 : /* di_nextents */
532 324990888 : fork_recs = XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
533 324990874 : switch (dip->di_format) {
534 119456590 : case XFS_DINODE_FMT_EXTENTS:
535 119456590 : if (nextents > fork_recs)
536 0 : xchk_ino_set_corrupt(sc, ino);
537 : break;
538 2435895 : case XFS_DINODE_FMT_BTREE:
539 2435895 : if (nextents <= fork_recs)
540 0 : xchk_ino_set_corrupt(sc, ino);
541 : break;
542 203098389 : default:
543 203098389 : if (nextents != 0)
544 0 : xchk_ino_set_corrupt(sc, ino);
545 : break;
546 : }
547 :
548 : /* di_forkoff */
549 649957768 : if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
550 0 : xchk_ino_set_corrupt(sc, ino);
551 324990874 : if (naextents != 0 && dip->di_forkoff == 0)
552 0 : xchk_ino_set_corrupt(sc, ino);
553 324990874 : if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
554 0 : xchk_ino_set_corrupt(sc, ino);
555 :
556 : /* di_aformat */
557 324990874 : if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
558 324990874 : dip->di_aformat != XFS_DINODE_FMT_EXTENTS &&
559 : dip->di_aformat != XFS_DINODE_FMT_BTREE)
560 0 : xchk_ino_set_corrupt(sc, ino);
561 :
562 : /* di_anextents */
563 324979817 : fork_recs = XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
564 324979815 : switch (dip->di_aformat) {
565 312534622 : case XFS_DINODE_FMT_EXTENTS:
566 312534622 : if (naextents > fork_recs)
567 0 : xchk_ino_set_corrupt(sc, ino);
568 : break;
569 12 : case XFS_DINODE_FMT_BTREE:
570 12 : if (naextents <= fork_recs)
571 0 : xchk_ino_set_corrupt(sc, ino);
572 : break;
573 12445181 : default:
574 12445181 : if (naextents != 0)
575 0 : xchk_ino_set_corrupt(sc, ino);
576 : }
577 :
578 324979815 : if (dip->di_version >= 3) {
579 324985621 : xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
580 324985579 : xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
581 324985296 : xchk_inode_cowextsize(sc, dip, ino, mode, flags,
582 : flags2);
583 : }
584 : }
585 :
586 : /*
587 : * Make sure the finobt doesn't think this inode is free.
588 : * We don't have to check the inobt ourselves because we got the inode via
589 : * IGET_UNTRUSTED, which checks the inobt for us.
590 : */
591 : static void
592 324987452 : xchk_inode_xref_finobt(
593 : struct xfs_scrub *sc,
594 : xfs_ino_t ino)
595 : {
596 324987452 : struct xfs_inobt_rec_incore rec;
597 324987452 : xfs_agino_t agino;
598 324987452 : int has_record;
599 324987452 : int error;
600 :
601 324987452 : if (!sc->sa.fino_cur || xchk_skip_xref(sc->sm))
602 313290564 : return;
603 :
604 324987436 : agino = XFS_INO_TO_AGINO(sc->mp, ino);
605 :
606 : /*
607 : * Try to get the finobt record. If we can't get it, then we're
608 : * in good shape.
609 : */
610 324987436 : error = xfs_inobt_lookup(sc->sa.fino_cur, agino, XFS_LOOKUP_LE,
611 : &has_record);
612 324989675 : if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
613 324991813 : !has_record)
614 : return;
615 :
616 48699281 : error = xfs_inobt_get_rec(sc->sa.fino_cur, &rec, &has_record);
617 48699267 : if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
618 48699273 : !has_record)
619 : return;
620 :
621 : /*
622 : * Otherwise, make sure this record either doesn't cover this inode,
623 : * or that it does but it's marked present.
624 : */
625 48699273 : if (rec.ir_startino > agino ||
626 48699273 : rec.ir_startino + XFS_INODES_PER_CHUNK <= agino)
627 : return;
628 :
629 11701257 : if (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))
630 0 : xchk_btree_xref_set_corrupt(sc, sc->sa.fino_cur, 0);
631 : }
632 :
633 : /* Cross reference the inode fields with the forks. */
634 : STATIC void
635 324982829 : xchk_inode_xref_bmap(
636 : struct xfs_scrub *sc,
637 : struct xfs_dinode *dip)
638 : {
639 324982829 : xfs_extnum_t nextents;
640 324982829 : xfs_filblks_t count;
641 324982829 : xfs_filblks_t acount;
642 324982829 : int error;
643 :
644 324982829 : if (xchk_skip_xref(sc->sm))
645 0 : return;
646 :
647 : /* Walk all the extents to check nextents/naextents/nblocks. */
648 324982829 : error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_DATA_FORK,
649 : &nextents, &count);
650 324991540 : if (!xchk_should_check_xref(sc, &error, NULL))
651 : return;
652 324990721 : if (nextents < xfs_dfork_data_extents(dip))
653 0 : xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
654 :
655 324990721 : error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
656 : &nextents, &acount);
657 324991536 : if (!xchk_should_check_xref(sc, &error, NULL))
658 : return;
659 324991210 : if (nextents != xfs_dfork_attr_extents(dip))
660 0 : xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
661 :
662 : /* Check nblocks against the inode. */
663 324991210 : if (count + acount != be64_to_cpu(dip->di_nblocks))
664 0 : xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
665 : }
666 :
667 : /* Cross-reference with the other btrees. */
668 : STATIC void
669 324977142 : xchk_inode_xref(
670 : struct xfs_scrub *sc,
671 : xfs_ino_t ino,
672 : struct xfs_dinode *dip)
673 : {
674 324977142 : xfs_agnumber_t agno;
675 324977142 : xfs_agblock_t agbno;
676 324977142 : int error;
677 :
678 324977142 : if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
679 0 : return;
680 :
681 324977142 : agno = XFS_INO_TO_AGNO(sc->mp, ino);
682 324977142 : agbno = XFS_INO_TO_AGBNO(sc->mp, ino);
683 :
684 324977142 : error = xchk_ag_init_existing(sc, agno, &sc->sa);
685 324990505 : if (!xchk_xref_process_error(sc, agno, agbno, &error))
686 2 : goto out_free;
687 :
688 324988125 : xchk_xref_is_used_space(sc, agbno, 1);
689 324991994 : xchk_inode_xref_finobt(sc, ino);
690 324990253 : xchk_xref_is_only_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_INODES);
691 324991972 : xchk_xref_is_not_shared(sc, agbno, 1);
692 324990823 : xchk_xref_is_not_cow_staging(sc, agbno, 1);
693 324992188 : xchk_inode_xref_bmap(sc, dip);
694 :
695 324990319 : out_free:
696 324990319 : xchk_ag_free(sc, &sc->sa);
697 : }
698 :
699 : /*
700 : * If the reflink iflag disagrees with a scan for shared data fork extents,
701 : * either flag an error (shared extents w/ no flag) or a preen (flag set w/o
702 : * any shared extents). We already checked for reflink iflag set on a non
703 : * reflink filesystem.
704 : */
705 : static void
706 95952233 : xchk_inode_check_reflink_iflag(
707 : struct xfs_scrub *sc,
708 : xfs_ino_t ino)
709 : {
710 95952233 : struct xfs_mount *mp = sc->mp;
711 95952233 : bool has_shared;
712 95952233 : int error;
713 :
714 95952233 : if (!xfs_has_reflink(mp))
715 53926978 : return;
716 :
717 42025255 : error = xfs_reflink_inode_has_shared_extents(sc->tp, sc->ip,
718 : &has_shared);
719 84050011 : if (!xchk_xref_process_error(sc, XFS_INO_TO_AGNO(mp, ino),
720 42024960 : XFS_INO_TO_AGBNO(mp, ino), &error))
721 : return;
722 42025051 : if (xfs_is_reflink_inode(sc->ip) && !has_shared)
723 4809200 : xchk_ino_set_preen(sc, ino);
724 37215851 : else if (!xfs_is_reflink_inode(sc->ip) && has_shared)
725 0 : xchk_ino_set_corrupt(sc, ino);
726 : }
727 :
728 : /* Scrub an inode. */
729 : int
730 324979641 : xchk_inode(
731 : struct xfs_scrub *sc)
732 : {
733 324979641 : struct xfs_dinode di;
734 324979641 : int error = 0;
735 :
736 : /*
737 : * If sc->ip is NULL, that means that the setup function called
738 : * xfs_iget to look up the inode. xfs_iget returned a EFSCORRUPTED
739 : * and a NULL inode, so flag the corruption error and return.
740 : */
741 324979641 : if (!sc->ip) {
742 0 : xchk_ino_set_corrupt(sc, sc->sm->sm_ino);
743 0 : return 0;
744 : }
745 :
746 : /* Scrub the inode core. */
747 324979641 : xfs_inode_to_disk(sc->ip, &di, 0);
748 324971904 : xchk_dinode(sc, &di, sc->ip->i_ino);
749 324987345 : if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
750 0 : goto out;
751 :
752 : /*
753 : * Look for discrepancies between file's data blocks and the reflink
754 : * iflag. We already checked the iflag against the file mode when
755 : * we scrubbed the dinode.
756 : */
757 324987345 : if (S_ISREG(VFS_I(sc->ip)->i_mode))
758 95953003 : xchk_inode_check_reflink_iflag(sc, sc->ip->i_ino);
759 :
760 324986687 : xchk_inode_xref(sc, sc->ip->i_ino, &di);
761 : out:
762 : return error;
763 : }
|