f2fs: count dirty inodes to flush node pages during checkpoint
Subsystems (2)
Jaegeuk Kim
maintainerPATCH 1/3 f2fs: count dirty inodes to flush node pages during checkpoint
If there are a lot of dirty inodes, we need to flush all of them when doing checkpoint. So, we need to count this for enough free space.
--- fs/f2fs/segment.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
fs/f2fs/segment.h +5 -2
@@ -471,11 +471,12 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi) {int node_secs =get_blocktype_secs (sbi,F2FS_DIRTY_NODES );int dent_secs =get_blocktype_secs (sbi,F2FS_DIRTY_DENTS ); +int imeta_secs =get_blocktype_secs (sbi,F2FS_DIRTY_IMETA );if (test_opt (sbi,LFS ))return false; -return free_sections (sbi) <= (node_secs +2 * dent_secs + +return free_sections (sbi) <= (node_secs +2 * dent_secs + imeta_secs +reserved_sections (sbi) +1 ); }
@@ -484,6 +485,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, {int node_secs =get_blocktype_secs (sbi,F2FS_DIRTY_NODES );int dent_secs =get_blocktype_secs (sbi,F2FS_DIRTY_DENTS ); +int imeta_secs =get_blocktype_secs (sbi,F2FS_DIRTY_IMETA ); node_secs +=get_blocktype_secs (sbi,F2FS_DIRTY_IMETA );
@@ -491,7 +493,8 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,return false;return (free_sections (sbi) + freed) <= - (node_secs +2 * dent_secs +reserved_sections (sbi) + needed); + (node_secs +2 * dent_secs + imeta_secs + +reserved_sections (sbi) + needed); }static inline bool excess_prefree_segs (struct f2fs_sb_info *sbi)
Signature · 1 line
2.8.3
Jaegeuk Kim
maintainerPATCH 2/3 f2fs: call f2fs_balance_fs for setattr
If inode becomes dirty, we need to check the # of dirty inodes whether or not further checkpoint would be required.
--- fs/f2fs/file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/f2fs/file.c +4 -1
@@ -694,7 +694,6 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) err =f2fs_truncate (inode);if (err)return err; -f2fs_balance_fs (F2FS_I_SB (inode), true); }else {/* * do not trim all blocks after i_size if target size is
@@ -723,6 +722,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) }f2fs_mark_inode_dirty_sync (inode); + +/* inode change will produce dirty node pages flushed by checkpoint */ +f2fs_balance_fs (F2FS_I_SB (inode), true); +return err; }
Signature · 1 line
2.8.3
Re: [PATCH 2/3] f2fs: call f2fs_balance_fs for setattr
Quoted 4 lines · Jaegeuk Kim
If inode becomes dirty, we need to check the # of dirty inodes whether or not further checkpoint would be required.
Signed-off-by Jaegeuk Kim <[email protected]>
Jaegeuk Kim
maintainerPATCH 3/3 f2fs: keep dirty inodes selectively for checkpoint
In reply to Jaegeuk KimThis is to avoid no free segment bug during checkpoint caused by a number of dirty inodes.
The case was reported by Chao like this.
1. mount with lazytime option
2. fragment space
3. touch all files in the image
4. umount
In this case, we actually don't need to flush dirty inode to inode page during checkpoint.
--- fs/f2fs/acl.c | 2 +- fs/f2fs/dir.c | 6 +++--- fs/f2fs/extent_cache.c | 2 +- fs/f2fs/f2fs.h | 25 +++++++++++++------------ fs/f2fs/file.c | 8 ++++---- fs/f2fs/inline.c | 2 +- fs/f2fs/inode.c | 10 +++++----- fs/f2fs/namei.c | 6 +++--- fs/f2fs/super.c | 3 +++ fs/f2fs/xattr.c | 4 ++-- 10 files changed, 36 insertions(+), 32 deletions(-)
fs/f2fs/acl.c +1 -1
@@ -386,7 +386,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,if (error)return error; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);if (default_acl) { error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
fs/f2fs/dir.c +3 -3
@@ -313,7 +313,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,set_page_dirty (page); dir->i_mtime = dir->i_ctime =CURRENT_TIME ; -f2fs_mark_inode_dirty_sync (dir); +f2fs_mark_inode_dirty_sync (dir, false);f2fs_put_page (page,1 ); }
@@ -466,7 +466,7 @@ void update_parent_metadata(struct inode *dir, struct inode *inode,clear_inode_flag (inode,FI_NEW_INODE ); } dir->i_mtime = dir->i_ctime =CURRENT_TIME ; -f2fs_mark_inode_dirty_sync (dir); +f2fs_mark_inode_dirty_sync (dir, false);if (F2FS_I (dir)->i_current_depth != current_depth)f2fs_i_depth_write (dir, current_depth);
@@ -731,7 +731,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,set_page_dirty (page); dir->i_ctime = dir->i_mtime =CURRENT_TIME ; -f2fs_mark_inode_dirty_sync (dir); +f2fs_mark_inode_dirty_sync (dir, false);if (inode)f2fs_drop_nlink (dir, inode);
fs/f2fs/extent_cache.c +1 -1
@@ -172,7 +172,7 @@ static void __drop_largest_extent(struct inode *inode,if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) { largest->len =0 ; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); } }
fs/f2fs/f2fs.h +13 -12
@@ -493,13 +493,13 @@ static inline bool __is_front_mergeable(struct extent_info *cur,return __is_extent_mergeable (cur, front); } -extern void f2fs_mark_inode_dirty_sync (struct inode *); +extern void f2fs_mark_inode_dirty_sync (struct inode *,bool );static inline void __try_update_largest_extent (struct inode *inode,struct extent_tree *et,struct extent_node *en) {if (en->ei.len > et->largest.len) { et->largest = en->ei; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -1593,6 +1593,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_DIRTY_INODE_SYNC ,/* indicate inode needs to be synced 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 */
@@ -1627,7 +1628,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -1654,7 +1655,7 @@ static inline void set_acl_inode(struct inode *inode, umode_t mode) {F2FS_I (inode)->i_acl_mode = mode;set_inode_flag (inode,FI_ACL_MODE ); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, false); }static inline void f2fs_i_links_write (struct inode *inode,bool inc)
@@ -1663,7 +1664,7 @@ static inline void f2fs_i_links_write(struct inode *inode, bool inc)inc_nlink (inode); elsedrop_nlink (inode ); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); } static inline void f2fs_i_blocks_write(struct inode *inode,
@@ -1674,7 +1675,7 @@ static inline void f2fs_i_blocks_write(struct inode *inode, inode->i_blocks = add ? inode->i_blocks + diff : inode->i_blocks - diff; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);if (clean || recover)set_inode_flag (inode,FI_AUTO_RECOVER ); }
@@ -1688,7 +1689,7 @@ static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size)return ;i_size_write (inode, i_size); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);if (clean || recover)set_inode_flag (inode,FI_AUTO_RECOVER ); }
@@ -1703,19 +1704,19 @@ static inline bool f2fs_skip_inode_update(struct inode *inode)static inline void f2fs_i_depth_write (struct inode *inode,unsigned int depth) {F2FS_I (inode)->i_current_depth = depth; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline void f2fs_i_pino_write (struct inode *inode,nid_t pino) {F2FS_I (inode)->i_pino = pino; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline void get_inline_info (struct inode *inode,struct f2fs_inode *ri)
@@ -1843,13 +1844,13 @@ static inline int is_file(struct inode *inode, int type)static inline void set_file (struct inode *inode,int type) {F2FS_I (inode)->i_advise |= type; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline void clear_file (struct inode *inode,int type) {F2FS_I (inode)->i_advise &= ~type; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline int f2fs_readonly (struct super_block *sb)
fs/f2fs/file.c +4 -4
@@ -264,7 +264,6 @@ sync_nodes: }if (need_inode_block_update (sbi, ino)) { -f2fs_mark_inode_dirty_sync (inode);f2fs_write_inode (inode,NULL ); goto sync_nodes; }
@@ -632,7 +631,7 @@ int f2fs_truncate(struct inode *inode)return err; inode->i_mtime = inode->i_ctime =CURRENT_TIME ; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, false);return 0 ; }
@@ -721,7 +720,8 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) } } -f2fs_mark_inode_dirty_sync (inode); +/* update attributes only */ +f2fs_mark_inode_dirty_sync (inode, false);/* inode change will produce dirty node pages flushed by checkpoint */ f2fs_balance_fs (F2FS_I_SB (inode), true);
@@ -1402,7 +1402,7 @@ static long f2fs_fallocate(struct file *file, int mode,if (!ret) { inode->i_mtime = inode->i_ctime =CURRENT_TIME ; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, false);f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); }
fs/f2fs/inline.c +1 -1
@@ -575,7 +575,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,f2fs_put_page (page,1 ); dir->i_ctime = dir->i_mtime =CURRENT_TIME ; -f2fs_mark_inode_dirty_sync (dir); +f2fs_mark_inode_dirty_sync (dir, false);if (inode)f2fs_drop_nlink (dir, inode);
fs/f2fs/inode.c +5 -5
@@ -19,10 +19,13 @@#include <trace/events/f2fs.h> -void f2fs_mark_inode_dirty_sync (struct inode *inode) +void f2fs_mark_inode_dirty_sync (struct inode *inode,bool sync) { +if (sync) +set_inode_flag (inode,FI_DIRTY_INODE_SYNC );if (f2fs_inode_dirtied (inode))return ; +mark_inode_dirty_sync (inode); }
@@ -43,7 +46,7 @@ void f2fs_set_inode_flags(struct inode *inode) new_fl |=S_DIRSYNC ;inode_set_flags (inode, new_fl,S_SYNC |S_APPEND |S_IMMUTABLE |S_NOATIME |S_DIRSYNC ); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, false); }static void __get_inode_rdev (struct inode *inode,struct f2fs_inode *ri)
@@ -331,9 +334,6 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) inode->i_ino == F2FS_META_INO(sbi))return 0 ; -if (!is_inode_flag_set (inode,FI_DIRTY_INODE )) -return 0 ; -/* * We need to balance fs here to prevent from producing dirty node pages * during the urgent cleaning time when runing out of free sections.
fs/f2fs/namei.c +3 -3
@@ -778,7 +778,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,up_write (&F2FS_I (old_inode)->i_sem); old_inode->i_ctime =CURRENT_TIME ; -f2fs_mark_inode_dirty_sync (old_inode); +f2fs_mark_inode_dirty_sync (old_inode, false);f2fs_delete_entry (old_entry, old_page, old_dir,NULL );
@@ -938,7 +938,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,f2fs_i_links_write (old_dir, old_nlink >0 );up_write (&F2FS_I (old_dir)->i_sem); } -f2fs_mark_inode_dirty_sync (old_dir); +f2fs_mark_inode_dirty_sync (old_dir, false);/* update directory entry info of new dir inode */ f2fs_set_link (new_dir, new_entry, new_page, old_inode);
@@ -953,7 +953,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,f2fs_i_links_write (new_dir, new_nlink >0 );up_write (&F2FS_I (new_dir)->i_sem); } -f2fs_mark_inode_dirty_sync (new_dir); +f2fs_mark_inode_dirty_sync (new_dir, false);f2fs_unlock_op (sbi);
fs/f2fs/super.c +3 -0
@@ -651,6 +651,7 @@ void f2fs_inode_synced(struct inode *inode) }list_del_init (&F2FS_I (inode)->gdirty_list);clear_inode_flag (inode,FI_DIRTY_INODE ); +clear_inode_flag (inode,FI_DIRTY_INODE_SYNC );clear_inode_flag (inode,FI_AUTO_RECOVER );dec_page_count (sbi,F2FS_DIRTY_IMETA );stat_dec_dirty_inode (F2FS_I_SB (inode),DIRTY_META );
@@ -672,6 +673,8 @@ static void f2fs_dirty_inode(struct inode *inode, int flags)if (flags ==I_DIRTY_TIME )return ; +if (!is_inode_flag_set (inode,FI_DIRTY_INODE_SYNC )) +return ;if (is_inode_flag_set (inode,FI_AUTO_RECOVER ))clear_inode_flag (inode,FI_AUTO_RECOVER );
fs/f2fs/xattr.c +2 -2
@@ -106,7 +106,7 @@ static int f2fs_xattr_advise_set(const struct xattr_handler *handler,return -EINVAL ;F2FS_I (inode)->i_advise |= *(char *)value; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);return 0 ; }
@@ -554,7 +554,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,if (index ==F2FS_XATTR_INDEX_ENCRYPTION && !strcmp (name,F2FS_XATTR_NAME_ENCRYPTION_CONTEXT ))f2fs_set_encrypted_inode (inode); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);if (!error &&S_ISDIR (inode->i_mode))set_sbi_flag (F2FS_I_SB (inode),SBI_NEED_CP ); exit:
Signature · 1 line
2.8.3
Jaegeuk Kim
maintainerRe: [PATCH 3/3 v2] f2fs: keep dirty inodes selectively for checkpoint
Change log from v1:
o avoid performance regression
Quoted 1 line
From
b34a3d3c4c3fa2d6e000acc99bc5216a247bd6cbMon Sep 17 00:00:00 2001
From: Jaegeuk Kim <[email protected]>
Date: Fri, 14 Oct 2016 11:51:23 -0700
Subject: [PATCH] f2fs: keep dirty inodes selectively for checkpoint
This is to avoid no free segment bug during checkpoint caused by a number of dirty inodes.
The case was reported by Chao like this.
1. mount with lazytime option
2. fragment space
3. touch all files in the image
4. umount
In this case, we actually don't need to flush dirty inode to inode page during checkpoint.
--- fs/f2fs/acl.c | 2 +- fs/f2fs/dir.c | 6 +++--- fs/f2fs/extent_cache.c | 2 +- fs/f2fs/f2fs.h | 26 +++++++++++++------------- fs/f2fs/file.c | 9 +++++---- fs/f2fs/inline.c | 2 +- fs/f2fs/inode.c | 7 ++++--- fs/f2fs/namei.c | 6 +++--- fs/f2fs/super.c | 29 ++++++++++++++++------------- fs/f2fs/xattr.c | 4 ++-- 10 files changed, 49 insertions(+), 44 deletions(-)
fs/f2fs/acl.c +1 -1
@@ -384,7 +384,7 @@ int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,if (error)return error; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);if (default_acl) { error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
fs/f2fs/dir.c +3 -3
@@ -313,7 +313,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,set_page_dirty (page); dir->i_mtime = dir->i_ctime =current_time (dir); -f2fs_mark_inode_dirty_sync (dir); +f2fs_mark_inode_dirty_sync (dir, false);f2fs_put_page (page,1 ); }
@@ -466,7 +466,7 @@ void update_parent_metadata(struct inode *dir, struct inode *inode,clear_inode_flag (inode,FI_NEW_INODE ); } dir->i_mtime = dir->i_ctime =current_time (dir); -f2fs_mark_inode_dirty_sync (dir); +f2fs_mark_inode_dirty_sync (dir, false);if (F2FS_I (dir)->i_current_depth != current_depth)f2fs_i_depth_write (dir, current_depth);
@@ -731,7 +731,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,set_page_dirty (page); dir->i_ctime = dir->i_mtime =current_time (dir); -f2fs_mark_inode_dirty_sync (dir); +f2fs_mark_inode_dirty_sync (dir, false);if (inode)f2fs_drop_nlink (dir, inode);
fs/f2fs/extent_cache.c +1 -1
@@ -172,7 +172,7 @@ static void __drop_largest_extent(struct inode *inode,if (fofs < largest->fofs + largest->len && fofs + len > largest->fofs) { largest->len =0 ; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); } }
fs/f2fs/f2fs.h +13 -13
@@ -493,13 +493,13 @@ static inline bool __is_front_mergeable(struct extent_info *cur,return __is_extent_mergeable (cur, front); } -extern void f2fs_mark_inode_dirty_sync (struct inode *); +extern void f2fs_mark_inode_dirty_sync (struct inode *,bool );static inline void __try_update_largest_extent (struct inode *inode,struct extent_tree *et,struct extent_node *en) {if (en->ei.len > et->largest.len) { et->largest = en->ei; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -1627,7 +1627,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,return ;case FI_DATA_EXIST :case FI_INLINE_DOTS : -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); } }
@@ -1654,7 +1654,7 @@ static inline void set_acl_inode(struct inode *inode, umode_t mode) {F2FS_I (inode)->i_acl_mode = mode;set_inode_flag (inode,FI_ACL_MODE ); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, false); }static inline void f2fs_i_links_write (struct inode *inode,bool inc)
@@ -1663,7 +1663,7 @@ static inline void f2fs_i_links_write(struct inode *inode, bool inc)inc_nlink (inode); elsedrop_nlink (inode ); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); } static inline void f2fs_i_blocks_write(struct inode *inode,
@@ -1674,7 +1674,7 @@ static inline void f2fs_i_blocks_write(struct inode *inode, inode->i_blocks = add ? inode->i_blocks + diff : inode->i_blocks - diff; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);if (clean || recover)set_inode_flag (inode,FI_AUTO_RECOVER ); }
@@ -1688,7 +1688,7 @@ static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size)return ;i_size_write (inode, i_size); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);if (clean || recover)set_inode_flag (inode,FI_AUTO_RECOVER ); }
@@ -1703,19 +1703,19 @@ static inline bool f2fs_skip_inode_update(struct inode *inode)static inline void f2fs_i_depth_write (struct inode *inode,unsigned int depth) {F2FS_I (inode)->i_current_depth = depth; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline void f2fs_i_xnid_write (struct inode *inode,nid_t xnid) {F2FS_I (inode)->i_xattr_nid = xnid; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline void f2fs_i_pino_write (struct inode *inode,nid_t pino) {F2FS_I (inode)->i_pino = pino; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline void get_inline_info (struct inode *inode,struct f2fs_inode *ri)
@@ -1843,13 +1843,13 @@ static inline int is_file(struct inode *inode, int type)static inline void set_file (struct inode *inode,int type) {F2FS_I (inode)->i_advise |= type; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline void clear_file (struct inode *inode,int type) {F2FS_I (inode)->i_advise &= ~type; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true); }static inline int f2fs_readonly (struct super_block *sb)
@@ -2001,7 +2001,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)/* * super.c */ -int f2fs_inode_dirtied (struct inode *); +int f2fs_inode_dirtied (struct inode *,bool );void f2fs_inode_synced (struct inode *);int f2fs_commit_super (struct f2fs_sb_info *,bool );int f2fs_sync_fs (struct super_block *,int );
fs/f2fs/file.c +5 -4
@@ -264,7 +264,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, }if (need_inode_block_update (sbi, ino)) { -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);f2fs_write_inode (inode,NULL ); goto sync_nodes; }
@@ -632,7 +632,7 @@ int f2fs_truncate(struct inode *inode)return err; inode->i_mtime = inode->i_ctime =current_time (inode); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, false);return 0 ; }
@@ -721,7 +721,8 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) } } -f2fs_mark_inode_dirty_sync (inode); +/* update attributes only */ +f2fs_mark_inode_dirty_sync (inode, false);/* inode change will produce dirty node pages flushed by checkpoint */ f2fs_balance_fs (F2FS_I_SB (inode), true);
@@ -1399,7 +1400,7 @@ static long f2fs_fallocate(struct file *file, int mode,if (!ret) { inode->i_mtime = inode->i_ctime =current_time (inode); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, false);f2fs_update_time (F2FS_I_SB (inode),REQ_TIME ); }
fs/f2fs/inline.c +1 -1
@@ -575,7 +575,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,f2fs_put_page (page,1 ); dir->i_ctime = dir->i_mtime =current_time (dir); -f2fs_mark_inode_dirty_sync (dir); +f2fs_mark_inode_dirty_sync (dir, false);if (inode)f2fs_drop_nlink (dir, inode);
fs/f2fs/inode.c +4 -3
@@ -19,10 +19,11 @@#include <trace/events/f2fs.h> -void f2fs_mark_inode_dirty_sync (struct inode *inode) +void f2fs_mark_inode_dirty_sync (struct inode *inode,bool sync) { -if (f2fs_inode_dirtied (inode)) +if (f2fs_inode_dirtied (inode, sync))return ; +mark_inode_dirty_sync (inode); }
@@ -43,7 +44,7 @@ void f2fs_set_inode_flags(struct inode *inode) new_fl |=S_DIRSYNC ;inode_set_flags (inode, new_fl,S_SYNC |S_APPEND |S_IMMUTABLE |S_NOATIME |S_DIRSYNC ); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, false); }static void __get_inode_rdev (struct inode *inode,struct f2fs_inode *ri)
fs/f2fs/namei.c +3 -3
@@ -778,7 +778,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,up_write (&F2FS_I (old_inode)->i_sem); old_inode->i_ctime =current_time (old_inode); -f2fs_mark_inode_dirty_sync (old_inode); +f2fs_mark_inode_dirty_sync (old_inode, false);f2fs_delete_entry (old_entry, old_page, old_dir,NULL );
@@ -938,7 +938,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,f2fs_i_links_write (old_dir, old_nlink >0 );up_write (&F2FS_I (old_dir)->i_sem); } -f2fs_mark_inode_dirty_sync (old_dir); +f2fs_mark_inode_dirty_sync (old_dir, false);/* update directory entry info of new dir inode */ f2fs_set_link (new_dir, new_entry, new_page, old_inode);
@@ -953,7 +953,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,f2fs_i_links_write (new_dir, new_nlink >0 );up_write (&F2FS_I (new_dir)->i_sem); } -f2fs_mark_inode_dirty_sync (new_dir); +f2fs_mark_inode_dirty_sync (new_dir, false);f2fs_unlock_op (sbi);
fs/f2fs/super.c +16 -13
@@ -620,24 +620,25 @@ static int f2fs_drop_inode(struct inode *inode)return generic_drop_inode (inode); } -int f2fs_inode_dirtied (struct inode *inode) +int f2fs_inode_dirtied (struct inode *inode,bool sync) {struct f2fs_sb_info *sbi =F2FS_I_SB (inode); +int ret =0 ;spin_lock (&sbi->inode_lock[DIRTY_META ]);if (is_inode_flag_set (inode,FI_DIRTY_INODE )) { -spin_unlock (&sbi->inode_lock[DIRTY_META ]); -return 1 ; + ret =1 ; + }else { +set_inode_flag (inode,FI_DIRTY_INODE ); +stat_inc_dirty_inode (sbi,DIRTY_META ); } - -set_inode_flag (inode,FI_DIRTY_INODE ); -list_add_tail (&F2FS_I (inode)->gdirty_list, +if (sync &&list_empty (&F2FS_I (inode)->gdirty_list)) { +list_add_tail (&F2FS_I (inode)->gdirty_list, &sbi->inode_list[DIRTY_META ]); -inc_page_count (sbi,F2FS_DIRTY_IMETA ); -stat_inc_dirty_inode (sbi,DIRTY_META ); +inc_page_count (sbi,F2FS_DIRTY_IMETA ); + }spin_unlock (&sbi->inode_lock[DIRTY_META ]); - -return 0 ; +return ret; }void f2fs_inode_synced (struct inode *inode)
@@ -649,10 +650,12 @@ void f2fs_inode_synced(struct inode *inode)spin_unlock (&sbi->inode_lock[DIRTY_META ]);return ; } -list_del_init (&F2FS_I (inode)->gdirty_list); +if (!list_empty (&F2FS_I (inode)->gdirty_list)) { +list_del_init (&F2FS_I (inode)->gdirty_list); +dec_page_count (sbi,F2FS_DIRTY_IMETA ); + }clear_inode_flag (inode,FI_DIRTY_INODE );clear_inode_flag (inode,FI_AUTO_RECOVER ); -dec_page_count (sbi,F2FS_DIRTY_IMETA );stat_dec_dirty_inode (F2FS_I_SB (inode),DIRTY_META );spin_unlock (&sbi->inode_lock[DIRTY_META ]); }
@@ -676,7 +679,7 @@ static void f2fs_dirty_inode(struct inode *inode, int flags)if (is_inode_flag_set (inode,FI_AUTO_RECOVER ))clear_inode_flag (inode,FI_AUTO_RECOVER ); -f2fs_inode_dirtied (inode); +f2fs_inode_dirtied (inode, false); }static void f2fs_i_callback (struct rcu_head *head)
fs/f2fs/xattr.c +2 -2
@@ -106,7 +106,7 @@ static int f2fs_xattr_advise_set(const struct xattr_handler *handler,return -EINVAL ;F2FS_I (inode)->i_advise |= *(char *)value; -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);return 0 ; }
@@ -554,7 +554,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,if (index ==F2FS_XATTR_INDEX_ENCRYPTION && !strcmp (name,F2FS_XATTR_NAME_ENCRYPTION_CONTEXT ))f2fs_set_encrypted_inode (inode); -f2fs_mark_inode_dirty_sync (inode); +f2fs_mark_inode_dirty_sync (inode, true);if (!error &&S_ISDIR (inode->i_mode))set_sbi_flag (F2FS_I_SB (inode),SBI_NEED_CP ); exit:
Signature · 1 line
2.8.3
Re: [f2fs-dev] [PATCH 3/3 v2] f2fs: keep dirty inodes selectively for checkpoint
Quoted 18 lines · Jaegeuk Kim
Change log from v1:
o avoid performance regressionQuoted 1 line
From
b34a3d3c4c3fa2d6e000acc99bc5216a247bd6cbMon Sep 17 00:00:00 2001From: Jaegeuk Kim <[email protected]>
Date: Fri, 14 Oct 2016 11:51:23 -0700
Subject: [PATCH] f2fs: keep dirty inodes selectively for checkpointThis is to avoid no free segment bug during checkpoint caused by a number of dirty inodes.
The case was reported by Chao like this.
1. mount with lazytime option
2. fragment space
3. touch all files in the image
4. umount
Quoted 5 lines
In this case, we actually don't need to flush dirty inode to inode page during checkpoint.
Reported-by Chao Yu <[email protected]>Signed-off-by Jaegeuk Kim <[email protected]>
Good job! IMO, main job of checkpoint is to keep filesystem being consistent, not flush dirty datas of vfs/fs as much as possible, if there are some restrictions for the interface like fsync, syncfs, sync, the caller of checkpoint() should do related job like marking lazytime inode I_DIRTY_SYNC or flush last data in dirty inode into filesystem's cache, and so on. :)
BTW, can you change commit log a bit as below:
1. mount with lazytime option
2. fill 4k file until disk is full
3. sync filesystem
4. read all files in the image
5. umount
Thanks,
Jaegeuk Kim
maintainerRe: [f2fs-dev] [PATCH 3/3 v2] f2fs: keep dirty inodes selectively for checkpoint
Quoted 25 lines · Chao Yu
Quoted 18 lines · Jaegeuk Kim
Change log from v1:
o avoid performance regressionQuoted 1 line
From
b34a3d3c4c3fa2d6e000acc99bc5216a247bd6cbMon Sep 17 00:00:00 2001From: Jaegeuk Kim <[email protected]>
Date: Fri, 14 Oct 2016 11:51:23 -0700
Subject: [PATCH] f2fs: keep dirty inodes selectively for checkpointThis is to avoid no free segment bug during checkpoint caused by a number of dirty inodes.
The case was reported by Chao like this.
1. mount with lazytime option
2. fragment space
3. touch all files in the image
4. umountQuoted 5 lines
In this case, we actually don't need to flush dirty inode to inode page during checkpoint.
Reported-by Chao Yu <[email protected]>Signed-off-by Jaegeuk Kim <[email protected]>
Quoted 7 lines
Good job! IMO, main job of checkpoint is to keep filesystem being consistent, not flush dirty datas of vfs/fs as much as possible, if there are some restrictions for the interface like fsync, syncfs, sync, the caller of
checkpoint()should do related job like marking lazytime inodeI_DIRTY_SYNCor flush last data in dirty inode into filesystem's cache, and so on. :)BTW, can you change commit log a bit as below:
Okay, not a big deal.
Quoted 10 lines
1. mount with lazytime option
2. fill 4k file until disk is full
3. sync filesystem
4. read all files in the image
5. umountReviewed-by Chao Yu <[email protected]>Thanks,
Quoted 4 lines · Jaegeuk Kim
If there are a lot of dirty inodes, we need to flush all of them when doing checkpoint. So, we need to count this for enough free space.
Signed-off-by Jaegeuk Kim <[email protected]>
Quoted 27 lines · Jaegeuk Kim
If there are a lot of dirty inodes, we need to flush all of them when doing checkpoint. So, we need to count this for enough free space.
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/segment.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)fs/f2fs/segment.h +2
-1@@ -471,11 +471,12 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi) {int node_secs =get_blocktype_secs (sbi,F2FS_DIRTY_NODES );int dent_secs =get_blocktype_secs (sbi,F2FS_DIRTY_DENTS ); +int imeta_secs =get_blocktype_secs (sbi,F2FS_DIRTY_IMETA );if (test_opt (sbi,LFS ))return false; -return free_sections (sbi) <= (node_secs +2 * dent_secs + +return free_sections (sbi) <= (node_secs +2 * dent_secs + imeta_secs +reserved_sections (sbi) +1 ); }
fs/f2fs/segment.h static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, · line 490
Quoted 6 lines
fs/f2fs/segment.h +1
-0@@ -484,6 +485,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, {int node_secs =get_blocktype_secs (sbi,F2FS_DIRTY_NODES );int dent_secs =get_blocktype_secs (sbi,F2FS_DIRTY_DENTS ); +int imeta_secs =get_blocktype_secs (sbi,F2FS_DIRTY_IMETA ); node_secs +=get_blocktype_secs (sbi,F2FS_DIRTY_IMETA );
This line should be removed if we start to count dirty meta with imeta_secs from now on.
Thanks,
Quoted 12 lines
fs/f2fs/segment.h +2
-1@@ -491,7 +493,8 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,return false;return (free_sections (sbi) + freed) <= - (node_secs +2 * dent_secs +reserved_sections (sbi) + needed); + (node_secs +2 * dent_secs + imeta_secs + +reserved_sections (sbi) + needed); }static inline bool excess_prefree_segs (struct f2fs_sb_info *sbi)
Jaegeuk Kim
maintainerQuoted 33 lines · Chao Yu
Quoted 32 lines · Jaegeuk Kim
If there are a lot of dirty inodes, we need to flush all of them when doing checkpoint. So, we need to count this for enough free space.
Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/segment.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)fs/f2fs/segment.h +3
-1@@ -471,11 +471,12 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi) {int node_secs =get_blocktype_secs (sbi,F2FS_DIRTY_NODES );int dent_secs =get_blocktype_secs (sbi,F2FS_DIRTY_DENTS ); +int imeta_secs =get_blocktype_secs (sbi,F2FS_DIRTY_IMETA );if (test_opt (sbi,LFS ))return false; -return free_sections (sbi) <= (node_secs +2 * dent_secs + +return free_sections (sbi) <= (node_secs +2 * dent_secs + imeta_secs +reserved_sections (sbi) +1 ); }@@ -484,6 +485,7 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, {int node_secs =get_blocktype_secs (sbi,F2FS_DIRTY_NODES );int dent_secs =get_blocktype_secs (sbi,F2FS_DIRTY_DENTS ); +int imeta_secs =get_blocktype_secs (sbi,F2FS_DIRTY_IMETA );
Quoted 4 lines
fs/f2fs/segment.h static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, · line 490
Quoted 1 line
fs/f2fs/segment.h +0
-0node_secs +=get_blocktype_secs (sbi,F2FS_DIRTY_IMETA );This line should be removed if we start to count dirty meta with
imeta_secsfrom now on.
Ah, yes.
Fixed.
Thanks,
Quoted 15 lines
Thanks,
Quoted 12 lines
fs/f2fs/segment.h +2
-1@@ -491,7 +493,8 @@ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,return false;return (free_sections (sbi) + freed) <= - (node_secs +2 * dent_secs +reserved_sections (sbi) + needed); + (node_secs +2 * dent_secs + imeta_secs + +reserved_sections (sbi) + needed); }static inline bool excess_prefree_segs (struct f2fs_sb_info *sbi)