diff options
author | Theodore Ts'o <tytso@mit.edu> | 2014-04-11 18:35:17 +0400 |
---|---|---|
committer | Jiri Slaby <jslaby@suse.cz> | 2014-05-15 11:55:43 +0400 |
commit | afeeb0349158c4f63285dd148eee0348581d723a (patch) | |
tree | e3081a4f3a8949788568256b122db6b5b2720a6c /fs/ext4 | |
parent | 44b9a5adc9a831167548d5a725bf3e60b80c4207 (diff) | |
download | linux-afeeb0349158c4f63285dd148eee0348581d723a.tar.xz |
ext4: move ext4_update_i_disksize() into mpage_map_and_submit_extent()
commit 622cad1325e404598fe3b148c3fa640dbaabc235 upstream.
The function ext4_update_i_disksize() is used in only one place, in
the function mpage_map_and_submit_extent(). Move its code to simplify
the code paths, and also move the call to ext4_mark_inode_dirty() into
the i_data_sem's critical region, to be consistent with all of the
other places where we update i_disksize. That way, we also keep the
raw_inode's i_disksize protected, to avoid the following race:
CPU #1 CPU #2
down_write(&i_data_sem)
Modify i_disk_size
up_write(&i_data_sem)
down_write(&i_data_sem)
Modify i_disk_size
Copy i_disk_size to on-disk inode
up_write(&i_data_sem)
Copy i_disk_size to on-disk inode
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 17 | ||||
-rw-r--r-- | fs/ext4/inode.c | 16 |
2 files changed, 13 insertions, 20 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index a9d2bf941066..1e25d6b57bc5 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2445,23 +2445,6 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize) up_write(&EXT4_I(inode)->i_data_sem); } -/* - * Update i_disksize after writeback has been started. Races with truncate - * are avoided by checking i_size under i_data_sem. - */ -static inline void ext4_wb_update_i_disksize(struct inode *inode, loff_t newsize) -{ - loff_t i_size; - - down_write(&EXT4_I(inode)->i_data_sem); - i_size = i_size_read(inode); - if (newsize > i_size) - newsize = i_size; - if (newsize > EXT4_I(inode)->i_disksize) - EXT4_I(inode)->i_disksize = newsize; - up_write(&EXT4_I(inode)->i_data_sem); -} - struct ext4_group_info { unsigned long bb_state; struct rb_root bb_free_root; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 8fdf99bf18d6..ea9793d8a77f 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2233,13 +2233,23 @@ static int mpage_map_and_submit_extent(handle_t *handle, return err; } while (map->m_len); - /* Update on-disk size after IO is submitted */ + /* + * Update on-disk size after IO is submitted. Races with + * truncate are avoided by checking i_size under i_data_sem. + */ disksize = ((loff_t)mpd->first_page) << PAGE_CACHE_SHIFT; if (disksize > EXT4_I(inode)->i_disksize) { int err2; - - ext4_wb_update_i_disksize(inode, disksize); + loff_t i_size; + + down_write(&EXT4_I(inode)->i_data_sem); + i_size = i_size_read(inode); + if (disksize > i_size) + disksize = i_size; + if (disksize > EXT4_I(inode)->i_disksize) + EXT4_I(inode)->i_disksize = disksize; err2 = ext4_mark_inode_dirty(handle, inode); + up_write(&EXT4_I(inode)->i_data_sem); if (err2) ext4_error(inode->i_sb, "Failed to mark inode %lu dirty", |