xfs: verify icount in superblock write
authorDarrick J. Wong <darrick.wong@oracle.com>
Thu, 26 Jul 2018 17:10:42 +0000 (10:10 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Tue, 31 Jul 2018 20:18:09 +0000 (13:18 -0700)
Add a helper predicate to check the inode count for sanity, then use it
in the superblock write verifier to inspect sb_icount.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Bill O'Donnell <billodo@redhat.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
fs/xfs/libxfs/xfs_sb.c
fs/xfs/libxfs/xfs_types.c
fs/xfs/libxfs/xfs_types.h

index 3d29f4a..05e7ed1 100644 (file)
@@ -154,9 +154,10 @@ xfs_validate_sb_write(
         * Carry out additional sb summary counter sanity checks when we write
         * the superblock.  We skip this in the read validator because there
         * could be newer superblocks in the log and if the values are garbage
-        * we'll recalculate them at the end of log mount.
+        * even after replay we'll recalculate them at the end of log mount.
         */
        if (sbp->sb_fdblocks > sbp->sb_dblocks ||
+           !xfs_verify_icount(mp, sbp->sb_icount) ||
            sbp->sb_ifree > sbp->sb_icount) {
                xfs_warn(mp, "SB summary counter sanity check failed");
                return -EFSCORRUPTED;
index 2e2a243..33a5ca3 100644 (file)
@@ -171,3 +171,37 @@ xfs_verify_rtbno(
 {
        return rtbno < mp->m_sb.sb_rblocks;
 }
+
+/* Calculate the range of valid icount values. */
+static void
+xfs_icount_range(
+       struct xfs_mount        *mp,
+       unsigned long long      *min,
+       unsigned long long      *max)
+{
+       unsigned long long      nr_inos = 0;
+       xfs_agnumber_t          agno;
+
+       /* root, rtbitmap, rtsum all live in the first chunk */
+       *min = XFS_INODES_PER_CHUNK;
+
+       for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
+               xfs_agino_t     first, last;
+
+               xfs_agino_range(mp, agno, &first, &last);
+               nr_inos += last - first + 1;
+       }
+       *max = nr_inos;
+}
+
+/* Sanity-checking of inode counts. */
+bool
+xfs_verify_icount(
+       struct xfs_mount        *mp,
+       unsigned long long      icount)
+{
+       unsigned long long      min, max;
+
+       xfs_icount_range(mp, &min, &max);
+       return icount >= min && icount <= max;
+}
index 4055d62..b9e6c89 100644 (file)
@@ -165,5 +165,6 @@ bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino);
 bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino);
 bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino);
 bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno);
+bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount);
 
 #endif /* __XFS_TYPES_H__ */