]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
f2fs: keep dirty inodes selectively for checkpoint
authorJaegeuk Kim <jaegeuk@kernel.org>
Fri, 14 Oct 2016 18:51:23 +0000 (11:51 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 23 Nov 2016 20:11:08 +0000 (12:11 -0800)
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. fill 4k file until disk is full
3. sync filesystem
4. read all files in the image
5. umount

In this case, we actually don't need to flush dirty inode to inode page during
checkpoint.

Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/acl.c
fs/f2fs/dir.c
fs/f2fs/extent_cache.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/inline.c
fs/f2fs/inode.c
fs/f2fs/namei.c
fs/f2fs/super.c
fs/f2fs/xattr.c

index 6fe23af509e1912739adf7fe46eef37633f16c31..8f487692c21f403b85225bb8a96ad44499daaf2f 100644 (file)
@@ -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,
index 9fd1b0e6d572b18337457d7feba5ddb5f6eae718..5f5678ecb4450b83c07522cbce5df82616a3e109 100644 (file)
@@ -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);
index 2b06d4fcd954eaaf8ac54d838db6dc728aa72dff..4db44da7ef69d1d4bb7be862d8266508c58a4793 100644 (file)
@@ -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);
        }
 }
 
index 692f08a53a3b764dac46543f74a6045d6cfd5dfe..e6d057ceaf760320423b01661335053ba1f0ce66 100644 (file)
@@ -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);
        else
                drop_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);
index 5e3e1674d4e8325d00114cf2907e750b5887c950..67a6b5ddc251cbcb9b34b1e72f80cdbc78e295bd 100644 (file)
@@ -264,7 +264,7 @@ sync_nodes:
        }
 
        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);
        }
 
index 9cd3379581be4e1d5310812c37818fc08044615f..8cab5df539c689765718b64b6fc9436f5034d11a 100644 (file)
@@ -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);
index d32fd0343eaed76b5441eb6d7eb8093feafd9bd2..bfa512dde4ab44cc3bf3aeb324c3254fcbee624f 100644 (file)
 
 #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)
index 489fa0d5f9149fc4b82c90a48d0278e8e81cb783..db33b5631dc81d16a88efd4a4f4de3f809be65b9 100644 (file)
@@ -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);
 
index bfa4414d707e798d2faacb18bcf74404e0d1df20..f8e2f319655d57466eff1dc8f5016c00e638ee5f 100644 (file)
@@ -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)
index 3e1c0280f8661dd26c790e682260ec01c422df48..c47ce2f330a14eba68de0c30c7f0f16358def5b4 100644 (file)
@@ -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: