]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
f2fs: fix to account FS_CP_DATA_IO correctly
authorChao Yu <chao@kernel.org>
Wed, 14 Sep 2022 13:28:46 +0000 (21:28 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Oct 2022 07:58:08 +0000 (09:58 +0200)
[ Upstream commit d80afefb17e01aa0c46a8eebc01882e0ebd8b0f6 ]

f2fs_inode_info.cp_task was introduced for FS_CP_DATA_IO accounting
since commit b0af6d491a6b ("f2fs: add app/fs io stat").

However, cp_task usage coverage has been increased due to below
commits:
commit 040d2bb318d1 ("f2fs: fix to avoid deadloop if data_flush is on")
commit 186857c5a14a ("f2fs: fix potential recursive call when enabling data_flush")

So that, if data_flush mountoption is on, when data flush was
triggered from background, the IO from data flush will be accounted
as checkpoint IO type incorrectly.

In order to fix this issue, this patch splits cp_task into two:
a) cp_task: used for IO accounting
b) wb_task: used to avoid deadlock

Fixes: 040d2bb318d1 ("f2fs: fix to avoid deadloop if data_flush is on")
Fixes: 186857c5a14a ("f2fs: fix potential recursive call when enabling data_flush")
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/segment.c

index 2a1930cfd513557d7ddbd481cbdfb3c669a9bd9b..5c77ae07150d32bd5994fdaf2de071e8c4403373 100644 (file)
@@ -1063,7 +1063,8 @@ void f2fs_remove_dirty_inode(struct inode *inode)
        spin_unlock(&sbi->inode_lock[type]);
 }
 
-int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
+int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type,
+                                               bool from_cp)
 {
        struct list_head *head;
        struct inode *inode;
@@ -1098,11 +1099,15 @@ retry:
        if (inode) {
                unsigned long cur_ino = inode->i_ino;
 
-               F2FS_I(inode)->cp_task = current;
+               if (from_cp)
+                       F2FS_I(inode)->cp_task = current;
+               F2FS_I(inode)->wb_task = current;
 
                filemap_fdatawrite(inode->i_mapping);
 
-               F2FS_I(inode)->cp_task = NULL;
+               F2FS_I(inode)->wb_task = NULL;
+               if (from_cp)
+                       F2FS_I(inode)->cp_task = NULL;
 
                iput(inode);
                /* We need to give cpu to another writers. */
@@ -1231,7 +1236,7 @@ retry_flush_dents:
        /* write all the dirty dentry pages */
        if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
                f2fs_unlock_all(sbi);
-               err = f2fs_sync_dirty_inodes(sbi, DIR_INODE);
+               err = f2fs_sync_dirty_inodes(sbi, DIR_INODE, true);
                if (err)
                        return err;
                cond_resched();
index f2a272613477919cae884be0c3ca2500a2c72003..d3768115e3b8dd763cd478b0e59ec2516595793d 100644 (file)
@@ -2843,7 +2843,7 @@ out:
        }
        unlock_page(page);
        if (!S_ISDIR(inode->i_mode) && !IS_NOQUOTA(inode) &&
-                       !F2FS_I(inode)->cp_task && allow_balance)
+                       !F2FS_I(inode)->wb_task && allow_balance)
                f2fs_balance_fs(sbi, need_balance_fs);
 
        if (unlikely(f2fs_cp_error(sbi))) {
@@ -3141,7 +3141,7 @@ static inline bool __should_serialize_io(struct inode *inode,
                                        struct writeback_control *wbc)
 {
        /* to avoid deadlock in path of data flush */
-       if (F2FS_I(inode)->cp_task)
+       if (F2FS_I(inode)->wb_task)
                return false;
 
        if (!S_ISREG(inode->i_mode))
index f9d5110bbcd820037acdf64890d5475e09b89b9c..7896cbadbcd753721d7a058899cc523ef39b85bb 100644 (file)
@@ -784,6 +784,7 @@ struct f2fs_inode_info {
        unsigned int clevel;            /* maximum level of given file name */
        struct task_struct *task;       /* lookup and create consistency */
        struct task_struct *cp_task;    /* separate cp/wb IO stats*/
+       struct task_struct *wb_task;    /* indicate inode is in context of writeback */
        nid_t i_xattr_nid;              /* node id that contains xattrs */
        loff_t  last_disk_size;         /* lastly written file size */
        spinlock_t i_size_lock;         /* protect last_disk_size */
@@ -3710,7 +3711,8 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi);
 int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi);
 void f2fs_update_dirty_folio(struct inode *inode, struct folio *folio);
 void f2fs_remove_dirty_inode(struct inode *inode);
-int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type);
+int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type,
+                                                               bool from_cp);
 void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type);
 u64 f2fs_get_sectors_written(struct f2fs_sb_info *sbi);
 int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc);
index 52df19a0638b1d762d2cd131e2ae1a2defc28bf1..b740ff81024e4a5fc2131ee617bbb9f71ee412b7 100644 (file)
@@ -469,7 +469,7 @@ do_sync:
                mutex_lock(&sbi->flush_lock);
 
                blk_start_plug(&plug);
-               f2fs_sync_dirty_inodes(sbi, FILE_INODE);
+               f2fs_sync_dirty_inodes(sbi, FILE_INODE, false);
                blk_finish_plug(&plug);
 
                mutex_unlock(&sbi->flush_lock);