On Sun 11-09-22 12:52:04, Zhihao Cheng wrote: > Following process may lead to fs corruption: > 1. ext4_create(dir/foo) > ext4_add_nondir > ext4_add_entry > ext4_dx_add_entry > a. add_dirent_to_buf > ext4_mark_inode_dirty > ext4_handle_dirty_metadata // dir inode bh is recorded into journal > b. ext4_append // dx_get_count(entries) == dx_get_limit(entries) > ext4_bread(EXT4_GET_BLOCKS_CREATE) > ext4_getblk > ext4_map_blocks > ext4_ext_map_blocks > ext4_mb_new_blocks > dquot_alloc_block > dquot_alloc_space_nodirty > inode_add_bytes // update dir's i_blocks > ext4_ext_insert_extent > ext4_ext_dirty // record extent bh into journal > ext4_handle_dirty_metadata(bh) > // record new block into journal > inode->i_size += inode->i_sb->s_blocksize // new size(in mem) > c. ext4_handle_dirty_dx_node(bh2) > // record dir's new block(dx_node) into journal > d. ext4_handle_dirty_dx_node((frame - 1)->bh) > e. ext4_handle_dirty_dx_node(frame->bh) > f. do_split // ret err! > g. add_dirent_to_buf > ext4_mark_inode_dirty(dir) // update raw_inode on disk(skipped) > 2. fsck -a /dev/sdb > drop last block(dx_node) which beyonds dir's i_size. > /dev/sdb: recovering journal > /dev/sdb contains a file system with errors, check forced. > /dev/sdb: Inode 12, end of extent exceeds allowed value > (logical block 128, physical block 3938, len 1) > 3. fsck -fn /dev/sdb > dx_node->entry[i].blk > dir->i_size > Pass 2: Checking directory structure > Problem in HTREE directory inode 12 (/dir): bad block number 128. > Clear HTree index? no > Problem in HTREE directory inode 12: block #3 has invalid depth (2) > Problem in HTREE directory inode 12: block #3 has bad max hash > Problem in HTREE directory inode 12: block #3 not referenced > > Fix it by marking inode dirty directly inside ext4_append(). > Fetch a reproducer in [Link]. > > Link: https://bugzilla.kernel.org/show_bug.cgi?id=216466 > CC: stable@xxxxxxxxxxxxxxx > Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx> Thanks! The patch looks good. Feel free to add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > v1->v2: mark inode dirty inside ext4_append(). > fs/ext4/namei.c | 15 ++++++++++----- > 1 file changed, 10 insertions(+), 5 deletions(-) > > diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c > index 3a31b662f661..0d0e41d2dee8 100644 > --- a/fs/ext4/namei.c > +++ b/fs/ext4/namei.c > @@ -85,15 +85,20 @@ static struct buffer_head *ext4_append(handle_t *handle, > return bh; > inode->i_size += inode->i_sb->s_blocksize; > EXT4_I(inode)->i_disksize = inode->i_size; > + err = ext4_mark_inode_dirty(handle, inode); > + if (err) > + goto out; > BUFFER_TRACE(bh, "get_write_access"); > err = ext4_journal_get_write_access(handle, inode->i_sb, bh, > EXT4_JTR_NONE); > - if (err) { > - brelse(bh); > - ext4_std_error(inode->i_sb, err); > - return ERR_PTR(err); > - } > + if (err) > + goto out; > return bh; > + > +out: > + brelse(bh); > + ext4_std_error(inode->i_sb, err); > + return ERR_PTR(err); > } > > static int ext4_dx_csum_verify(struct inode *inode, > -- > 2.31.1 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR