xref: /linux/fs/f2fs/extent_cache.c (revision 79952bdcbcea53e57c2ca97e7448f8a6bdb6106a)
17c1a000dSChao Yu // SPDX-License-Identifier: GPL-2.0
2a28ef1f5SChao Yu /*
3a28ef1f5SChao Yu  * f2fs extent cache support
4a28ef1f5SChao Yu  *
5a28ef1f5SChao Yu  * Copyright (c) 2015 Motorola Mobility
6a28ef1f5SChao Yu  * Copyright (c) 2015 Samsung Electronics
7a28ef1f5SChao Yu  * Authors: Jaegeuk Kim <jaegeuk@kernel.org>
8a28ef1f5SChao Yu  *          Chao Yu <chao2.yu@samsung.com>
971644dffSJaegeuk Kim  *
1071644dffSJaegeuk Kim  * block_age-based extent cache added by:
1171644dffSJaegeuk Kim  * Copyright (c) 2022 xiaomi Co., Ltd.
1271644dffSJaegeuk Kim  *             http://www.xiaomi.com/
13a28ef1f5SChao Yu  */
14a28ef1f5SChao Yu 
15a28ef1f5SChao Yu #include <linux/fs.h>
16a28ef1f5SChao Yu #include <linux/f2fs_fs.h>
17a28ef1f5SChao Yu 
18a28ef1f5SChao Yu #include "f2fs.h"
19a28ef1f5SChao Yu #include "node.h"
20a28ef1f5SChao Yu #include <trace/events/f2fs.h>
21a28ef1f5SChao Yu 
22d7409b05SChao Yu bool sanity_check_extent_cache(struct inode *inode, struct page *ipage)
23269d1194SChao Yu {
24269d1194SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
25d7409b05SChao Yu 	struct f2fs_extent *i_ext = &F2FS_INODE(ipage)->i_ext;
26d7409b05SChao Yu 	struct extent_info ei;
27269d1194SChao Yu 
28d7409b05SChao Yu 	get_read_extent_info(&ei, i_ext);
29d7409b05SChao Yu 
30d7409b05SChao Yu 	if (!ei.len)
31269d1194SChao Yu 		return true;
32269d1194SChao Yu 
33d7409b05SChao Yu 	if (!f2fs_is_valid_blkaddr(sbi, ei.blk, DATA_GENERIC_ENHANCE) ||
34d7409b05SChao Yu 	    !f2fs_is_valid_blkaddr(sbi, ei.blk + ei.len - 1,
35bd90c5cdSJaegeuk Kim 					DATA_GENERIC_ENHANCE)) {
36269d1194SChao Yu 		f2fs_warn(sbi, "%s: inode (ino=%lx) extent info [%u, %u, %u] is incorrect, run fsck to fix",
37269d1194SChao Yu 			  __func__, inode->i_ino,
38d7409b05SChao Yu 			  ei.blk, ei.fofs, ei.len);
39269d1194SChao Yu 		return false;
40269d1194SChao Yu 	}
41269d1194SChao Yu 	return true;
42269d1194SChao Yu }
43269d1194SChao Yu 
443bac20a8SJaegeuk Kim static void __set_extent_info(struct extent_info *ei,
453bac20a8SJaegeuk Kim 				unsigned int fofs, unsigned int len,
46e7547dacSJaegeuk Kim 				block_t blk, bool keep_clen,
4771644dffSJaegeuk Kim 				unsigned long age, unsigned long last_blocks,
48e7547dacSJaegeuk Kim 				enum extent_type type)
493bac20a8SJaegeuk Kim {
503bac20a8SJaegeuk Kim 	ei->fofs = fofs;
513bac20a8SJaegeuk Kim 	ei->len = len;
523bac20a8SJaegeuk Kim 
53e7547dacSJaegeuk Kim 	if (type == EX_READ) {
54e7547dacSJaegeuk Kim 		ei->blk = blk;
553bac20a8SJaegeuk Kim 		if (keep_clen)
563bac20a8SJaegeuk Kim 			return;
573bac20a8SJaegeuk Kim #ifdef CONFIG_F2FS_FS_COMPRESSION
583bac20a8SJaegeuk Kim 		ei->c_len = 0;
593bac20a8SJaegeuk Kim #endif
6071644dffSJaegeuk Kim 	} else if (type == EX_BLOCK_AGE) {
6171644dffSJaegeuk Kim 		ei->age = age;
6271644dffSJaegeuk Kim 		ei->last_blocks = last_blocks;
633bac20a8SJaegeuk Kim 	}
64e7547dacSJaegeuk Kim }
653bac20a8SJaegeuk Kim 
6672840cccSJaegeuk Kim static bool __init_may_extent_tree(struct inode *inode, enum extent_type type)
6772840cccSJaegeuk Kim {
6872840cccSJaegeuk Kim 	if (type == EX_READ)
69f8039821SJaegeuk Kim 		return test_opt(F2FS_I_SB(inode), READ_EXTENT_CACHE) &&
70f8039821SJaegeuk Kim 			S_ISREG(inode->i_mode);
71f8039821SJaegeuk Kim 	if (type == EX_BLOCK_AGE)
72f8039821SJaegeuk Kim 		return test_opt(F2FS_I_SB(inode), AGE_EXTENT_CACHE) &&
73f8039821SJaegeuk Kim 			(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode));
7472840cccSJaegeuk Kim 	return false;
7572840cccSJaegeuk Kim }
7672840cccSJaegeuk Kim 
77e7547dacSJaegeuk Kim static bool __may_extent_tree(struct inode *inode, enum extent_type type)
783bac20a8SJaegeuk Kim {
793bac20a8SJaegeuk Kim 	/*
803bac20a8SJaegeuk Kim 	 * for recovered files during mount do not create extents
813bac20a8SJaegeuk Kim 	 * if shrinker is not registered.
823bac20a8SJaegeuk Kim 	 */
8372840cccSJaegeuk Kim 	if (list_empty(&F2FS_I_SB(inode)->s_list))
843bac20a8SJaegeuk Kim 		return false;
853bac20a8SJaegeuk Kim 
86f8039821SJaegeuk Kim 	if (!__init_may_extent_tree(inode, type))
87f8039821SJaegeuk Kim 		return false;
88f8039821SJaegeuk Kim 
89f8039821SJaegeuk Kim 	if (type == EX_READ) {
90f8039821SJaegeuk Kim 		if (is_inode_flag_set(inode, FI_NO_EXTENT))
91f8039821SJaegeuk Kim 			return false;
92f8039821SJaegeuk Kim 		if (is_inode_flag_set(inode, FI_COMPRESSED_FILE) &&
93f8039821SJaegeuk Kim 				 !f2fs_sb_has_readonly(F2FS_I_SB(inode)))
94f8039821SJaegeuk Kim 			return false;
95f8039821SJaegeuk Kim 	} else if (type == EX_BLOCK_AGE) {
96f8039821SJaegeuk Kim 		if (is_inode_flag_set(inode, FI_COMPRESSED_FILE))
97f8039821SJaegeuk Kim 			return false;
98f8039821SJaegeuk Kim 		if (file_is_cold(inode))
99f8039821SJaegeuk Kim 			return false;
100f8039821SJaegeuk Kim 	}
101f8039821SJaegeuk Kim 	return true;
1023bac20a8SJaegeuk Kim }
1033bac20a8SJaegeuk Kim 
1043bac20a8SJaegeuk Kim static void __try_update_largest_extent(struct extent_tree *et,
1053bac20a8SJaegeuk Kim 						struct extent_node *en)
1063bac20a8SJaegeuk Kim {
107e7547dacSJaegeuk Kim 	if (et->type != EX_READ)
108e7547dacSJaegeuk Kim 		return;
1093bac20a8SJaegeuk Kim 	if (en->ei.len <= et->largest.len)
1103bac20a8SJaegeuk Kim 		return;
1113bac20a8SJaegeuk Kim 
1123bac20a8SJaegeuk Kim 	et->largest = en->ei;
1133bac20a8SJaegeuk Kim 	et->largest_updated = true;
1143bac20a8SJaegeuk Kim }
1153bac20a8SJaegeuk Kim 
1163bac20a8SJaegeuk Kim static bool __is_extent_mergeable(struct extent_info *back,
117e7547dacSJaegeuk Kim 		struct extent_info *front, enum extent_type type)
1183bac20a8SJaegeuk Kim {
119e7547dacSJaegeuk Kim 	if (type == EX_READ) {
1203bac20a8SJaegeuk Kim #ifdef CONFIG_F2FS_FS_COMPRESSION
1213bac20a8SJaegeuk Kim 		if (back->c_len && back->len != back->c_len)
1223bac20a8SJaegeuk Kim 			return false;
1233bac20a8SJaegeuk Kim 		if (front->c_len && front->len != front->c_len)
1243bac20a8SJaegeuk Kim 			return false;
1253bac20a8SJaegeuk Kim #endif
1263bac20a8SJaegeuk Kim 		return (back->fofs + back->len == front->fofs &&
1273bac20a8SJaegeuk Kim 				back->blk + back->len == front->blk);
12871644dffSJaegeuk Kim 	} else if (type == EX_BLOCK_AGE) {
12971644dffSJaegeuk Kim 		return (back->fofs + back->len == front->fofs &&
13071644dffSJaegeuk Kim 			abs(back->age - front->age) <= SAME_AGE_REGION &&
13171644dffSJaegeuk Kim 			abs(back->last_blocks - front->last_blocks) <=
13271644dffSJaegeuk Kim 							SAME_AGE_REGION);
1333bac20a8SJaegeuk Kim 	}
134e7547dacSJaegeuk Kim 	return false;
135e7547dacSJaegeuk Kim }
1363bac20a8SJaegeuk Kim 
1373bac20a8SJaegeuk Kim static bool __is_back_mergeable(struct extent_info *cur,
138e7547dacSJaegeuk Kim 		struct extent_info *back, enum extent_type type)
1393bac20a8SJaegeuk Kim {
140e7547dacSJaegeuk Kim 	return __is_extent_mergeable(back, cur, type);
1413bac20a8SJaegeuk Kim }
1423bac20a8SJaegeuk Kim 
1433bac20a8SJaegeuk Kim static bool __is_front_mergeable(struct extent_info *cur,
144e7547dacSJaegeuk Kim 		struct extent_info *front, enum extent_type type)
1453bac20a8SJaegeuk Kim {
146e7547dacSJaegeuk Kim 	return __is_extent_mergeable(cur, front, type);
1473bac20a8SJaegeuk Kim }
1483bac20a8SJaegeuk Kim 
149bf21acf9SJaegeuk Kim static struct extent_node *__lookup_extent_node(struct rb_root_cached *root,
150bf21acf9SJaegeuk Kim 			struct extent_node *cached_en, unsigned int fofs)
15154c2258cSChao Yu {
1524dada3fdSChao Yu 	struct rb_node *node = root->rb_root.rb_node;
153bf21acf9SJaegeuk Kim 	struct extent_node *en;
15454c2258cSChao Yu 
155bf21acf9SJaegeuk Kim 	/* check a cached entry */
156bf21acf9SJaegeuk Kim 	if (cached_en && cached_en->ei.fofs <= fofs &&
157bf21acf9SJaegeuk Kim 			cached_en->ei.fofs + cached_en->ei.len > fofs)
158bf21acf9SJaegeuk Kim 		return cached_en;
159bf21acf9SJaegeuk Kim 
160bf21acf9SJaegeuk Kim 	/* check rb_tree */
16154c2258cSChao Yu 	while (node) {
162bf21acf9SJaegeuk Kim 		en = rb_entry(node, struct extent_node, rb_node);
16354c2258cSChao Yu 
164bf21acf9SJaegeuk Kim 		if (fofs < en->ei.fofs)
16554c2258cSChao Yu 			node = node->rb_left;
166bf21acf9SJaegeuk Kim 		else if (fofs >= en->ei.fofs + en->ei.len)
16754c2258cSChao Yu 			node = node->rb_right;
16854c2258cSChao Yu 		else
169bf21acf9SJaegeuk Kim 			return en;
17054c2258cSChao Yu 	}
17154c2258cSChao Yu 	return NULL;
17254c2258cSChao Yu }
17354c2258cSChao Yu 
17454c2258cSChao Yu /*
175bf21acf9SJaegeuk Kim  * lookup rb entry in position of @fofs in rb-tree,
17654c2258cSChao Yu  * if hit, return the entry, otherwise, return NULL
177bf21acf9SJaegeuk Kim  * @prev_ex: extent before fofs
178bf21acf9SJaegeuk Kim  * @next_ex: extent after fofs
179bf21acf9SJaegeuk Kim  * @insert_p: insert point for new extent at fofs
180146949deSJinyoung CHOI  * in order to simplify the insertion after.
18154c2258cSChao Yu  * tree must stay unchanged between lookup and insertion.
18254c2258cSChao Yu  */
183bf21acf9SJaegeuk Kim static struct extent_node *__lookup_extent_node_ret(struct rb_root_cached *root,
184bf21acf9SJaegeuk Kim 				struct extent_node *cached_en,
185bf21acf9SJaegeuk Kim 				unsigned int fofs,
186bf21acf9SJaegeuk Kim 				struct extent_node **prev_entry,
187bf21acf9SJaegeuk Kim 				struct extent_node **next_entry,
18854c2258cSChao Yu 				struct rb_node ***insert_p,
189004b6862SChao Yu 				struct rb_node **insert_parent,
190bf21acf9SJaegeuk Kim 				bool *leftmost)
19154c2258cSChao Yu {
1924dada3fdSChao Yu 	struct rb_node **pnode = &root->rb_root.rb_node;
19354c2258cSChao Yu 	struct rb_node *parent = NULL, *tmp_node;
194bf21acf9SJaegeuk Kim 	struct extent_node *en = cached_en;
19554c2258cSChao Yu 
19654c2258cSChao Yu 	*insert_p = NULL;
19754c2258cSChao Yu 	*insert_parent = NULL;
19854c2258cSChao Yu 	*prev_entry = NULL;
19954c2258cSChao Yu 	*next_entry = NULL;
20054c2258cSChao Yu 
2014dada3fdSChao Yu 	if (RB_EMPTY_ROOT(&root->rb_root))
20254c2258cSChao Yu 		return NULL;
20354c2258cSChao Yu 
204bf21acf9SJaegeuk Kim 	if (en && en->ei.fofs <= fofs && en->ei.fofs + en->ei.len > fofs)
20554c2258cSChao Yu 		goto lookup_neighbors;
20654c2258cSChao Yu 
2074dada3fdSChao Yu 	*leftmost = true;
2084dada3fdSChao Yu 
20954c2258cSChao Yu 	while (*pnode) {
21054c2258cSChao Yu 		parent = *pnode;
211bf21acf9SJaegeuk Kim 		en = rb_entry(*pnode, struct extent_node, rb_node);
21254c2258cSChao Yu 
213bf21acf9SJaegeuk Kim 		if (fofs < en->ei.fofs) {
21454c2258cSChao Yu 			pnode = &(*pnode)->rb_left;
215bf21acf9SJaegeuk Kim 		} else if (fofs >= en->ei.fofs + en->ei.len) {
21654c2258cSChao Yu 			pnode = &(*pnode)->rb_right;
2174dada3fdSChao Yu 			*leftmost = false;
2184dada3fdSChao Yu 		} else {
21954c2258cSChao Yu 			goto lookup_neighbors;
22054c2258cSChao Yu 		}
2214dada3fdSChao Yu 	}
22254c2258cSChao Yu 
22354c2258cSChao Yu 	*insert_p = pnode;
22454c2258cSChao Yu 	*insert_parent = parent;
22554c2258cSChao Yu 
226bf21acf9SJaegeuk Kim 	en = rb_entry(parent, struct extent_node, rb_node);
22754c2258cSChao Yu 	tmp_node = parent;
228bf21acf9SJaegeuk Kim 	if (parent && fofs > en->ei.fofs)
22954c2258cSChao Yu 		tmp_node = rb_next(parent);
230bf21acf9SJaegeuk Kim 	*next_entry = rb_entry_safe(tmp_node, struct extent_node, rb_node);
23154c2258cSChao Yu 
23254c2258cSChao Yu 	tmp_node = parent;
233bf21acf9SJaegeuk Kim 	if (parent && fofs < en->ei.fofs)
23454c2258cSChao Yu 		tmp_node = rb_prev(parent);
235bf21acf9SJaegeuk Kim 	*prev_entry = rb_entry_safe(tmp_node, struct extent_node, rb_node);
23654c2258cSChao Yu 	return NULL;
23754c2258cSChao Yu 
23854c2258cSChao Yu lookup_neighbors:
239bf21acf9SJaegeuk Kim 	if (fofs == en->ei.fofs) {
24054c2258cSChao Yu 		/* lookup prev node for merging backward later */
241bf21acf9SJaegeuk Kim 		tmp_node = rb_prev(&en->rb_node);
242bf21acf9SJaegeuk Kim 		*prev_entry = rb_entry_safe(tmp_node,
243bf21acf9SJaegeuk Kim 					struct extent_node, rb_node);
24454c2258cSChao Yu 	}
245bf21acf9SJaegeuk Kim 	if (fofs == en->ei.fofs + en->ei.len - 1) {
24654c2258cSChao Yu 		/* lookup next node for merging frontward later */
247bf21acf9SJaegeuk Kim 		tmp_node = rb_next(&en->rb_node);
248bf21acf9SJaegeuk Kim 		*next_entry = rb_entry_safe(tmp_node,
249bf21acf9SJaegeuk Kim 					struct extent_node, rb_node);
25054c2258cSChao Yu 	}
251bf21acf9SJaegeuk Kim 	return en;
25254c2258cSChao Yu }
25354c2258cSChao Yu 
254a28ef1f5SChao Yu static struct kmem_cache *extent_tree_slab;
255a28ef1f5SChao Yu static struct kmem_cache *extent_node_slab;
256a28ef1f5SChao Yu 
257a28ef1f5SChao Yu static struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi,
258a28ef1f5SChao Yu 				struct extent_tree *et, struct extent_info *ei,
2594dada3fdSChao Yu 				struct rb_node *parent, struct rb_node **p,
2604dada3fdSChao Yu 				bool leftmost)
261a28ef1f5SChao Yu {
262e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
263a28ef1f5SChao Yu 	struct extent_node *en;
264a28ef1f5SChao Yu 
26532410577SChao Yu 	en = f2fs_kmem_cache_alloc(extent_node_slab, GFP_ATOMIC, false, sbi);
266a28ef1f5SChao Yu 	if (!en)
267a28ef1f5SChao Yu 		return NULL;
268a28ef1f5SChao Yu 
269a28ef1f5SChao Yu 	en->ei = *ei;
270a28ef1f5SChao Yu 	INIT_LIST_HEAD(&en->list);
271201ef5e0SHou Pengyang 	en->et = et;
272a28ef1f5SChao Yu 
273a28ef1f5SChao Yu 	rb_link_node(&en->rb_node, parent, p);
2744dada3fdSChao Yu 	rb_insert_color_cached(&en->rb_node, &et->root, leftmost);
27568e35385SChao Yu 	atomic_inc(&et->node_cnt);
276e7547dacSJaegeuk Kim 	atomic_inc(&eti->total_ext_node);
277a28ef1f5SChao Yu 	return en;
278a28ef1f5SChao Yu }
279a28ef1f5SChao Yu 
280a28ef1f5SChao Yu static void __detach_extent_node(struct f2fs_sb_info *sbi,
281a28ef1f5SChao Yu 				struct extent_tree *et, struct extent_node *en)
282a28ef1f5SChao Yu {
283e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
284e7547dacSJaegeuk Kim 
2854dada3fdSChao Yu 	rb_erase_cached(&en->rb_node, &et->root);
28668e35385SChao Yu 	atomic_dec(&et->node_cnt);
287e7547dacSJaegeuk Kim 	atomic_dec(&eti->total_ext_node);
288a28ef1f5SChao Yu 
289a28ef1f5SChao Yu 	if (et->cached_en == en)
290a28ef1f5SChao Yu 		et->cached_en = NULL;
291a03f01f2SHou Pengyang 	kmem_cache_free(extent_node_slab, en);
292a03f01f2SHou Pengyang }
293a03f01f2SHou Pengyang 
294a03f01f2SHou Pengyang /*
295a03f01f2SHou Pengyang  * Flow to release an extent_node:
296a03f01f2SHou Pengyang  * 1. list_del_init
297a03f01f2SHou Pengyang  * 2. __detach_extent_node
298a03f01f2SHou Pengyang  * 3. kmem_cache_free.
299a03f01f2SHou Pengyang  */
300a03f01f2SHou Pengyang static void __release_extent_node(struct f2fs_sb_info *sbi,
301a03f01f2SHou Pengyang 			struct extent_tree *et, struct extent_node *en)
302a03f01f2SHou Pengyang {
303e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
304e7547dacSJaegeuk Kim 
305e7547dacSJaegeuk Kim 	spin_lock(&eti->extent_lock);
306201ef5e0SHou Pengyang 	f2fs_bug_on(sbi, list_empty(&en->list));
307a03f01f2SHou Pengyang 	list_del_init(&en->list);
308e7547dacSJaegeuk Kim 	spin_unlock(&eti->extent_lock);
309a03f01f2SHou Pengyang 
310a03f01f2SHou Pengyang 	__detach_extent_node(sbi, et, en);
311a28ef1f5SChao Yu }
312a28ef1f5SChao Yu 
313e7547dacSJaegeuk Kim static struct extent_tree *__grab_extent_tree(struct inode *inode,
314e7547dacSJaegeuk Kim 						enum extent_type type)
315a28ef1f5SChao Yu {
316a28ef1f5SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
317e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[type];
318a28ef1f5SChao Yu 	struct extent_tree *et;
319a28ef1f5SChao Yu 	nid_t ino = inode->i_ino;
320a28ef1f5SChao Yu 
321e7547dacSJaegeuk Kim 	mutex_lock(&eti->extent_tree_lock);
322e7547dacSJaegeuk Kim 	et = radix_tree_lookup(&eti->extent_tree_root, ino);
323a28ef1f5SChao Yu 	if (!et) {
32432410577SChao Yu 		et = f2fs_kmem_cache_alloc(extent_tree_slab,
32532410577SChao Yu 					GFP_NOFS, true, NULL);
326e7547dacSJaegeuk Kim 		f2fs_radix_tree_insert(&eti->extent_tree_root, ino, et);
327a28ef1f5SChao Yu 		memset(et, 0, sizeof(struct extent_tree));
328a28ef1f5SChao Yu 		et->ino = ino;
329e7547dacSJaegeuk Kim 		et->type = type;
3304dada3fdSChao Yu 		et->root = RB_ROOT_CACHED;
331a28ef1f5SChao Yu 		et->cached_en = NULL;
332a28ef1f5SChao Yu 		rwlock_init(&et->lock);
333137d09f0SJaegeuk Kim 		INIT_LIST_HEAD(&et->list);
33468e35385SChao Yu 		atomic_set(&et->node_cnt, 0);
335e7547dacSJaegeuk Kim 		atomic_inc(&eti->total_ext_tree);
33674fd8d99SJaegeuk Kim 	} else {
337e7547dacSJaegeuk Kim 		atomic_dec(&eti->total_zombie_tree);
338137d09f0SJaegeuk Kim 		list_del_init(&et->list);
339a28ef1f5SChao Yu 	}
340e7547dacSJaegeuk Kim 	mutex_unlock(&eti->extent_tree_lock);
341a28ef1f5SChao Yu 
342a28ef1f5SChao Yu 	/* never died until evict_inode */
343e7547dacSJaegeuk Kim 	F2FS_I(inode)->extent_tree[type] = et;
344a28ef1f5SChao Yu 
345a28ef1f5SChao Yu 	return et;
346a28ef1f5SChao Yu }
347a28ef1f5SChao Yu 
348a28ef1f5SChao Yu static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi,
349201ef5e0SHou Pengyang 					struct extent_tree *et)
350a28ef1f5SChao Yu {
351a28ef1f5SChao Yu 	struct rb_node *node, *next;
352a28ef1f5SChao Yu 	struct extent_node *en;
35368e35385SChao Yu 	unsigned int count = atomic_read(&et->node_cnt);
354a28ef1f5SChao Yu 
3554dada3fdSChao Yu 	node = rb_first_cached(&et->root);
356a28ef1f5SChao Yu 	while (node) {
357a28ef1f5SChao Yu 		next = rb_next(node);
358a28ef1f5SChao Yu 		en = rb_entry(node, struct extent_node, rb_node);
359a03f01f2SHou Pengyang 		__release_extent_node(sbi, et, en);
360a28ef1f5SChao Yu 		node = next;
361a28ef1f5SChao Yu 	}
362a28ef1f5SChao Yu 
36368e35385SChao Yu 	return count - atomic_read(&et->node_cnt);
364a28ef1f5SChao Yu }
365a28ef1f5SChao Yu 
366b430f726SZhikang Zhang static void __drop_largest_extent(struct extent_tree *et,
36741a099deSFan Li 					pgoff_t fofs, unsigned int len)
368a28ef1f5SChao Yu {
369*1cade98cSNikita Zhandarovich 	if (fofs < (pgoff_t)et->largest.fofs + et->largest.len &&
370b430f726SZhikang Zhang 			fofs + len > et->largest.fofs) {
371b430f726SZhikang Zhang 		et->largest.len = 0;
372b430f726SZhikang Zhang 		et->largest_updated = true;
373205b9822SJaegeuk Kim 	}
374a28ef1f5SChao Yu }
375a28ef1f5SChao Yu 
37672840cccSJaegeuk Kim void f2fs_init_read_extent_tree(struct inode *inode, struct page *ipage)
377a28ef1f5SChao Yu {
378a28ef1f5SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
37972840cccSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[EX_READ];
38072840cccSJaegeuk Kim 	struct f2fs_extent *i_ext = &F2FS_INODE(ipage)->i_ext;
381a28ef1f5SChao Yu 	struct extent_tree *et;
382a28ef1f5SChao Yu 	struct extent_node *en;
383a28ef1f5SChao Yu 	struct extent_info ei;
384a28ef1f5SChao Yu 
38572840cccSJaegeuk Kim 	if (!__may_extent_tree(inode, EX_READ)) {
386e7547dacSJaegeuk Kim 		/* drop largest read extent */
387d7409b05SChao Yu 		if (i_ext->len) {
388a6d601f3SChao Yu 			f2fs_wait_on_page_writeback(ipage, NODE, true, true);
389ed3d1256SJaegeuk Kim 			i_ext->len = 0;
390a6d601f3SChao Yu 			set_page_dirty(ipage);
391ed3d1256SJaegeuk Kim 		}
392d7409b05SChao Yu 		set_inode_flag(inode, FI_NO_EXTENT);
393d7409b05SChao Yu 		return;
394ed3d1256SJaegeuk Kim 	}
395a28ef1f5SChao Yu 
39672840cccSJaegeuk Kim 	et = __grab_extent_tree(inode, EX_READ);
397a28ef1f5SChao Yu 
39812607c1bSJaegeuk Kim 	get_read_extent_info(&ei, i_ext);
399a28ef1f5SChao Yu 
400a28ef1f5SChao Yu 	write_lock(&et->lock);
401d7409b05SChao Yu 	if (atomic_read(&et->node_cnt) || !ei.len)
402d7409b05SChao Yu 		goto skip;
403a28ef1f5SChao Yu 
404749d543cSJaegeuk Kim 	en = __attach_extent_node(sbi, et, &ei, NULL,
405749d543cSJaegeuk Kim 				&et->root.rb_root.rb_node, true);
406a28ef1f5SChao Yu 	if (en) {
407749d543cSJaegeuk Kim 		et->largest = en->ei;
408749d543cSJaegeuk Kim 		et->cached_en = en;
409749d543cSJaegeuk Kim 
410e7547dacSJaegeuk Kim 		spin_lock(&eti->extent_lock);
411e7547dacSJaegeuk Kim 		list_add_tail(&en->list, &eti->extent_list);
412e7547dacSJaegeuk Kim 		spin_unlock(&eti->extent_lock);
413a28ef1f5SChao Yu 	}
414d7409b05SChao Yu skip:
415d7409b05SChao Yu 	/* Let's drop, if checkpoint got corrupted. */
416d7409b05SChao Yu 	if (f2fs_cp_error(sbi)) {
417d7409b05SChao Yu 		et->largest.len = 0;
418d7409b05SChao Yu 		et->largest_updated = true;
419d7409b05SChao Yu 	}
420a28ef1f5SChao Yu 	write_unlock(&et->lock);
421a28ef1f5SChao Yu }
422a28ef1f5SChao Yu 
42371644dffSJaegeuk Kim void f2fs_init_age_extent_tree(struct inode *inode)
42471644dffSJaegeuk Kim {
42571644dffSJaegeuk Kim 	if (!__init_may_extent_tree(inode, EX_BLOCK_AGE))
42671644dffSJaegeuk Kim 		return;
42771644dffSJaegeuk Kim 	__grab_extent_tree(inode, EX_BLOCK_AGE);
42871644dffSJaegeuk Kim }
42971644dffSJaegeuk Kim 
43072840cccSJaegeuk Kim void f2fs_init_extent_tree(struct inode *inode)
431dad48e73SYunlei He {
432e7547dacSJaegeuk Kim 	/* initialize read cache */
43372840cccSJaegeuk Kim 	if (__init_may_extent_tree(inode, EX_READ))
43472840cccSJaegeuk Kim 		__grab_extent_tree(inode, EX_READ);
43571644dffSJaegeuk Kim 
43671644dffSJaegeuk Kim 	/* initialize block age cache */
43771644dffSJaegeuk Kim 	if (__init_may_extent_tree(inode, EX_BLOCK_AGE))
43871644dffSJaegeuk Kim 		__grab_extent_tree(inode, EX_BLOCK_AGE);
439dad48e73SYunlei He }
440dad48e73SYunlei He 
441e7547dacSJaegeuk Kim static bool __lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
442e7547dacSJaegeuk Kim 			struct extent_info *ei, enum extent_type type)
443a28ef1f5SChao Yu {
444a28ef1f5SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
445e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[type];
446e7547dacSJaegeuk Kim 	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
447a28ef1f5SChao Yu 	struct extent_node *en;
448a28ef1f5SChao Yu 	bool ret = false;
449a28ef1f5SChao Yu 
450df9d44b6SJaegeuk Kim 	if (!et)
451df9d44b6SJaegeuk Kim 		return false;
452a28ef1f5SChao Yu 
453e7547dacSJaegeuk Kim 	trace_f2fs_lookup_extent_tree_start(inode, pgofs, type);
454a28ef1f5SChao Yu 
455a28ef1f5SChao Yu 	read_lock(&et->lock);
456a28ef1f5SChao Yu 
457e7547dacSJaegeuk Kim 	if (type == EX_READ &&
458e7547dacSJaegeuk Kim 			et->largest.fofs <= pgofs &&
459*1cade98cSNikita Zhandarovich 			(pgoff_t)et->largest.fofs + et->largest.len > pgofs) {
460a28ef1f5SChao Yu 		*ei = et->largest;
461a28ef1f5SChao Yu 		ret = true;
46291c481ffSChao Yu 		stat_inc_largest_node_hit(sbi);
463a28ef1f5SChao Yu 		goto out;
464a28ef1f5SChao Yu 	}
465a28ef1f5SChao Yu 
466bf21acf9SJaegeuk Kim 	en = __lookup_extent_node(&et->root, et->cached_en, pgofs);
46754c2258cSChao Yu 	if (!en)
46854c2258cSChao Yu 		goto out;
46954c2258cSChao Yu 
47054c2258cSChao Yu 	if (en == et->cached_en)
471e7547dacSJaegeuk Kim 		stat_inc_cached_node_hit(sbi, type);
47254c2258cSChao Yu 	else
473e7547dacSJaegeuk Kim 		stat_inc_rbtree_node_hit(sbi, type);
47454c2258cSChao Yu 
475a28ef1f5SChao Yu 	*ei = en->ei;
476e7547dacSJaegeuk Kim 	spin_lock(&eti->extent_lock);
47742926744SJaegeuk Kim 	if (!list_empty(&en->list)) {
478e7547dacSJaegeuk Kim 		list_move_tail(&en->list, &eti->extent_list);
479a28ef1f5SChao Yu 		et->cached_en = en;
48042926744SJaegeuk Kim 	}
481e7547dacSJaegeuk Kim 	spin_unlock(&eti->extent_lock);
482a28ef1f5SChao Yu 	ret = true;
483a28ef1f5SChao Yu out:
484e7547dacSJaegeuk Kim 	stat_inc_total_hit(sbi, type);
485a28ef1f5SChao Yu 	read_unlock(&et->lock);
486a28ef1f5SChao Yu 
487e7547dacSJaegeuk Kim 	if (type == EX_READ)
488e7547dacSJaegeuk Kim 		trace_f2fs_lookup_read_extent_tree_end(inode, pgofs, ei);
48971644dffSJaegeuk Kim 	else if (type == EX_BLOCK_AGE)
49071644dffSJaegeuk Kim 		trace_f2fs_lookup_age_extent_tree_end(inode, pgofs, ei);
491a28ef1f5SChao Yu 	return ret;
492a28ef1f5SChao Yu }
493a28ef1f5SChao Yu 
494b430f726SZhikang Zhang static struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi,
4950f825ee6SFan Li 				struct extent_tree *et, struct extent_info *ei,
4960f825ee6SFan Li 				struct extent_node *prev_ex,
497ef05e221SChao Yu 				struct extent_node *next_ex)
4980f825ee6SFan Li {
499e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
5000f825ee6SFan Li 	struct extent_node *en = NULL;
5010f825ee6SFan Li 
502e7547dacSJaegeuk Kim 	if (prev_ex && __is_back_mergeable(ei, &prev_ex->ei, et->type)) {
5030f825ee6SFan Li 		prev_ex->ei.len += ei->len;
5040f825ee6SFan Li 		ei = &prev_ex->ei;
5050f825ee6SFan Li 		en = prev_ex;
5060f825ee6SFan Li 	}
507ef05e221SChao Yu 
508e7547dacSJaegeuk Kim 	if (next_ex && __is_front_mergeable(ei, &next_ex->ei, et->type)) {
5090f825ee6SFan Li 		next_ex->ei.fofs = ei->fofs;
5100f825ee6SFan Li 		next_ex->ei.len += ei->len;
511e7547dacSJaegeuk Kim 		if (et->type == EX_READ)
512e7547dacSJaegeuk Kim 			next_ex->ei.blk = ei->blk;
5137855eba4SYunlei He 		if (en)
5147855eba4SYunlei He 			__release_extent_node(sbi, et, prev_ex);
5157855eba4SYunlei He 
5160f825ee6SFan Li 		en = next_ex;
5170f825ee6SFan Li 	}
518ef05e221SChao Yu 
51943a2fa18SJaegeuk Kim 	if (!en)
52043a2fa18SJaegeuk Kim 		return NULL;
52143a2fa18SJaegeuk Kim 
522b430f726SZhikang Zhang 	__try_update_largest_extent(et, en);
52343a2fa18SJaegeuk Kim 
524e7547dacSJaegeuk Kim 	spin_lock(&eti->extent_lock);
52542926744SJaegeuk Kim 	if (!list_empty(&en->list)) {
526e7547dacSJaegeuk Kim 		list_move_tail(&en->list, &eti->extent_list);
52742926744SJaegeuk Kim 		et->cached_en = en;
52842926744SJaegeuk Kim 	}
529e7547dacSJaegeuk Kim 	spin_unlock(&eti->extent_lock);
530ef05e221SChao Yu 	return en;
531ef05e221SChao Yu }
532ef05e221SChao Yu 
533b430f726SZhikang Zhang static struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi,
534ef05e221SChao Yu 				struct extent_tree *et, struct extent_info *ei,
535ef05e221SChao Yu 				struct rb_node **insert_p,
5364dada3fdSChao Yu 				struct rb_node *insert_parent,
5374dada3fdSChao Yu 				bool leftmost)
538ef05e221SChao Yu {
539e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
540bf21acf9SJaegeuk Kim 	struct rb_node **p = &et->root.rb_root.rb_node;
541ef05e221SChao Yu 	struct rb_node *parent = NULL;
542ef05e221SChao Yu 	struct extent_node *en = NULL;
5430f825ee6SFan Li 
5440f825ee6SFan Li 	if (insert_p && insert_parent) {
5450f825ee6SFan Li 		parent = insert_parent;
5460f825ee6SFan Li 		p = insert_p;
5470f825ee6SFan Li 		goto do_insert;
5480f825ee6SFan Li 	}
5490f825ee6SFan Li 
5504dada3fdSChao Yu 	leftmost = true;
5514dada3fdSChao Yu 
552bf21acf9SJaegeuk Kim 	/* look up extent_node in the rb tree */
553bf21acf9SJaegeuk Kim 	while (*p) {
554bf21acf9SJaegeuk Kim 		parent = *p;
555bf21acf9SJaegeuk Kim 		en = rb_entry(parent, struct extent_node, rb_node);
556bf21acf9SJaegeuk Kim 
557bf21acf9SJaegeuk Kim 		if (ei->fofs < en->ei.fofs) {
558bf21acf9SJaegeuk Kim 			p = &(*p)->rb_left;
559bf21acf9SJaegeuk Kim 		} else if (ei->fofs >= en->ei.fofs + en->ei.len) {
560bf21acf9SJaegeuk Kim 			p = &(*p)->rb_right;
561bf21acf9SJaegeuk Kim 			leftmost = false;
562bf21acf9SJaegeuk Kim 		} else {
563bf21acf9SJaegeuk Kim 			f2fs_bug_on(sbi, 1);
564bf21acf9SJaegeuk Kim 		}
565bf21acf9SJaegeuk Kim 	}
566bf21acf9SJaegeuk Kim 
5670f825ee6SFan Li do_insert:
5684dada3fdSChao Yu 	en = __attach_extent_node(sbi, et, ei, parent, p, leftmost);
5690f825ee6SFan Li 	if (!en)
5700f825ee6SFan Li 		return NULL;
571ef05e221SChao Yu 
572b430f726SZhikang Zhang 	__try_update_largest_extent(et, en);
57343a2fa18SJaegeuk Kim 
57443a2fa18SJaegeuk Kim 	/* update in global extent list */
575e7547dacSJaegeuk Kim 	spin_lock(&eti->extent_lock);
576e7547dacSJaegeuk Kim 	list_add_tail(&en->list, &eti->extent_list);
57742926744SJaegeuk Kim 	et->cached_en = en;
578e7547dacSJaegeuk Kim 	spin_unlock(&eti->extent_lock);
5790f825ee6SFan Li 	return en;
5800f825ee6SFan Li }
5810f825ee6SFan Li 
582e7547dacSJaegeuk Kim static void __update_extent_tree_range(struct inode *inode,
583e7547dacSJaegeuk Kim 			struct extent_info *tei, enum extent_type type)
584a28ef1f5SChao Yu {
585a28ef1f5SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
586e7547dacSJaegeuk Kim 	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
5874d1fa815SFan Li 	struct extent_node *en = NULL, *en1 = NULL;
58819b2c30dSChao Yu 	struct extent_node *prev_en = NULL, *next_en = NULL;
589a28ef1f5SChao Yu 	struct extent_info ei, dei, prev;
5900f825ee6SFan Li 	struct rb_node **insert_p = NULL, *insert_parent = NULL;
591e7547dacSJaegeuk Kim 	unsigned int fofs = tei->fofs, len = tei->len;
59219b2c30dSChao Yu 	unsigned int end = fofs + len;
593b430f726SZhikang Zhang 	bool updated = false;
594f9aa52a8SChao Yu 	bool leftmost = false;
595a28ef1f5SChao Yu 
596a28ef1f5SChao Yu 	if (!et)
597317e1300SChao Yu 		return;
598a28ef1f5SChao Yu 
599e7547dacSJaegeuk Kim 	if (type == EX_READ)
600e7547dacSJaegeuk Kim 		trace_f2fs_update_read_extent_tree_range(inode, fofs, len,
601e7547dacSJaegeuk Kim 						tei->blk, 0);
60271644dffSJaegeuk Kim 	else if (type == EX_BLOCK_AGE)
60371644dffSJaegeuk Kim 		trace_f2fs_update_age_extent_tree_range(inode, fofs, len,
60471644dffSJaegeuk Kim 						tei->age, tei->last_blocks);
60571644dffSJaegeuk Kim 
606a28ef1f5SChao Yu 	write_lock(&et->lock);
607a28ef1f5SChao Yu 
608e7547dacSJaegeuk Kim 	if (type == EX_READ) {
60991942321SJaegeuk Kim 		if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
610a28ef1f5SChao Yu 			write_unlock(&et->lock);
611317e1300SChao Yu 			return;
612a28ef1f5SChao Yu 		}
613a28ef1f5SChao Yu 
614a28ef1f5SChao Yu 		prev = et->largest;
615a28ef1f5SChao Yu 		dei.len = 0;
616a28ef1f5SChao Yu 
6174d1fa815SFan Li 		/*
6184d1fa815SFan Li 		 * drop largest extent before lookup, in case it's already
6194d1fa815SFan Li 		 * been shrunk from extent tree
6204d1fa815SFan Li 		 */
621b430f726SZhikang Zhang 		__drop_largest_extent(et, fofs, len);
622e7547dacSJaegeuk Kim 	}
623a28ef1f5SChao Yu 
62419b2c30dSChao Yu 	/* 1. lookup first extent node in range [fofs, fofs + len - 1] */
625bf21acf9SJaegeuk Kim 	en = __lookup_extent_node_ret(&et->root,
626bf21acf9SJaegeuk Kim 					et->cached_en, fofs,
627bf21acf9SJaegeuk Kim 					&prev_en, &next_en,
628bf21acf9SJaegeuk Kim 					&insert_p, &insert_parent,
6294dada3fdSChao Yu 					&leftmost);
6304d1fa815SFan Li 	if (!en)
63119b2c30dSChao Yu 		en = next_en;
63219b2c30dSChao Yu 
633146949deSJinyoung CHOI 	/* 2. invalidate all extent nodes in range [fofs, fofs + len - 1] */
6344d1fa815SFan Li 	while (en && en->ei.fofs < end) {
6354d1fa815SFan Li 		unsigned int org_end;
6364d1fa815SFan Li 		int parts = 0;	/* # of parts current extent split into */
63719b2c30dSChao Yu 
6384d1fa815SFan Li 		next_en = en1 = NULL;
639a28ef1f5SChao Yu 
640a28ef1f5SChao Yu 		dei = en->ei;
6414d1fa815SFan Li 		org_end = dei.fofs + dei.len;
642e7547dacSJaegeuk Kim 		f2fs_bug_on(sbi, fofs >= org_end);
64319b2c30dSChao Yu 
644e7547dacSJaegeuk Kim 		if (fofs > dei.fofs && (type != EX_READ ||
645e7547dacSJaegeuk Kim 				fofs - dei.fofs >= F2FS_MIN_EXTENT_LEN)) {
646e7547dacSJaegeuk Kim 			en->ei.len = fofs - en->ei.fofs;
6474d1fa815SFan Li 			prev_en = en;
6484d1fa815SFan Li 			parts = 1;
64919b2c30dSChao Yu 		}
65019b2c30dSChao Yu 
651e7547dacSJaegeuk Kim 		if (end < org_end && (type != EX_READ ||
652e7547dacSJaegeuk Kim 				org_end - end >= F2FS_MIN_EXTENT_LEN)) {
6534d1fa815SFan Li 			if (parts) {
6543bac20a8SJaegeuk Kim 				__set_extent_info(&ei,
6553bac20a8SJaegeuk Kim 					end, org_end - end,
656e7547dacSJaegeuk Kim 					end - dei.fofs + dei.blk, false,
65771644dffSJaegeuk Kim 					dei.age, dei.last_blocks,
658e7547dacSJaegeuk Kim 					type);
659b430f726SZhikang Zhang 				en1 = __insert_extent_tree(sbi, et, &ei,
6604dada3fdSChao Yu 							NULL, NULL, true);
6614d1fa815SFan Li 				next_en = en1;
6624d1fa815SFan Li 			} else {
6633bac20a8SJaegeuk Kim 				__set_extent_info(&en->ei,
6643bac20a8SJaegeuk Kim 					end, en->ei.len - (end - dei.fofs),
665e7547dacSJaegeuk Kim 					en->ei.blk + (end - dei.fofs), true,
66671644dffSJaegeuk Kim 					dei.age, dei.last_blocks,
667e7547dacSJaegeuk Kim 					type);
6684d1fa815SFan Li 				next_en = en;
6694d1fa815SFan Li 			}
6704d1fa815SFan Li 			parts++;
67119b2c30dSChao Yu 		}
67219b2c30dSChao Yu 
6734d1fa815SFan Li 		if (!next_en) {
6744d1fa815SFan Li 			struct rb_node *node = rb_next(&en->rb_node);
6754d1fa815SFan Li 
676ed0b5620SGeliang Tang 			next_en = rb_entry_safe(node, struct extent_node,
677ed0b5620SGeliang Tang 						rb_node);
6784d1fa815SFan Li 		}
6794d1fa815SFan Li 
6804abd3f5aSChao Yu 		if (parts)
681b430f726SZhikang Zhang 			__try_update_largest_extent(et, en);
6824abd3f5aSChao Yu 		else
683a03f01f2SHou Pengyang 			__release_extent_node(sbi, et, en);
68419b2c30dSChao Yu 
68519b2c30dSChao Yu 		/*
6864d1fa815SFan Li 		 * if original extent is split into zero or two parts, extent
6874d1fa815SFan Li 		 * tree has been altered by deletion or insertion, therefore
6884d1fa815SFan Li 		 * invalidate pointers regard to tree.
68919b2c30dSChao Yu 		 */
6904d1fa815SFan Li 		if (parts != 1) {
69119b2c30dSChao Yu 			insert_p = NULL;
69219b2c30dSChao Yu 			insert_parent = NULL;
69319b2c30dSChao Yu 		}
6944d1fa815SFan Li 		en = next_en;
69519b2c30dSChao Yu 	}
696a28ef1f5SChao Yu 
69771644dffSJaegeuk Kim 	if (type == EX_BLOCK_AGE)
69871644dffSJaegeuk Kim 		goto update_age_extent_cache;
69971644dffSJaegeuk Kim 
700e7547dacSJaegeuk Kim 	/* 3. update extent in read extent cache */
701e7547dacSJaegeuk Kim 	BUG_ON(type != EX_READ);
702e7547dacSJaegeuk Kim 
703e7547dacSJaegeuk Kim 	if (tei->blk) {
70471644dffSJaegeuk Kim 		__set_extent_info(&ei, fofs, len, tei->blk, false,
70571644dffSJaegeuk Kim 				  0, 0, EX_READ);
706b430f726SZhikang Zhang 		if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
707b430f726SZhikang Zhang 			__insert_extent_tree(sbi, et, &ei,
7084dada3fdSChao Yu 					insert_p, insert_parent, leftmost);
709a28ef1f5SChao Yu 
710a28ef1f5SChao Yu 		/* give up extent_cache, if split and small updates happen */
711a28ef1f5SChao Yu 		if (dei.len >= 1 &&
712a28ef1f5SChao Yu 				prev.len < F2FS_MIN_EXTENT_LEN &&
713a28ef1f5SChao Yu 				et->largest.len < F2FS_MIN_EXTENT_LEN) {
714b430f726SZhikang Zhang 			et->largest.len = 0;
715b430f726SZhikang Zhang 			et->largest_updated = true;
71691942321SJaegeuk Kim 			set_inode_flag(inode, FI_NO_EXTENT);
717a28ef1f5SChao Yu 		}
71819b2c30dSChao Yu 	}
719a28ef1f5SChao Yu 
72091942321SJaegeuk Kim 	if (is_inode_flag_set(inode, FI_NO_EXTENT))
721201ef5e0SHou Pengyang 		__free_extent_tree(sbi, et);
722a28ef1f5SChao Yu 
723b430f726SZhikang Zhang 	if (et->largest_updated) {
724b430f726SZhikang Zhang 		et->largest_updated = false;
725b430f726SZhikang Zhang 		updated = true;
726b430f726SZhikang Zhang 	}
72771644dffSJaegeuk Kim 	goto out_read_extent_cache;
72871644dffSJaegeuk Kim update_age_extent_cache:
72971644dffSJaegeuk Kim 	if (!tei->last_blocks)
73071644dffSJaegeuk Kim 		goto out_read_extent_cache;
731b430f726SZhikang Zhang 
73271644dffSJaegeuk Kim 	__set_extent_info(&ei, fofs, len, 0, false,
73371644dffSJaegeuk Kim 			tei->age, tei->last_blocks, EX_BLOCK_AGE);
73471644dffSJaegeuk Kim 	if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
73571644dffSJaegeuk Kim 		__insert_extent_tree(sbi, et, &ei,
73671644dffSJaegeuk Kim 					insert_p, insert_parent, leftmost);
73771644dffSJaegeuk Kim out_read_extent_cache:
738a28ef1f5SChao Yu 	write_unlock(&et->lock);
739b430f726SZhikang Zhang 
740b430f726SZhikang Zhang 	if (updated)
741b430f726SZhikang Zhang 		f2fs_mark_inode_dirty_sync(inode, true);
742a28ef1f5SChao Yu }
743a28ef1f5SChao Yu 
74494afd6d6SChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
745e7547dacSJaegeuk Kim void f2fs_update_read_extent_tree_range_compressed(struct inode *inode,
74694afd6d6SChao Yu 				pgoff_t fofs, block_t blkaddr, unsigned int llen,
74794afd6d6SChao Yu 				unsigned int c_len)
74894afd6d6SChao Yu {
74994afd6d6SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
750e7547dacSJaegeuk Kim 	struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
75194afd6d6SChao Yu 	struct extent_node *en = NULL;
75294afd6d6SChao Yu 	struct extent_node *prev_en = NULL, *next_en = NULL;
75394afd6d6SChao Yu 	struct extent_info ei;
75494afd6d6SChao Yu 	struct rb_node **insert_p = NULL, *insert_parent = NULL;
75594afd6d6SChao Yu 	bool leftmost = false;
75694afd6d6SChao Yu 
757e7547dacSJaegeuk Kim 	trace_f2fs_update_read_extent_tree_range(inode, fofs, llen,
758e7547dacSJaegeuk Kim 						blkaddr, c_len);
75994afd6d6SChao Yu 
76094afd6d6SChao Yu 	/* it is safe here to check FI_NO_EXTENT w/o et->lock in ro image */
76194afd6d6SChao Yu 	if (is_inode_flag_set(inode, FI_NO_EXTENT))
76294afd6d6SChao Yu 		return;
76394afd6d6SChao Yu 
76494afd6d6SChao Yu 	write_lock(&et->lock);
76594afd6d6SChao Yu 
766bf21acf9SJaegeuk Kim 	en = __lookup_extent_node_ret(&et->root,
767bf21acf9SJaegeuk Kim 					et->cached_en, fofs,
768bf21acf9SJaegeuk Kim 					&prev_en, &next_en,
769bf21acf9SJaegeuk Kim 					&insert_p, &insert_parent,
77094afd6d6SChao Yu 					&leftmost);
77194afd6d6SChao Yu 	if (en)
77294afd6d6SChao Yu 		goto unlock_out;
77394afd6d6SChao Yu 
77471644dffSJaegeuk Kim 	__set_extent_info(&ei, fofs, llen, blkaddr, true, 0, 0, EX_READ);
77594afd6d6SChao Yu 	ei.c_len = c_len;
77694afd6d6SChao Yu 
77794afd6d6SChao Yu 	if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
77894afd6d6SChao Yu 		__insert_extent_tree(sbi, et, &ei,
77994afd6d6SChao Yu 				insert_p, insert_parent, leftmost);
78094afd6d6SChao Yu unlock_out:
78194afd6d6SChao Yu 	write_unlock(&et->lock);
78294afd6d6SChao Yu }
78394afd6d6SChao Yu #endif
78494afd6d6SChao Yu 
785d23be468Sqixiaoyu1 static unsigned long long __calculate_block_age(struct f2fs_sb_info *sbi,
786d23be468Sqixiaoyu1 						unsigned long long new,
78771644dffSJaegeuk Kim 						unsigned long long old)
78871644dffSJaegeuk Kim {
789b03a41a4Sqixiaoyu1 	unsigned int rem_old, rem_new;
790b03a41a4Sqixiaoyu1 	unsigned long long res;
791d23be468Sqixiaoyu1 	unsigned int weight = sbi->last_age_weight;
79271644dffSJaegeuk Kim 
793d23be468Sqixiaoyu1 	res = div_u64_rem(new, 100, &rem_new) * (100 - weight)
794d23be468Sqixiaoyu1 		+ div_u64_rem(old, 100, &rem_old) * weight;
79571644dffSJaegeuk Kim 
796b03a41a4Sqixiaoyu1 	if (rem_new)
797d23be468Sqixiaoyu1 		res += rem_new * (100 - weight) / 100;
798b03a41a4Sqixiaoyu1 	if (rem_old)
799d23be468Sqixiaoyu1 		res += rem_old * weight / 100;
800b03a41a4Sqixiaoyu1 
801b03a41a4Sqixiaoyu1 	return res;
80271644dffSJaegeuk Kim }
80371644dffSJaegeuk Kim 
80471644dffSJaegeuk Kim /* This returns a new age and allocated blocks in ei */
805ed272476SJaegeuk Kim static int __get_new_block_age(struct inode *inode, struct extent_info *ei,
806ed272476SJaegeuk Kim 						block_t blkaddr)
80771644dffSJaegeuk Kim {
80871644dffSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
80971644dffSJaegeuk Kim 	loff_t f_size = i_size_read(inode);
81071644dffSJaegeuk Kim 	unsigned long long cur_blocks =
81171644dffSJaegeuk Kim 				atomic64_read(&sbi->allocated_data_blocks);
81222a341b4SJaegeuk Kim 	struct extent_info tei = *ei;	/* only fofs and len are valid */
81371644dffSJaegeuk Kim 
81471644dffSJaegeuk Kim 	/*
81571644dffSJaegeuk Kim 	 * When I/O is not aligned to a PAGE_SIZE, update will happen to the last
81671644dffSJaegeuk Kim 	 * file block even in seq write. So don't record age for newly last file
81771644dffSJaegeuk Kim 	 * block here.
81871644dffSJaegeuk Kim 	 */
81971644dffSJaegeuk Kim 	if ((f_size >> PAGE_SHIFT) == ei->fofs && f_size & (PAGE_SIZE - 1) &&
820ed272476SJaegeuk Kim 			blkaddr == NEW_ADDR)
82171644dffSJaegeuk Kim 		return -EINVAL;
82271644dffSJaegeuk Kim 
82322a341b4SJaegeuk Kim 	if (__lookup_extent_tree(inode, ei->fofs, &tei, EX_BLOCK_AGE)) {
82471644dffSJaegeuk Kim 		unsigned long long cur_age;
82571644dffSJaegeuk Kim 
82622a341b4SJaegeuk Kim 		if (cur_blocks >= tei.last_blocks)
82722a341b4SJaegeuk Kim 			cur_age = cur_blocks - tei.last_blocks;
82871644dffSJaegeuk Kim 		else
82971644dffSJaegeuk Kim 			/* allocated_data_blocks overflow */
83022a341b4SJaegeuk Kim 			cur_age = ULLONG_MAX - tei.last_blocks + cur_blocks;
83171644dffSJaegeuk Kim 
83222a341b4SJaegeuk Kim 		if (tei.age)
833d23be468Sqixiaoyu1 			ei->age = __calculate_block_age(sbi, cur_age, tei.age);
83471644dffSJaegeuk Kim 		else
83571644dffSJaegeuk Kim 			ei->age = cur_age;
83671644dffSJaegeuk Kim 		ei->last_blocks = cur_blocks;
83771644dffSJaegeuk Kim 		WARN_ON(ei->age > cur_blocks);
83871644dffSJaegeuk Kim 		return 0;
83971644dffSJaegeuk Kim 	}
84071644dffSJaegeuk Kim 
841ed272476SJaegeuk Kim 	f2fs_bug_on(sbi, blkaddr == NULL_ADDR);
84271644dffSJaegeuk Kim 
84371644dffSJaegeuk Kim 	/* the data block was allocated for the first time */
844ed272476SJaegeuk Kim 	if (blkaddr == NEW_ADDR)
84571644dffSJaegeuk Kim 		goto out;
84671644dffSJaegeuk Kim 
847ed272476SJaegeuk Kim 	if (__is_valid_data_blkaddr(blkaddr) &&
84831f85cccSZhiguo Niu 	    !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE))
84971644dffSJaegeuk Kim 		return -EINVAL;
85071644dffSJaegeuk Kim out:
85171644dffSJaegeuk Kim 	/*
85271644dffSJaegeuk Kim 	 * init block age with zero, this can happen when the block age extent
85371644dffSJaegeuk Kim 	 * was reclaimed due to memory constraint or system reboot
85471644dffSJaegeuk Kim 	 */
85571644dffSJaegeuk Kim 	ei->age = 0;
85671644dffSJaegeuk Kim 	ei->last_blocks = cur_blocks;
85771644dffSJaegeuk Kim 	return 0;
85871644dffSJaegeuk Kim }
85971644dffSJaegeuk Kim 
860e7547dacSJaegeuk Kim static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type type)
861a28ef1f5SChao Yu {
862fe59109aSJaegeuk Kim 	struct extent_info ei = {};
863e7547dacSJaegeuk Kim 
864e7547dacSJaegeuk Kim 	if (!__may_extent_tree(dn->inode, type))
865e7547dacSJaegeuk Kim 		return;
866e7547dacSJaegeuk Kim 
867e7547dacSJaegeuk Kim 	ei.fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
868e7547dacSJaegeuk Kim 								dn->ofs_in_node;
869e7547dacSJaegeuk Kim 	ei.len = 1;
870e7547dacSJaegeuk Kim 
871e7547dacSJaegeuk Kim 	if (type == EX_READ) {
872e7547dacSJaegeuk Kim 		if (dn->data_blkaddr == NEW_ADDR)
873e7547dacSJaegeuk Kim 			ei.blk = NULL_ADDR;
874e7547dacSJaegeuk Kim 		else
875e7547dacSJaegeuk Kim 			ei.blk = dn->data_blkaddr;
87671644dffSJaegeuk Kim 	} else if (type == EX_BLOCK_AGE) {
877ed272476SJaegeuk Kim 		if (__get_new_block_age(dn->inode, &ei, dn->data_blkaddr))
87871644dffSJaegeuk Kim 			return;
879e7547dacSJaegeuk Kim 	}
880e7547dacSJaegeuk Kim 	__update_extent_tree_range(dn->inode, &ei, type);
881e7547dacSJaegeuk Kim }
882e7547dacSJaegeuk Kim 
883e7547dacSJaegeuk Kim static unsigned int __shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink,
884e7547dacSJaegeuk Kim 					enum extent_type type)
885e7547dacSJaegeuk Kim {
886e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[type];
887137d09f0SJaegeuk Kim 	struct extent_tree *et, *next;
888201ef5e0SHou Pengyang 	struct extent_node *en;
889a28ef1f5SChao Yu 	unsigned int node_cnt = 0, tree_cnt = 0;
890a28ef1f5SChao Yu 	int remained;
891a28ef1f5SChao Yu 
892e7547dacSJaegeuk Kim 	if (!atomic_read(&eti->total_zombie_tree))
89374fd8d99SJaegeuk Kim 		goto free_node;
89474fd8d99SJaegeuk Kim 
895e7547dacSJaegeuk Kim 	if (!mutex_trylock(&eti->extent_tree_lock))
896a28ef1f5SChao Yu 		goto out;
897a28ef1f5SChao Yu 
898a28ef1f5SChao Yu 	/* 1. remove unreferenced extent tree */
899e7547dacSJaegeuk Kim 	list_for_each_entry_safe(et, next, &eti->zombie_list, list) {
9009b72a388SChao Yu 		if (atomic_read(&et->node_cnt)) {
901a28ef1f5SChao Yu 			write_lock(&et->lock);
902201ef5e0SHou Pengyang 			node_cnt += __free_extent_tree(sbi, et);
903a28ef1f5SChao Yu 			write_unlock(&et->lock);
9049b72a388SChao Yu 		}
905201ef5e0SHou Pengyang 		f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
906137d09f0SJaegeuk Kim 		list_del_init(&et->list);
907e7547dacSJaegeuk Kim 		radix_tree_delete(&eti->extent_tree_root, et->ino);
908a28ef1f5SChao Yu 		kmem_cache_free(extent_tree_slab, et);
909e7547dacSJaegeuk Kim 		atomic_dec(&eti->total_ext_tree);
910e7547dacSJaegeuk Kim 		atomic_dec(&eti->total_zombie_tree);
911a28ef1f5SChao Yu 		tree_cnt++;
912a28ef1f5SChao Yu 
913a28ef1f5SChao Yu 		if (node_cnt + tree_cnt >= nr_shrink)
914a28ef1f5SChao Yu 			goto unlock_out;
9156fe2bc95SJaegeuk Kim 		cond_resched();
916a28ef1f5SChao Yu 	}
917e7547dacSJaegeuk Kim 	mutex_unlock(&eti->extent_tree_lock);
918a28ef1f5SChao Yu 
91974fd8d99SJaegeuk Kim free_node:
920a28ef1f5SChao Yu 	/* 2. remove LRU extent entries */
921e7547dacSJaegeuk Kim 	if (!mutex_trylock(&eti->extent_tree_lock))
922a28ef1f5SChao Yu 		goto out;
923a28ef1f5SChao Yu 
924a28ef1f5SChao Yu 	remained = nr_shrink - (node_cnt + tree_cnt);
925a28ef1f5SChao Yu 
926e7547dacSJaegeuk Kim 	spin_lock(&eti->extent_lock);
927201ef5e0SHou Pengyang 	for (; remained > 0; remained--) {
928e7547dacSJaegeuk Kim 		if (list_empty(&eti->extent_list))
929a28ef1f5SChao Yu 			break;
930e7547dacSJaegeuk Kim 		en = list_first_entry(&eti->extent_list,
931201ef5e0SHou Pengyang 					struct extent_node, list);
932201ef5e0SHou Pengyang 		et = en->et;
933201ef5e0SHou Pengyang 		if (!write_trylock(&et->lock)) {
934201ef5e0SHou Pengyang 			/* refresh this extent node's position in extent list */
935e7547dacSJaegeuk Kim 			list_move_tail(&en->list, &eti->extent_list);
936201ef5e0SHou Pengyang 			continue;
937201ef5e0SHou Pengyang 		}
938201ef5e0SHou Pengyang 
939a28ef1f5SChao Yu 		list_del_init(&en->list);
940e7547dacSJaegeuk Kim 		spin_unlock(&eti->extent_lock);
941201ef5e0SHou Pengyang 
942201ef5e0SHou Pengyang 		__detach_extent_node(sbi, et, en);
943201ef5e0SHou Pengyang 
944201ef5e0SHou Pengyang 		write_unlock(&et->lock);
945201ef5e0SHou Pengyang 		node_cnt++;
946e7547dacSJaegeuk Kim 		spin_lock(&eti->extent_lock);
947a28ef1f5SChao Yu 	}
948e7547dacSJaegeuk Kim 	spin_unlock(&eti->extent_lock);
949a28ef1f5SChao Yu 
950a28ef1f5SChao Yu unlock_out:
951e7547dacSJaegeuk Kim 	mutex_unlock(&eti->extent_tree_lock);
952a28ef1f5SChao Yu out:
953e7547dacSJaegeuk Kim 	trace_f2fs_shrink_extent_tree(sbi, node_cnt, tree_cnt, type);
954a28ef1f5SChao Yu 
955a28ef1f5SChao Yu 	return node_cnt + tree_cnt;
956a28ef1f5SChao Yu }
957a28ef1f5SChao Yu 
958e7547dacSJaegeuk Kim /* read extent cache operations */
959e7547dacSJaegeuk Kim bool f2fs_lookup_read_extent_cache(struct inode *inode, pgoff_t pgofs,
960e7547dacSJaegeuk Kim 				struct extent_info *ei)
961e7547dacSJaegeuk Kim {
962e7547dacSJaegeuk Kim 	if (!__may_extent_tree(inode, EX_READ))
963e7547dacSJaegeuk Kim 		return false;
964e7547dacSJaegeuk Kim 
965e7547dacSJaegeuk Kim 	return __lookup_extent_tree(inode, pgofs, ei, EX_READ);
966e7547dacSJaegeuk Kim }
967e7547dacSJaegeuk Kim 
96804a91ab0SChristoph Hellwig bool f2fs_lookup_read_extent_cache_block(struct inode *inode, pgoff_t index,
96904a91ab0SChristoph Hellwig 				block_t *blkaddr)
97004a91ab0SChristoph Hellwig {
97104a91ab0SChristoph Hellwig 	struct extent_info ei = {};
97204a91ab0SChristoph Hellwig 
97304a91ab0SChristoph Hellwig 	if (!f2fs_lookup_read_extent_cache(inode, index, &ei))
97404a91ab0SChristoph Hellwig 		return false;
97504a91ab0SChristoph Hellwig 	*blkaddr = ei.blk + index - ei.fofs;
97604a91ab0SChristoph Hellwig 	return true;
97704a91ab0SChristoph Hellwig }
97804a91ab0SChristoph Hellwig 
979e7547dacSJaegeuk Kim void f2fs_update_read_extent_cache(struct dnode_of_data *dn)
980e7547dacSJaegeuk Kim {
981e7547dacSJaegeuk Kim 	return __update_extent_cache(dn, EX_READ);
982e7547dacSJaegeuk Kim }
983e7547dacSJaegeuk Kim 
984e7547dacSJaegeuk Kim void f2fs_update_read_extent_cache_range(struct dnode_of_data *dn,
985e7547dacSJaegeuk Kim 				pgoff_t fofs, block_t blkaddr, unsigned int len)
986e7547dacSJaegeuk Kim {
987e7547dacSJaegeuk Kim 	struct extent_info ei = {
988e7547dacSJaegeuk Kim 		.fofs = fofs,
989e7547dacSJaegeuk Kim 		.len = len,
990e7547dacSJaegeuk Kim 		.blk = blkaddr,
991e7547dacSJaegeuk Kim 	};
992e7547dacSJaegeuk Kim 
993e7547dacSJaegeuk Kim 	if (!__may_extent_tree(dn->inode, EX_READ))
994e7547dacSJaegeuk Kim 		return;
995e7547dacSJaegeuk Kim 
996e7547dacSJaegeuk Kim 	__update_extent_tree_range(dn->inode, &ei, EX_READ);
997e7547dacSJaegeuk Kim }
998e7547dacSJaegeuk Kim 
999e7547dacSJaegeuk Kim unsigned int f2fs_shrink_read_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
1000e7547dacSJaegeuk Kim {
1001e7547dacSJaegeuk Kim 	if (!test_opt(sbi, READ_EXTENT_CACHE))
1002e7547dacSJaegeuk Kim 		return 0;
1003e7547dacSJaegeuk Kim 
1004e7547dacSJaegeuk Kim 	return __shrink_extent_tree(sbi, nr_shrink, EX_READ);
1005e7547dacSJaegeuk Kim }
1006e7547dacSJaegeuk Kim 
100771644dffSJaegeuk Kim /* block age extent cache operations */
100871644dffSJaegeuk Kim bool f2fs_lookup_age_extent_cache(struct inode *inode, pgoff_t pgofs,
100971644dffSJaegeuk Kim 				struct extent_info *ei)
101071644dffSJaegeuk Kim {
101171644dffSJaegeuk Kim 	if (!__may_extent_tree(inode, EX_BLOCK_AGE))
101271644dffSJaegeuk Kim 		return false;
101371644dffSJaegeuk Kim 
101471644dffSJaegeuk Kim 	return __lookup_extent_tree(inode, pgofs, ei, EX_BLOCK_AGE);
101571644dffSJaegeuk Kim }
101671644dffSJaegeuk Kim 
101771644dffSJaegeuk Kim void f2fs_update_age_extent_cache(struct dnode_of_data *dn)
101871644dffSJaegeuk Kim {
101971644dffSJaegeuk Kim 	return __update_extent_cache(dn, EX_BLOCK_AGE);
102071644dffSJaegeuk Kim }
102171644dffSJaegeuk Kim 
102271644dffSJaegeuk Kim void f2fs_update_age_extent_cache_range(struct dnode_of_data *dn,
102371644dffSJaegeuk Kim 				pgoff_t fofs, unsigned int len)
102471644dffSJaegeuk Kim {
102571644dffSJaegeuk Kim 	struct extent_info ei = {
102671644dffSJaegeuk Kim 		.fofs = fofs,
102771644dffSJaegeuk Kim 		.len = len,
102871644dffSJaegeuk Kim 	};
102971644dffSJaegeuk Kim 
103071644dffSJaegeuk Kim 	if (!__may_extent_tree(dn->inode, EX_BLOCK_AGE))
103171644dffSJaegeuk Kim 		return;
103271644dffSJaegeuk Kim 
103371644dffSJaegeuk Kim 	__update_extent_tree_range(dn->inode, &ei, EX_BLOCK_AGE);
103471644dffSJaegeuk Kim }
103571644dffSJaegeuk Kim 
103671644dffSJaegeuk Kim unsigned int f2fs_shrink_age_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
103771644dffSJaegeuk Kim {
103871644dffSJaegeuk Kim 	if (!test_opt(sbi, AGE_EXTENT_CACHE))
103971644dffSJaegeuk Kim 		return 0;
104071644dffSJaegeuk Kim 
104171644dffSJaegeuk Kim 	return __shrink_extent_tree(sbi, nr_shrink, EX_BLOCK_AGE);
104271644dffSJaegeuk Kim }
104371644dffSJaegeuk Kim 
1044e7547dacSJaegeuk Kim static unsigned int __destroy_extent_node(struct inode *inode,
1045e7547dacSJaegeuk Kim 					enum extent_type type)
1046a28ef1f5SChao Yu {
1047a28ef1f5SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1048e7547dacSJaegeuk Kim 	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
1049a28ef1f5SChao Yu 	unsigned int node_cnt = 0;
1050a28ef1f5SChao Yu 
10519b72a388SChao Yu 	if (!et || !atomic_read(&et->node_cnt))
1052a28ef1f5SChao Yu 		return 0;
1053a28ef1f5SChao Yu 
1054a28ef1f5SChao Yu 	write_lock(&et->lock);
1055201ef5e0SHou Pengyang 	node_cnt = __free_extent_tree(sbi, et);
1056a28ef1f5SChao Yu 	write_unlock(&et->lock);
1057a28ef1f5SChao Yu 
1058a28ef1f5SChao Yu 	return node_cnt;
1059a28ef1f5SChao Yu }
1060a28ef1f5SChao Yu 
1061e7547dacSJaegeuk Kim void f2fs_destroy_extent_node(struct inode *inode)
1062e7547dacSJaegeuk Kim {
1063e7547dacSJaegeuk Kim 	__destroy_extent_node(inode, EX_READ);
106471644dffSJaegeuk Kim 	__destroy_extent_node(inode, EX_BLOCK_AGE);
1065e7547dacSJaegeuk Kim }
1066e7547dacSJaegeuk Kim 
1067e7547dacSJaegeuk Kim static void __drop_extent_tree(struct inode *inode, enum extent_type type)
10685f281fabSJaegeuk Kim {
10695f281fabSJaegeuk Kim 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1070e7547dacSJaegeuk Kim 	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
1071b430f726SZhikang Zhang 	bool updated = false;
10725f281fabSJaegeuk Kim 
1073e7547dacSJaegeuk Kim 	if (!__may_extent_tree(inode, type))
1074bf617f7aSChao Yu 		return;
1075bf617f7aSChao Yu 
10765f281fabSJaegeuk Kim 	write_lock(&et->lock);
10775f281fabSJaegeuk Kim 	__free_extent_tree(sbi, et);
1078e7547dacSJaegeuk Kim 	if (type == EX_READ) {
1079e7547dacSJaegeuk Kim 		set_inode_flag(inode, FI_NO_EXTENT);
1080b430f726SZhikang Zhang 		if (et->largest.len) {
1081b430f726SZhikang Zhang 			et->largest.len = 0;
1082b430f726SZhikang Zhang 			updated = true;
1083b430f726SZhikang Zhang 		}
1084e7547dacSJaegeuk Kim 	}
10855f281fabSJaegeuk Kim 	write_unlock(&et->lock);
1086b430f726SZhikang Zhang 	if (updated)
1087b430f726SZhikang Zhang 		f2fs_mark_inode_dirty_sync(inode, true);
10885f281fabSJaegeuk Kim }
10895f281fabSJaegeuk Kim 
1090e7547dacSJaegeuk Kim void f2fs_drop_extent_tree(struct inode *inode)
1091e7547dacSJaegeuk Kim {
1092e7547dacSJaegeuk Kim 	__drop_extent_tree(inode, EX_READ);
109371644dffSJaegeuk Kim 	__drop_extent_tree(inode, EX_BLOCK_AGE);
1094e7547dacSJaegeuk Kim }
1095e7547dacSJaegeuk Kim 
1096e7547dacSJaegeuk Kim static void __destroy_extent_tree(struct inode *inode, enum extent_type type)
1097a28ef1f5SChao Yu {
1098a28ef1f5SChao Yu 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1099e7547dacSJaegeuk Kim 	struct extent_tree_info *eti = &sbi->extent_tree[type];
1100e7547dacSJaegeuk Kim 	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
1101a28ef1f5SChao Yu 	unsigned int node_cnt = 0;
1102a28ef1f5SChao Yu 
1103a28ef1f5SChao Yu 	if (!et)
1104a28ef1f5SChao Yu 		return;
1105a28ef1f5SChao Yu 
110668e35385SChao Yu 	if (inode->i_nlink && !is_bad_inode(inode) &&
110768e35385SChao Yu 					atomic_read(&et->node_cnt)) {
1108e7547dacSJaegeuk Kim 		mutex_lock(&eti->extent_tree_lock);
1109e7547dacSJaegeuk Kim 		list_add_tail(&et->list, &eti->zombie_list);
1110e7547dacSJaegeuk Kim 		atomic_inc(&eti->total_zombie_tree);
1111e7547dacSJaegeuk Kim 		mutex_unlock(&eti->extent_tree_lock);
1112a28ef1f5SChao Yu 		return;
1113a28ef1f5SChao Yu 	}
1114a28ef1f5SChao Yu 
1115a28ef1f5SChao Yu 	/* free all extent info belong to this extent tree */
1116e7547dacSJaegeuk Kim 	node_cnt = __destroy_extent_node(inode, type);
1117a28ef1f5SChao Yu 
1118a28ef1f5SChao Yu 	/* delete extent tree entry in radix tree */
1119e7547dacSJaegeuk Kim 	mutex_lock(&eti->extent_tree_lock);
112068e35385SChao Yu 	f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
1121e7547dacSJaegeuk Kim 	radix_tree_delete(&eti->extent_tree_root, inode->i_ino);
1122a28ef1f5SChao Yu 	kmem_cache_free(extent_tree_slab, et);
1123e7547dacSJaegeuk Kim 	atomic_dec(&eti->total_ext_tree);
1124e7547dacSJaegeuk Kim 	mutex_unlock(&eti->extent_tree_lock);
1125a28ef1f5SChao Yu 
1126e7547dacSJaegeuk Kim 	F2FS_I(inode)->extent_tree[type] = NULL;
1127a28ef1f5SChao Yu 
1128e7547dacSJaegeuk Kim 	trace_f2fs_destroy_extent_tree(inode, node_cnt, type);
1129a28ef1f5SChao Yu }
1130a28ef1f5SChao Yu 
1131e7547dacSJaegeuk Kim void f2fs_destroy_extent_tree(struct inode *inode)
1132a28ef1f5SChao Yu {
1133e7547dacSJaegeuk Kim 	__destroy_extent_tree(inode, EX_READ);
113471644dffSJaegeuk Kim 	__destroy_extent_tree(inode, EX_BLOCK_AGE);
1135a28ef1f5SChao Yu }
1136a28ef1f5SChao Yu 
1137e7547dacSJaegeuk Kim static void __init_extent_tree_info(struct extent_tree_info *eti)
1138a28ef1f5SChao Yu {
1139e7547dacSJaegeuk Kim 	INIT_RADIX_TREE(&eti->extent_tree_root, GFP_NOIO);
1140e7547dacSJaegeuk Kim 	mutex_init(&eti->extent_tree_lock);
1141e7547dacSJaegeuk Kim 	INIT_LIST_HEAD(&eti->extent_list);
1142e7547dacSJaegeuk Kim 	spin_lock_init(&eti->extent_lock);
1143e7547dacSJaegeuk Kim 	atomic_set(&eti->total_ext_tree, 0);
1144e7547dacSJaegeuk Kim 	INIT_LIST_HEAD(&eti->zombie_list);
1145e7547dacSJaegeuk Kim 	atomic_set(&eti->total_zombie_tree, 0);
1146e7547dacSJaegeuk Kim 	atomic_set(&eti->total_ext_node, 0);
1147a28ef1f5SChao Yu }
1148a28ef1f5SChao Yu 
11494d57b86dSChao Yu void f2fs_init_extent_cache_info(struct f2fs_sb_info *sbi)
1150a28ef1f5SChao Yu {
1151e7547dacSJaegeuk Kim 	__init_extent_tree_info(&sbi->extent_tree[EX_READ]);
115271644dffSJaegeuk Kim 	__init_extent_tree_info(&sbi->extent_tree[EX_BLOCK_AGE]);
115371644dffSJaegeuk Kim 
115471644dffSJaegeuk Kim 	/* initialize for block age extents */
115571644dffSJaegeuk Kim 	atomic64_set(&sbi->allocated_data_blocks, 0);
115671644dffSJaegeuk Kim 	sbi->hot_data_age_threshold = DEF_HOT_DATA_AGE_THRESHOLD;
115771644dffSJaegeuk Kim 	sbi->warm_data_age_threshold = DEF_WARM_DATA_AGE_THRESHOLD;
1158d23be468Sqixiaoyu1 	sbi->last_age_weight = LAST_AGE_WEIGHT;
1159a28ef1f5SChao Yu }
1160a28ef1f5SChao Yu 
11614d57b86dSChao Yu int __init f2fs_create_extent_cache(void)
1162a28ef1f5SChao Yu {
1163a28ef1f5SChao Yu 	extent_tree_slab = f2fs_kmem_cache_create("f2fs_extent_tree",
1164a28ef1f5SChao Yu 			sizeof(struct extent_tree));
1165a28ef1f5SChao Yu 	if (!extent_tree_slab)
1166a28ef1f5SChao Yu 		return -ENOMEM;
1167a28ef1f5SChao Yu 	extent_node_slab = f2fs_kmem_cache_create("f2fs_extent_node",
1168a28ef1f5SChao Yu 			sizeof(struct extent_node));
1169a28ef1f5SChao Yu 	if (!extent_node_slab) {
1170a28ef1f5SChao Yu 		kmem_cache_destroy(extent_tree_slab);
1171a28ef1f5SChao Yu 		return -ENOMEM;
1172a28ef1f5SChao Yu 	}
1173a28ef1f5SChao Yu 	return 0;
1174a28ef1f5SChao Yu }
1175a28ef1f5SChao Yu 
11764d57b86dSChao Yu void f2fs_destroy_extent_cache(void)
1177a28ef1f5SChao Yu {
1178a28ef1f5SChao Yu 	kmem_cache_destroy(extent_node_slab);
1179a28ef1f5SChao Yu 	kmem_cache_destroy(extent_tree_slab);
1180a28ef1f5SChao Yu }
1181