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 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
|
|||
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 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode,
|
|||
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 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
|
|||
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…
Reference in a new issue