0001
0002
0003
0004
0005
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_trans_resv.h"
0011 #include "xfs_mount.h"
0012 #include "xfs_btree.h"
0013 #include "xfs_log_format.h"
0014 #include "xfs_inode.h"
0015 #include "xfs_ialloc.h"
0016 #include "xfs_da_format.h"
0017 #include "xfs_reflink.h"
0018 #include "xfs_rmap.h"
0019 #include "xfs_bmap_util.h"
0020 #include "scrub/scrub.h"
0021 #include "scrub/common.h"
0022 #include "scrub/btree.h"
0023
0024
0025
0026
0027
0028
0029 int
0030 xchk_setup_inode(
0031 struct xfs_scrub *sc)
0032 {
0033 int error;
0034
0035
0036
0037
0038
0039 error = xchk_get_inode(sc);
0040 switch (error) {
0041 case 0:
0042 break;
0043 case -EFSCORRUPTED:
0044 case -EFSBADCRC:
0045 return xchk_trans_alloc(sc, 0);
0046 default:
0047 return error;
0048 }
0049
0050
0051 sc->ilock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
0052 xfs_ilock(sc->ip, sc->ilock_flags);
0053 error = xchk_trans_alloc(sc, 0);
0054 if (error)
0055 goto out;
0056 sc->ilock_flags |= XFS_ILOCK_EXCL;
0057 xfs_ilock(sc->ip, XFS_ILOCK_EXCL);
0058
0059 out:
0060
0061 return error;
0062 }
0063
0064
0065
0066
0067 STATIC void
0068 xchk_inode_extsize(
0069 struct xfs_scrub *sc,
0070 struct xfs_dinode *dip,
0071 xfs_ino_t ino,
0072 uint16_t mode,
0073 uint16_t flags)
0074 {
0075 xfs_failaddr_t fa;
0076 uint32_t value = be32_to_cpu(dip->di_extsize);
0077
0078 fa = xfs_inode_validate_extsize(sc->mp, value, mode, flags);
0079 if (fa)
0080 xchk_ino_set_corrupt(sc, ino);
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091 if ((flags & XFS_DIFLAG_RTINHERIT) &&
0092 (flags & XFS_DIFLAG_EXTSZINHERIT) &&
0093 value % sc->mp->m_sb.sb_rextsize > 0)
0094 xchk_ino_set_warning(sc, ino);
0095 }
0096
0097
0098
0099
0100
0101
0102
0103 STATIC void
0104 xchk_inode_cowextsize(
0105 struct xfs_scrub *sc,
0106 struct xfs_dinode *dip,
0107 xfs_ino_t ino,
0108 uint16_t mode,
0109 uint16_t flags,
0110 uint64_t flags2)
0111 {
0112 xfs_failaddr_t fa;
0113
0114 fa = xfs_inode_validate_cowextsize(sc->mp,
0115 be32_to_cpu(dip->di_cowextsize), mode, flags,
0116 flags2);
0117 if (fa)
0118 xchk_ino_set_corrupt(sc, ino);
0119 }
0120
0121
0122 STATIC void
0123 xchk_inode_flags(
0124 struct xfs_scrub *sc,
0125 struct xfs_dinode *dip,
0126 xfs_ino_t ino,
0127 uint16_t mode,
0128 uint16_t flags)
0129 {
0130 struct xfs_mount *mp = sc->mp;
0131
0132
0133 if (flags & ~XFS_DIFLAG_ANY)
0134 goto bad;
0135
0136
0137 if ((flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)
0138 goto bad;
0139
0140
0141 if ((flags & XFS_DIFLAG_NEWRTBM) && ino != mp->m_sb.sb_rbmino)
0142 goto bad;
0143
0144
0145 if ((flags & (XFS_DIFLAG_RTINHERIT |
0146 XFS_DIFLAG_EXTSZINHERIT |
0147 XFS_DIFLAG_PROJINHERIT |
0148 XFS_DIFLAG_NOSYMLINKS)) &&
0149 !S_ISDIR(mode))
0150 goto bad;
0151
0152
0153 if ((flags & (XFS_DIFLAG_REALTIME | FS_XFLAG_EXTSIZE)) &&
0154 !S_ISREG(mode))
0155 goto bad;
0156
0157
0158 if ((flags & XFS_DIFLAG_FILESTREAM) && (flags & XFS_DIFLAG_REALTIME))
0159 goto bad;
0160
0161 return;
0162 bad:
0163 xchk_ino_set_corrupt(sc, ino);
0164 }
0165
0166
0167 STATIC void
0168 xchk_inode_flags2(
0169 struct xfs_scrub *sc,
0170 struct xfs_dinode *dip,
0171 xfs_ino_t ino,
0172 uint16_t mode,
0173 uint16_t flags,
0174 uint64_t flags2)
0175 {
0176 struct xfs_mount *mp = sc->mp;
0177
0178
0179 if (flags2 & ~XFS_DIFLAG2_ANY)
0180 xchk_ino_set_warning(sc, ino);
0181
0182
0183 if ((flags2 & XFS_DIFLAG2_REFLINK) &&
0184 !xfs_has_reflink(mp))
0185 goto bad;
0186
0187
0188
0189
0190 if ((flags2 & XFS_DIFLAG2_DAX) && !(S_ISREG(mode) || S_ISDIR(mode)))
0191 goto bad;
0192
0193
0194 if ((flags2 & XFS_DIFLAG2_REFLINK) && !S_ISREG(mode))
0195 goto bad;
0196
0197
0198 if ((flags & XFS_DIFLAG_REALTIME) && (flags2 & XFS_DIFLAG2_REFLINK))
0199 goto bad;
0200
0201
0202 if (xfs_dinode_has_bigtime(dip) && !xfs_has_bigtime(mp))
0203 goto bad;
0204
0205 return;
0206 bad:
0207 xchk_ino_set_corrupt(sc, ino);
0208 }
0209
0210 static inline void
0211 xchk_dinode_nsec(
0212 struct xfs_scrub *sc,
0213 xfs_ino_t ino,
0214 struct xfs_dinode *dip,
0215 const xfs_timestamp_t ts)
0216 {
0217 struct timespec64 tv;
0218
0219 tv = xfs_inode_from_disk_ts(dip, ts);
0220 if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
0221 xchk_ino_set_corrupt(sc, ino);
0222 }
0223
0224
0225 STATIC void
0226 xchk_dinode(
0227 struct xfs_scrub *sc,
0228 struct xfs_dinode *dip,
0229 xfs_ino_t ino)
0230 {
0231 struct xfs_mount *mp = sc->mp;
0232 size_t fork_recs;
0233 unsigned long long isize;
0234 uint64_t flags2;
0235 xfs_extnum_t nextents;
0236 xfs_extnum_t naextents;
0237 prid_t prid;
0238 uint16_t flags;
0239 uint16_t mode;
0240
0241 flags = be16_to_cpu(dip->di_flags);
0242 if (dip->di_version >= 3)
0243 flags2 = be64_to_cpu(dip->di_flags2);
0244 else
0245 flags2 = 0;
0246
0247
0248 mode = be16_to_cpu(dip->di_mode);
0249 switch (mode & S_IFMT) {
0250 case S_IFLNK:
0251 case S_IFREG:
0252 case S_IFDIR:
0253 case S_IFCHR:
0254 case S_IFBLK:
0255 case S_IFIFO:
0256 case S_IFSOCK:
0257
0258 break;
0259 default:
0260 xchk_ino_set_corrupt(sc, ino);
0261 break;
0262 }
0263
0264
0265 switch (dip->di_version) {
0266 case 1:
0267
0268
0269
0270
0271 xchk_ino_set_preen(sc, ino);
0272 prid = 0;
0273 break;
0274 case 2:
0275 case 3:
0276 if (dip->di_onlink != 0)
0277 xchk_ino_set_corrupt(sc, ino);
0278
0279 if (dip->di_mode == 0 && sc->ip)
0280 xchk_ino_set_corrupt(sc, ino);
0281
0282 if (dip->di_projid_hi != 0 &&
0283 !xfs_has_projid32(mp))
0284 xchk_ino_set_corrupt(sc, ino);
0285
0286 prid = be16_to_cpu(dip->di_projid_lo);
0287 break;
0288 default:
0289 xchk_ino_set_corrupt(sc, ino);
0290 return;
0291 }
0292
0293 if (xfs_has_projid32(mp))
0294 prid |= (prid_t)be16_to_cpu(dip->di_projid_hi) << 16;
0295
0296
0297
0298
0299
0300 if (dip->di_uid == cpu_to_be32(-1U) ||
0301 dip->di_gid == cpu_to_be32(-1U))
0302 xchk_ino_set_warning(sc, ino);
0303
0304
0305
0306
0307
0308 if (prid == -1U)
0309 xchk_ino_set_warning(sc, ino);
0310
0311
0312 switch (dip->di_format) {
0313 case XFS_DINODE_FMT_DEV:
0314 if (!S_ISCHR(mode) && !S_ISBLK(mode) &&
0315 !S_ISFIFO(mode) && !S_ISSOCK(mode))
0316 xchk_ino_set_corrupt(sc, ino);
0317 break;
0318 case XFS_DINODE_FMT_LOCAL:
0319 if (!S_ISDIR(mode) && !S_ISLNK(mode))
0320 xchk_ino_set_corrupt(sc, ino);
0321 break;
0322 case XFS_DINODE_FMT_EXTENTS:
0323 if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
0324 xchk_ino_set_corrupt(sc, ino);
0325 break;
0326 case XFS_DINODE_FMT_BTREE:
0327 if (!S_ISREG(mode) && !S_ISDIR(mode))
0328 xchk_ino_set_corrupt(sc, ino);
0329 break;
0330 case XFS_DINODE_FMT_UUID:
0331 default:
0332 xchk_ino_set_corrupt(sc, ino);
0333 break;
0334 }
0335
0336
0337 xchk_dinode_nsec(sc, ino, dip, dip->di_atime);
0338 xchk_dinode_nsec(sc, ino, dip, dip->di_mtime);
0339 xchk_dinode_nsec(sc, ino, dip, dip->di_ctime);
0340
0341
0342
0343
0344
0345
0346 isize = be64_to_cpu(dip->di_size);
0347 if (isize & (1ULL << 63))
0348 xchk_ino_set_corrupt(sc, ino);
0349
0350
0351 if (!S_ISDIR(mode) && !S_ISREG(mode) && !S_ISLNK(mode) && isize != 0)
0352 xchk_ino_set_corrupt(sc, ino);
0353
0354
0355 if (S_ISDIR(mode) && (isize == 0 || isize >= XFS_DIR2_SPACE_SIZE))
0356 xchk_ino_set_corrupt(sc, ino);
0357
0358
0359 if (S_ISLNK(mode) && (isize == 0 || isize >= XFS_SYMLINK_MAXLEN))
0360 xchk_ino_set_corrupt(sc, ino);
0361
0362
0363
0364
0365
0366
0367
0368 if (isize >= mp->m_super->s_maxbytes)
0369 xchk_ino_set_warning(sc, ino);
0370
0371
0372 if (flags2 & XFS_DIFLAG2_REFLINK) {
0373 ;
0374 } else if (flags & XFS_DIFLAG_REALTIME) {
0375
0376
0377
0378
0379
0380
0381
0382 if (be64_to_cpu(dip->di_nblocks) >=
0383 mp->m_sb.sb_dblocks + mp->m_sb.sb_rblocks)
0384 xchk_ino_set_corrupt(sc, ino);
0385 } else {
0386 if (be64_to_cpu(dip->di_nblocks) >= mp->m_sb.sb_dblocks)
0387 xchk_ino_set_corrupt(sc, ino);
0388 }
0389
0390 xchk_inode_flags(sc, dip, ino, mode, flags);
0391
0392 xchk_inode_extsize(sc, dip, ino, mode, flags);
0393
0394 nextents = xfs_dfork_data_extents(dip);
0395 naextents = xfs_dfork_attr_extents(dip);
0396
0397
0398 fork_recs = XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
0399 switch (dip->di_format) {
0400 case XFS_DINODE_FMT_EXTENTS:
0401 if (nextents > fork_recs)
0402 xchk_ino_set_corrupt(sc, ino);
0403 break;
0404 case XFS_DINODE_FMT_BTREE:
0405 if (nextents <= fork_recs)
0406 xchk_ino_set_corrupt(sc, ino);
0407 break;
0408 default:
0409 if (nextents != 0)
0410 xchk_ino_set_corrupt(sc, ino);
0411 break;
0412 }
0413
0414
0415 if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
0416 xchk_ino_set_corrupt(sc, ino);
0417 if (naextents != 0 && dip->di_forkoff == 0)
0418 xchk_ino_set_corrupt(sc, ino);
0419 if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
0420 xchk_ino_set_corrupt(sc, ino);
0421
0422
0423 if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
0424 dip->di_aformat != XFS_DINODE_FMT_EXTENTS &&
0425 dip->di_aformat != XFS_DINODE_FMT_BTREE)
0426 xchk_ino_set_corrupt(sc, ino);
0427
0428
0429 fork_recs = XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
0430 switch (dip->di_aformat) {
0431 case XFS_DINODE_FMT_EXTENTS:
0432 if (naextents > fork_recs)
0433 xchk_ino_set_corrupt(sc, ino);
0434 break;
0435 case XFS_DINODE_FMT_BTREE:
0436 if (naextents <= fork_recs)
0437 xchk_ino_set_corrupt(sc, ino);
0438 break;
0439 default:
0440 if (naextents != 0)
0441 xchk_ino_set_corrupt(sc, ino);
0442 }
0443
0444 if (dip->di_version >= 3) {
0445 xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
0446 xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
0447 xchk_inode_cowextsize(sc, dip, ino, mode, flags,
0448 flags2);
0449 }
0450 }
0451
0452
0453
0454
0455
0456
0457 static void
0458 xchk_inode_xref_finobt(
0459 struct xfs_scrub *sc,
0460 xfs_ino_t ino)
0461 {
0462 struct xfs_inobt_rec_incore rec;
0463 xfs_agino_t agino;
0464 int has_record;
0465 int error;
0466
0467 if (!sc->sa.fino_cur || xchk_skip_xref(sc->sm))
0468 return;
0469
0470 agino = XFS_INO_TO_AGINO(sc->mp, ino);
0471
0472
0473
0474
0475
0476 error = xfs_inobt_lookup(sc->sa.fino_cur, agino, XFS_LOOKUP_LE,
0477 &has_record);
0478 if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
0479 !has_record)
0480 return;
0481
0482 error = xfs_inobt_get_rec(sc->sa.fino_cur, &rec, &has_record);
0483 if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
0484 !has_record)
0485 return;
0486
0487
0488
0489
0490
0491 if (rec.ir_startino > agino ||
0492 rec.ir_startino + XFS_INODES_PER_CHUNK <= agino)
0493 return;
0494
0495 if (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))
0496 xchk_btree_xref_set_corrupt(sc, sc->sa.fino_cur, 0);
0497 }
0498
0499
0500 STATIC void
0501 xchk_inode_xref_bmap(
0502 struct xfs_scrub *sc,
0503 struct xfs_dinode *dip)
0504 {
0505 xfs_extnum_t nextents;
0506 xfs_filblks_t count;
0507 xfs_filblks_t acount;
0508 int error;
0509
0510 if (xchk_skip_xref(sc->sm))
0511 return;
0512
0513
0514 error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_DATA_FORK,
0515 &nextents, &count);
0516 if (!xchk_should_check_xref(sc, &error, NULL))
0517 return;
0518 if (nextents < xfs_dfork_data_extents(dip))
0519 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
0520
0521 error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
0522 &nextents, &acount);
0523 if (!xchk_should_check_xref(sc, &error, NULL))
0524 return;
0525 if (nextents != xfs_dfork_attr_extents(dip))
0526 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
0527
0528
0529 if (count + acount != be64_to_cpu(dip->di_nblocks))
0530 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
0531 }
0532
0533
0534 STATIC void
0535 xchk_inode_xref(
0536 struct xfs_scrub *sc,
0537 xfs_ino_t ino,
0538 struct xfs_dinode *dip)
0539 {
0540 xfs_agnumber_t agno;
0541 xfs_agblock_t agbno;
0542 int error;
0543
0544 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0545 return;
0546
0547 agno = XFS_INO_TO_AGNO(sc->mp, ino);
0548 agbno = XFS_INO_TO_AGBNO(sc->mp, ino);
0549
0550 error = xchk_ag_init_existing(sc, agno, &sc->sa);
0551 if (!xchk_xref_process_error(sc, agno, agbno, &error))
0552 goto out_free;
0553
0554 xchk_xref_is_used_space(sc, agbno, 1);
0555 xchk_inode_xref_finobt(sc, ino);
0556 xchk_xref_is_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_INODES);
0557 xchk_xref_is_not_shared(sc, agbno, 1);
0558 xchk_inode_xref_bmap(sc, dip);
0559
0560 out_free:
0561 xchk_ag_free(sc, &sc->sa);
0562 }
0563
0564
0565
0566
0567
0568
0569
0570 static void
0571 xchk_inode_check_reflink_iflag(
0572 struct xfs_scrub *sc,
0573 xfs_ino_t ino)
0574 {
0575 struct xfs_mount *mp = sc->mp;
0576 bool has_shared;
0577 int error;
0578
0579 if (!xfs_has_reflink(mp))
0580 return;
0581
0582 error = xfs_reflink_inode_has_shared_extents(sc->tp, sc->ip,
0583 &has_shared);
0584 if (!xchk_xref_process_error(sc, XFS_INO_TO_AGNO(mp, ino),
0585 XFS_INO_TO_AGBNO(mp, ino), &error))
0586 return;
0587 if (xfs_is_reflink_inode(sc->ip) && !has_shared)
0588 xchk_ino_set_preen(sc, ino);
0589 else if (!xfs_is_reflink_inode(sc->ip) && has_shared)
0590 xchk_ino_set_corrupt(sc, ino);
0591 }
0592
0593
0594 int
0595 xchk_inode(
0596 struct xfs_scrub *sc)
0597 {
0598 struct xfs_dinode di;
0599 int error = 0;
0600
0601
0602
0603
0604
0605
0606 if (!sc->ip) {
0607 xchk_ino_set_corrupt(sc, sc->sm->sm_ino);
0608 return 0;
0609 }
0610
0611
0612 xfs_inode_to_disk(sc->ip, &di, 0);
0613 xchk_dinode(sc, &di, sc->ip->i_ino);
0614 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0615 goto out;
0616
0617
0618
0619
0620
0621
0622 if (S_ISREG(VFS_I(sc->ip)->i_mode))
0623 xchk_inode_check_reflink_iflag(sc, sc->ip->i_ino);
0624
0625 xchk_inode_xref(sc, sc->ip->i_ino, &di);
0626 out:
0627 return error;
0628 }