xfs: refactor xfs_iomap_prealloc_size

Refactor xfs_iomap_prealloc_size to be the function that dynamically
computes the per-file preallocation size by moving the allocsize= case
to the caller.  Break up the huge comment preceding the function to
annotate the relevant parts of the code, and remove the impossible
check_writeio case.

Suggested-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
This commit is contained in:
Darrick J. Wong 2020-05-23 09:43:30 -07:00
parent f0322c7cc0
commit 590b16516e
1 changed files with 35 additions and 48 deletions

View File

@ -352,22 +352,10 @@ xfs_quota_calc_throttle(
} }
/* /*
* If we are doing a write at the end of the file and there are no allocations
* past this one, then extend the allocation out to the file system's write
* iosize.
*
* If we don't have a user specified preallocation size, dynamically increase * If we don't have a user specified preallocation size, dynamically increase
* the preallocation size as the size of the file grows. Cap the maximum size * the preallocation size as the size of the file grows. Cap the maximum size
* at a single extent or less if the filesystem is near full. The closer the * at a single extent or less if the filesystem is near full. The closer the
* filesystem is to full, the smaller the maximum prealocation. * filesystem is to being full, the smaller the maximum preallocation.
*
* As an exception we don't do any preallocation at all if the file is smaller
* than the minimum preallocation and we are using the default dynamic
* preallocation scheme, as it is likely this is the only write to the file that
* is going to be done.
*
* We clean up any extra space left over when the file is closed in
* xfs_inactive().
*/ */
STATIC xfs_fsblock_t STATIC xfs_fsblock_t
xfs_iomap_prealloc_size( xfs_iomap_prealloc_size(
@ -389,41 +377,28 @@ xfs_iomap_prealloc_size(
int shift = 0; int shift = 0;
int qshift = 0; int qshift = 0;
if (offset + count <= XFS_ISIZE(ip)) /*
return 0; * As an exception we don't do any preallocation at all if the file is
* smaller than the minimum preallocation and we are using the default
if (!(mp->m_flags & XFS_MOUNT_ALLOCSIZE) && * dynamic preallocation scheme, as it is likely this is the only write
(XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_allocsize_blocks))) * to the file that is going to be done.
*/
if (XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_allocsize_blocks))
return 0; return 0;
/* /*
* If an explicit allocsize is set, the file is small, or we * Use the minimum preallocation size for small files or if we are
* are writing behind a hole, then use the minimum prealloc: * writing right after a hole.
*/ */
if ((mp->m_flags & XFS_MOUNT_ALLOCSIZE) || if (XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) ||
XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) ||
!xfs_iext_prev_extent(ifp, &ncur, &prev) || !xfs_iext_prev_extent(ifp, &ncur, &prev) ||
prev.br_startoff + prev.br_blockcount < offset_fsb) prev.br_startoff + prev.br_blockcount < offset_fsb)
return mp->m_allocsize_blocks; return mp->m_allocsize_blocks;
/* /*
* Determine the initial size of the preallocation. We are beyond the * Take the size of the preceding data extents as the basis for the
* current EOF here, but we need to take into account whether this is * preallocation size. Note that we don't care if the previous extents
* a sparse write or an extending write when determining the * are written or not.
* preallocation size. Hence we need to look up the extent that ends
* at the current write offset and use the result to determine the
* preallocation size.
*
* If the extent is a hole, then preallocation is essentially disabled.
* Otherwise we take the size of the preceding data extents as the basis
* for the preallocation size. Note that we don't care if the previous
* extents are written or not.
*
* If the size of the extents is greater than half the maximum extent
* length, then use the current offset as the basis. This ensures that
* for large files the preallocation size always extends to MAXEXTLEN
* rather than falling short due to things like stripe unit/width
* alignment of real extents.
*/ */
plen = prev.br_blockcount; plen = prev.br_blockcount;
while (xfs_iext_prev_extent(ifp, &ncur, &got)) { while (xfs_iext_prev_extent(ifp, &ncur, &got)) {
@ -435,19 +410,25 @@ xfs_iomap_prealloc_size(
plen += got.br_blockcount; plen += got.br_blockcount;
prev = got; prev = got;
} }
/*
* If the size of the extents is greater than half the maximum extent
* length, then use the current offset as the basis. This ensures that
* for large files the preallocation size always extends to MAXEXTLEN
* rather than falling short due to things like stripe unit/width
* alignment of real extents.
*/
alloc_blocks = plen * 2; alloc_blocks = plen * 2;
if (alloc_blocks > MAXEXTLEN) if (alloc_blocks > MAXEXTLEN)
alloc_blocks = XFS_B_TO_FSB(mp, offset); alloc_blocks = XFS_B_TO_FSB(mp, offset);
if (!alloc_blocks)
goto check_writeio;
qblocks = alloc_blocks; qblocks = alloc_blocks;
/* /*
* MAXEXTLEN is not a power of two value but we round the prealloc down * MAXEXTLEN is not a power of two value but we round the prealloc down
* to the nearest power of two value after throttling. To prevent the * to the nearest power of two value after throttling. To prevent the
* round down from unconditionally reducing the maximum supported prealloc * round down from unconditionally reducing the maximum supported
* size, we round up first, apply appropriate throttling, round down and * prealloc size, we round up first, apply appropriate throttling,
* cap the value to MAXEXTLEN. * round down and cap the value to MAXEXTLEN.
*/ */
alloc_blocks = XFS_FILEOFF_MIN(roundup_pow_of_two(MAXEXTLEN), alloc_blocks = XFS_FILEOFF_MIN(roundup_pow_of_two(MAXEXTLEN),
alloc_blocks); alloc_blocks);
@ -508,7 +489,6 @@ xfs_iomap_prealloc_size(
*/ */
while (alloc_blocks && alloc_blocks >= freesp) while (alloc_blocks && alloc_blocks >= freesp)
alloc_blocks >>= 4; alloc_blocks >>= 4;
check_writeio:
if (alloc_blocks < mp->m_allocsize_blocks) if (alloc_blocks < mp->m_allocsize_blocks)
alloc_blocks = mp->m_allocsize_blocks; alloc_blocks = mp->m_allocsize_blocks;
trace_xfs_iomap_prealloc_size(ip, alloc_blocks, shift, trace_xfs_iomap_prealloc_size(ip, alloc_blocks, shift,
@ -975,9 +955,16 @@ xfs_buffered_write_iomap_begin(
if (error) if (error)
goto out_unlock; goto out_unlock;
if (eof) { if (eof && offset + count > XFS_ISIZE(ip)) {
prealloc_blocks = xfs_iomap_prealloc_size(ip, allocfork, offset, /*
count, &icur); * Determine the initial size of the preallocation.
* We clean up any extra preallocation when the file is closed.
*/
if (mp->m_flags & XFS_MOUNT_ALLOCSIZE)
prealloc_blocks = mp->m_allocsize_blocks;
else
prealloc_blocks = xfs_iomap_prealloc_size(ip, allocfork,
offset, count, &icur);
if (prealloc_blocks) { if (prealloc_blocks) {
xfs_extlen_t align; xfs_extlen_t align;
xfs_off_t end_offset; xfs_off_t end_offset;