ext4: Clean up s_dirt handling
We don't need to set s_dirt in most of the ext4 code when journaling is enabled. In ext3/4 some of the summary statistics for # of free inodes, blocks, and directories are calculated from the per-block group statistics when the file system is mounted or unmounted. As a result the superblock doesn't have to be updated, either via the journal or by setting s_dirt. There are a few exceptions, most notably when resizing the file system, where the superblock needs to be modified --- and in that case it should be done as a journalled operation if possible, and s_dirt set only in no-journal mode. This patch will optimize out some unneeded disk writes when using ext4 with a journal. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
		
					parent
					
						
							
								7e27d6e778
							
						
					
				
			
			
				commit
				
					
						a0375156ca
					
				
			
		
					 9 changed files with 36 additions and 16 deletions
				
			
		|  | @ -377,14 +377,11 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, | |||
| 	ext4_grpblk_t bit; | ||||
| 	unsigned int i; | ||||
| 	struct ext4_group_desc *desc; | ||||
| 	struct ext4_super_block *es; | ||||
| 	struct ext4_sb_info *sbi; | ||||
| 	struct ext4_sb_info *sbi = EXT4_SB(sb); | ||||
| 	int err = 0, ret, blk_free_count; | ||||
| 	ext4_grpblk_t blocks_freed; | ||||
| 	struct ext4_group_info *grp; | ||||
| 
 | ||||
| 	sbi = EXT4_SB(sb); | ||||
| 	es = sbi->s_es; | ||||
| 	ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1); | ||||
| 
 | ||||
| 	ext4_get_group_no_and_offset(sb, block, &block_group, &bit); | ||||
|  | @ -477,7 +474,6 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb, | |||
| 	ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh); | ||||
| 	if (!err) | ||||
| 		err = ret; | ||||
| 	sb->s_dirt = 1; | ||||
| 
 | ||||
| error_return: | ||||
| 	brelse(bitmap_bh); | ||||
|  |  | |||
|  | @ -1860,6 +1860,12 @@ static inline void ext4_unlock_group(struct super_block *sb, | |||
| 	spin_unlock(ext4_group_lock_ptr(sb, group)); | ||||
| } | ||||
| 
 | ||||
| static inline void ext4_mark_super_dirty(struct super_block *sb) | ||||
| { | ||||
| 	if (EXT4_SB(sb)->s_journal == NULL) | ||||
| 		sb->s_dirt =1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Inodes and files operations | ||||
|  */ | ||||
|  |  | |||
|  | @ -143,3 +143,19 @@ int __ext4_handle_dirty_metadata(const char *where, handle_t *handle, | |||
| 	} | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| int __ext4_handle_dirty_super(const char *where, handle_t *handle, | ||||
| 			      struct super_block *sb) | ||||
| { | ||||
| 	struct buffer_head *bh = EXT4_SB(sb)->s_sbh; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	if (ext4_handle_valid(handle)) { | ||||
| 		err = jbd2_journal_dirty_metadata(handle, bh); | ||||
| 		if (err) | ||||
| 			ext4_journal_abort_handle(where, __func__, bh, | ||||
| 						  handle, err); | ||||
| 	} else | ||||
| 		sb->s_dirt = 1; | ||||
| 	return err; | ||||
| } | ||||
|  |  | |||
|  | @ -141,6 +141,9 @@ int __ext4_journal_get_create_access(const char *where, | |||
| int __ext4_handle_dirty_metadata(const char *where, handle_t *handle, | ||||
| 				 struct inode *inode, struct buffer_head *bh); | ||||
| 
 | ||||
| int __ext4_handle_dirty_super(const char *where, handle_t *handle, | ||||
| 			      struct super_block *sb); | ||||
| 
 | ||||
| #define ext4_journal_get_undo_access(handle, bh) \ | ||||
| 	__ext4_journal_get_undo_access(__func__, (handle), (bh)) | ||||
| #define ext4_journal_get_write_access(handle, bh) \ | ||||
|  | @ -152,6 +155,8 @@ int __ext4_handle_dirty_metadata(const char *where, handle_t *handle, | |||
| 	__ext4_journal_get_create_access(__func__, (handle), (bh)) | ||||
| #define ext4_handle_dirty_metadata(handle, inode, bh) \ | ||||
| 	__ext4_handle_dirty_metadata(__func__, (handle), (inode), (bh)) | ||||
| #define ext4_handle_dirty_super(handle, sb) \ | ||||
| 	__ext4_handle_dirty_super(__func__, (handle), (sb)) | ||||
| 
 | ||||
| handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); | ||||
| int __ext4_journal_stop(const char *where, handle_t *handle); | ||||
|  |  | |||
|  | @ -123,7 +123,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp) | |||
| 		if (!IS_ERR(cp)) { | ||||
| 			memcpy(sbi->s_es->s_last_mounted, cp, | ||||
| 			       sizeof(sbi->s_es->s_last_mounted)); | ||||
| 			sb->s_dirt = 1; | ||||
| 			ext4_mark_super_dirty(sb); | ||||
| 		} | ||||
| 	} | ||||
| 	return dquot_file_open(inode, filp); | ||||
|  |  | |||
|  | @ -279,7 +279,7 @@ out: | |||
| 		err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); | ||||
| 		if (!fatal) | ||||
| 			fatal = err; | ||||
| 		sb->s_dirt = 1; | ||||
| 		ext4_mark_super_dirty(sb); | ||||
| 	} else | ||||
| 		ext4_error(sb, "bit already cleared for inode %lu", ino); | ||||
| 
 | ||||
|  | @ -965,7 +965,7 @@ got: | |||
| 	percpu_counter_dec(&sbi->s_freeinodes_counter); | ||||
| 	if (S_ISDIR(mode)) | ||||
| 		percpu_counter_inc(&sbi->s_dirs_counter); | ||||
| 	sb->s_dirt = 1; | ||||
| 	ext4_mark_super_dirty(sb); | ||||
| 
 | ||||
| 	if (sbi->s_log_groups_per_flex) { | ||||
| 		flex_group = ext4_flex_group(sbi, group); | ||||
|  |  | |||
|  | @ -2812,7 +2812,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | |||
| 	err = ext4_handle_dirty_metadata(handle, NULL, gdp_bh); | ||||
| 
 | ||||
| out_err: | ||||
| 	sb->s_dirt = 1; | ||||
| 	ext4_mark_super_dirty(sb); | ||||
| 	brelse(bitmap_bh); | ||||
| 	return err; | ||||
| } | ||||
|  | @ -4680,7 +4680,7 @@ do_more: | |||
| 		put_bh(bitmap_bh); | ||||
| 		goto do_more; | ||||
| 	} | ||||
| 	sb->s_dirt = 1; | ||||
| 	ext4_mark_super_dirty(sb); | ||||
| error_return: | ||||
| 	if (freed) | ||||
| 		dquot_free_block(inode, freed); | ||||
|  |  | |||
|  | @ -921,8 +921,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
| 			   &sbi->s_flex_groups[flex_group].free_inodes); | ||||
| 	} | ||||
| 
 | ||||
| 	ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh); | ||||
| 	sb->s_dirt = 1; | ||||
| 	ext4_handle_dirty_super(handle, sb); | ||||
| 
 | ||||
| exit_journal: | ||||
| 	mutex_unlock(&sbi->s_resize_lock); | ||||
|  | @ -1045,13 +1044,12 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, | |||
| 		goto exit_put; | ||||
| 	} | ||||
| 	ext4_blocks_count_set(es, o_blocks_count + add); | ||||
| 	ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); | ||||
| 	sb->s_dirt = 1; | ||||
| 	mutex_unlock(&EXT4_SB(sb)->s_resize_lock); | ||||
| 	ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count, | ||||
| 		   o_blocks_count + add); | ||||
| 	/* We add the blocks to the bitmap and set the group need init bit */ | ||||
| 	ext4_add_groupblocks(handle, sb, o_blocks_count, add); | ||||
| 	ext4_handle_dirty_super(handle, sb); | ||||
| 	ext4_debug("freed blocks %llu through %llu\n", o_blocks_count, | ||||
| 		   o_blocks_count + add); | ||||
| 	if ((err = ext4_journal_stop(handle))) | ||||
|  |  | |||
|  | @ -458,8 +458,7 @@ static void ext4_xattr_update_super_block(handle_t *handle, | |||
| 
 | ||||
| 	if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) { | ||||
| 		EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR); | ||||
| 		sb->s_dirt = 1; | ||||
| 		ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); | ||||
| 		ext4_handle_dirty_super(handle, sb); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Theodore Ts'o
				Theodore Ts'o