Skip to content

Commit

Permalink
ext4: fix fdatasync() for files with only i_size changes
Browse files Browse the repository at this point in the history
Code tracking when transaction needs to be committed on fdatasync(2) forgets
to handle a situation when only inode's i_size is changed. Thus in such
situations fdatasync(2) doesn't force transaction with new i_size to disk
and that can result in wrong i_size after a crash.

Fix the issue by updating inode's i_datasync_tid whenever its size is
updated.

CC: <stable@vger.kernel.org> # >= 2.6.32
Reported-by: Kristian Nielsen <knielsen@knielsen-hq.org>
Signed-off-by: Jan Kara <jack@suse.cz>
  • Loading branch information
jankara authored and tytso committed Sep 27, 2012
1 parent 6a08f44 commit b71fc07
Showing 1 changed file with 6 additions and 2 deletions.
8 changes: 6 additions & 2 deletions fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -4054,6 +4054,7 @@ static int ext4_do_update_inode(handle_t *handle,
struct ext4_inode_info *ei = EXT4_I(inode);
struct buffer_head *bh = iloc->bh;
int err = 0, rc, block;
int need_datasync = 0;
uid_t i_uid;
gid_t i_gid;

Expand Down Expand Up @@ -4104,7 +4105,10 @@ static int ext4_do_update_inode(handle_t *handle,
raw_inode->i_file_acl_high =
cpu_to_le16(ei->i_file_acl >> 32);
raw_inode->i_file_acl_lo = cpu_to_le32(ei->i_file_acl);
ext4_isize_set(raw_inode, ei->i_disksize);
if (ei->i_disksize != ext4_isize(raw_inode)) {
ext4_isize_set(raw_inode, ei->i_disksize);
need_datasync = 1;
}
if (ei->i_disksize > 0x7fffffffULL) {
struct super_block *sb = inode->i_sb;
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
Expand Down Expand Up @@ -4157,7 +4161,7 @@ static int ext4_do_update_inode(handle_t *handle,
err = rc;
ext4_clear_inode_state(inode, EXT4_STATE_NEW);

ext4_update_inode_fsync_trans(handle, inode, 0);
ext4_update_inode_fsync_trans(handle, inode, need_datasync);
out_brelse:
brelse(bh);
ext4_std_error(inode->i_sb, err);
Expand Down

0 comments on commit b71fc07

Please sign in to comment.