aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim2020-11-06 15:22:05 -0600
committerJaegeuk Kim2020-12-21 15:33:17 -0600
commit317c4f58d6e31cfe26e86f734fb6288530acc637 (patch)
treee00a1e144d7f333026920f59f2600c1f660f5bd1
parent46806a8d82aa96dcd0afa49da257f5f56c011a09 (diff)
downloadkernel-317c4f58d6e31cfe26e86f734fb6288530acc637.tar.gz
kernel-317c4f58d6e31cfe26e86f734fb6288530acc637.tar.xz
kernel-317c4f58d6e31cfe26e86f734fb6288530acc637.zip
f2fs: avoid race condition for shrinker count
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>
-rw-r--r--fs/f2fs/checkpoint.c2
-rw-r--r--fs/f2fs/debug.c11
-rw-r--r--fs/f2fs/f2fs.h10
-rw-r--r--fs/f2fs/node.c29
-rw-r--r--fs/f2fs/node.h4
-rw-r--r--fs/f2fs/shrinker.c4
6 files changed, 36 insertions, 24 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 14ba1519639e..617d0f6b0836 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -1619,7 +1619,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
1619 goto out; 1619 goto out;
1620 } 1620 }
1621 1621
1622 if (NM_I(sbi)->dirty_nat_cnt == 0 && 1622 if (NM_I(sbi)->nat_cnt[DIRTY_NAT] == 0 &&
1623 SIT_I(sbi)->dirty_sentries == 0 && 1623 SIT_I(sbi)->dirty_sentries == 0 &&
1624 prefree_segments(sbi) == 0) { 1624 prefree_segments(sbi) == 0) {
1625 f2fs_flush_sit_entries(sbi, cpc); 1625 f2fs_flush_sit_entries(sbi, cpc);
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index a8357fd4f5fa..197c914119da 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -145,8 +145,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
145 si->node_pages = NODE_MAPPING(sbi)->nrpages; 145 si->node_pages = NODE_MAPPING(sbi)->nrpages;
146 if (sbi->meta_inode) 146 if (sbi->meta_inode)
147 si->meta_pages = META_MAPPING(sbi)->nrpages; 147 si->meta_pages = META_MAPPING(sbi)->nrpages;
148 si->nats = NM_I(sbi)->nat_cnt; 148 si->nats = NM_I(sbi)->nat_cnt[TOTAL_NAT];
149 si->dirty_nats = NM_I(sbi)->dirty_nat_cnt; 149 si->dirty_nats = NM_I(sbi)->nat_cnt[DIRTY_NAT];
150 si->sits = MAIN_SEGS(sbi); 150 si->sits = MAIN_SEGS(sbi);
151 si->dirty_sits = SIT_I(sbi)->dirty_sentries; 151 si->dirty_sits = SIT_I(sbi)->dirty_sentries;
152 si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID]; 152 si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID];
@@ -278,9 +278,10 @@ get_cache:
278 si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID] + 278 si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID] +
279 NM_I(sbi)->nid_cnt[PREALLOC_NID]) * 279 NM_I(sbi)->nid_cnt[PREALLOC_NID]) *
280 sizeof(struct free_nid); 280 sizeof(struct free_nid);
281 si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry); 281 si->cache_mem += NM_I(sbi)->nat_cnt[TOTAL_NAT] *
282 si->cache_mem += NM_I(sbi)->dirty_nat_cnt * 282 sizeof(struct nat_entry);
283 sizeof(struct nat_entry_set); 283 si->cache_mem += NM_I(sbi)->nat_cnt[DIRTY_NAT] *
284 sizeof(struct nat_entry_set);
284 si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages); 285 si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
285 for (i = 0; i < MAX_INO_ENTRY; i++) 286 for (i = 0; i < MAX_INO_ENTRY; i++)
286 si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry); 287 si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 7c02b6d8465c..36090cd09011 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -820,6 +820,13 @@ enum nid_state {
820 MAX_NID_STATE, 820 MAX_NID_STATE,
821}; 821};
822 822
823enum nat_state {
824 TOTAL_NAT,
825 DIRTY_NAT,
826 RECLAIMABLE_NAT,
827 MAX_NAT_STATE,
828};
829
823struct f2fs_nm_info { 830struct f2fs_nm_info {
824 block_t nat_blkaddr; /* base disk address of NAT */ 831 block_t nat_blkaddr; /* base disk address of NAT */
825 nid_t max_nid; /* maximum possible node ids */ 832 nid_t max_nid; /* maximum possible node ids */
@@ -835,8 +842,7 @@ struct f2fs_nm_info {
835 struct rw_semaphore nat_tree_lock; /* protect nat_tree_lock */ 842 struct rw_semaphore nat_tree_lock; /* protect nat_tree_lock */
836 struct list_head nat_entries; /* cached nat entry list (clean) */ 843 struct list_head nat_entries; /* cached nat entry list (clean) */
837 spinlock_t nat_list_lock; /* protect clean nat entry list */ 844 spinlock_t nat_list_lock; /* protect clean nat entry list */
838 unsigned int nat_cnt; /* the # of cached nat entries */ 845 unsigned int nat_cnt[MAX_NAT_STATE]; /* the # of cached nat entries */
839 unsigned int dirty_nat_cnt; /* total num of nat entries in set */
840 unsigned int nat_blocks; /* # of nat blocks */ 846 unsigned int nat_blocks; /* # of nat blocks */
841 847
842 /* free node ids management */ 848 /* free node ids management */
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 42394de6c7eb..e65d73293a3f 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -62,8 +62,8 @@ bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type)
62 sizeof(struct free_nid)) >> PAGE_SHIFT; 62 sizeof(struct free_nid)) >> PAGE_SHIFT;
63 res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2); 63 res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
64 } else if (type == NAT_ENTRIES) { 64 } else if (type == NAT_ENTRIES) {
65 mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 65 mem_size = (nm_i->nat_cnt[TOTAL_NAT] *
66 PAGE_SHIFT; 66 sizeof(struct nat_entry)) >> PAGE_SHIFT;
67 res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2); 67 res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
68 if (excess_cached_nats(sbi)) 68 if (excess_cached_nats(sbi))
69 res = false; 69 res = false;
@@ -177,7 +177,8 @@ static struct nat_entry *__init_nat_entry(struct f2fs_nm_info *nm_i,
177 list_add_tail(&ne->list, &nm_i->nat_entries); 177 list_add_tail(&ne->list, &nm_i->nat_entries);
178 spin_unlock(&nm_i->nat_list_lock); 178 spin_unlock(&nm_i->nat_list_lock);
179 179
180 nm_i->nat_cnt++; 180 nm_i->nat_cnt[TOTAL_NAT]++;
181 nm_i->nat_cnt[RECLAIMABLE_NAT]++;
181 return ne; 182 return ne;
182} 183}
183 184
@@ -207,7 +208,8 @@ static unsigned int __gang_lookup_nat_cache(struct f2fs_nm_info *nm_i,
207static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e) 208static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e)
208{ 209{
209 radix_tree_delete(&nm_i->nat_root, nat_get_nid(e)); 210 radix_tree_delete(&nm_i->nat_root, nat_get_nid(e));
210 nm_i->nat_cnt--; 211 nm_i->nat_cnt[TOTAL_NAT]--;
212 nm_i->nat_cnt[RECLAIMABLE_NAT]--;
211 __free_nat_entry(e); 213 __free_nat_entry(e);
212} 214}
213 215
@@ -253,7 +255,8 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
253 if (get_nat_flag(ne, IS_DIRTY)) 255 if (get_nat_flag(ne, IS_DIRTY))
254 goto refresh_list; 256 goto refresh_list;
255 257
256 nm_i->dirty_nat_cnt++; 258 nm_i->nat_cnt[DIRTY_NAT]++;
259 nm_i->nat_cnt[RECLAIMABLE_NAT]--;
257 set_nat_flag(ne, IS_DIRTY, true); 260 set_nat_flag(ne, IS_DIRTY, true);
258refresh_list: 261refresh_list:
259 spin_lock(&nm_i->nat_list_lock); 262 spin_lock(&nm_i->nat_list_lock);
@@ -273,7 +276,8 @@ static void __clear_nat_cache_dirty(struct f2fs_nm_info *nm_i,
273 276
274 set_nat_flag(ne, IS_DIRTY, false); 277 set_nat_flag(ne, IS_DIRTY, false);
275 set->entry_cnt--; 278 set->entry_cnt--;
276 nm_i->dirty_nat_cnt--; 279 nm_i->nat_cnt[DIRTY_NAT]--;
280 nm_i->nat_cnt[RECLAIMABLE_NAT]++;
277} 281}
278 282
279static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i, 283static 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)
2944 LIST_HEAD(sets); 2948 LIST_HEAD(sets);
2945 int err = 0; 2949 int err = 0;
2946 2950
2947 /* during unmount, let's flush nat_bits before checking dirty_nat_cnt */ 2951 /*
2952 * during unmount, let's flush nat_bits before checking
2953 * nat_cnt[DIRTY_NAT].
2954 */
2948 if (enabled_nat_bits(sbi, cpc)) { 2955 if (enabled_nat_bits(sbi, cpc)) {
2949 down_write(&nm_i->nat_tree_lock); 2956 down_write(&nm_i->nat_tree_lock);
2950 remove_nats_in_journal(sbi); 2957 remove_nats_in_journal(sbi);
2951 up_write(&nm_i->nat_tree_lock); 2958 up_write(&nm_i->nat_tree_lock);
2952 } 2959 }
2953 2960
2954 if (!nm_i->dirty_nat_cnt) 2961 if (!nm_i->nat_cnt[DIRTY_NAT])
2955 return 0; 2962 return 0;
2956 2963
2957 down_write(&nm_i->nat_tree_lock); 2964 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)
2962 * into nat entry set. 2969 * into nat entry set.
2963 */ 2970 */
2964 if (enabled_nat_bits(sbi, cpc) || 2971 if (enabled_nat_bits(sbi, cpc) ||
2965 !__has_cursum_space(journal, nm_i->dirty_nat_cnt, NAT_JOURNAL)) 2972 !__has_cursum_space(journal,
2973 nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL))
2966 remove_nats_in_journal(sbi); 2974 remove_nats_in_journal(sbi);
2967 2975
2968 while ((found = __gang_lookup_nat_set(nm_i, 2976 while ((found = __gang_lookup_nat_set(nm_i,
@@ -3086,7 +3094,6 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
3086 F2FS_RESERVED_NODE_NUM; 3094 F2FS_RESERVED_NODE_NUM;
3087 nm_i->nid_cnt[FREE_NID] = 0; 3095 nm_i->nid_cnt[FREE_NID] = 0;
3088 nm_i->nid_cnt[PREALLOC_NID] = 0; 3096 nm_i->nid_cnt[PREALLOC_NID] = 0;
3089 nm_i->nat_cnt = 0;
3090 nm_i->ram_thresh = DEF_RAM_THRESHOLD; 3097 nm_i->ram_thresh = DEF_RAM_THRESHOLD;
3091 nm_i->ra_nid_pages = DEF_RA_NID_PAGES; 3098 nm_i->ra_nid_pages = DEF_RA_NID_PAGES;
3092 nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD; 3099 nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD;
@@ -3220,7 +3227,7 @@ void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi)
3220 __del_from_nat_cache(nm_i, natvec[idx]); 3227 __del_from_nat_cache(nm_i, natvec[idx]);
3221 } 3228 }
3222 } 3229 }
3223 f2fs_bug_on(sbi, nm_i->nat_cnt); 3230 f2fs_bug_on(sbi, nm_i->nat_cnt[TOTAL_NAT]);
3224 3231
3225 /* destroy nat set cache */ 3232 /* destroy nat set cache */
3226 nid = 0; 3233 nid = 0;
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index 69e5859e993c..f84541b57acb 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -126,13 +126,13 @@ static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne,
126 126
127static inline bool excess_dirty_nats(struct f2fs_sb_info *sbi) 127static inline bool excess_dirty_nats(struct f2fs_sb_info *sbi)
128{ 128{
129 return NM_I(sbi)->dirty_nat_cnt >= NM_I(sbi)->max_nid * 129 return NM_I(sbi)->nat_cnt[DIRTY_NAT] >= NM_I(sbi)->max_nid *
130 NM_I(sbi)->dirty_nats_ratio / 100; 130 NM_I(sbi)->dirty_nats_ratio / 100;
131} 131}
132 132
133static inline bool excess_cached_nats(struct f2fs_sb_info *sbi) 133static inline bool excess_cached_nats(struct f2fs_sb_info *sbi)
134{ 134{
135 return NM_I(sbi)->nat_cnt >= DEF_NAT_CACHE_THRESHOLD; 135 return NM_I(sbi)->nat_cnt[TOTAL_NAT] >= DEF_NAT_CACHE_THRESHOLD;
136} 136}
137 137
138static inline bool excess_dirty_nodes(struct f2fs_sb_info *sbi) 138static inline bool excess_dirty_nodes(struct f2fs_sb_info *sbi)
diff --git a/fs/f2fs/shrinker.c b/fs/f2fs/shrinker.c
index d66de5999a26..dd3c3c7a90ec 100644
--- a/fs/f2fs/shrinker.c
+++ b/fs/f2fs/shrinker.c
@@ -18,9 +18,7 @@ static unsigned int shrinker_run_no;
18 18
19static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi) 19static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi)
20{ 20{
21 long count = NM_I(sbi)->nat_cnt - NM_I(sbi)->dirty_nat_cnt; 21 return NM_I(sbi)->nat_cnt[RECLAIMABLE_NAT];
22
23 return count > 0 ? count : 0;
24} 22}
25 23
26static unsigned long __count_free_nids(struct f2fs_sb_info *sbi) 24static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)