diff options
author | Dave Chinner <dchinner@redhat.com> | 2010-11-29 23:16:02 -0500 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-12-01 08:40:20 -0500 |
commit | 309c848002052edbec650075a1eb098b17c17f35 (patch) | |
tree | 7e3e38c9ebcfa539716298c0f8a0000b45cffd8e /fs/xfs | |
parent | 90810b9e82a36c3c57c1aeb8b2918b242a130b26 (diff) |
xfs: delayed alloc blocks beyond EOF are valid after writeback
There is an assumption in the parts of XFS that flushing a dirty
file will make all the delayed allocation blocks disappear from an
inode. That is, that after calling xfs_flush_pages() then
ip->i_delayed_blks will be zero.
This is an invalid assumption as we may have specualtive
preallocation beyond EOF and they are recorded in
ip->i_delayed_blks. A flush of the dirty pages of an inode will not
change the state of these blocks beyond EOF, so a non-zero
deeelalloc block count after a flush is valid.
The bmap code has an invalid ASSERT() that needs to be removed, and
the swapext code has a bug in that while it swaps the data forks
around, it fails to swap the i_delayed_blks counter associated with
the fork and hence can get the block accounting wrong.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_dfrag.c | 13 |
2 files changed, 20 insertions, 2 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 08b179fa9e8f..4111cd3966c7 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -5471,8 +5471,13 @@ xfs_getbmap( | |||
5471 | if (error) | 5471 | if (error) |
5472 | goto out_unlock_iolock; | 5472 | goto out_unlock_iolock; |
5473 | } | 5473 | } |
5474 | 5474 | /* | |
5475 | ASSERT(ip->i_delayed_blks == 0); | 5475 | * even after flushing the inode, there can still be delalloc |
5476 | * blocks on the inode beyond EOF due to speculative | ||
5477 | * preallocation. These are not removed until the release | ||
5478 | * function is called or the inode is inactivated. Hence we | ||
5479 | * cannot assert here that ip->i_delayed_blks == 0. | ||
5480 | */ | ||
5476 | } | 5481 | } |
5477 | 5482 | ||
5478 | lock = xfs_ilock_map_shared(ip); | 5483 | lock = xfs_ilock_map_shared(ip); |
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 3b9582c60a22..e60490bc00a6 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c | |||
@@ -377,6 +377,19 @@ xfs_swap_extents( | |||
377 | ip->i_d.di_format = tip->i_d.di_format; | 377 | ip->i_d.di_format = tip->i_d.di_format; |
378 | tip->i_d.di_format = tmp; | 378 | tip->i_d.di_format = tmp; |
379 | 379 | ||
380 | /* | ||
381 | * The extents in the source inode could still contain speculative | ||
382 | * preallocation beyond EOF (e.g. the file is open but not modified | ||
383 | * while defrag is in progress). In that case, we need to copy over the | ||
384 | * number of delalloc blocks the data fork in the source inode is | ||
385 | * tracking beyond EOF so that when the fork is truncated away when the | ||
386 | * temporary inode is unlinked we don't underrun the i_delayed_blks | ||
387 | * counter on that inode. | ||
388 | */ | ||
389 | ASSERT(tip->i_delayed_blks == 0); | ||
390 | tip->i_delayed_blks = ip->i_delayed_blks; | ||
391 | ip->i_delayed_blks = 0; | ||
392 | |||
380 | ilf_fields = XFS_ILOG_CORE; | 393 | ilf_fields = XFS_ILOG_CORE; |
381 | 394 | ||
382 | switch(ip->i_d.di_format) { | 395 | switch(ip->i_d.di_format) { |