f2fs: Prevent s_writer rw_sem count mismatch in f2fs_evict_inode
authorYeongjin Gil <youngjin.gil@samsung.com>
Fri, 22 Mar 2024 04:16:39 +0000 (13:16 +0900)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 26 Mar 2024 16:52:26 +0000 (16:52 +0000)
If f2fs_evict_inode is called between freeze_super and thaw_super, the
s_writer rwsem count may become negative, resulting in hang.

CPU1                       CPU2

f2fs_resize_fs()           f2fs_evict_inode()
  f2fs_freeze
    set SBI_IS_FREEZING
                             skip sb_start_intwrite
  f2fs_unfreeze
    clear SBI_IS_FREEZING
                             sb_end_intwrite

To solve this problem, the call to sb_end_write is determined by whether
sb_start_intwrite is called, rather than the current freezing status.

Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
Reviewed-by: Sunmin Jeong <s_min.jeong@samsung.com>
Signed-off-by: Yeongjin Gil <youngjin.gil@samsung.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/inode.c

index c26effdce9aa7952e234cbff641b7d6f9721682d..12b1fef31f4375a7a48cde84a8053e9ddddebe78 100644 (file)
@@ -804,6 +804,7 @@ void f2fs_evict_inode(struct inode *inode)
        struct f2fs_inode_info *fi = F2FS_I(inode);
        nid_t xnid = fi->i_xattr_nid;
        int err = 0;
+       bool freeze_protected = false;
 
        f2fs_abort_atomic_write(inode, true);
 
@@ -843,8 +844,10 @@ void f2fs_evict_inode(struct inode *inode)
        f2fs_remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
        f2fs_remove_ino_entry(sbi, inode->i_ino, FLUSH_INO);
 
-       if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING))
+       if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING)) {
                sb_start_intwrite(inode->i_sb);
+               freeze_protected = true;
+       }
        set_inode_flag(inode, FI_NO_ALLOC);
        i_size_write(inode, 0);
 retry:
@@ -887,7 +890,7 @@ retry:
                if (dquot_initialize_needed(inode))
                        set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
        }
-       if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING))
+       if (freeze_protected)
                sb_end_intwrite(inode->i_sb);
 no_delete:
        dquot_drop(inode);