aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2014-03-18 18:05:35 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-03-18 18:05:35 -0400
commitb8a8684502a0fc852afa0056c6bb2a9273f6fcc0 (patch)
tree3b7c2058c86f5247a31e02e1a04182c40775e268
parent0e8b6879f3c234036181526683be2b0231892ae4 (diff)
ext4: Introduce FALLOC_FL_ZERO_RANGE flag for fallocate
Introduce new FALLOC_FL_ZERO_RANGE flag for fallocate. This has the same functionality as xfs ioctl XFS_IOC_ZERO_RANGE. It can be used to convert a range of file to zeros preferably without issuing data IO. Blocks should be preallocated for the regions that span holes in the file, and the entire range is preferable converted to unwritten extents This can be also used to preallocate blocks past EOF in the same way as with fallocate. Flag FALLOC_FL_KEEP_SIZE which should cause the inode size to remain the same. Also add appropriate tracepoints. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/ext4.h2
-rw-r--r--fs/ext4/extents.c273
-rw-r--r--fs/ext4/inode.c17
-rw-r--r--include/trace/events/ext4.h68
4 files changed, 307 insertions, 53 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index beec42750a8c..1b3cbf8cacf9 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -568,6 +568,8 @@ enum {
568#define EXT4_GET_BLOCKS_NO_LOCK 0x0100 568#define EXT4_GET_BLOCKS_NO_LOCK 0x0100
569 /* Do not put hole in extent cache */ 569 /* Do not put hole in extent cache */
570#define EXT4_GET_BLOCKS_NO_PUT_HOLE 0x0200 570#define EXT4_GET_BLOCKS_NO_PUT_HOLE 0x0200
571 /* Convert written extents to unwritten */
572#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0400
571 573
572/* 574/*
573 * The bit position of these flags must not overlap with any of the 575 * 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 2db2d77769a2..464e95da716e 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3602,6 +3602,8 @@ out:
3602 * b> Splits in two extents: Write is happening at either end of the extent 3602 * b> Splits in two extents: Write is happening at either end of the extent
3603 * c> Splits in three extents: Somone is writing in middle of the extent 3603 * c> Splits in three extents: Somone is writing in middle of the extent
3604 * 3604 *
3605 * This works the same way in the case of initialized -> unwritten conversion.
3606 *
3605 * One of more index blocks maybe needed if the extent tree grow after 3607 * One of more index blocks maybe needed if the extent tree grow after
3606 * the uninitialized extent split. To prevent ENOSPC occur at the IO 3608 * the uninitialized extent split. To prevent ENOSPC occur at the IO
3607 * complete, we need to split the uninitialized extent before DIO submit 3609 * complete, we need to split the uninitialized extent before DIO submit
@@ -3612,7 +3614,7 @@ out:
3612 * 3614 *
3613 * Returns the size of uninitialized extent to be written on success. 3615 * Returns the size of uninitialized extent to be written on success.
3614 */ 3616 */
3615static int ext4_split_unwritten_extents(handle_t *handle, 3617static int ext4_split_convert_extents(handle_t *handle,
3616 struct inode *inode, 3618 struct inode *inode,
3617 struct ext4_map_blocks *map, 3619 struct ext4_map_blocks *map,
3618 struct ext4_ext_path *path, 3620 struct ext4_ext_path *path,
@@ -3624,9 +3626,9 @@ static int ext4_split_unwritten_extents(handle_t *handle,
3624 unsigned int ee_len; 3626 unsigned int ee_len;
3625 int split_flag = 0, depth; 3627 int split_flag = 0, depth;
3626 3628
3627 ext_debug("ext4_split_unwritten_extents: inode %lu, logical" 3629 ext_debug("%s: inode %lu, logical block %llu, max_blocks %u\n",
3628 "block %llu, max_blocks %u\n", inode->i_ino, 3630 __func__, inode->i_ino,
3629 (unsigned long long)map->m_lblk, map->m_len); 3631 (unsigned long long)map->m_lblk, map->m_len);
3630 3632
3631 eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> 3633 eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
3632 inode->i_sb->s_blocksize_bits; 3634 inode->i_sb->s_blocksize_bits;
@@ -3641,14 +3643,73 @@ static int ext4_split_unwritten_extents(handle_t *handle,
3641 ee_block = le32_to_cpu(ex->ee_block); 3643 ee_block = le32_to_cpu(ex->ee_block);
3642 ee_len = ext4_ext_get_actual_len(ex); 3644 ee_len = ext4_ext_get_actual_len(ex);
3643 3645
3644 split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0; 3646 /* Convert to unwritten */
3645 split_flag |= EXT4_EXT_MARK_UNINIT2; 3647 if (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN) {
3646 if (flags & EXT4_GET_BLOCKS_CONVERT) 3648 split_flag |= EXT4_EXT_DATA_VALID1;
3647 split_flag |= EXT4_EXT_DATA_VALID2; 3649 /* Convert to initialized */
3650 } else if (flags & EXT4_GET_BLOCKS_CONVERT) {
3651 split_flag |= ee_block + ee_len <= eof_block ?
3652 EXT4_EXT_MAY_ZEROOUT : 0;
3653 split_flag |= (EXT4_EXT_MARK_UNINIT2 | EXT4_EXT_DATA_VALID2);
3654 }
3648 flags |= EXT4_GET_BLOCKS_PRE_IO; 3655 flags |= EXT4_GET_BLOCKS_PRE_IO;
3649 return ext4_split_extent(handle, inode, path, map, split_flag, flags); 3656 return ext4_split_extent(handle, inode, path, map, split_flag, flags);
3650} 3657}
3651 3658
3659static int ext4_convert_initialized_extents(handle_t *handle,
3660 struct inode *inode,
3661 struct ext4_map_blocks *map,
3662 struct ext4_ext_path *path)
3663{
3664 struct ext4_extent *ex;
3665 ext4_lblk_t ee_block;
3666 unsigned int ee_len;
3667 int depth;
3668 int err = 0;
3669
3670 depth = ext_depth(inode);
3671 ex = path[depth].p_ext;
3672 ee_block = le32_to_cpu(ex->ee_block);
3673 ee_len = ext4_ext_get_actual_len(ex);
3674
3675 ext_debug("%s: inode %lu, logical"
3676 "block %llu, max_blocks %u\n", __func__, inode->i_ino,
3677 (unsigned long long)ee_block, ee_len);
3678
3679 if (ee_block != map->m_lblk || ee_len > map->m_len) {
3680 err = ext4_split_convert_extents(handle, inode, map, path,
3681 EXT4_GET_BLOCKS_CONVERT_UNWRITTEN);
3682 if (err < 0)
3683 goto out;
3684 ext4_ext_drop_refs(path);
3685 path = ext4_ext_find_extent(inode, map->m_lblk, path, 0);
3686 if (IS_ERR(path)) {
3687 err = PTR_ERR(path);
3688 goto out;
3689 }
3690 depth = ext_depth(inode);
3691 ex = path[depth].p_ext;
3692 }
3693
3694 err = ext4_ext_get_access(handle, inode, path + depth);
3695 if (err)
3696 goto out;
3697 /* first mark the extent as uninitialized */
3698 ext4_ext_mark_uninitialized(ex);
3699
3700 /* note: ext4_ext_correct_indexes() isn't needed here because
3701 * borders are not changed
3702 */
3703 ext4_ext_try_to_merge(handle, inode, path, ex);
3704
3705 /* Mark modified extent as dirty */
3706 err = ext4_ext_dirty(handle, inode, path + path->p_depth);
3707out:
3708 ext4_ext_show_leaf(inode, path);
3709 return err;
3710}
3711
3712
3652static int ext4_convert_unwritten_extents_endio(handle_t *handle, 3713static int ext4_convert_unwritten_extents_endio(handle_t *handle,
3653 struct inode *inode, 3714 struct inode *inode,
3654 struct ext4_map_blocks *map, 3715 struct ext4_map_blocks *map,
@@ -3682,8 +3743,8 @@ static int ext4_convert_unwritten_extents_endio(handle_t *handle,
3682 inode->i_ino, (unsigned long long)ee_block, ee_len, 3743 inode->i_ino, (unsigned long long)ee_block, ee_len,
3683 (unsigned long long)map->m_lblk, map->m_len); 3744 (unsigned long long)map->m_lblk, map->m_len);
3684#endif 3745#endif
3685 err = ext4_split_unwritten_extents(handle, inode, map, path, 3746 err = ext4_split_convert_extents(handle, inode, map, path,
3686 EXT4_GET_BLOCKS_CONVERT); 3747 EXT4_GET_BLOCKS_CONVERT);
3687 if (err < 0) 3748 if (err < 0)
3688 goto out; 3749 goto out;
3689 ext4_ext_drop_refs(path); 3750 ext4_ext_drop_refs(path);
@@ -3884,6 +3945,38 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start,
3884} 3945}
3885 3946
3886static int 3947static int
3948ext4_ext_convert_initialized_extent(handle_t *handle, struct inode *inode,
3949 struct ext4_map_blocks *map,
3950 struct ext4_ext_path *path, int flags,
3951 unsigned int allocated, ext4_fsblk_t newblock)
3952{
3953 int ret = 0;
3954 int err = 0;
3955
3956 /*
3957 * Make sure that the extent is no bigger than we support with
3958 * uninitialized extent
3959 */
3960 if (map->m_len > EXT_UNINIT_MAX_LEN)
3961 map->m_len = EXT_UNINIT_MAX_LEN / 2;
3962
3963 ret = ext4_convert_initialized_extents(handle, inode, map,
3964 path);
3965 if (ret >= 0) {
3966 ext4_update_inode_fsync_trans(handle, inode, 1);
3967 err = check_eofblocks_fl(handle, inode, map->m_lblk,
3968 path, map->m_len);
3969 } else
3970 err = ret;
3971 map->m_flags |= EXT4_MAP_UNWRITTEN;
3972 if (allocated > map->m_len)
3973 allocated = map->m_len;
3974 map->m_len = allocated;
3975
3976 return err ? err : allocated;
3977}
3978
3979static int
3887ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, 3980ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
3888 struct ext4_map_blocks *map, 3981 struct ext4_map_blocks *map,
3889 struct ext4_ext_path *path, int flags,