diff options
-rw-r--r-- | fs/ext4/ext4.h | 4 | ||||
-rw-r--r-- | fs/ext4/extents.c | 8 | ||||
-rw-r--r-- | fs/ext4/inode.c | 25 | ||||
-rw-r--r-- | include/trace/events/ext4.h | 3 |
4 files changed, 36 insertions, 4 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ffc6ab000c78..ae900b530d37 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -557,6 +557,10 @@ enum { | |||
557 | #define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080 | 557 | #define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080 |
558 | /* Convert written extents to unwritten */ | 558 | /* Convert written extents to unwritten */ |
559 | #define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0100 | 559 | #define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0100 |
560 | /* Write zeros to newly created written extents */ | ||
561 | #define EXT4_GET_BLOCKS_ZERO 0x0200 | ||
562 | #define EXT4_GET_BLOCKS_CREATE_ZERO (EXT4_GET_BLOCKS_CREATE |\ | ||
563 | EXT4_GET_BLOCKS_ZERO) | ||
560 | 564 | ||
561 | /* | 565 | /* |
562 | * The bit position of these flags must not overlap with any of the | 566 | * The bit position of these flags must not overlap with any of the |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 867e98b6bc6c..b52fea3b7219 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -4044,6 +4044,14 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode, | |||
4044 | } | 4044 | } |
4045 | /* IO end_io complete, convert the filled extent to written */ | 4045 | /* IO end_io complete, convert the filled extent to written */ |
4046 | if (flags & EXT4_GET_BLOCKS_CONVERT) { | 4046 | if (flags & EXT4_GET_BLOCKS_CONVERT) { |
4047 | if (flags & EXT4_GET_BLOCKS_ZERO) { | ||
4048 | if (allocated > map->m_len) | ||
4049 | allocated = map->m_len; | ||
4050 | err = ext4_issue_zeroout(inode, map->m_lblk, newblock, | ||
4051 | allocated); | ||
4052 | if (err < 0) | ||
4053 | goto out2; | ||
4054 | } | ||
4047 | ret = ext4_convert_unwritten_extents_endio(handle, inode, map, | 4055 | ret = ext4_convert_unwritten_extents_endio(handle, inode, map, |
4048 | ppath); | 4056 | ppath); |
4049 | if (ret >= 0) { | 4057 | if (ret >= 0) { |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 0c9a5ee3e106..4241d0cff062 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -637,13 +637,29 @@ found: | |||
637 | } | 637 | } |
638 | 638 | ||
639 | /* | 639 | /* |
640 | * We have to zeroout blocks before inserting them into extent | ||
641 | * status tree. Otherwise someone could look them up there and | ||
642 | * use them before they are really zeroed. | ||
643 | */ | ||
644 | if (flags & EXT4_GET_BLOCKS_ZERO && | ||
645 | map->m_flags & EXT4_MAP_MAPPED && | ||
646 | map->m_flags & EXT4_MAP_NEW) { | ||
647 | ret = ext4_issue_zeroout(inode, map->m_lblk, | ||
648 | map->m_pblk, map->m_len); | ||
649 | if (ret) { | ||
650 | retval = ret; | ||
651 | goto out_sem; | ||
652 | } | ||
653 | } | ||
654 | |||
655 | /* | ||
640 | * If the extent has been zeroed out, we don't need to update | 656 | * If the extent has been zeroed out, we don't need to update |
641 | * extent status tree. | 657 | * extent status tree. |
642 | */ | 658 | */ |
643 | if ((flags & EXT4_GET_BLOCKS_PRE_IO) && | 659 | if ((flags & EXT4_GET_BLOCKS_PRE_IO) && |
644 | ext4_es_lookup_extent(inode, map->m_lblk, &es)) { | 660 | ext4_es_lookup_extent(inode, map->m_lblk, &es)) { |
645 | if (ext4_es_is_written(&es)) | 661 | if (ext4_es_is_written(&es)) |
646 | goto has_zeroout; | 662 | goto out_sem; |
647 | } | 663 | } |
648 | status = map->m_flags & EXT4_MAP_UNWRITTEN ? | 664 | status = map->m_flags & EXT4_MAP_UNWRITTEN ? |
649 | EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; | 665 | EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; |
@@ -654,11 +670,13 @@ found: | |||
654 | status |= EXTENT_STATUS_DELAYED; | 670 | status |= EXTENT_STATUS_DELAYED; |
655 | ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, | 671 | ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, |
656 | map->m_pblk, status); | 672 | map->m_pblk, status); |
657 | if (ret < 0) | 673 | if (ret < 0) { |
658 | retval = ret; | 674 | retval = ret; |
675 | goto out_sem; | ||
676 | } | ||
659 | } | 677 | } |
660 | 678 | ||
661 | has_zeroout: | 679 | out_sem: |
662 | up_write((&EXT4_I(inode)->i_data_sem)); | 680 | up_write((&EXT4_I(inode)->i_data_sem)); |
663 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { | 681 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { |
664 | ret = check_block_validity(inode, map); | 682 | ret = check_block_validity(inode, map); |
@@ -3083,6 +3101,7 @@ int ext4_get_block_dax(struct inode *inode, sector_t iblock, | |||
3083 | struct buffer_head *bh_result, int create) | 3101 | struct buffer_head *bh_result, int create) |
3084 | { | 3102 | { |
3085 | int flags = EXT4_GET_BLOCKS_PRE_IO | EXT4_GET_BLOCKS_UNWRIT_EXT; | 3103 | int flags = EXT4_GET_BLOCKS_PRE_IO | EXT4_GET_BLOCKS_UNWRIT_EXT; |
3104 | |||
3086 | if (create) | 3105 | if (create) |
3087 | flags |= EXT4_GET_BLOCKS_CREATE; | 3106 | flags |= EXT4_GET_BLOCKS_CREATE; |
3088 | ext4_debug("ext4_get_block_dax: inode %lu, create flag %d\n", | 3107 | ext4_debug("ext4_get_block_dax: inode %lu, create flag %d\n", |
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 5f2ace56efc5..4e4b2fa78609 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h | |||
@@ -42,7 +42,8 @@ struct extent_status; | |||
42 | { EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \ | 42 | { EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \ |
43 | { EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \ | 43 | { EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \ |
44 | { EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \ | 44 | { EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \ |
45 | { EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }) | 45 | { EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \ |
46 | { EXT4_GET_BLOCKS_ZERO, "ZERO" }) | ||
46 | 47 | ||
47 | #define show_mflags(flags) __print_flags(flags, "", \ | 48 | #define show_mflags(flags) __print_flags(flags, "", \ |
48 | { EXT4_MAP_NEW, "N" }, \ | 49 | { EXT4_MAP_NEW, "N" }, \ |