diff options
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 67 |
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; |
2879 | insert: | 2898 | insert: |
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; |
3064 | insert: | 3099 | insert: |
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; |