Commit 33005fd0 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: refactor file range validation

Refactor all the open-coded validation of file block ranges into a
single helper, and teach the bmap scrubber to check the ranges.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 18695ad4
...@@ -6227,7 +6227,7 @@ xfs_bmap_validate_extent( ...@@ -6227,7 +6227,7 @@ xfs_bmap_validate_extent(
{ {
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = ip->i_mount;
if (irec->br_startoff + irec->br_blockcount <= irec->br_startoff) if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
return __this_address; return __this_address;
if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) { if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) {
......
...@@ -258,3 +258,28 @@ xfs_verify_dablk( ...@@ -258,3 +258,28 @@ xfs_verify_dablk(
return dabno <= max_dablk; return dabno <= max_dablk;
} }
/* Check that a file block offset does not exceed the maximum. */
bool
xfs_verify_fileoff(
struct xfs_mount *mp,
xfs_fileoff_t off)
{
return off <= XFS_MAX_FILEOFF;
}
/* Check that a range of file block offsets do not exceed the maximum. */
bool
xfs_verify_fileext(
struct xfs_mount *mp,
xfs_fileoff_t off,
xfs_fileoff_t len)
{
if (off + len <= off)
return false;
if (!xfs_verify_fileoff(mp, off))
return false;
return xfs_verify_fileoff(mp, off + len - 1);
}
...@@ -203,5 +203,8 @@ bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount); ...@@ -203,5 +203,8 @@ bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount);
bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off); bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off);
void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min, void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min,
unsigned long long *max); unsigned long long *max);
bool xfs_verify_fileoff(struct xfs_mount *mp, xfs_fileoff_t off);
bool xfs_verify_fileext(struct xfs_mount *mp, xfs_fileoff_t off,
xfs_fileoff_t len);
#endif /* __XFS_TYPES_H__ */ #endif /* __XFS_TYPES_H__ */
...@@ -329,6 +329,10 @@ xchk_bmap_iextent( ...@@ -329,6 +329,10 @@ xchk_bmap_iextent(
xchk_fblock_set_corrupt(info->sc, info->whichfork, xchk_fblock_set_corrupt(info->sc, info->whichfork,
irec->br_startoff); irec->br_startoff);
if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
xchk_fblock_set_corrupt(info->sc, info->whichfork,
irec->br_startoff);
xchk_bmap_dirattr_extent(ip, info, irec); xchk_bmap_dirattr_extent(ip, info, irec);
/* There should never be a "hole" extent in either extent list. */ /* There should never be a "hole" extent in either extent list. */
......
...@@ -445,7 +445,7 @@ xfs_bui_validate( ...@@ -445,7 +445,7 @@ xfs_bui_validate(
if (!xfs_verify_ino(mp, bmap->me_owner)) if (!xfs_verify_ino(mp, bmap->me_owner))
return false; return false;
if (bmap->me_startoff + bmap->me_len <= bmap->me_startoff) if (!xfs_verify_fileext(mp, bmap->me_startoff, bmap->me_len))
return false; return false;
return xfs_verify_fsbext(mp, bmap->me_startblock, bmap->me_len); return xfs_verify_fsbext(mp, bmap->me_startblock, bmap->me_len);
......
...@@ -1521,7 +1521,7 @@ xfs_itruncate_extents_flags( ...@@ -1521,7 +1521,7 @@ xfs_itruncate_extents_flags(
* the page cache can't scale that far. * the page cache can't scale that far.
*/ */
first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
if (first_unmap_block >= XFS_MAX_FILEOFF) { if (!xfs_verify_fileoff(mp, first_unmap_block)) {
WARN_ON_ONCE(first_unmap_block > XFS_MAX_FILEOFF); WARN_ON_ONCE(first_unmap_block > XFS_MAX_FILEOFF);
return 0; return 0;
} }
......
...@@ -490,7 +490,7 @@ xfs_rui_validate_map( ...@@ -490,7 +490,7 @@ xfs_rui_validate_map(
!xfs_verify_ino(mp, rmap->me_owner)) !xfs_verify_ino(mp, rmap->me_owner))
return false; return false;
if (rmap->me_startoff + rmap->me_len <= rmap->me_startoff) if (!xfs_verify_fileext(mp, rmap->me_startoff, rmap->me_len))
return false; return false;
return xfs_verify_fsbext(mp, rmap->me_startblock, rmap->me_len); return xfs_verify_fsbext(mp, rmap->me_startblock, rmap->me_len);
......
...@@ -1517,7 +1517,7 @@ xfs_fc_fill_super( ...@@ -1517,7 +1517,7 @@ xfs_fc_fill_super(
* Avoid integer overflow by comparing the maximum bmbt offset to the * Avoid integer overflow by comparing the maximum bmbt offset to the
* maximum pagecache offset in units of fs blocks. * maximum pagecache offset in units of fs blocks.
*/ */
if (XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE) > XFS_MAX_FILEOFF) { if (!xfs_verify_fileoff(mp, XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE))) {
xfs_warn(mp, xfs_warn(mp,
"MAX_LFS_FILESIZE block offset (%llu) exceeds extent map maximum (%llu)!", "MAX_LFS_FILESIZE block offset (%llu) exceeds extent map maximum (%llu)!",
XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE), XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment