Skip to content

Commit f0322c7

Browse files
committed
xfs: measure all contiguous previous extents for prealloc size
When we're estimating a new speculative preallocation length for an extending write, we should walk backwards through the extent list to determine the number of number of blocks that are physically and logically contiguous with the write offset, and use that as an input to the preallocation size computation. This way, preallocation length is truly measured by the effectiveness of the allocator in giving us contiguous allocations without being influenced by the state of a given extent. This fixes both the problem where ZERO_RANGE within an EOF can reduce preallocation, and prevents the unnecessary shrinkage of preallocation when delalloc extents are turned into unwritten extents. This was found as a regression in xfs/014 after changing delalloc writes to create unwritten extents during writeback. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Brian Foster <[email protected]>
1 parent 1edd2c0 commit f0322c7

File tree

1 file changed

+27
-13
lines changed

1 file changed

+27
-13
lines changed

fs/xfs/xfs_iomap.c

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -377,15 +377,17 @@ xfs_iomap_prealloc_size(
377377
loff_t count,
378378
struct xfs_iext_cursor *icur)
379379
{
380+
struct xfs_iext_cursor ncur = *icur;
381+
struct xfs_bmbt_irec prev, got;
380382
struct xfs_mount *mp = ip->i_mount;
381383
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
382384
xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
383-
struct xfs_bmbt_irec prev;
384-
int shift = 0;
385385
int64_t freesp;
386386
xfs_fsblock_t qblocks;
387-
int qshift = 0;
388387
xfs_fsblock_t alloc_blocks = 0;
388+
xfs_extlen_t plen;
389+
int shift = 0;
390+
int qshift = 0;
389391

390392
if (offset + count <= XFS_ISIZE(ip))
391393
return 0;
@@ -400,7 +402,7 @@ xfs_iomap_prealloc_size(
400402
*/
401403
if ((mp->m_flags & XFS_MOUNT_ALLOCSIZE) ||
402404
XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) ||
403-
!xfs_iext_peek_prev_extent(ifp, icur, &prev) ||
405+
!xfs_iext_prev_extent(ifp, &ncur, &prev) ||
404406
prev.br_startoff + prev.br_blockcount < offset_fsb)
405407
return mp->m_allocsize_blocks;
406408

@@ -413,16 +415,28 @@ xfs_iomap_prealloc_size(
413415
* preallocation size.
414416
*
415417
* If the extent is a hole, then preallocation is essentially disabled.
416-
* Otherwise we take the size of the preceding data extent as the basis
417-
* for the preallocation size. If the size of the extent is greater than
418-
* half the maximum extent length, then use the current offset as the
419-
* basis. This ensures that for large files the preallocation size
420-
* always extends to MAXEXTLEN rather than falling short due to things
421-
* like stripe unit/width alignment of real extents.
418+
* Otherwise we take the size of the preceding data extents as the basis
419+
* for the preallocation size. Note that we don't care if the previous
420+
* extents are written or not.
421+
*
422+
* If the size of the extents is greater than half the maximum extent
423+
* length, then use the current offset as the basis. This ensures that
424+
* for large files the preallocation size always extends to MAXEXTLEN
425+
* rather than falling short due to things like stripe unit/width
426+
* alignment of real extents.
422427
*/
423-
if (prev.br_blockcount <= (MAXEXTLEN >> 1))
424-
alloc_blocks = prev.br_blockcount << 1;
425-
else
428+
plen = prev.br_blockcount;
429+
while (xfs_iext_prev_extent(ifp, &ncur, &got)) {
430+
if (plen > MAXEXTLEN / 2 ||
431+
isnullstartblock(got.br_startblock) ||
432+
got.br_startoff + got.br_blockcount != prev.br_startoff ||
433+
got.br_startblock + got.br_blockcount != prev.br_startblock)
434+
break;
435+
plen += got.br_blockcount;
436+
prev = got;
437+
}
438+
alloc_blocks = plen * 2;
439+
if (alloc_blocks > MAXEXTLEN)
426440
alloc_blocks = XFS_B_TO_FSB(mp, offset);
427441
if (!alloc_blocks)
428442
goto check_writeio;

0 commit comments

Comments
 (0)