Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 281518c6 authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim
Browse files

f2fs: fix fdatasync



For below two cases, we can't guarantee data consistence:

a)
1. xfs_io "pwrite 0 4195328" "fsync"
2. xfs_io "pwrite 4195328 1024" "fdatasync"
3. godown
4. umount & mount
--> isize we updated before fdatasync won't be recovered

b)
1. xfs_io "pwrite -S 0xcc 0 4202496" "fsync"
2. xfs_io "fpunch 4194304 4096" "fdatasync"
3. godown
4. umount & mount
--> dnode we punched before fdatasync won't be recovered

The reason is that normally fdatasync won't be aware of modification
of metadata in file, e.g. isize changing, dnode updating, so in ->fsync
we will skip flushing node pages for above cases, result in making
fdatasynced file being lost during recovery.

Currently we have introduced DIRTY_META global list in sbi for tracking
dirty inode selectively, so in fdatasync we can choose to flush nodes
depend on dirty state of current inode in the list.

Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 04d47e67
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -1710,8 +1710,17 @@ static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size)
		set_inode_flag(inode, FI_AUTO_RECOVER);
}

static inline bool f2fs_skip_inode_update(struct inode *inode)
static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync)
{
	if (dsync) {
		struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
		bool ret;

		spin_lock(&sbi->inode_lock[DIRTY_META]);
		ret = list_empty(&F2FS_I(inode)->gdirty_list);
		spin_unlock(&sbi->inode_lock[DIRTY_META]);
		return ret;
	}
	if (!is_inode_flag_set(inode, FI_AUTO_RECOVER))
		return false;
	return F2FS_I(inode)->last_disk_size == i_size_read(inode);
+1 −1
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
	}

	/* if the inode is dirty, let's recover all the time */
	if (!datasync && !f2fs_skip_inode_update(inode)) {
	if (!f2fs_skip_inode_update(inode, datasync)) {
		f2fs_write_inode(inode, NULL);
		goto go_write;
	}