xfs: prevent 32bit overflow in space reservation
If we attempt to preallocate more than 2^32 blocks of space in a single syscall, the transaction block reservation will overflow leading to a hangs in the superblock block accounting code. This is trivially reproduced with xfs_io. Fix the problem by capping the allocation reservation to the maximum number of blocks a single xfs_bmapi() call can allocate (2^21 blocks). Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
committed by
Dave Chinner
parent
9bc08a45fb
commit
72656c46f5
@@ -2299,15 +2299,22 @@ xfs_alloc_file_space(
|
|||||||
e = allocatesize_fsb;
|
e = allocatesize_fsb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The transaction reservation is limited to a 32-bit block
|
||||||
|
* count, hence we need to limit the number of blocks we are
|
||||||
|
* trying to reserve to avoid an overflow. We can't allocate
|
||||||
|
* more than @nimaps extents, and an extent is limited on disk
|
||||||
|
* to MAXEXTLEN (21 bits), so use that to enforce the limit.
|
||||||
|
*/
|
||||||
|
resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps));
|
||||||
if (unlikely(rt)) {
|
if (unlikely(rt)) {
|
||||||
resrtextents = qblocks = (uint)(e - s);
|
resrtextents = qblocks = resblks;
|
||||||
resrtextents /= mp->m_sb.sb_rextsize;
|
resrtextents /= mp->m_sb.sb_rextsize;
|
||||||
resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
|
resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
|
||||||
quota_flag = XFS_QMOPT_RES_RTBLKS;
|
quota_flag = XFS_QMOPT_RES_RTBLKS;
|
||||||
} else {
|
} else {
|
||||||
resrtextents = 0;
|
resrtextents = 0;
|
||||||
resblks = qblocks = \
|
resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks);
|
||||||
XFS_DIOSTRAT_SPACE_RES(mp, (uint)(e - s));
|
|
||||||
quota_flag = XFS_QMOPT_RES_REGBLKS;
|
quota_flag = XFS_QMOPT_RES_REGBLKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user