aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-04-29 08:11:12 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-04-29 08:11:12 -0400
commitfd28784adc079afa905df56204b1298ddb4d0bfe (patch)
tree3ede312b77a14e75d7b31c0df874b6eb160bfb61 /fs
parent267e4db9ac28a09973476e7ec2cb6807e609d35a (diff)
ext4: Fix fallocate to update the file size in each transaction
ext4_fallocate needs to update file size in each transaction. Otherwise if we crash the file size won't be seen. We were also not marking the inode dirty after updating file size before. Also when we try to retry allocation due to ENOSPC, make sure we reset the variable ret so that we actually do a retry. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/extents.c89
1 files changed, 38 insertions, 51 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 668d82e494dd..c2b004e29ad8 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2785,6 +2785,28 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
2785 return needed; 2785 return needed;
2786} 2786}
2787 2787
2788static void ext4_falloc_update_inode(struct inode *inode,
2789 int mode, loff_t new_size, int update_ctime)
2790{
2791 struct timespec now;
2792
2793 if (update_ctime) {
2794 now = current_fs_time(inode->i_sb);
2795 if (!timespec_equal(&inode->i_ctime, &now))
2796 inode->i_ctime = now;
2797 }
2798 /*
2799 * Update only when preallocation was requested beyond
2800 * the file size.
2801 */
2802 if (!(mode & FALLOC_FL_KEEP_SIZE) &&
2803 new_size > i_size_read(inode)) {
2804 i_size_write(inode, new_size);
2805 EXT4_I(inode)->i_disksize = new_size;
2806 }
2807
2808}
2809
2788/* 2810/*
2789 * preallocate space for a file. This implements ext4's fallocate inode 2811 * preallocate space for a file. This implements ext4's fallocate inode
2790 * operation, which gets called from sys_fallocate system call. 2812 * operation, which gets called from sys_fallocate system call.
@@ -2796,8 +2818,8 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
2796{ 2818{
2797 handle_t *handle; 2819 handle_t *handle;
2798 ext4_lblk_t block; 2820 ext4_lblk_t block;
2821 loff_t new_size;
2799 unsigned long max_blocks; 2822 unsigned long max_blocks;
2800 ext4_fsblk_t nblocks = 0;
2801 int ret = 0; 2823 int ret = 0;
2802 int ret2 = 0; 2824 int ret2 = 0;
2803 int retries = 0; 2825 int retries = 0;
@@ -2816,9 +2838,12 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
2816 return -ENODEV; 2838 return -ENODEV;
2817 2839
2818 block = offset >> blkbits; 2840 block = offset >> blkbits;
2841 /*
2842 * We can't just convert len to max_blocks because
2843 * If blocksize = 4096 offset = 3072 and len = 2048
2844 */
2819 max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) 2845 max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
2820 - block; 2846 - block;
2821
2822 /* 2847 /*
2823 * credits to insert 1 extent into extent tree + buffers to be able to 2848 * credits to insert 1 extent into extent tree + buffers to be able to
2824 * modify 1 super block, 1 block bitmap and 1 group descriptor. 2849 * modify 1 super block, 1 block bitmap and 1 group descriptor.
@@ -2834,7 +2859,6 @@ retry:
2834 ret = PTR_ERR(handle); 2859 ret = PTR_ERR(handle);
2835 break; 2860 break;
2836 } 2861 }
2837
2838 ret = ext4_get_blocks_wrap(handle, inode, block, 2862 ret = ext4_get_blocks_wrap(handle, inode, block,
2839 max_blocks, &map_bh, 2863 max_blocks, &map_bh,
2840 EXT4_CREATE_UNINITIALIZED_EXT, 0); 2864 EXT4_CREATE_UNINITIALIZED_EXT, 0);
@@ -2850,61 +2874,24 @@ retry:
2850 ret2 = ext4_journal_stop(handle); 2874 ret2 = ext4_journal_stop(handle);
2851 break; 2875 break;
2852 } 2876 }
2853 if (ret > 0) { 2877 if ((block + ret) >= (EXT4_BLOCK_ALIGN(offset + len,
2854 /* check wrap through sign-bit/zero here */ 2878 blkbits) >> blkbits))
2855 if ((block + ret) < 0 || (block + ret) < block) { 2879 new_size = offset + len;
2856 ret = -EIO; 2880 else
2857 ext4_mark_inode_dirty(handle, inode); 2881 new_size = (block + ret) << blkbits;
2858 ret2 = ext4_journal_stop(handle);
2859 break;
2860 }
2861 if (buffer_new(&map_bh) && ((block + ret) >
2862 (EXT4_BLOCK_ALIGN(i_size_read(inode), blkbits)
2863 >> blkbits)))
2864 nblocks = nblocks + ret;
2865 }
2866
2867 /* Update ctime if new blocks get allocated */
2868 if (nblocks) {
2869 struct timespec now;
2870
2871 now = current_fs_time(inode->i_sb);
2872 if (!timespec_equal(&inode->i_ctime, &now))
2873 inode->i_ctime = now;
2874 }
2875 2882
2883 ext4_falloc_update_inode(inode, mode, new_size,
2884 buffer_new(&map_bh));
2876 ext4_mark_inode_dirty(handle, inode); 2885 ext4_mark_inode_dirty(handle, inode);
2877 ret2 = ext4_journal_stop(handle); 2886 ret2 = ext4_journal_stop(handle);
2878 if (ret2) 2887 if (ret2)
2879 break; 2888 break;
2880 } 2889 }
2881 2890 if (ret == -ENOSPC &&
2882 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 2891 ext4_should_retry_alloc(inode->i_sb, &retries)) {
2892 ret = 0;
2883 goto retry; 2893 goto retry;
2884
2885 /*
2886 * Time to update the file size.
2887 * Update only when preallocation was requested beyond the file size.
2888 */
2889 if (!(mode & FALLOC_FL_KEEP_SIZE) &&
2890 (offset + len) > i_size_read(inode)) {
2891 if (ret > 0) {
2892 /*
2893 * if no error, we assume preallocation succeeded
2894 * completely
2895 */
2896 i_size_write(inode, offset + len);
2897 EXT4_I(inode)->i_disksize = i_size_read(inode);
2898 } else if (ret < 0 && nblocks) {
2899 /* Handle partial allocation scenario */
2900 loff_t newsize;
2901
2902 newsize = (nblocks << blkbits) + i_size_read(inode);
2903 i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
2904 EXT4_I(inode)->i_disksize = i_size_read(inode);
2905 }
2906 } 2894 }
2907
2908 mutex_unlock(&inode->i_mutex); 2895 mutex_unlock(&inode->i_mutex);
2909 return ret > 0 ? ret2 : ret; 2896 return ret > 0 ? ret2 : ret;
2910} 2897}