aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2010-05-16 06:00:00 -0400
committerTheodore Ts'o <tytso@mit.edu>2010-05-16 06:00:00 -0400
commit21ca087a3891efab4d45488db8febee474d26c68 (patch)
tree343af5d07c11d614835eac004be36382cec27dc0 /fs/ext4/extents.c
parentc35a56a090eacefca07afeb994029b57d8dd8025 (diff)
ext4: Do not zero out uninitialized extents beyond i_size
The extents code will sometimes zero out blocks and mark them as initialized instead of splitting an extent into several smaller ones. This optimization however, causes problems if the extent is beyond i_size because fsck will complain if there are uninitialized blocks after i_size as this can not be distinguished from an inode that has an incorrect i_size field. https://bugzilla.kernel.org/show_bug.cgi?id=15742 Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r--fs/ext4/extents.c67
1 files changed, 51 insertions, 16 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 228eeaf2dccf..ee611daf0748 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2631,11 +2631,21 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2631 struct ext4_extent *ex2 = NULL; 2631 struct ext4_extent *ex2 = NULL;
2632 struct ext4_extent *ex3 = NULL; 2632 struct ext4_extent *ex3 = NULL;
2633 struct ext4_extent_header *eh; 2633 struct ext4_extent_header *eh;
2634 ext4_lblk_t ee_block; 2634 ext4_lblk_t ee_block, eof_block;
2635 unsigned int allocated, ee_len, depth; 2635 unsigned int allocated, ee_len, depth;
2636 ext4_fsblk_t newblock; 2636 ext4_fsblk_t newblock;
2637 int err = 0; 2637 int err = 0;
2638 int ret = 0; 2638 int ret = 0;
2639 int may_zeroout;
2640
2641 ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical"
2642 "block %llu, max_blocks %u\n", inode->i_ino,
2643 (unsigned long long)iblock, max_blocks);
2644
2645 eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
2646 inode->i_sb->s_blocksize_bits;
2647 if (eof_block < iblock + max_blocks)
2648 eof_block = iblock + max_blocks;
2639 2649
2640 depth = ext_depth(inode); 2650 depth = ext_depth(inode);
2641 eh = path[depth].p_hdr; 2651 eh = path[depth].p_hdr;
@@ -2644,16 +2654,23 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2644 ee_len = ext4_ext_get_actual_len(ex); 2654 ee_len = ext4_ext_get_actual_len(ex);
2645 allocated = ee_len - (iblock - ee_block); 2655 allocated = ee_len - (iblock - ee_block);
2646 newblock = iblock - ee_block + ext_pblock(ex); 2656 newblock = iblock - ee_block + ext_pblock(ex);
2657
2647 ex2 = ex; 2658 ex2 = ex;
2648 orig_ex.ee_block = ex->ee_block; 2659 orig_ex.ee_block = ex->ee_block;
2649 orig_ex.ee_len = cpu_to_le16(ee_len); 2660 orig_ex.ee_len = cpu_to_le16(ee_len);
2650 ext4_ext_store_pblock(&orig_ex, ext_pblock(ex)); 2661 ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
2651 2662
2663 /*
2664 * It is safe to convert extent to initialized via explicit
2665 * zeroout only if extent is fully insde i_size or new_size.
2666 */
2667 may_zeroout = ee_block + ee_len <= eof_block;
2668
2652 err = ext4_ext_get_access(handle, inode, path + depth); 2669 err = ext4_ext_get_access(handle, inode, path + depth);
2653 if (err) 2670 if (err)
2654 goto out; 2671 goto out;
2655 /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */ 2672 /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */
2656 if (ee_len <= 2*EXT4_EXT_ZERO_LEN) { 2673 if (ee_len <= 2*EXT4_EXT_ZERO_LEN && may_zeroout) {
2657 err = ext4_ext_zeroout(inode, &orig_ex); 2674 err = ext4_ext_zeroout(inode, &orig_ex);
2658 if (err) 2675 if (err)
2659 goto fix_extent_len; 2676 goto fix_extent_len;
@@ -2684,7 +2701,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2684 if (allocated > max_blocks) { 2701 if (allocated > max_blocks) {
2685 unsigned int newdepth; 2702 unsigned int newdepth;
2686 /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */ 2703 /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
2687 if (allocated <= EXT4_EXT_ZERO_LEN) { 2704 if (allocated <= EXT4_EXT_ZERO_LEN && may_zeroout) {
2688 /* 2705 /*
2689 * iblock == ee_block is handled by the zerouout 2706 * iblock == ee_block is handled by the zerouout
2690 * at the beginning. 2707 * at the beginning.
@@ -2760,7 +2777,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2760 ex3->ee_len = cpu_to_le16(allocated - max_blocks); 2777 ex3->ee_len = cpu_to_le16(allocated - max_blocks);
2761 ext4_ext_mark_uninitialized(ex3); 2778 ext4_ext_mark_uninitialized(ex3);
2762 err = ext4_ext_insert_extent(handle, inode, path, ex3, 0); 2779 err = ext4_ext_insert_extent(handle, inode, path, ex3, 0);
2763 if (err == -ENOSPC) { 2780 if (err == -ENOSPC && may_zeroout) {
2764 err = ext4_ext_zeroout(inode, &orig_ex); 2781 err = ext4_ext_zeroout(inode, &orig_ex);
2765 if (err) 2782 if (err)
2766 goto fix_extent_len; 2783 goto fix_extent_len;
@@ -2784,8 +2801,10 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2784 * update the extent length after successful insert of the 2801 * update the extent length after successful insert of the
2785 * split extent 2802 * split extent
2786 */ 2803 */
2787 orig_ex.ee_len = cpu_to_le16(ee_len - 2804 ee_len -= ext4_ext_get_actual_len(ex3);
2788 ext4_ext_get_actual_len(ex3)); 2805 orig_ex.ee_len = cpu_to_le16(ee_len);
2806 may_zeroout = ee_block + ee_len <= eof_block;
2807
2789 depth = newdepth; 2808 depth = newdepth;
2790 ext4_ext_drop_refs(path); 2809 ext4_ext_drop_refs(path);
2791 path = ext4_ext_find_extent(inode, iblock, path); 2810 path = ext4_ext_find_extent(inode, iblock, path);
@@ -2809,7 +2828,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2809 * otherwise give the extent a chance to merge to left 2828 * otherwise give the extent a chance to merge to left
2810 */ 2829 */
2811 if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN && 2830 if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
2812 iblock != ee_block) { 2831 iblock != ee_block && may_zeroout) {
2813 err = ext4_ext_zeroout(inode, &orig_ex); 2832 err = ext4_ext_zeroout(inode, &orig_ex);
2814 if (err) 2833 if (err)
2815 goto fix_extent_len; 2834 goto fix_extent_len;
@@ -2878,7 +2897,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
2878 goto out; 2897 goto out;
2879insert: 2898insert:
2880 err = ext4_ext_insert_extent(handle, inode, path, &newex, 0); 2899 err = ext4_ext_insert_extent(handle, inode, path, &newex, 0);
2881 if (err == -ENOSPC) { 2900 if (err == -ENOSPC && may_zeroout) {
2882 err = ext4_ext_zeroout(inode, &orig_ex); 2901 err = ext4_ext_zeroout(inode, &orig_ex);
2883 if (err) 2902 if (err)
2884 goto fix_extent_len; 2903 goto fix_extent_len;
@@ -2938,14 +2957,21 @@ static int ext4_split_unwritten_extents(handle_t *handle,
2938 struct ext4_extent *ex2 = NULL; 2957 struct ext4_extent *ex2 = NULL;
2939 struct ext4_extent *ex3 = NULL; 2958 struct ext4_extent *ex3 = NULL;
2940 struct ext4_extent_header *eh; 2959 struct ext4_extent_header *eh;
2941 ext4_lblk_t ee_block; 2960 ext4_lblk_t ee_block, eof_block;
2942 unsigned int allocated, ee_len, depth; 2961 unsigned int allocated, ee_len, depth;
2943 ext4_fsblk_t newblock; 2962 ext4_fsblk_t newblock;
2944 int err = 0; 2963 int err = 0;
2964 int may_zeroout;
2965
2966 ext_debug("ext4_split_unwritten_extents: inode %lu, logical"
2967 "block %llu, max_blocks %u\n", inode->i_ino,
2968 (unsigned long long)iblock, max_blocks);
2969
2970 eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
2971 inode->i_sb->s_blocksize_bits;
2972 if (eof_block < iblock + max_blocks)
2973 eof_block = iblock + max_blocks;
2945 2974
2946 ext_debug("ext4_split_unwritten_extents: inode %lu,"
2947 "iblock %llu, max_blocks %u\n", inode->i_ino,
2948 (unsigned long long)iblock, max_blocks);
2949 depth = ext_depth(inode); 2975 depth = ext_depth(inode);
2950 eh = path[depth].p_hdr; 2976 eh = path[depth].p_hdr;
2951 ex = path[depth].p_ext; 2977 ex = path[depth].p_ext;
@@ -2953,12 +2979,19 @@ static int ext4_split_unwritten_extents(handle_t *handle,
2953 ee_len = ext4_ext_get_actual_len(ex); 2979 ee_len = ext4_ext_get_actual_len(ex);
2954 allocated = ee_len - (iblock - ee_block); 2980 allocated = ee_len - (iblock - ee_block);
2955 newblock = iblock - ee_block + ext_pblock(ex); 2981 newblock = iblock - ee_block + ext_pblock(ex);
2982
2956 ex2 = ex; 2983 ex2 = ex;
2957 orig_ex.ee_block = ex->ee_block; 2984 orig_ex.ee_block = ex->ee_block;
2958 orig_ex.ee_len = cpu_to_le16(ee_len); 2985 orig_ex.ee_len = cpu_to_le16(ee_len);
2959 ext4_ext_store_pblock(&orig_ex, ext_pblock(ex)); 2986 ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
2960 2987
2961 /* 2988 /*
2989 * It is safe to convert extent to initialized via explicit
2990 * zeroout only if extent is fully insde i_size or new_size.
2991 */
2992 may_zeroout = ee_block + ee_len <= eof_block;
2993
2994 /*
2962 * If the uninitialized extent begins at the same logical 2995 * If the uninitialized extent begins at the same logical
2963 * block where the write begins, and the write completely 2996 * block where the write begins, and the write completely
2964 * covers the extent, then we don't need to split it. 2997 * covers the extent, then we don't need to split it.
@@ -2992,7 +3025,7 @@ static int ext4_split_unwritten_extents(handle_t *handle,
2992 ex3->ee_len = cpu_to_le16(allocated - max_blocks); 3025 ex3->ee_len = cpu_to_le16(allocated - max_blocks);
2993 ext4_ext_mark_uninitialized(ex3); 3026 ext4_ext_mark_uninitialized(ex3);
2994 err = ext4_ext_insert_extent(handle, inode, path, ex3, flags); 3027 err = ext4_ext_insert_extent(handle, inode, path, ex3, flags);
2995 if (err == -ENOSPC) { 3028 if (err == -ENOSPC && may_zeroout) {
2996 err = ext4_ext_zeroout(inode, &orig_ex); 3029 err = ext4_ext_zeroout(inode, &orig_ex);
2997 if (err) 3030 if (err)
2998 goto fix_extent_len; 3031 goto fix_extent_len;
@@ -3016,8 +3049,10 @@ static int ext4_split_unwritten_extents(handle_t *handle,
3016 * update the extent length after successful insert of the 3049 * update the extent length after successful insert of the
3017 * split extent 3050 * split extent
3018 */ 3051 */
3019 orig_ex.ee_len = cpu_to_le16(ee_len - 3052 ee_len -= ext4_ext_get_actual_len(ex3);
3020 ext4_ext_get_actual_len(ex3)); 3053 orig_ex.ee_len = cpu_to_le16(ee_len);
3054 may_zeroout = ee_block + ee_len <= eof_block;
3055
3021 depth = newdepth; 3056 depth = newdepth;
3022 ext4_ext_drop_refs(path); 3057 ext4_ext_drop_refs(path);
3023 path = ext4_ext_find_extent(inode, iblock, path); 3058 path = ext4_ext_find_extent(inode, iblock, path);
@@ -3063,7 +3098,7 @@ static int ext4_split_unwritten_extents(handle_t *handle,
3063 goto out; 3098 goto out;
3064insert: 3099insert:
3065 err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); 3100 err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
3066 if (err == -ENOSPC) { 3101 if (err == -ENOSPC && may_zeroout) {
3067 err = ext4_ext_zeroout(inode, &orig_ex); 3102 err = ext4_ext_zeroout(inode, &orig_ex);
3068 if (err) 3103 if (err)
3069 goto fix_extent_len; 3104 goto fix_extent_len;