diff options
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 88 |
1 files changed, 44 insertions, 44 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 76c2df382b7d..74292a71b384 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -4665,7 +4665,8 @@ retry: | |||
4665 | } | 4665 | } |
4666 | 4666 | ||
4667 | static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, | 4667 | static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, |
4668 | ext4_lblk_t len, int flags, int mode) | 4668 | ext4_lblk_t len, loff_t new_size, |
4669 | int flags, int mode) | ||
4669 | { | 4670 | { |
4670 | struct inode *inode = file_inode(file); | 4671 | struct inode *inode = file_inode(file); |
4671 | handle_t *handle; | 4672 | handle_t *handle; |
@@ -4674,8 +4675,10 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, | |||
4674 | int retries = 0; | 4675 | int retries = 0; |
4675 | struct ext4_map_blocks map; | 4676 | struct ext4_map_blocks map; |
4676 | unsigned int credits; | 4677 | unsigned int credits; |
4678 | loff_t epos; | ||
4677 | 4679 | ||
4678 | map.m_lblk = offset; | 4680 | map.m_lblk = offset; |
4681 | map.m_len = len; | ||
4679 | /* | 4682 | /* |
4680 | * Don't normalize the request if it can fit in one extent so | 4683 | * Don't normalize the request if it can fit in one extent so |
4681 | * that it doesn't get unnecessarily split into multiple | 4684 | * that it doesn't get unnecessarily split into multiple |
@@ -4690,9 +4693,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, | |||
4690 | credits = ext4_chunk_trans_blocks(inode, len); | 4693 | credits = ext4_chunk_trans_blocks(inode, len); |
4691 | 4694 | ||
4692 | retry: | 4695 | retry: |
4693 | while (ret >= 0 && ret < len) { | 4696 | while (ret >= 0 && len) { |
4694 | map.m_lblk = map.m_lblk + ret; | ||
4695 | map.m_len = len = len - ret; | ||
4696 | handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, | 4697 | handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, |
4697 | credits); | 4698 | credits); |
4698 | if (IS_ERR(handle)) { | 4699 | if (IS_ERR(handle)) { |
@@ -4709,6 +4710,21 @@ retry: | |||
4709 | ret2 = ext4_journal_stop(handle); | 4710 | ret2 = ext4_journal_stop(handle); |
4710 | break; | 4711 | break; |
4711 | } | 4712 | } |
4713 | map.m_lblk += ret; | ||
4714 | map.m_len = len = len - ret; | ||
4715 | epos = (loff_t)map.m_lblk << inode->i_blkbits; | ||
4716 | inode->i_ctime = ext4_current_time(inode); | ||
4717 | if (new_size) { | ||
4718 | if (epos > new_size) | ||
4719 | epos = new_size; | ||
4720 | if (ext4_update_inode_size(inode, epos) & 0x1) | ||
4721 | inode->i_mtime = inode->i_ctime; | ||
4722 | } else { | ||
4723 | if (epos > inode->i_size) | ||
4724 | ext4_set_inode_flag(inode, | ||
4725 | EXT4_INODE_EOFBLOCKS); | ||
4726 | } | ||
4727 | ext4_mark_inode_dirty(handle, inode); | ||
4712 | ret2 = ext4_journal_stop(handle); | 4728 | ret2 = ext4_journal_stop(handle); |
4713 | if (ret2) | 4729 | if (ret2) |
4714 | break; | 4730 | break; |
@@ -4731,7 +4747,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
4731 | loff_t new_size = 0; | 4747 | loff_t new_size = 0; |
4732 | int ret = 0; | 4748 | int ret = 0; |
4733 | int flags; | 4749 | int flags; |
4734 | int partial; | 4750 | int credits; |
4751 | int partial_begin, partial_end; | ||
4735 | loff_t start, end; | 4752 | loff_t start, end; |
4736 | ext4_lblk_t lblk; | 4753 | ext4_lblk_t lblk; |
4737 | struct address_space *mapping = inode->i_mapping; | 4754 | struct address_space *mapping = inode->i_mapping; |
@@ -4771,7 +4788,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
4771 | 4788 | ||
4772 | if (start < offset || end > offset + len) | 4789 | if (start < offset || end > offset + len) |
4773 | return -EINVAL; | 4790 | return -EINVAL; |
4774 | partial = (offset + len) & ((1 << blkbits) - 1); | 4791 | partial_begin = offset & ((1 << blkbits) - 1); |
4792 | partial_end = (offset + len) & ((1 << blkbits) - 1); | ||
4775 | 4793 | ||
4776 | lblk = start >> blkbits; | 4794 | lblk = start >> blkbits; |
4777 | max_blocks = (end >> blkbits); | 4795 | max_blocks = (end >> blkbits); |
@@ -4805,7 +4823,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
4805 | * If we have a partial block after EOF we have to allocate | 4823 | * If we have a partial block after EOF we have to allocate |
4806 | * the entire block. | 4824 | * the entire block. |
4807 | */ | 4825 | */ |
4808 | if (partial) | 4826 | if (partial_end) |
4809 | max_blocks += 1; | 4827 | max_blocks += 1; |
4810 | } | 4828 | } |
4811 | 4829 | ||
@@ -4813,6 +4831,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
4813 | 4831 | ||
4814 | /* Now release the pages and zero block aligned part of pages*/ | 4832 | /* Now release the pages and zero block aligned part of pages*/ |
4815 | truncate_pagecache_range(inode, start, end - 1); | 4833 | truncate_pagecache_range(inode, start, end - 1); |
4834 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | ||
4816 | 4835 | ||
4817 | /* Wait all existing dio workers, newcomers will block on i_mutex */ | 4836 | /* Wait all existing dio workers, newcomers will block on i_mutex */ |
4818 | ext4_inode_block_unlocked_dio(inode); | 4837 | ext4_inode_block_unlocked_dio(inode); |
@@ -4825,13 +4844,22 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
4825 | if (ret) | 4844 | if (ret) |
4826 | goto out_dio; | 4845 | goto out_dio; |
4827 | 4846 | ||
4828 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, | 4847 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, |
4829 | mode); | 4848 | flags, mode); |
4830 | if (ret) | 4849 | if (ret) |
4831 | goto out_dio; | 4850 | goto out_dio; |
4832 | } | 4851 | } |
4852 | if (!partial_begin && !partial_end) | ||
4853 | goto out_dio; | ||
4833 | 4854 | ||
4834 | handle = ext4_journal_start(inode, EXT4_HT_MISC, 4); | 4855 | /* |
4856 | * In worst case we have to writeout two nonadjacent unwritten | ||
4857 | * blocks and update the inode | ||
4858 | */ | ||
4859 | credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1; | ||
4860 | if (ext4_should_journal_data(inode)) | ||
4861 | credits += 2; | ||
4862 | handle = ext4_journal_start(inode, EXT4_HT_MISC, credits); | ||
4835 | if (IS_ERR(handle)) { | 4863 | if (IS_ERR(handle)) { |
4836 | ret = PTR_ERR(handle); | 4864 | ret = PTR_ERR(handle); |
4837 | ext4_std_error(inode->i_sb, ret); | 4865 | ext4_std_error(inode->i_sb, ret); |
@@ -4839,12 +4867,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
4839 | } | 4867 | } |
4840 | 4868 | ||
4841 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | 4869 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); |
4842 | |||
4843 | if (new_size) { | 4870 | if (new_size) { |
4844 | if (new_size > i_size_read(inode)) | 4871 | ext4_update_inode_size(inode, new_size); |
4845 | i_size_write(inode, new_size); | ||
4846 | if (new_size > EXT4_I(inode)->i_disksize) | ||
4847 | ext4_update_i_disksize(inode, new_size); | ||
4848 | } else { | 4872 | } else { |
4849 | /* | 4873 | /* |
4850 | * Mark that we allocate beyond EOF so the subsequent truncate | 4874 | * Mark that we allocate beyond EOF so the subsequent truncate |
@@ -4853,7 +4877,6 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
4853 | if ((offset + len) > i_size_read(inode)) | 4877 | if ((offset + len) > i_size_read(inode)) |
4854 | ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); | 4878 | ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); |
4855 | } | 4879 | } |
4856 | |||
4857 | ext4_mark_inode_dirty(handle, inode); | 4880 | ext4_mark_inode_dirty(handle, inode); |
4858 | 4881 | ||
4859 | /* Zero out partial block at the edges of the range */ | 4882 | /* Zero out partial block at the edges of the range */ |
@@ -4880,13 +4903,11 @@ out_mutex: | |||
4880 | long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | 4903 | long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) |
4881 | { | 4904 | { |
4882 | struct inode *inode = file_inode(file); | 4905 | struct inode *inode = file_inode(file); |
4883 | handle_t *handle; | ||
4884 | loff_t new_size = 0; | 4906 | loff_t new_size = 0; |
4885 | unsigned int max_blocks; | 4907 | unsigned int max_blocks; |
4886 | int ret = 0; | 4908 | int ret = 0; |
4887 | int flags; | 4909 | int flags; |
4888 | ext4_lblk_t lblk; | 4910 | ext4_lblk_t lblk; |
4889 | struct timespec tv; | ||
4890 | unsigned int blkbits = inode->i_blkbits; | 4911 | unsigned int blkbits = inode->i_blkbits; |
4891 | 4912 | ||
4892 | /* Return error if mode is not supported */ | 4913 | /* Return error if mode is not supported */ |
@@ -4937,36 +4958,15 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
4937 | goto out; | 4958 | goto out; |
4938 | } | 4959 | } |
4939 | 4960 | ||
4940 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, mode); | 4961 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, |
4962 | flags, mode); | ||
4941 | if (ret) | 4963 | if (ret) |
4942 | goto out; | 4964 | goto out; |
4943 | 4965 | ||
4944 | handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); | 4966 | if (file->f_flags & O_SYNC && EXT4_SB(inode->i_sb)->s_journal) { |
4945 | if (IS_ERR(handle)) | 4967 | ret = jbd2_complete_transaction(EXT4_SB(inode->i_sb)->s_journal, |
4946 | goto out; | 4968 | EXT4_I(inode)->i_sync_tid); |
4947 | |||
4948 | tv = inode->i_ctime = ext4_current_time(inode); | ||
4949 | |||
4950 | if (new_size) { | ||
4951 | if (new_size > i_size_read(inode)) { | ||
4952 | i_size_write(inode, new_size); | ||
4953 | inode->i_mtime = tv; | ||
4954 | } | ||
4955 | if (new_size > EXT4_I(inode)->i_disksize) | ||
4956 | ext4_update_i_disksize(inode, new_size); | ||
4957 | } else { | ||
4958 | /* | ||
4959 | * Mark that we allocate beyond EOF so the subsequent truncate | ||
4960 | * can proceed even if the new size is the same as i_size. | ||
4961 | */ | ||
4962 | if ((offset + len) > i_size_read(inode)) | ||
4963 | ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); | ||
4964 | } | 4969 | } |
4965 | ext4_mark_inode_dirty(handle, inode); | ||
4966 | if (file->f_flags & O_SYNC) | ||
4967 | ext4_handle_sync(handle); | ||
4968 | |||
4969 | ext4_journal_stop(handle); | ||
4970 | out: | 4970 | out: |
4971 | mutex_unlock(&inode->i_mutex); | 4971 | mutex_unlock(&inode->i_mutex); |
4972 | trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); | 4972 | trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); |