summaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2013-08-17 16:09:31 +0200
committerTheodore Ts'o <tytso@mit.edu>2013-08-17 16:09:31 +0200
commit90e775b71ac4e685898c7995756fe58c135adaa6 (patch)
treee7e84b7990ad61717808830726b0fce4e9c0464a /fs/ext4/extents.c
parentext4: simplify truncation code in ext4_setattr() (diff)
downloadlinux-90e775b71ac4e685898c7995756fe58c135adaa6.tar.xz
linux-90e775b71ac4e685898c7995756fe58c135adaa6.zip
ext4: fix lost truncate due to race with writeback
The following race can lead to a loss of i_disksize update from truncate thus resulting in a wrong inode size if the inode size isn't updated again before inode is reclaimed: ext4_setattr() mpage_map_and_submit_extent() EXT4_I(inode)->i_disksize = attr->ia_size; ... ... disksize = ((loff_t)mpd->first_page) << PAGE_CACHE_SHIFT /* False because i_size isn't * updated yet */ if (disksize > i_size_read(inode)) /* True, because i_disksize is * already truncated */ if (disksize > EXT4_I(inode)->i_disksize) /* Overwrite i_disksize * update from truncate */ ext4_update_i_disksize() i_size_write(inode, attr->ia_size); For other places updating i_disksize such race cannot happen because i_mutex prevents these races. Writeback is the only place where we do not hold i_mutex and we cannot grab it there because of lock ordering. We fix the race by doing both i_disksize and i_size update in truncate atomically under i_data_sem and in mpage_map_and_submit_extent() we move the check against i_size under i_data_sem as well. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/ext4/extents.c')
0 files changed, 0 insertions, 0 deletions