diff options
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7b93df9aa182..f023f0cb46fc 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -2247,13 +2247,23 @@ static int mpage_map_and_submit_extent(handle_t *handle, | |||
2247 | return err; | 2247 | return err; |
2248 | } while (map->m_len); | 2248 | } while (map->m_len); |
2249 | 2249 | ||
2250 | /* Update on-disk size after IO is submitted */ | 2250 | /* |
2251 | * Update on-disk size after IO is submitted. Races with | ||
2252 | * truncate are avoided by checking i_size under i_data_sem. | ||
2253 | */ | ||
2251 | disksize = ((loff_t)mpd->first_page) << PAGE_CACHE_SHIFT; | 2254 | disksize = ((loff_t)mpd->first_page) << PAGE_CACHE_SHIFT; |
2252 | if (disksize > EXT4_I(inode)->i_disksize) { | 2255 | if (disksize > EXT4_I(inode)->i_disksize) { |
2253 | int err2; | 2256 | int err2; |
2254 | 2257 | loff_t i_size; | |
2255 | ext4_wb_update_i_disksize(inode, disksize); | 2258 | |
2259 | down_write(&EXT4_I(inode)->i_data_sem); | ||
2260 | i_size = i_size_read(inode); | ||
2261 | if (disksize > i_size) | ||
2262 | disksize = i_size; | ||
2263 | if (disksize > EXT4_I(inode)->i_disksize) | ||
2264 | EXT4_I(inode)->i_disksize = disksize; | ||
2256 | err2 = ext4_mark_inode_dirty(handle, inode); | 2265 | err2 = ext4_mark_inode_dirty(handle, inode); |
2266 | up_write(&EXT4_I(inode)->i_data_sem); | ||
2257 | if (err2) | 2267 | if (err2) |
2258 | ext4_error(inode->i_sb, | 2268 | ext4_error(inode->i_sb, |
2259 | "Failed to mark inode %lu dirty", | 2269 | "Failed to mark inode %lu dirty", |