lkml.org 
[lkml]   [2017]   [Jun]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 49/53] xfs: fix indlen accounting error on partial delalloc conversion
    Date
    4.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Brian Foster <bfoster@redhat.com>

    commit 0daaecacb83bc6b656a56393ab77a31c28139bc7 upstream.

    The delalloc -> real block conversion path uses an incorrect
    calculation in the case where the middle part of a delalloc extent
    is being converted. This is documented as a rare situation because
    XFS generally attempts to maximize contiguity by converting as much
    of a delalloc extent as possible.

    If this situation does occur, the indlen reservation for the two new
    delalloc extents left behind by the conversion of the middle range
    is calculated and compared with the original reservation. If more
    blocks are required, the delta is allocated from the global block
    pool. This delta value can be characterized as the difference
    between the new total requirement (temp + temp2) and the currently
    available reservation minus those blocks that have already been
    allocated (startblockval(PREV.br_startblock) - allocated).

    The problem is that the current code does not account for previously
    allocated blocks correctly. It subtracts the current allocation
    count from the (new - old) delta rather than the old indlen
    reservation. This means that more indlen blocks than have been
    allocated end up stashed in the remaining extents and free space
    accounting is broken as a result.

    Fix up the calculation to subtract the allocated block count from
    the original extent indlen and thus correctly allocate the
    reservation delta based on the difference between the new total
    requirement and the unused blocks from the original reservation.
    Also remove a bogus assert that contradicts the fact that the new
    indlen reservation can be larger than the original indlen
    reservation.

    Signed-off-by: Brian Foster <bfoster@redhat.com>
    Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
    Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/xfs/libxfs/xfs_bmap.c | 7 ++++---
    1 file changed, 4 insertions(+), 3 deletions(-)

    --- a/fs/xfs/libxfs/xfs_bmap.c
    +++ b/fs/xfs/libxfs/xfs_bmap.c
    @@ -2179,8 +2179,10 @@ xfs_bmap_add_extent_delay_real(
    }
    temp = xfs_bmap_worst_indlen(bma->ip, temp);
    temp2 = xfs_bmap_worst_indlen(bma->ip, temp2);
    - diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) -
    - (bma->cur ? bma->cur->bc_private.b.allocated : 0));
    + diff = (int)(temp + temp2 -
    + (startblockval(PREV.br_startblock) -
    + (bma->cur ?
    + bma->cur->bc_private.b.allocated : 0)));
    if (diff > 0) {
    error = xfs_mod_fdblocks(bma->ip->i_mount,
    -((int64_t)diff), false);
    @@ -2232,7 +2234,6 @@ xfs_bmap_add_extent_delay_real(
    temp = da_new;
    if (bma->cur)
    temp += bma->cur->bc_private.b.allocated;
    - ASSERT(temp <= da_old);
    if (temp < da_old)
    xfs_mod_fdblocks(bma->ip->i_mount,
    (int64_t)(da_old - temp), false);

    \
     
     \ /
      Last update: 2017-06-12 00:30    [W:4.291 / U:0.728 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site