Skip to content

Commit

Permalink
ext4: only call ext4_truncate when size <= isize
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Josef Bacik authored and Theodore Ts'o committed Jun 22, 2015
1 parent 04e2241 commit 3da40c7
Showing 1 changed file with 18 additions and 20 deletions.
38 changes: 18 additions & 20 deletions fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -4681,33 +4681,37 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
ext4_journal_stop(handle);
}

if (attr->ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
if (attr->ia_valid & ATTR_SIZE) {
handle_t *handle;
loff_t oldsize = inode->i_size;
int shrink = (attr->ia_size <= inode->i_size);

if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);

if (attr->ia_size > sbi->s_bitmap_maxbytes)
return -EFBIG;
}
if (!S_ISREG(inode->i_mode))
return -EINVAL;

if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size)
inode_inc_iversion(inode);

if (S_ISREG(inode->i_mode) &&
if (ext4_should_order_data(inode) &&
(attr->ia_size < inode->i_size)) {
if (ext4_should_order_data(inode)) {
error = ext4_begin_ordered_truncate(inode,
error = ext4_begin_ordered_truncate(inode,
attr->ia_size);
if (error)
goto err_out;
}
if (error)
goto err_out;
}
if (attr->ia_size != inode->i_size) {
handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
if (IS_ERR(handle)) {
error = PTR_ERR(handle);
goto err_out;
}
if (ext4_handle_valid(handle)) {
if (ext4_handle_valid(handle) && shrink) {
error = ext4_orphan_add(handle, inode);
orphan = 1;
}
Expand All @@ -4726,15 +4730,13 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
up_write(&EXT4_I(inode)->i_data_sem);
ext4_journal_stop(handle);
if (error) {
ext4_orphan_del(NULL, inode);
if (orphan)
ext4_orphan_del(NULL, inode);
goto err_out;
}
} else {
loff_t oldsize = inode->i_size;

i_size_write(inode, attr->ia_size);
pagecache_isize_extended(inode, oldsize, inode->i_size);
}
if (!shrink)
pagecache_isize_extended(inode, oldsize, inode->i_size);

/*
* Blocks are going to be removed from the inode. Wait
Expand All @@ -4754,13 +4756,9 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
* in data=journal mode to make pages freeable.
*/
truncate_pagecache(inode, inode->i_size);
if (shrink)
ext4_truncate(inode);
}
/*
* We want to call ext4_truncate() even if attr->ia_size ==
* inode->i_size for cases like truncation of fallocated space
*/
if (attr->ia_valid & ATTR_SIZE)
ext4_truncate(inode);

if (!rc) {
setattr_copy(inode, attr);
Expand Down

0 comments on commit 3da40c7

Please sign in to comment.