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: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Darrick J. Wong 2020-12-04 13:28:35 -08:00
parent 18695ad425
commit 33005fd0a5
8 changed files with 37 additions and 5 deletions

View File

@ -6227,7 +6227,7 @@ xfs_bmap_validate_extent(
{
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;
if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) {

View File

@ -258,3 +258,28 @@ xfs_verify_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);
}

View File

@ -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);
void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min,
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__ */

View File

@ -329,6 +329,10 @@ xchk_bmap_iextent(
xchk_fblock_set_corrupt(info->sc, info->whichfork,
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);
/* There should never be a "hole" extent in either extent list. */

View File

@ -445,7 +445,7 @@ xfs_bui_validate(
if (!xfs_verify_ino(mp, bmap->me_owner))
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 xfs_verify_fsbext(mp, bmap->me_startblock, bmap->me_len);

View File

@ -1521,7 +1521,7 @@ xfs_itruncate_extents_flags(
* the page cache can't scale that far.
*/
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);
return 0;
}

View File

@ -490,7 +490,7 @@ xfs_rui_validate_map(
!xfs_verify_ino(mp, rmap->me_owner))
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 xfs_verify_fsbext(mp, rmap->me_startblock, rmap->me_len);

View File

@ -1517,7 +1517,7 @@ xfs_fc_fill_super(
* Avoid integer overflow by comparing the maximum bmbt offset to the
* 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,
"MAX_LFS_FILESIZE block offset (%llu) exceeds extent map maximum (%llu)!",
XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE),