| From 599ea31d13617c5484c40cdf50d88301dc351cfc Mon Sep 17 00:00:00 2001 |
| From: Xin Yin <yinxin.x@bytedance.com> |
| Date: Mon, 10 Jan 2022 11:51:40 +0800 |
| Subject: ext4: prevent used blocks from being allocated during fast commit replay |
| |
| From: Xin Yin <yinxin.x@bytedance.com> |
| |
| commit 599ea31d13617c5484c40cdf50d88301dc351cfc upstream. |
| |
| During fast commit replay procedure, we clear inode blocks bitmap in |
| ext4_ext_clear_bb(), this may cause ext4_mb_new_blocks_simple() allocate |
| blocks still in use. |
| |
| Make ext4_fc_record_regions() also record physical disk regions used by |
| inodes during replay procedure. Then ext4_mb_new_blocks_simple() can |
| excludes these blocks in use. |
| |
| Signed-off-by: Xin Yin <yinxin.x@bytedance.com> |
| Link: https://lore.kernel.org/r/20220110035141.1980-2-yinxin.x@bytedance.com |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Cc: stable@kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/ext4/ext4.h | 3 +++ |
| fs/ext4/extents.c | 4 ++++ |
| fs/ext4/fast_commit.c | 20 +++++++++++++++----- |
| 3 files changed, 22 insertions(+), 5 deletions(-) |
| |
| --- a/fs/ext4/ext4.h |
| +++ b/fs/ext4/ext4.h |
| @@ -2779,6 +2779,9 @@ void ext4_fc_replay_cleanup(struct super |
| int ext4_fc_commit(journal_t *journal, tid_t commit_tid); |
| int __init ext4_fc_init_dentry_cache(void); |
| void ext4_fc_destroy_dentry_cache(void); |
| +int ext4_fc_record_regions(struct super_block *sb, int ino, |
| + ext4_lblk_t lblk, ext4_fsblk_t pblk, |
| + int len, int replay); |
| |
| /* mballoc.c */ |
| extern const struct seq_operations ext4_mb_seq_groups_ops; |
| --- a/fs/ext4/extents.c |
| +++ b/fs/ext4/extents.c |
| @@ -6088,11 +6088,15 @@ int ext4_ext_clear_bb(struct inode *inod |
| |
| ext4_mb_mark_bb(inode->i_sb, |
| path[j].p_block, 1, 0); |
| + ext4_fc_record_regions(inode->i_sb, inode->i_ino, |
| + 0, path[j].p_block, 1, 1); |
| } |
| ext4_ext_drop_refs(path); |
| kfree(path); |
| } |
| ext4_mb_mark_bb(inode->i_sb, map.m_pblk, map.m_len, 0); |
| + ext4_fc_record_regions(inode->i_sb, inode->i_ino, |
| + map.m_lblk, map.m_pblk, map.m_len, 1); |
| } |
| cur = cur + map.m_len; |
| } |
| --- a/fs/ext4/fast_commit.c |
| +++ b/fs/ext4/fast_commit.c |
| @@ -1558,16 +1558,23 @@ out: |
| } |
| |
| /* |
| - * Record physical disk regions which are in use as per fast commit area. Our |
| - * simple replay phase allocator excludes these regions from allocation. |
| + * Record physical disk regions which are in use as per fast commit area, |
| + * and used by inodes during replay phase. Our simple replay phase |
| + * allocator excludes these regions from allocation. |
| */ |
| -static int ext4_fc_record_regions(struct super_block *sb, int ino, |
| - ext4_lblk_t lblk, ext4_fsblk_t pblk, int len) |
| +int ext4_fc_record_regions(struct super_block *sb, int ino, |
| + ext4_lblk_t lblk, ext4_fsblk_t pblk, int len, int replay) |
| { |
| struct ext4_fc_replay_state *state; |
| struct ext4_fc_alloc_region *region; |
| |
| state = &EXT4_SB(sb)->s_fc_replay_state; |
| + /* |
| + * during replay phase, the fc_regions_valid may not same as |
| + * fc_regions_used, update it when do new additions. |
| + */ |
| + if (replay && state->fc_regions_used != state->fc_regions_valid) |
| + state->fc_regions_used = state->fc_regions_valid; |
| if (state->fc_regions_used == state->fc_regions_size) { |
| state->fc_regions_size += |
| EXT4_FC_REPLAY_REALLOC_INCREMENT; |
| @@ -1585,6 +1592,9 @@ static int ext4_fc_record_regions(struct |
| region->pblk = pblk; |
| region->len = len; |
| |
| + if (replay) |
| + state->fc_regions_valid++; |
| + |
| return 0; |
| } |
| |
| @@ -1954,7 +1964,7 @@ static int ext4_fc_replay_scan(journal_t |
| ret = ext4_fc_record_regions(sb, |
| le32_to_cpu(ext.fc_ino), |
| le32_to_cpu(ex->ee_block), ext4_ext_pblock(ex), |
| - ext4_ext_get_actual_len(ex)); |
| + ext4_ext_get_actual_len(ex), 0); |
| if (ret < 0) |
| break; |
| ret = JBD2_FC_REPLAY_CONTINUE; |