diff options
author | Jan Kara <jack@suse.cz> | 2013-08-17 10:07:17 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-09-26 20:18:15 -0400 |
commit | 263c784f2b66e18e34208a2f0e56df65c039d918 (patch) | |
tree | b75d6004263d8604544d4050ff7ddbdf50811e9a /fs/ext4/inode.c | |
parent | 25a870d4dc930531f545aa1ae0cdca281d99f980 (diff) |
ext4: simplify truncation code in ext4_setattr()
commit 5208386c501276df18fee464e21d3c58d2d79517 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 <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 109 |
1 files changed, 49 insertions, 60 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ccbfbbb12dc5..904ca1a21dce 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -4706,7 +4706,9 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
4706 | ext4_journal_stop(handle); | 4706 | ext4_journal_stop(handle); |
4707 | } | 4707 | } |
4708 | 4708 | ||
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; | ||
4710 | 4712 | ||
4711 | if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { | 4713 | if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { |
4712 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | 4714 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
@@ -4714,73 +4716,60 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
4714 | if (attr->ia_size > sbi->s_bitmap_maxbytes) | 4716 | if (attr->ia_size > sbi->s_bitmap_maxbytes) |
4715 | return -EFBIG; | 4717 | return -EFBIG; |
4716 | } | 4718 | } |
4717 | } | 4719 | if (S_ISREG(inode->i_mode) && |
4718 | 4720 | (attr->ia_size < inode->i_size)) { | |
4719 | if (S_ISREG(inode->i_mode) && | 4721 | if (ext4_should_order_data(inode)) { |
4720 | attr->ia_valid & ATTR_SIZE && | 4722 | error = ext4_begin_ordered_truncate(inode, |
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, | ||
4741 | attr->ia_size); | 4723 | attr->ia_size); |
4742 | if (error) { | 4724 | 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); | ||
4748 | goto err_out; | 4725 | goto err_out; |
4749 | } | 4726 | } |
4750 | ext4_orphan_del(handle, inode); | 4727 | handle = ext4_journal_start(inode, EXT4_HT_INODE, 3); |
4751 | orphan = 0; | 4728 | if (IS_ERR(handle)) { |
4752 | ext4_journal_stop(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); | ||
4753 | goto err_out; | 4743 | goto err_out; |
4754 | } | 4744 | } |
4755 | } | 4745 | } |
4756 | } | ||
4757 | |||
4758 | if (attr->ia_valid & ATTR_SIZE) { | ||
4759 | if (attr->ia_size != inode->i_size) { | ||
4760 | loff_t oldsize = inode->i_size; | ||
4761 | 4746 | ||
4762 | i_size_write(inode, attr->ia_size); | 4747 | i_size_write(inode, attr->ia_size); |
4763 | /* | 4748 | /* |
4764 | * Blocks are going to be removed from the inode. Wait | 4749 | * Blocks are going to be removed from the inode. Wait |
4765 | * for dio in flight. Temporarily disable | 4750 | * for dio in flight. Temporarily disable |
4766 | * dioread_nolock to prevent livelock. | 4751 | * dioread_nolock to prevent livelock. |
4767 | */ | 4752 | */ |
4768 | if (orphan) { | 4753 | if (orphan) { |
4769 | if (!ext4_should_journal_data(inode)) { | 4754 | if (!ext4_should_journal_data(inode)) { |
4770 | ext4_inode_block_unlocked_dio(inode); | 4755 | ext4_inode_block_unlocked_dio(inode); |
4771 | inode_dio_wait(inode); | 4756 | inode_dio_wait(inode); |
4772 | ext4_inode_resume_unlocked_dio(inode); | 4757 | ext4_inode_resume_unlocked_dio(inode); |
4773 | } else | 4758 | } else |
4774 | ext4_wait_for_tail_page_commit(inode); | 4759 | 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); | ||
4781 | } | 4760 | } |
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); | ||
4783 | } | 4766 | } |
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); | ||
4784 | 4773 | ||
4785 | if (!rc) { | 4774 | if (!rc) { |
4786 | setattr_copy(inode, attr); | 4775 | setattr_copy(inode, attr); |