Commit ba900534 authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: don't get FREEZE lock in f2fs_evict_inode in frozen fs



Let's purge inode cache in order to avoid the below deadlock.

[freeze test]                         shrinkder
freeze_super
 - pwercpu_down_write(SB_FREEZE_FS)
                                       - super_cache_scan
                                         - down_read(&sb->s_umount)
                                           - prune_icache_sb
                                            - dispose_list
                                             - evict
                                              - f2fs_evict_inode
thaw_super
 - down_write(&sb->s_umount);
                                              - __percpu_down_read(SB_FREEZE_FS)

Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent d13732cc
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -458,6 +458,7 @@ Description: Show status of f2fs superblock in real time.
		0x800  SBI_QUOTA_SKIP_FLUSH  skip flushing quota in current CP
		0x1000 SBI_QUOTA_NEED_REPAIR quota file may be corrupted
		0x2000 SBI_IS_RESIZEFS       resizefs is in process
		0x4000 SBI_IS_FREEZING       freefs is in process
		====== ===================== =================================

What:		/sys/fs/f2fs/<disk>/ckpt_thread_ioprio
+1 −0
Original line number Diff line number Diff line
@@ -338,6 +338,7 @@ static char *s_flag[] = {
	[SBI_QUOTA_SKIP_FLUSH]	= " quota_skip_flush",
	[SBI_QUOTA_NEED_REPAIR]	= " quota_need_repair",
	[SBI_IS_RESIZEFS]	= " resizefs",
	[SBI_IS_FREEZING]	= " freezefs",
};

static int stat_show(struct seq_file *s, void *v)
+1 −0
Original line number Diff line number Diff line
@@ -1293,6 +1293,7 @@ enum {
	SBI_QUOTA_SKIP_FLUSH,			/* skip flushing quota in current CP */
	SBI_QUOTA_NEED_REPAIR,			/* quota file may be corrupted */
	SBI_IS_RESIZEFS,			/* resizefs is in process */
	SBI_IS_FREEZING,			/* freezefs is in process */
};

enum {
+4 −2
Original line number Diff line number Diff line
@@ -778,6 +778,7 @@ 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))
		sb_start_intwrite(inode->i_sb);
	set_inode_flag(inode, FI_NO_ALLOC);
	i_size_write(inode, 0);
@@ -809,6 +810,7 @@ void f2fs_evict_inode(struct inode *inode)
		if (dquot_initialize_needed(inode))
			set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
	}
	if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING))
		sb_end_intwrite(inode->i_sb);
no_delete:
	dquot_drop(inode);
+4 −0
Original line number Diff line number Diff line
@@ -1663,11 +1663,15 @@ static int f2fs_freeze(struct super_block *sb)
	/* ensure no checkpoint required */
	if (!llist_empty(&F2FS_SB(sb)->cprc_info.issue_list))
		return -EINVAL;

	/* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */
	set_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
	return 0;
}

static int f2fs_unfreeze(struct super_block *sb)
{
	clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
	return 0;
}