diff options
| -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; |
