aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2012-09-28 23:36:25 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-09-28 23:36:25 -0400
commit82e54229118785badffb4ef5ba4803df25fe007f (patch)
tree270d0afb27dce342b7508cd05bb0db45cdad089d /fs/ext4/extents.c
parente27f41e1b789e60e7d8cc9c81fd93ca49ef31f13 (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.c21
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;