Commit 42b8645e authored by Zhihao Cheng's avatar Zhihao Cheng
Browse files

ext4: Track data blocks freeing operation in journal

Offering: HULK
hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I9DN5Z



--------------------------------

Since commit 7f6416dc ("ext4: implement writeback iomap path"), the
order mode is removed in iomap framework, which lets ext4_mb_clear_bb()
free data blocks immediately. It may cause stale data read from truncated
file in power-cut case. Following is details:
    P1                         P2
vfs_truncate(file A)
 ext4_setattr
  EXT4_I(inode)->i_disksize = attr->ia_size // record in journal
  ext4_truncate
   ext4_mb_clear_bb
    mb_free_blocks // free block i
                      vfs_write(file B) // get block i and writeback
      >> powercut <<
In the next mount, inode size and extent tree is stale(before truncated),
the content in block i is file B.
Fix the problem by tracking free data blocks in journal for
iomap/non-writeback case.

Fixes: 7f6416dc ("ext4: implement writeback iomap path")
Signed-off-by: default avatarZhihao Cheng <chengzhihao1@huawei.com>
parent 552667f6
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -11,18 +11,13 @@ int ext4_inode_journal_mode(struct inode *inode)
{
	if (EXT4_JOURNAL(inode) == NULL)
		return EXT4_INODE_WRITEBACK_DATA_MODE;	/* writeback */
	/*
	 * Ordered mode is no longer needed for the inode that use the
	 * iomap path, always use writeback mode.
	 */
	if (ext4_test_inode_state(inode, EXT4_STATE_BUFFERED_IOMAP))
		return EXT4_INODE_WRITEBACK_DATA_MODE;	/* writeback */
	/* We do not support data journalling with delayed allocation */
	if (!S_ISREG(inode->i_mode) ||
	    ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) ||
	    test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
	    (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
	    !test_opt(inode->i_sb, DELALLOC))) {
	    !test_opt(inode->i_sb, DELALLOC) &&
	    !ext4_test_inode_state(inode, EXT4_STATE_BUFFERED_IOMAP))) {
		/* We do not support data journalling for encrypted data */
		if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode))
			return EXT4_INODE_ORDERED_DATA_MODE;  /* ordered */
+7 −0
Original line number Diff line number Diff line
@@ -467,6 +467,13 @@ static inline int ext4_should_journal_data(struct inode *inode)

static inline int ext4_should_order_data(struct inode *inode)
{
	/*
	 * Ordered mode is no longer needed for the inode that use the
	 * iomap path, always use writeback mode.
	 */
	if (ext4_test_inode_state(inode, EXT4_STATE_BUFFERED_IOMAP))
		return 0;	/* writeback */

	return ext4_inode_journal_mode(inode) & EXT4_INODE_ORDERED_DATA_MODE;
}