OSDN Git Service

xfs: scrub should flag dir/attr offsets that aren't mappable with xfs_dablk_t
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 1 Feb 2019 17:08:53 +0000 (09:08 -0800)
committerDarrick J. Wong <darrick.wong@oracle.com>
Tue, 12 Feb 2019 00:06:40 +0000 (16:06 -0800)
Teach scrub to flag extent maps that exceed the range that can be mapped
with a xfs_dablk_t.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
fs/xfs/libxfs/xfs_types.c
fs/xfs/libxfs/xfs_types.h
fs/xfs/scrub/bmap.c

index 3306fc4..451608b 100644 (file)
@@ -204,3 +204,14 @@ xfs_verify_icount(
        xfs_icount_range(mp, &min, &max);
        return icount >= min && icount <= max;
 }
+
+/* Sanity-checking of dir/attr block offsets. */
+bool
+xfs_verify_dablk(
+       struct xfs_mount        *mp,
+       xfs_fileoff_t           dabno)
+{
+       xfs_dablk_t             max_dablk = -1U;
+
+       return dabno <= max_dablk;
+}
index 8f02855..704b4f3 100644 (file)
@@ -188,5 +188,6 @@ 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);
+bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off);
 
 #endif /* __XFS_TYPES_H__ */
index e1d11f3..a703cd5 100644 (file)
@@ -281,6 +281,31 @@ xchk_bmap_extent_xref(
        xchk_ag_free(info->sc, &info->sc->sa);
 }
 
+/*
+ * Directories and attr forks should never have blocks that can't be addressed
+ * by a xfs_dablk_t.
+ */
+STATIC void
+xchk_bmap_dirattr_extent(
+       struct xfs_inode        *ip,
+       struct xchk_bmap_info   *info,
+       struct xfs_bmbt_irec    *irec)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       xfs_fileoff_t           off;
+
+       if (!S_ISDIR(VFS_I(ip)->i_mode) && info->whichfork != XFS_ATTR_FORK)
+               return;
+
+       if (!xfs_verify_dablk(mp, irec->br_startoff))
+               xchk_fblock_set_corrupt(info->sc, info->whichfork,
+                               irec->br_startoff);
+
+       off = irec->br_startoff + irec->br_blockcount - 1;
+       if (!xfs_verify_dablk(mp, off))
+               xchk_fblock_set_corrupt(info->sc, info->whichfork, off);
+}
+
 /* Scrub a single extent record. */
 STATIC int
 xchk_bmap_extent(
@@ -305,6 +330,8 @@ xchk_bmap_extent(
                xchk_fblock_set_corrupt(info->sc, info->whichfork,
                                irec->br_startoff);
 
+       xchk_bmap_dirattr_extent(ip, info, irec);
+
        /* There should never be a "hole" extent in either extent list. */
        if (irec->br_startblock == HOLESTARTBLOCK)
                xchk_fblock_set_corrupt(info->sc, info->whichfork,