xref: /OK3568_Linux_fs/kernel/fs/f2fs/shrinker.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * f2fs shrinker support
4*4882a593Smuzhiyun  *   the basic infra was copied from fs/ubifs/shrinker.c
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (c) 2015 Motorola Mobility
7*4882a593Smuzhiyun  * Copyright (c) 2015 Jaegeuk Kim <jaegeuk@kernel.org>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun #include <linux/fs.h>
10*4882a593Smuzhiyun #include <linux/f2fs_fs.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "f2fs.h"
13*4882a593Smuzhiyun #include "node.h"
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun static LIST_HEAD(f2fs_list);
16*4882a593Smuzhiyun static DEFINE_SPINLOCK(f2fs_list_lock);
17*4882a593Smuzhiyun static unsigned int shrinker_run_no;
18*4882a593Smuzhiyun 
__count_nat_entries(struct f2fs_sb_info * sbi)19*4882a593Smuzhiyun static unsigned long __count_nat_entries(struct f2fs_sb_info *sbi)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	return NM_I(sbi)->nat_cnt[RECLAIMABLE_NAT];
22*4882a593Smuzhiyun }
23*4882a593Smuzhiyun 
__count_free_nids(struct f2fs_sb_info * sbi)24*4882a593Smuzhiyun static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	long count = NM_I(sbi)->nid_cnt[FREE_NID] - MAX_FREE_NIDS;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	return count > 0 ? count : 0;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
__count_extent_cache(struct f2fs_sb_info * sbi,enum extent_type type)31*4882a593Smuzhiyun static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi,
32*4882a593Smuzhiyun 					enum extent_type type)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	struct extent_tree_info *eti = &sbi->extent_tree[type];
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	return atomic_read(&eti->total_zombie_tree) +
37*4882a593Smuzhiyun 				atomic_read(&eti->total_ext_node);
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
f2fs_shrink_count(struct shrinker * shrink,struct shrink_control * sc)40*4882a593Smuzhiyun unsigned long f2fs_shrink_count(struct shrinker *shrink,
41*4882a593Smuzhiyun 				struct shrink_control *sc)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	struct f2fs_sb_info *sbi;
44*4882a593Smuzhiyun 	struct list_head *p;
45*4882a593Smuzhiyun 	unsigned long count = 0;
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	spin_lock(&f2fs_list_lock);
48*4882a593Smuzhiyun 	p = f2fs_list.next;
49*4882a593Smuzhiyun 	while (p != &f2fs_list) {
50*4882a593Smuzhiyun 		sbi = list_entry(p, struct f2fs_sb_info, s_list);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 		/* stop f2fs_put_super */
53*4882a593Smuzhiyun 		if (!mutex_trylock(&sbi->umount_mutex)) {
54*4882a593Smuzhiyun 			p = p->next;
55*4882a593Smuzhiyun 			continue;
56*4882a593Smuzhiyun 		}
57*4882a593Smuzhiyun 		spin_unlock(&f2fs_list_lock);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 		/* count read extent cache entries */
60*4882a593Smuzhiyun 		count += __count_extent_cache(sbi, EX_READ);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 		/* count block age extent cache entries */
63*4882a593Smuzhiyun 		count += __count_extent_cache(sbi, EX_BLOCK_AGE);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 		/* count clean nat cache entries */
66*4882a593Smuzhiyun 		count += __count_nat_entries(sbi);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 		/* count free nids cache entries */
69*4882a593Smuzhiyun 		count += __count_free_nids(sbi);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 		spin_lock(&f2fs_list_lock);
72*4882a593Smuzhiyun 		p = p->next;
73*4882a593Smuzhiyun 		mutex_unlock(&sbi->umount_mutex);
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun 	spin_unlock(&f2fs_list_lock);
76*4882a593Smuzhiyun 	return count;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
f2fs_shrink_scan(struct shrinker * shrink,struct shrink_control * sc)79*4882a593Smuzhiyun unsigned long f2fs_shrink_scan(struct shrinker *shrink,
80*4882a593Smuzhiyun 				struct shrink_control *sc)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	unsigned long nr = sc->nr_to_scan;
83*4882a593Smuzhiyun 	struct f2fs_sb_info *sbi;
84*4882a593Smuzhiyun 	struct list_head *p;
85*4882a593Smuzhiyun 	unsigned int run_no;
86*4882a593Smuzhiyun 	unsigned long freed = 0;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	spin_lock(&f2fs_list_lock);
89*4882a593Smuzhiyun 	do {
90*4882a593Smuzhiyun 		run_no = ++shrinker_run_no;
91*4882a593Smuzhiyun 	} while (run_no == 0);
92*4882a593Smuzhiyun 	p = f2fs_list.next;
93*4882a593Smuzhiyun 	while (p != &f2fs_list) {
94*4882a593Smuzhiyun 		sbi = list_entry(p, struct f2fs_sb_info, s_list);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 		if (sbi->shrinker_run_no == run_no)
97*4882a593Smuzhiyun 			break;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 		/* stop f2fs_put_super */
100*4882a593Smuzhiyun 		if (!mutex_trylock(&sbi->umount_mutex)) {
101*4882a593Smuzhiyun 			p = p->next;
102*4882a593Smuzhiyun 			continue;
103*4882a593Smuzhiyun 		}
104*4882a593Smuzhiyun 		spin_unlock(&f2fs_list_lock);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 		sbi->shrinker_run_no = run_no;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 		/* shrink extent cache entries */
109*4882a593Smuzhiyun 		freed += f2fs_shrink_age_extent_tree(sbi, nr >> 2);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 		/* shrink read extent cache entries */
112*4882a593Smuzhiyun 		freed += f2fs_shrink_read_extent_tree(sbi, nr >> 2);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 		/* shrink clean nat cache entries */
115*4882a593Smuzhiyun 		if (freed < nr)
116*4882a593Smuzhiyun 			freed += f2fs_try_to_free_nats(sbi, nr - freed);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 		/* shrink free nids cache entries */
119*4882a593Smuzhiyun 		if (freed < nr)
120*4882a593Smuzhiyun 			freed += f2fs_try_to_free_nids(sbi, nr - freed);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		spin_lock(&f2fs_list_lock);
123*4882a593Smuzhiyun 		p = p->next;
124*4882a593Smuzhiyun 		list_move_tail(&sbi->s_list, &f2fs_list);
125*4882a593Smuzhiyun 		mutex_unlock(&sbi->umount_mutex);
126*4882a593Smuzhiyun 		if (freed >= nr)
127*4882a593Smuzhiyun 			break;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 	spin_unlock(&f2fs_list_lock);
130*4882a593Smuzhiyun 	return freed;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
f2fs_join_shrinker(struct f2fs_sb_info * sbi)133*4882a593Smuzhiyun void f2fs_join_shrinker(struct f2fs_sb_info *sbi)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	spin_lock(&f2fs_list_lock);
136*4882a593Smuzhiyun 	list_add_tail(&sbi->s_list, &f2fs_list);
137*4882a593Smuzhiyun 	spin_unlock(&f2fs_list_lock);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
f2fs_leave_shrinker(struct f2fs_sb_info * sbi)140*4882a593Smuzhiyun void f2fs_leave_shrinker(struct f2fs_sb_info *sbi)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	f2fs_shrink_read_extent_tree(sbi, __count_extent_cache(sbi, EX_READ));
143*4882a593Smuzhiyun 	f2fs_shrink_age_extent_tree(sbi,
144*4882a593Smuzhiyun 				__count_extent_cache(sbi, EX_BLOCK_AGE));
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	spin_lock(&f2fs_list_lock);
147*4882a593Smuzhiyun 	list_del_init(&sbi->s_list);
148*4882a593Smuzhiyun 	spin_unlock(&f2fs_list_lock);
149*4882a593Smuzhiyun }
150