diff options
author | Jan Kara <jack@suse.cz> | 2009-12-08 23:51:10 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-12-08 23:51:10 -0500 |
commit | b436b9bef84de6893e86346d8fbf7104bc520645 (patch) | |
tree | 50fb9ae167bcd622e9adf47646bcf3b4c7dd111d /fs/ext4/extents.c | |
parent | 194074acacebc169ded90a4657193f5180015051 (diff) |
ext4: Wait for proper transaction commit on fsync
We cannot rely on buffer dirty bits during fsync because pdflush can come
before fsync is called and clear dirty bits without forcing a transaction
commit. What we do is that we track which transaction has last changed
the inode and which transaction last changed allocation and force it to
disk on fsync.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 5967f18fd7e7..700206e525da 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -3058,6 +3058,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
3058 | if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) { | 3058 | if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) { |
3059 | ret = ext4_convert_unwritten_extents_dio(handle, inode, | 3059 | ret = ext4_convert_unwritten_extents_dio(handle, inode, |
3060 | path); | 3060 | path); |
3061 | if (ret >= 0) | ||
3062 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
3061 | goto out2; | 3063 | goto out2; |
3062 | } | 3064 | } |
3063 | /* buffered IO case */ | 3065 | /* buffered IO case */ |
@@ -3085,6 +3087,8 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, | |||
3085 | ret = ext4_ext_convert_to_initialized(handle, inode, | 3087 | ret = ext4_ext_convert_to_initialized(handle, inode, |
3086 | path, iblock, | 3088 | path, iblock, |
3087 | max_blocks); | 3089 | max_blocks); |
3090 | if (ret >= 0) | ||
3091 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
3088 | out: | 3092 | out: |
3089 | if (ret <= 0) { | 3093 | if (ret <= 0) { |
3090 | err = ret; | 3094 | err = ret; |
@@ -3323,10 +3327,16 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
3323 | allocated = ext4_ext_get_actual_len(&newex); | 3327 | allocated = ext4_ext_get_actual_len(&newex); |
3324 | set_buffer_new(bh_result); | 3328 | set_buffer_new(bh_result); |
3325 | 3329 | ||
3326 | /* Cache only when it is _not_ an uninitialized extent */ | 3330 | /* |
3327 | if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) | 3331 | * Cache the extent and update transaction to commit on fdatasync only |
3332 | * when it is _not_ an uninitialized extent. | ||
3333 | */ | ||
3334 | if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) { | ||
3328 | ext4_ext_put_in_cache(inode, iblock, allocated, newblock, | 3335 | ext4_ext_put_in_cache(inode, iblock, allocated, newblock, |
3329 | EXT4_EXT_CACHE_EXTENT); | 3336 | EXT4_EXT_CACHE_EXTENT); |
3337 | ext4_update_inode_fsync_trans(handle, inode, 1); | ||
3338 | } else | ||
3339 | ext4_update_inode_fsync_trans(handle, inode, 0); | ||
3330 | out: | 3340 | out: |
3331 | if (allocated > max_blocks) | 3341 | if (allocated > max_blocks) |
3332 | allocated = max_blocks; | 3342 | allocated = max_blocks; |