diff options
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 89 |
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 | ||
2788 | static 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 | } |