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

Commit 26de9b11 authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: avoid unnecessary updating inode during fsync



If roll-forward recovery can recover i_size, we don't need to update inode's
metadata during fsync.

Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent ee6d182f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1204,6 +1204,7 @@ static int f2fs_write_data_page(struct page *page,
	loff_t i_size = i_size_read(inode);
	const pgoff_t end_index = ((unsigned long long) i_size)
							>> PAGE_SHIFT;
	loff_t psize = (page->index + 1) << PAGE_SHIFT;
	unsigned offset = 0;
	bool need_balance_fs = false;
	int err = 0;
@@ -1265,6 +1266,8 @@ static int f2fs_write_data_page(struct page *page,
		err = f2fs_write_inline_data(inode, page);
	if (err == -EAGAIN)
		err = do_write_data_page(&fio);
	if (F2FS_I(inode)->last_disk_size < psize)
		F2FS_I(inode)->last_disk_size = psize;
	f2fs_unlock_op(sbi);
done:
	if (err && err != -ENOENT)
+21 −2
Original line number Diff line number Diff line
@@ -441,6 +441,7 @@ struct f2fs_inode_info {
	unsigned int clevel;		/* maximum level of given file name */
	nid_t i_xattr_nid;		/* node id that contains xattrs */
	unsigned long long xattr_ver;	/* cp version of xattr modification */
	loff_t	last_disk_size;		/* lastly written file size */

	struct list_head dirty_list;	/* dirty list for dirs and files */
	struct list_head gdirty_list;	/* linked in global dirty list */
@@ -1516,6 +1517,7 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr)
enum {
	FI_NEW_INODE,		/* indicate newly allocated inode */
	FI_DIRTY_INODE,		/* indicate inode is dirty or not */
	FI_AUTO_RECOVER,	/* indicate inode is recoverable */
	FI_DIRTY_DIR,		/* indicate directory has dirty pages */
	FI_INC_LINK,		/* need to increment i_nlink */
	FI_ACL_MODE,		/* indicate acl mode */
@@ -1591,18 +1593,35 @@ static inline void f2fs_i_links_write(struct inode *inode, bool inc)
static inline void f2fs_i_blocks_write(struct inode *inode,
					blkcnt_t diff, bool add)
{
	bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE);
	bool recover = is_inode_flag_set(inode, FI_AUTO_RECOVER);

	inode->i_blocks = add ? inode->i_blocks + diff :
				inode->i_blocks - diff;
	mark_inode_dirty_sync(inode);
	if (clean || recover)
		set_inode_flag(inode, FI_AUTO_RECOVER);
}

static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size)
{
	bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE);
	bool recover = is_inode_flag_set(inode, FI_AUTO_RECOVER);

	if (i_size_read(inode) == i_size)
		return;

	i_size_write(inode, i_size);
	mark_inode_dirty_sync(inode);
	if (clean || recover)
		set_inode_flag(inode, FI_AUTO_RECOVER);
}

static inline bool f2fs_skip_inode_update(struct inode *inode)
{
	if (!is_inode_flag_set(inode, FI_AUTO_RECOVER))
		return false;
	return F2FS_I(inode)->last_disk_size == i_size_read(inode);
}

static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)
@@ -1936,8 +1955,8 @@ void ra_node_page(struct f2fs_sb_info *, nid_t);
struct page *get_node_page(struct f2fs_sb_info *, pgoff_t);
struct page *get_node_page_ra(struct page *, int);
void move_node_page(struct page *, int);
int fsync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *,
								bool);
int fsync_node_pages(struct f2fs_sb_info *, struct inode *,
			struct writeback_control *, bool);
int sync_node_pages(struct f2fs_sb_info *, struct writeback_control *);
bool alloc_nid(struct f2fs_sb_info *, nid_t *);
void alloc_nid_done(struct f2fs_sb_info *, nid_t);
+2 −2
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) {
	if (!datasync && !f2fs_skip_inode_update(inode)) {
		f2fs_write_inode(inode, NULL);
		goto go_write;
	}
@@ -251,7 +251,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
		goto out;
	}
sync_nodes:
	ret = fsync_node_pages(sbi, ino, &wbc, atomic);
	ret = fsync_node_pages(sbi, inode, &wbc, atomic);
	if (ret)
		goto out;

+3 −0
Original line number Diff line number Diff line
@@ -154,6 +154,9 @@ static int do_read_inode(struct inode *inode)
	if (__written_first_block(ri))
		set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);

	if (!need_inode_block_update(sbi, inode->i_ino))
		fi->last_disk_size = inode->i_size;

	f2fs_put_page(node_page, 1);

	stat_inc_inline_xattr(inode);
+7 −2
Original line number Diff line number Diff line
@@ -1293,7 +1293,7 @@ static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino)
	return last_page;
}

int fsync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
			struct writeback_control *wbc, bool atomic)
{
	pgoff_t index, end;
@@ -1301,6 +1301,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
	int ret = 0;
	struct page *last_page = NULL;
	bool marked = false;
	nid_t ino = inode->i_ino;

	if (atomic) {
		last_page = last_fsync_dnode(sbi, ino);
@@ -1354,9 +1355,13 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,

			if (!atomic || page == last_page) {
				set_fsync_mark(page, 1);
				if (IS_INODE(page))
				if (IS_INODE(page)) {
					if (is_inode_flag_set(inode,
								FI_DIRTY_INODE))
						update_inode(inode, page);
					set_dentry_mark(page,
						need_dentry_mark(sbi, ino));
				}
				/*  may be written by other thread */
				if (!PageDirty(page))
					set_page_dirty(page);
Loading