diff options
author | Jiaying Zhang <jiayingz@google.com> | 2010-03-04 16:14:02 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2010-03-04 16:14:02 -0500 |
commit | 744692dc059845b2a3022119871846e74d4f6e11 (patch) | |
tree | ed246651aebcb8dae57de8c58dc20983064ee017 /fs/ext4/extents.c | |
parent | c7064ef13b2181a489836349f9baf87df0dab28f (diff) |
ext4: use ext4_get_block_write in buffer write
Allocate uninitialized extent before ext4 buffer write and
convert the extent to initialized after io completes.
The purpose is to make sure an extent can only be marked
initialized after it has been written with new data so
we can safely drop the i_mutex lock in ext4 DIO read without
exposing stale data. This helps to improve multi-thread DIO
read performance on high-speed disks.
Skip the nobh and data=journal mount cases to make things simple for now.
Signed-off-by: Jiaying Zhang <jiayingz@google.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 90ba8d9df697..c7f166ab50eb 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -1619,7 +1619,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, | |||
1619 | BUG_ON(path[depth].p_hdr == NULL); | 1619 | BUG_ON(path[depth].p_hdr == NULL); |
1620 | 1620 | ||
1621 | /* try to insert block into found extent and return */ | 1621 | /* try to insert block into found extent and return */ |
1622 | if (ex && (flag != EXT4_GET_BLOCKS_PRE_IO) | 1622 | if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO) |
1623 | && ext4_can_extents_be_merged(inode, ex, newext)) { | 1623 | && ext4_can_extents_be_merged(inode, ex, newext)) { |
1624 | ext_debug("append [%d]%d block to %d:[%d]%d (from %llu)\n", | 1624 | ext_debug("append [%d]%d block to %d:[%d]%d (from %llu)\n", |
1625 | ext4_ext_is_uninitialized(newext), | 1625 | ext4_ext_is_uninitialized(newext), |
@@ -1740,7 +1740,7 @@ has_space: | |||
1740 | 1740 | ||
1741 | merge: | 1741 | merge: |
1742 | /* try to merge extents to the right */ | 1742 | /* try to merge extents to the right */ |
1743 | if (flag != EXT4_GET_BLOCKS_PRE_IO) | 1743 | if (!(flag & EXT4_GET_BLOCKS_PRE_IO)) |
1744 | ext4_ext_try_to_merge(inode, path, nearex); | 1744 | ext4_ext_try_to_merge(inode, path, nearex); |
1745 | 1745 | ||
1746 | /* try to merge extents to the left */ | 1746 | /* try to merge extents to the left */ |
@@ -3065,7 +3065,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
3065 | ext4_ext_show_leaf(inode, path); | 3065 | ext4_ext_show_leaf(inode, path); |
3066 | 3066 | ||
3067 | /* get_block() before submit the IO, split the extent */ | 3067 | /* get_block() before submit the IO, split the extent */ |
3068 | if (flags == EXT4_GET_BLOCKS_PRE_IO) { | 3068 | if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { |
3069 | ret = ext4_split_unwritten_extents(handle, | 3069 | ret = ext4_split_unwritten_extents(handle, |
3070 | inode, path, iblock, | 3070 | inode, path, iblock, |
3071 | max_blocks, flags); | 3071 | max_blocks, flags); |
@@ -3078,10 +3078,12 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
3078 | io->flag = EXT4_IO_UNWRITTEN; | 3078 | io->flag = EXT4_IO_UNWRITTEN; |
3079 | else | 3079 | else |
3080 | ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN); | 3080 | ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN); |
3081 | if (ext4_should_dioread_nolock(inode)) | ||
3082 | set_buffer_uninit(bh_result); | ||
3081 | goto out; | 3083 | goto out; |
3082 | } | 3084 | } |
3083 | /* IO end_io complete, convert the filled extent to written */ | 3085 | /* IO end_io complete, convert the filled extent to written */ |
3084 | if (flags == EXT4_GET_BLOCKS_CONVERT) { | 3086 | if ((flags & EXT4_GET_BLOCKS_CONVERT)) { |
3085 | ret = ext4_convert_unwritten_extents_endio(handle, inode, | 3087 | ret = ext4_convert_unwritten_extents_endio(handle, inode, |
3086 | path); | 3088 | path); |
3087 | if (ret >= 0) | 3089 | if (ret >= 0) |
@@ -3351,21 +3353,21 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
3351 | if (flags & EXT4_GET_BLOCKS_UNINIT_EXT){ | 3353 | if (flags & EXT4_GET_BLOCKS_UNINIT_EXT){ |
3352 | ext4_ext_mark_uninitialized(&newex); | 3354 | ext4_ext_mark_uninitialized(&newex); |
3353 | /* | 3355 | /* |
3354 | * io_end structure was created for every async | 3356 | * io_end structure was created for every IO write to an |
3355 | * direct IO write to the middle of the file. | 3357 | * uninitialized extent. To avoid unecessary conversion, |
3356 | * To avoid unecessary convertion for every aio dio rewrite | 3358 | * here we flag the IO that really needs the conversion. |
3357 | * to the mid of file, here we flag the IO that is really | ||
3358 | * need the convertion. | ||
3359 | * For non asycn direct IO case, flag the inode state | 3359 | * For non asycn direct IO case, flag the inode state |
3360 | * that we need to perform convertion when IO is done. | 3360 | * that we need to perform convertion when IO is done. |
3361 | */ | 3361 | */ |
3362 | if (flags == EXT4_GET_BLOCKS_PRE_IO) { | 3362 | if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { |
3363 | if (io) | 3363 | if (io) |
3364 | io->flag = EXT4_IO_UNWRITTEN; | 3364 | io->flag = EXT4_IO_UNWRITTEN; |
3365 | else | 3365 | else |
3366 | ext4_set_inode_state(inode, | 3366 | ext4_set_inode_state(inode, |
3367 | EXT4_STATE_DIO_UNWRITTEN); | 3367 | EXT4_STATE_DIO_UNWRITTEN); |
3368 | } | 3368 | } |
3369 | if (ext4_should_dioread_nolock(inode)) | ||
3370 | set_buffer_uninit(bh_result); | ||
3369 | } | 3371 | } |
3370 | 3372 | ||
3371 | if (unlikely(EXT4_I(inode)->i_flags & EXT4_EOFBLOCKS_FL)) { | 3373 | if (unlikely(EXT4_I(inode)->i_flags & EXT4_EOFBLOCKS_FL)) { |