aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2017-05-12 13:44:08 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2017-05-16 12:24:35 -0400
commit0daaecacb83bc6b656a56393ab77a31c28139bc7 (patch)
treef4a35ca60f6ec2fe6a1847381dfc4257d2432484
parent2ea659a9ef488125eb46da6eb571de5eae5c43f6 (diff)
xfs: fix indlen accounting error on partial delalloc conversion
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>
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index f02eb7673392..8adb91b05588 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -2065,8 +2065,10 @@ xfs_bmap_add_extent_delay_real(
2065 } 2065 }
2066 temp = xfs_bmap_worst_indlen(bma->ip, temp); 2066 temp = xfs_bmap_worst_indlen(bma->ip, temp);
2067 temp2 = xfs_bmap_worst_indlen(bma->ip, temp2); 2067 temp2 = xfs_bmap_worst_indlen(bma->ip, temp2);
2068 diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) - 2068 diff = (int)(temp + temp2 -
2069 (bma->cur ? bma->cur->bc_private.b.allocated : 0)); 2069 (startblockval(PREV.br_startblock) -
2070 (bma->cur ?
2071 bma->cur->bc_private.b.allocated : 0)));
2070 if (diff > 0) { 2072 if (diff > 0) {
2071 error = xfs_mod_fdblocks(bma->ip->i_mount, 2073 error = xfs_mod_fdblocks(bma->ip->i_mount,
2072 -((int64_t)diff), false); 2074 -((int64_t)diff), false);
@@ -2123,7 +2125,6 @@ xfs_bmap_add_extent_delay_real(
2123 temp = da_new; 2125 temp = da_new;
2124 if (bma->cur) 2126 if (bma->cur)
2125 temp += bma->cur->bc_private.b.allocated; 2127 temp += bma->cur->bc_private.b.allocated;
2126 ASSERT(temp <= da_old);
2127 if (temp < da_old) 2128 if (temp < da_old)
2128 xfs_mod_fdblocks(bma->ip->i_mount, 2129 xfs_mod_fdblocks(bma->ip->i_mount,
2129 (int64_t)(da_old - temp), false); 2130 (int64_t)(da_old - temp), false);