f2fs: avoid race condition for shrinker count
[ Upstream commit a95ba66ac1457b76fe472c8e092ab1006271f16c ] Light reported sometimes shinker gets nat_cnt < dirty_nat_cnt resulting in wrong do_shinker work. Let's avoid to return insane overflowed value by adding single tracking value. Reported-by: Light Hsieh <Light.Hsieh@mediatek.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
3c0f0f5f58
commit
ee3f8aefd0
@@ -62,8 +62,8 @@ bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type)
|
||||
sizeof(struct free_nid)) >> PAGE_SHIFT;
|
||||
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
|
||||
} else if (type == NAT_ENTRIES) {
|
||||
mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >>
|
||||
PAGE_SHIFT;
|
||||
mem_size = (nm_i->nat_cnt[TOTAL_NAT] *
|
||||
sizeof(struct nat_entry)) >> PAGE_SHIFT;
|
||||
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
|
||||
if (excess_cached_nats(sbi))
|
||||
res = false;
|
||||
@@ -177,7 +177,8 @@ static struct nat_entry *__init_nat_entry(struct f2fs_nm_info *nm_i,
|
||||
list_add_tail(&ne->list, &nm_i->nat_entries);
|
||||
spin_unlock(&nm_i->nat_list_lock);
|
||||
|
||||
nm_i->nat_cnt++;
|
||||
nm_i->nat_cnt[TOTAL_NAT]++;
|
||||
nm_i->nat_cnt[RECLAIMABLE_NAT]++;
|
||||
return ne;
|
||||
}
|
||||
|
||||
@@ -207,7 +208,8 @@ static unsigned int __gang_lookup_nat_cache(struct f2fs_nm_info *nm_i,
|
||||
static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e)
|
||||
{
|
||||
radix_tree_delete(&nm_i->nat_root, nat_get_nid(e));
|
||||
nm_i->nat_cnt--;
|
||||
nm_i->nat_cnt[TOTAL_NAT]--;
|
||||
nm_i->nat_cnt[RECLAIMABLE_NAT]--;
|
||||
__free_nat_entry(e);
|
||||
}
|
||||
|
||||
@@ -253,7 +255,8 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
|
||||
if (get_nat_flag(ne, IS_DIRTY))
|
||||
goto refresh_list;
|
||||
|
||||
nm_i->dirty_nat_cnt++;
|
||||
nm_i->nat_cnt[DIRTY_NAT]++;
|
||||
nm_i->nat_cnt[RECLAIMABLE_NAT]--;
|
||||
set_nat_flag(ne, IS_DIRTY, true);
|
||||
refresh_list:
|
||||
spin_lock(&nm_i->nat_list_lock);
|
||||
@@ -273,7 +276,8 @@ static void __clear_nat_cache_dirty(struct f2fs_nm_info *nm_i,
|
||||
|
||||
set_nat_flag(ne, IS_DIRTY, false);
|
||||
set->entry_cnt--;
|
||||
nm_i->dirty_nat_cnt--;
|
||||
nm_i->nat_cnt[DIRTY_NAT]--;
|
||||
nm_i->nat_cnt[RECLAIMABLE_NAT]++;
|
||||
}
|
||||
|
||||
static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i,
|
||||
@@ -2944,14 +2948,17 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
LIST_HEAD(sets);
|
||||
int err = 0;
|
||||
|
||||
/* during unmount, let's flush nat_bits before checking dirty_nat_cnt */
|
||||
/*
|
||||
* during unmount, let's flush nat_bits before checking
|
||||
* nat_cnt[DIRTY_NAT].
|
||||
*/
|
||||
if (enabled_nat_bits(sbi, cpc)) {
|
||||
down_write(&nm_i->nat_tree_lock);
|
||||
remove_nats_in_journal(sbi);
|
||||
up_write(&nm_i->nat_tree_lock);
|
||||
}
|
||||
|
||||
if (!nm_i->dirty_nat_cnt)
|
||||
if (!nm_i->nat_cnt[DIRTY_NAT])
|
||||
return 0;
|
||||
|
||||
down_write(&nm_i->nat_tree_lock);
|
||||
@@ -2962,7 +2969,8 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
* into nat entry set.
|
||||
*/
|
||||
if (enabled_nat_bits(sbi, cpc) ||
|
||||
!__has_cursum_space(journal, nm_i->dirty_nat_cnt, NAT_JOURNAL))
|
||||
!__has_cursum_space(journal,
|
||||
nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL))
|
||||
remove_nats_in_journal(sbi);
|
||||
|
||||
while ((found = __gang_lookup_nat_set(nm_i,
|
||||
@@ -3086,7 +3094,6 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
|
||||
F2FS_RESERVED_NODE_NUM;
|
||||
nm_i->nid_cnt[FREE_NID] = 0;
|
||||
nm_i->nid_cnt[PREALLOC_NID] = 0;
|
||||
nm_i->nat_cnt = 0;
|
||||
nm_i->ram_thresh = DEF_RAM_THRESHOLD;
|
||||
nm_i->ra_nid_pages = DEF_RA_NID_PAGES;
|
||||
nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD;
|
||||
@@ -3220,7 +3227,7 @@ void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
__del_from_nat_cache(nm_i, natvec[idx]);
|
||||
}
|
||||
}
|
||||
f2fs_bug_on(sbi, nm_i->nat_cnt);
|
||||
f2fs_bug_on(sbi, nm_i->nat_cnt[TOTAL_NAT]);
|
||||
|
||||
/* destroy nat set cache */
|
||||
nid = 0;
|
||||
|
Reference in New Issue
Block a user