aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2015-06-22 00:31:26 -0400
committerTheodore Ts'o <tytso@mit.edu>2015-06-22 00:31:26 -0400
commit3da40c7b089810ac9cf2bb1e59633f619f3a7312 (patch)
treee1649f9e7cbe2ae93c7e1cd82ae21fbdef8342a6
parent04e22412f420ade46dbf792a10e7f0d26ae55359 (diff)
ext4: only call ext4_truncate when size <= isize
At LSF we decided that if we truncate up from isize we shouldn't trim fallocated blocks that were fallocated with KEEP_SIZE and are past the new i_size. This patch fixes ext4 to do this. [ Completely reworked patch so that i_disksize would actually get set when truncating up. Also reworked the code for handling truncate so that it's easier to handle. -- tytso ] Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Lukas Czerner <lczerner@redhat.com>
-rw-r--r--fs/ext4/inode.c38
1 files changed, 18 insertions, 20 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index ae93f0bb9485..e057c6fcc227 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4681,8 +4681,10 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
4681 ext4_journal_stop(handle); 4681 ext4_journal_stop(handle);
4682 } 4682 }
4683 4683
4684 if (attr->ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { 4684 if (attr->ia_valid & ATTR_SIZE) {
4685 handle_t *handle; 4685 handle_t *handle;
4686 loff_t oldsize = inode->i_size;
4687 int shrink = (attr->ia_size <= inode->i_size);
4686 4688
4687 if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { 4689 if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
4688 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 4690 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
@@ -4690,24 +4692,26 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
4690 if (attr->ia_size > sbi->s_bitmap_maxbytes) 4692 if (attr->ia_size > sbi->s_bitmap_maxbytes)
4691 return -EFBIG; 4693 return -EFBIG;
4692 } 4694 }
4695 if (!S_ISREG(inode->i_mode))
4696 return -EINVAL;
4693 4697
4694 if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size) 4698 if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size)
4695 inode_inc_iversion(inode); 4699 inode_inc_iversion(inode);
4696 4700
4697 if (S_ISREG(inode->i_mode) && 4701 if (ext4_should_order_data(inode) &&
4698 (attr->ia_size < inode->i_size)) { 4702 (attr->ia_size < inode->i_size)) {
4699 if (ext4_should_order_data(inode)) { 4703 error = ext4_begin_ordered_truncate(inode,
4700 error = ext4_begin_ordered_truncate(inode,
4701 attr->ia_size); 4704 attr->ia_size);
4702 if (error) 4705 if (error)
4703 goto err_out; 4706 goto err_out;
4704 } 4707 }
4708 if (attr->ia_size != inode->i_size) {
4705 handle = ext4_journal_start(inode, EXT4_HT_INODE, 3); 4709 handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
4706 if (IS_ERR(handle)) { 4710 if (IS_ERR(handle)) {
4707 error = PTR_ERR(handle); 4711 error = PTR_ERR(handle);
4708 goto err_out; 4712 goto err_out;
4709 } 4713 }
4710 if (ext4_handle_valid(handle)) { 4714 if (ext4_handle_valid(handle) && shrink) {
4711 error = ext4_orphan_add(handle, inode); 4715 error = ext4_orphan_add(handle, inode);
4712 orphan = 1; 4716 orphan = 1;
4713 } 4717 }
@@ -4726,15 +4730,13 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
4726 up_write(&EXT4_I(inode)->i_data_sem); 4730 up_write(&EXT4_I(inode)->i_data_sem);
4727 ext4_journal_stop(handle); 4731 ext4_journal_stop(handle);
4728 if (error) { 4732 if (error) {
4729 ext4_orphan_del(NULL, inode); 4733 if (orphan)
4734 ext4_orphan_del(NULL, inode);
4730 goto err_out; 4735 goto err_out;
4731 } 4736 }
4732 } else {
4733 loff_t oldsize = inode->i_size;
4734
4735 i_size_write(inode, attr->ia_size);
4736 pagecache_isize_extended(inode, oldsize, inode->i_size);
4737 } 4737 }
4738 if (!shrink)
4739 pagecache_isize_extended(inode, oldsize, inode->i_size);
4738 4740
4739 /* 4741 /*
4740 * Blocks are going to be removed from the inode. Wait 4742 * Blocks are going to be removed from the inode. Wait
@@ -4754,13 +4756,9 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
4754 * in data=journal mode to make pages freeable. 4756 * in data=journal mode to make pages freeable.
4755 */ 4757 */
4756 truncate_pagecache(inode, inode->i_size); 4758 truncate_pagecache(inode, inode->i_size);
4759 if (shrink)
4760 ext4_truncate(inode);
4757 } 4761 }
4758 /*
4759 * We want to call ext4_truncate() even if attr->ia_size ==
4760 * inode->i_size for cases like truncation of fallocated space
4761 */
4762 if (attr->ia_valid & ATTR_SIZE)
4763 ext4_truncate(inode);
4764 4762
4765 if (!rc) { 4763 if (!rc) {
4766 setattr_copy(inode, attr); 4764 setattr_copy(inode, attr);