@@ -2941,7 +2941,7 @@ extern int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
struct dx_hash_info *hinfo);
/* ialloc.c */
-extern int ext4_mark_inode_used(struct super_block *sb, int ino);
+extern int ext4_mark_inode_used(struct super_block *sb, int ino, umode_t mode);
extern struct inode *__ext4_new_inode(struct mnt_idmap *, handle_t *,
struct inode *, umode_t,
const struct qstr *qstr, __u32 goal,
@@ -1578,7 +1578,7 @@ static int ext4_fc_replay_inode(struct super_block *sb,
ret = sync_dirty_buffer(iloc.bh);
if (ret)
goto out_brelse;
- ret = ext4_mark_inode_used(sb, ino);
+ ret = ext4_mark_inode_used(sb, ino, le16_to_cpu(raw_fc_inode->i_mode));
if (ret)
goto out_brelse;
@@ -1635,11 +1635,7 @@ static int ext4_fc_replay_create(struct super_block *sb,
trace_ext4_fc_replay(sb, EXT4_FC_TAG_CREAT, darg.ino,
darg.parent_ino, darg.dname_len);
- /* This takes care of update group descriptor and other metadata */
- ret = ext4_mark_inode_used(sb, darg.ino);
- if (ret)
- goto out;
-
+ /* Inode already on disk from TAG_INODE replay; iget first for mode. */
inode = ext4_iget(sb, darg.ino, EXT4_IGET_NORMAL);
if (IS_ERR(inode)) {
ext4_debug("inode %d not found.", darg.ino);
@@ -1648,6 +1644,11 @@ static int ext4_fc_replay_create(struct super_block *sb,
goto out;
}
+ /* This takes care of update group descriptor and other metadata */
+ ret = ext4_mark_inode_used(sb, darg.ino, inode->i_mode);
+ if (ret)
+ goto out;
+
if (S_ISDIR(inode->i_mode)) {
/*
* If we are creating a directory, we need to make sure that the
@@ -756,11 +756,12 @@ static int find_inode_bit(struct super_block *sb, ext4_group_t group,
return 1;
}
-int ext4_mark_inode_used(struct super_block *sb, int ino)
+int ext4_mark_inode_used(struct super_block *sb, int ino, umode_t mode)
{
unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count);
struct buffer_head *inode_bitmap_bh = NULL, *group_desc_bh = NULL;
struct ext4_group_desc *gdp;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
ext4_group_t group;
int bit;
int err;
@@ -858,6 +859,16 @@ int ext4_mark_inode_used(struct super_block *sb, int ino)
}
ext4_free_inodes_set(sb, gdp, ext4_free_inodes_count(sb, gdp) - 1);
+ if (S_ISDIR(mode)) {
+ ext4_used_dirs_set(sb, gdp, ext4_used_dirs_count(sb, gdp) + 1);
+ if (sbi->s_log_groups_per_flex) {
+ ext4_group_t f = ext4_flex_group(sbi, group);
+
+ atomic_inc(&sbi_array_rcu_deref(sbi, s_flex_groups,
+ f)->used_dirs);
+ }
+ }
+
if (ext4_has_group_desc_csum(sb)) {
ext4_inode_bitmap_csum_set(sb, gdp, inode_bitmap_bh);
ext4_group_desc_csum_set(sb, group, gdp);
ext4_mark_inode_used() did not update bg_used_dirs_count for directory inodes during fast commit replay because it lacked the inode mode. Add a mode parameter and pass it from both ext4_fc_replay_inode() (from raw_fc_inode) and ext4_fc_replay_create() (after ext4_iget). Fixes: 8016e29f4362 ("ext4: fast commit recovery path") Signed-off-by: Baokun Li <libaokun@linux.alibaba.com> --- fs/ext4/ext4.h | 2 +- fs/ext4/fast_commit.c | 13 +++++++------ fs/ext4/ialloc.c | 13 ++++++++++++- 3 files changed, 20 insertions(+), 8 deletions(-)