diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-06-17 17:14:39 -0400 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-07-01 08:52:33 -0400 |
commit | a71754fc68f740b7ed46bb83123c63fbbc130611 (patch) | |
tree | c39655c68a713d4707cb476ac28702bb4e302ed2 /fs/btrfs/inode.c | |
parent | 0b08851fdaa5f9f74357345d7be44ea584665d5f (diff) |
Btrfs: move btrfs_truncate_page to btrfs_cont_expand instead of btrfs_truncate
This has plagued us forever and I'm so over working around it. When we truncate
down to a non-page aligned offset we will call btrfs_truncate_page to zero out
the end of the page and write it back to disk, this will keep us from exposing
stale data if we truncate back up from that point. The problem with this is it
requires data space to do this, and people don't really expect to get ENOSPC
from truncate() for these sort of things. This also tends to bite the orphan
cleanup stuff too which keeps people from mounting. To get around this we can
just move this into btrfs_cont_expand() to make sure if we are truncating up
from a non-page size aligned i_size we will zero out the rest of this page so
that we don't expose stale data. This will give ENOSPC if you try to truncate()
up or if you try to write past the end of isize, which is much more reasonable.
This fixes xfstests generic/083 failing to mount because of the orphan cleanup
failing. Thanks,
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 509112da6118..b7fa96f72ecd 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4253,6 +4253,15 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) | |||
4253 | u64 hole_size; | 4253 | u64 hole_size; |
4254 | int err = 0; | 4254 | int err = 0; |
4255 | 4255 | ||
4256 | /* | ||
4257 | * If our size started in the middle of a page we need to zero out the | ||
4258 | * rest of the page before we expand the i_size, otherwise we could | ||
4259 | * expose stale data. | ||
4260 | */ | ||
4261 | err = btrfs_truncate_page(inode, oldsize, 0, 0); | ||
4262 | if (err) | ||
4263 | return err; | ||
4264 | |||
4256 | if (size <= hole_start) | 4265 | if (size <= hole_start) |
4257 | return 0; | 4266 | return 0; |
4258 | 4267 | ||
@@ -7565,16 +7574,12 @@ static int btrfs_truncate(struct inode *inode) | |||
7565 | { | 7574 | { |
7566 | struct btrfs_root *root = BTRFS_I(inode)->root; | 7575 | struct btrfs_root *root = BTRFS_I(inode)->root; |
7567 | struct btrfs_block_rsv *rsv; | 7576 | struct btrfs_block_rsv *rsv; |
7568 | int ret; | 7577 | int ret = 0; |
7569 | int err = 0; | 7578 | int err = 0; |
7570 | struct btrfs_trans_handle *trans; | 7579 | struct btrfs_trans_handle *trans; |
7571 | u64 mask = root->sectorsize - 1; | 7580 | u64 mask = root->sectorsize - 1; |
7572 | u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); | 7581 | u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); |
7573 | 7582 | ||
7574 | ret = btrfs_truncate_page(inode, inode->i_size, 0, 0); | ||
7575 | if (ret) | ||
7576 | return ret; | ||
7577 | |||
7578 | btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1); | 7583 | btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1); |
7579 | btrfs_ordered_update_i_size(inode, inode->i_size, NULL); | 7584 | btrfs_ordered_update_i_size(inode, inode->i_size, NULL); |
7580 | 7585 | ||