diff options
| author | Theodore Ts'o <tytso@mit.edu> | 2014-04-11 10:35:17 -0400 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-06 07:59:37 -0700 | 
| commit | de65d2a2221ab864583fee719b8a3f9e045a385b (patch) | |
| tree | 5948b0b142893a1457439a62d31dab1fd9393b72 /fs | |
| parent | 58b9dc7b5d9d84783ea2d317b5fe29efbe4c9c83 (diff) | |
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
| -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 d3a534fdc5ff..3a603a8d9f96 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2462,23 +2462,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 b0d5860c0e50..4e8903d0432e 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2236,13 +2236,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", | 
