diff options
author | Dmitry Monakhov <dmonakhov@openvz.org> | 2012-09-28 23:36:25 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-09-28 23:36:25 -0400 |
commit | 82e54229118785badffb4ef5ba4803df25fe007f (patch) | |
tree | 270d0afb27dce342b7508cd05bb0db45cdad089d /fs/ext4/extents.c | |
parent | e27f41e1b789e60e7d8cc9c81fd93ca49ef31f13 (diff) |
ext4: fix unwritten counter leakage
ext4_set_io_unwritten_flag() will increment i_unwritten counter, so
once we mark end_io with EXT4_END_IO_UNWRITTEN we have to revert it back
on error path.
- add missed error checks to prevent counter leakage
- ext4_end_io_nolock() will clear EXT4_END_IO_UNWRITTEN flag to signal
that conversion finished.
- add BUG_ON to ext4_free_end_io() to prevent similar leakage in future.
Visible effect of this bug is that unaligned aio_stress may deadlock
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index a1f56c3e773b..54a94426ef7b 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -3633,6 +3633,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
3633 | if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { | 3633 | if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { |
3634 | ret = ext4_split_unwritten_extents(handle, inode, map, | 3634 | ret = ext4_split_unwritten_extents(handle, inode, map, |
3635 | path, flags); | 3635 | path, flags); |
3636 | if (ret <= 0) | ||
3637 | goto out; | ||
3636 | /* | 3638 | /* |
3637 | * Flag the inode(non aio case) or end_io struct (aio case) | 3639 | * Flag the inode(non aio case) or end_io struct (aio case) |
3638 | * that this IO needs to conversion to written when IO is | 3640 | * that this IO needs to conversion to written when IO is |
@@ -3878,6 +3880,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
3878 | struct ext4_allocation_request ar; | 3880 | struct ext4_allocation_request ar; |
3879 | ext4_io_end_t *io = ext4_inode_aio(inode); | 3881 | ext4_io_end_t *io = ext4_inode_aio(inode); |
3880 | ext4_lblk_t cluster_offset; | 3882 | ext4_lblk_t cluster_offset; |
3883 | int set_unwritten = 0; | ||
3881 | 3884 | ||
3882 | ext_debug("blocks %u/%u requested for inode %lu\n", | 3885 | ext_debug("blocks %u/%u requested for inode %lu\n", |
3883 | map->m_lblk, map->m_len, inode->i_ino); | 3886 | map->m_lblk, map->m_len, inode->i_ino); |
@@ -4100,13 +4103,8 @@ got_allocated_blocks: | |||
4100 | * For non asycn direct IO case, flag the inode state | 4103 | * For non asycn direct IO case, flag the inode state |
4101 | * that we need to perform conversion when IO is done. | 4104 | * that we need to perform conversion when IO is done. |
4102 | */ | 4105 | */ |
4103 | if ((flags & EXT4_GET_BLOCKS_PRE_IO)) { | 4106 | if ((flags & EXT4_GET_BLOCKS_PRE_IO)) |
4104 | if (io) | 4107 | set_unwritten = 1; |
4105 | ext4_set_io_unwritten_flag(inode, io); | ||
4106 | else | ||
4107 | ext4_set_inode_state(inode, | ||
4108 | EXT4_STATE_DIO_UNWRITTEN); | ||
4109 | } | ||
4110 | if (ext4_should_dioread_nolock(inode)) | 4108 | if (ext4_should_dioread_nolock(inode)) |
4111 | map->m_flags |= EXT4_MAP_UNINIT; | 4109 | map->m_flags |= EXT4_MAP_UNINIT; |
4112 | } | 4110 | } |
@@ -4118,6 +4116,15 @@ got_allocated_blocks: | |||
4118 | if (!err) | 4116 | if (!err) |
4119 | err = ext4_ext_insert_extent(handle, inode, path, | 4117 | err = ext4_ext_insert_extent(handle, inode, path, |
4120 | &newex, flags); | 4118 | &newex, flags); |
4119 | |||
4120 | if (!err && set_unwritten) { | ||
4121 | if (io) | ||
4122 | ext4_set_io_unwritten_flag(inode, io); | ||
4123 | else | ||
4124 | ext4_set_inode_state(inode, | ||
4125 | EXT4_STATE_DIO_UNWRITTEN); | ||
4126 | } | ||
4127 | |||
4121 | if (err && free_on_err) { | 4128 | if (err && free_on_err) { |
4122 | int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? | 4129 | int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? |
4123 | EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0; | 4130 | EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0; |