diff options
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/extents.c | 35 | ||||
-rw-r--r-- | fs/ext4/extents_status.c | 17 | ||||
-rw-r--r-- | fs/ext4/extents_status.h | 3 | ||||
-rw-r--r-- | fs/ext4/inode.c | 10 |
4 files changed, 61 insertions, 4 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 110e85a1f82a..7e37018d1753 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -2925,7 +2925,7 @@ static int ext4_split_extent_at(handle_t *handle, | |||
2925 | { | 2925 | { |
2926 | ext4_fsblk_t newblock; | 2926 | ext4_fsblk_t newblock; |
2927 | ext4_lblk_t ee_block; | 2927 | ext4_lblk_t ee_block; |
2928 | struct ext4_extent *ex, newex, orig_ex; | 2928 | struct ext4_extent *ex, newex, orig_ex, zero_ex; |
2929 | struct ext4_extent *ex2 = NULL; | 2929 | struct ext4_extent *ex2 = NULL; |
2930 | unsigned int ee_len, depth; | 2930 | unsigned int ee_len, depth; |
2931 | int err = 0; | 2931 | int err = 0; |
@@ -2996,12 +2996,26 @@ static int ext4_split_extent_at(handle_t *handle, | |||
2996 | err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); | 2996 | err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); |
2997 | if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) { | 2997 | if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) { |
2998 | if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) { | 2998 | if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) { |
2999 | if (split_flag & EXT4_EXT_DATA_VALID1) | 2999 | if (split_flag & EXT4_EXT_DATA_VALID1) { |
3000 | err = ext4_ext_zeroout(inode, ex2); | 3000 | err = ext4_ext_zeroout(inode, ex2); |
3001 | else | 3001 | zero_ex.ee_block = ex2->ee_block; |
3002 | zero_ex.ee_len = ext4_ext_get_actual_len(ex2); | ||
3003 | ext4_ext_store_pblock(&zero_ex, | ||
3004 | ext4_ext_pblock(ex2)); | ||
3005 | } else { | ||
3002 | err = ext4_ext_zeroout(inode, ex); | 3006 | err = ext4_ext_zeroout(inode, ex); |
3003 | } else | 3007 | zero_ex.ee_block = ex->ee_block; |
3008 | zero_ex.ee_len = ext4_ext_get_actual_len(ex); | ||
3009 | ext4_ext_store_pblock(&zero_ex, | ||
3010 | ext4_ext_pblock(ex)); | ||
3011 | } | ||
3012 | } else { | ||
3004 | err = ext4_ext_zeroout(inode, &orig_ex); | 3013 | err = ext4_ext_zeroout(inode, &orig_ex); |
3014 | zero_ex.ee_block = orig_ex.ee_block; | ||
3015 | zero_ex.ee_len = ext4_ext_get_actual_len(&orig_ex); | ||
3016 | ext4_ext_store_pblock(&zero_ex, | ||
3017 | ext4_ext_pblock(&orig_ex)); | ||
3018 | } | ||
3005 | 3019 | ||
3006 | if (err) | 3020 | if (err) |
3007 | goto fix_extent_len; | 3021 | goto fix_extent_len; |
@@ -3009,6 +3023,12 @@ static int ext4_split_extent_at(handle_t *handle, | |||
3009 | ex->ee_len = cpu_to_le16(ee_len); | 3023 | ex->ee_len = cpu_to_le16(ee_len); |
3010 | ext4_ext_try_to_merge(handle, inode, path, ex); | 3024 | ext4_ext_try_to_merge(handle, inode, path, ex); |
3011 | err = ext4_ext_dirty(handle, inode, path + path->p_depth); | 3025 | err = ext4_ext_dirty(handle, inode, path + path->p_depth); |
3026 | if (err) | ||
3027 | goto fix_extent_len; | ||
3028 | |||
3029 | /* update extent status tree */ | ||
3030 | err = ext4_es_zeroout(inode, &zero_ex); | ||
3031 | |||
3012 | goto out; | 3032 | goto out; |
3013 | } else if (err) | 3033 | } else if (err) |
3014 | goto fix_extent_len; | 3034 | goto fix_extent_len; |
@@ -3150,6 +3170,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
3150 | ee_block = le32_to_cpu(ex->ee_block); | 3170 | ee_block = le32_to_cpu(ex->ee_block); |
3151 | ee_len = ext4_ext_get_actual_len(ex); | 3171 | ee_len = ext4_ext_get_actual_len(ex); |
3152 | allocated = ee_len - (map->m_lblk - ee_block); | 3172 | allocated = ee_len - (map->m_lblk - ee_block); |
3173 | zero_ex.ee_len = 0; | ||
3153 | 3174 | ||
3154 | trace_ext4_ext_convert_to_initialized_enter(inode, map, ex); | 3175 | trace_ext4_ext_convert_to_initialized_enter(inode, map, ex); |
3155 | 3176 | ||
@@ -3247,6 +3268,9 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
3247 | err = ext4_ext_zeroout(inode, ex); | 3268 | err = ext4_ext_zeroout(inode, ex); |
3248 | if (err) | 3269 | if (err) |
3249 | goto out; | 3270 | goto out; |
3271 | zero_ex.ee_block = ex->ee_block; | ||
3272 | zero_ex.ee_len = ext4_ext_get_actual_len(ex); | ||
3273 | ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex)); | ||
3250 | 3274 | ||
3251 | err = ext4_ext_get_access(handle, inode, path + depth); | 3275 | err = ext4_ext_get_access(handle, inode, path + depth); |
3252 | if (err) | 3276 | if (err) |
@@ -3305,6 +3329,9 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
3305 | err = allocated; | 3329 | err = allocated; |
3306 | 3330 | ||
3307 | out: | 3331 | out: |
3332 | /* If we have gotten a failure, don't zero out status tree */ | ||
3333 | if (!err) | ||
3334 | err = ext4_es_zeroout(inode, &zero_ex); | ||
3308 | return err ? err : allocated; | 3335 | return err ? err : allocated; |
3309 | } | 3336 | } |
3310 | 3337 | ||
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index d2a8cb74676b..fe3337a85ede 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c | |||
@@ -854,6 +854,23 @@ int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk, | |||
854 | return err; | 854 | return err; |
855 | } | 855 | } |
856 | 856 | ||
857 | int ext4_es_zeroout(struct inode *inode, struct ext4_extent *ex) | ||
858 | { | ||
859 | ext4_lblk_t ee_block; | ||
860 | ext4_fsblk_t ee_pblock; | ||
861 | unsigned int ee_len; | ||
862 | |||
863 | ee_block = le32_to_cpu(ex->ee_block); | ||
864 | ee_len = ext4_ext_get_actual_len(ex); | ||
865 | ee_pblock = ext4_ext_pblock(ex); | ||
866 | |||
867 | if (ee_len == 0) | ||
868 | return 0; | ||
869 | |||
870 | return ext4_es_insert_extent(inode, ee_block, ee_len, ee_pblock, | ||
871 | EXTENT_STATUS_WRITTEN); | ||
872 | } | ||
873 | |||
857 | static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | 874 | static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) |
858 | { | 875 | { |
859 | struct ext4_sb_info *sbi = container_of(shrink, | 876 | struct ext4_sb_info *sbi = container_of(shrink, |
diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h index 56140ad4150b..d8e2d4dc311e 100644 --- a/fs/ext4/extents_status.h +++ b/fs/ext4/extents_status.h | |||
@@ -39,6 +39,8 @@ | |||
39 | EXTENT_STATUS_DELAYED | \ | 39 | EXTENT_STATUS_DELAYED | \ |
40 | EXTENT_STATUS_HOLE) | 40 | EXTENT_STATUS_HOLE) |
41 | 41 | ||
42 | struct ext4_extent; | ||
43 | |||
42 | struct extent_status { | 44 | struct extent_status { |
43 | struct rb_node rb_node; | 45 | struct rb_node rb_node; |
44 | ext4_lblk_t es_lblk; /* first logical block extent covers */ | 46 | ext4_lblk_t es_lblk; /* first logical block extent covers */ |
@@ -64,6 +66,7 @@ extern void ext4_es_find_delayed_extent(struct inode *inode, ext4_lblk_t lblk, | |||
64 | struct extent_status *es); | 66 | struct extent_status *es); |
65 | extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, | 67 | extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, |
66 | struct extent_status *es); | 68 | struct extent_status *es); |
69 | extern int ext4_es_zeroout(struct inode *inode, struct ext4_extent *ex); | ||
67 | 70 | ||
68 | static inline int ext4_es_is_written(struct extent_status *es) | 71 | static inline int ext4_es_is_written(struct extent_status *es) |
69 | { | 72 | { |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 3186a43fa4b0..4f1d54a88d8c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -722,6 +722,15 @@ found: | |||
722 | } | 722 | } |
723 | #endif | 723 | #endif |
724 | 724 | ||
725 | /* | ||
726 | * If the extent has been zeroed out, we don't need to update | ||
727 | * extent status tree. | ||
728 | */ | ||
729 | if ((flags & EXT4_GET_BLOCKS_PRE_IO) && | ||
730 | ext4_es_lookup_extent(inode, map->m_lblk, &es)) { | ||
731 | if (ext4_es_is_written(&es)) | ||
732 | goto has_zeroout; | ||
733 | } | ||
725 | status = map->m_flags & EXT4_MAP_UNWRITTEN ? | 734 | status = map->m_flags & EXT4_MAP_UNWRITTEN ? |
726 | EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; | 735 | EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; |
727 | if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && | 736 | if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && |
@@ -734,6 +743,7 @@ found: | |||
734 | retval = ret; | 743 | retval = ret; |
735 | } | 744 | } |
736 | 745 | ||
746 | has_zeroout: | ||
737 | up_write((&EXT4_I(inode)->i_data_sem)); | 747 | up_write((&EXT4_I(inode)->i_data_sem)); |
738 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { | 748 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { |
739 | int ret = check_block_validity(inode, map); | 749 | int ret = check_block_validity(inode, map); |