Skip to content

Commit 263c784

Browse files
jankaragregkh
authored andcommitted
ext4: simplify truncation code in ext4_setattr()
commit 5208386 upstream. Merge conditions in ext4_setattr() handling inode size changes, also move ext4_begin_ordered_truncate() call somewhat earlier because it simplifies error recovery in case of failure. Also add error handling in case i_disksize update fails. Signed-off-by: Jan Kara <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 25a870d commit 263c784

File tree

1 file changed

+49
-60
lines changed

1 file changed

+49
-60
lines changed

fs/ext4/inode.c

Lines changed: 49 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4706,81 +4706,70 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
47064706
ext4_journal_stop(handle);
47074707
}
47084708

4709-
if (attr->ia_valid & ATTR_SIZE) {
4709+
if (attr->ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
4710+
handle_t *handle;
4711+
loff_t oldsize = inode->i_size;
47104712

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

47144716
if (attr->ia_size > sbi->s_bitmap_maxbytes)
47154717
return -EFBIG;
47164718
}
4717-
}
4718-
4719-
if (S_ISREG(inode->i_mode) &&
4720-
attr->ia_valid & ATTR_SIZE &&
4721-
(attr->ia_size < inode->i_size)) {
4722-
handle_t *handle;
4723-
4724-
handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
4725-
if (IS_ERR(handle)) {
4726-
error = PTR_ERR(handle);
4727-
goto err_out;
4728-
}
4729-
if (ext4_handle_valid(handle)) {
4730-
error = ext4_orphan_add(handle, inode);
4731-
orphan = 1;
4732-
}
4733-
EXT4_I(inode)->i_disksize = attr->ia_size;
4734-
rc = ext4_mark_inode_dirty(handle, inode);
4735-
if (!error)
4736-
error = rc;
4737-
ext4_journal_stop(handle);
4738-
4739-
if (ext4_should_order_data(inode)) {
4740-
error = ext4_begin_ordered_truncate(inode,
4719+
if (S_ISREG(inode->i_mode) &&
4720+
(attr->ia_size < inode->i_size)) {
4721+
if (ext4_should_order_data(inode)) {
4722+
error = ext4_begin_ordered_truncate(inode,
47414723
attr->ia_size);
4742-
if (error) {
4743-
/* Do as much error cleanup as possible */
4744-
handle = ext4_journal_start(inode,
4745-
EXT4_HT_INODE, 3);
4746-
if (IS_ERR(handle)) {
4747-
ext4_orphan_del(NULL, inode);
4724+
if (error)
47484725
goto err_out;
4749-
}
4750-
ext4_orphan_del(handle, inode);
4751-
orphan = 0;
4752-
ext4_journal_stop(handle);
4726+
}
4727+
handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
4728+
if (IS_ERR(handle)) {
4729+
error = PTR_ERR(handle);
4730+
goto err_out;
4731+
}
4732+
if (ext4_handle_valid(handle)) {
4733+
error = ext4_orphan_add(handle, inode);
4734+
orphan = 1;
4735+
}
4736+
EXT4_I(inode)->i_disksize = attr->ia_size;
4737+
rc = ext4_mark_inode_dirty(handle, inode);
4738+
if (!error)
4739+
error = rc;
4740+
ext4_journal_stop(handle);
4741+
if (error) {
4742+
ext4_orphan_del(NULL, inode);
47534743
goto err_out;
47544744
}
47554745
}
4756-
}
4757-
4758-
if (attr->ia_valid & ATTR_SIZE) {
4759-
if (attr->ia_size != inode->i_size) {
4760-
loff_t oldsize = inode->i_size;
47614746

4762-
i_size_write(inode, attr->ia_size);
4763-
/*
4764-
* Blocks are going to be removed from the inode. Wait
4765-
* for dio in flight. Temporarily disable
4766-
* dioread_nolock to prevent livelock.
4767-
*/
4768-
if (orphan) {
4769-
if (!ext4_should_journal_data(inode)) {
4770-
ext4_inode_block_unlocked_dio(inode);
4771-
inode_dio_wait(inode);
4772-
ext4_inode_resume_unlocked_dio(inode);
4773-
} else
4774-
ext4_wait_for_tail_page_commit(inode);
4775-
}
4776-
/*
4777-
* Truncate pagecache after we've waited for commit
4778-
* in data=journal mode to make pages freeable.
4779-
*/
4780-
truncate_pagecache(inode, oldsize, inode->i_size);
4747+
i_size_write(inode, attr->ia_size);
4748+
/*
4749+
* Blocks are going to be removed from the inode. Wait
4750+
* for dio in flight. Temporarily disable
4751+
* dioread_nolock to prevent livelock.
4752+
*/
4753+
if (orphan) {
4754+
if (!ext4_should_journal_data(inode)) {
4755+
ext4_inode_block_unlocked_dio(inode);
4756+
inode_dio_wait(inode);
4757+
ext4_inode_resume_unlocked_dio(inode);
4758+
} else
4759+
ext4_wait_for_tail_page_commit(inode);
47814760
}
4782-
ext4_truncate(inode);
4761+
/*
4762+
* Truncate pagecache after we've waited for commit
4763+
* in data=journal mode to make pages freeable.
4764+
*/
4765+
truncate_pagecache(inode, oldsize, inode->i_size);
47834766
}
4767+
/*
4768+
* We want to call ext4_truncate() even if attr->ia_size ==
4769+
* inode->i_size for cases like truncation of fallocated space
4770+
*/
4771+
if (attr->ia_valid & ATTR_SIZE)
4772+
ext4_truncate(inode);
47844773

47854774
if (!rc) {
47864775
setattr_copy(inode, attr);

0 commit comments

Comments
 (0)