162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * f2fs extent cache support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2015 Motorola Mobility
662306a36Sopenharmony_ci * Copyright (c) 2015 Samsung Electronics
762306a36Sopenharmony_ci * Authors: Jaegeuk Kim <jaegeuk@kernel.org>
862306a36Sopenharmony_ci *          Chao Yu <chao2.yu@samsung.com>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * block_age-based extent cache added by:
1162306a36Sopenharmony_ci * Copyright (c) 2022 xiaomi Co., Ltd.
1262306a36Sopenharmony_ci *             http://www.xiaomi.com/
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/fs.h>
1662306a36Sopenharmony_ci#include <linux/f2fs_fs.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "f2fs.h"
1962306a36Sopenharmony_ci#include "node.h"
2062306a36Sopenharmony_ci#include <trace/events/f2fs.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cibool sanity_check_extent_cache(struct inode *inode)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2562306a36Sopenharmony_ci	struct f2fs_inode_info *fi = F2FS_I(inode);
2662306a36Sopenharmony_ci	struct extent_tree *et = fi->extent_tree[EX_READ];
2762306a36Sopenharmony_ci	struct extent_info *ei;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (!et)
3062306a36Sopenharmony_ci		return true;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	ei = &et->largest;
3362306a36Sopenharmony_ci	if (!ei->len)
3462306a36Sopenharmony_ci		return true;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	/* Let's drop, if checkpoint got corrupted. */
3762306a36Sopenharmony_ci	if (is_set_ckpt_flags(sbi, CP_ERROR_FLAG)) {
3862306a36Sopenharmony_ci		ei->len = 0;
3962306a36Sopenharmony_ci		et->largest_updated = true;
4062306a36Sopenharmony_ci		return true;
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC_ENHANCE) ||
4462306a36Sopenharmony_ci	    !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
4562306a36Sopenharmony_ci					DATA_GENERIC_ENHANCE)) {
4662306a36Sopenharmony_ci		set_sbi_flag(sbi, SBI_NEED_FSCK);
4762306a36Sopenharmony_ci		f2fs_warn(sbi, "%s: inode (ino=%lx) extent info [%u, %u, %u] is incorrect, run fsck to fix",
4862306a36Sopenharmony_ci			  __func__, inode->i_ino,
4962306a36Sopenharmony_ci			  ei->blk, ei->fofs, ei->len);
5062306a36Sopenharmony_ci		return false;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	return true;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void __set_extent_info(struct extent_info *ei,
5662306a36Sopenharmony_ci				unsigned int fofs, unsigned int len,
5762306a36Sopenharmony_ci				block_t blk, bool keep_clen,
5862306a36Sopenharmony_ci				unsigned long age, unsigned long last_blocks,
5962306a36Sopenharmony_ci				enum extent_type type)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	ei->fofs = fofs;
6262306a36Sopenharmony_ci	ei->len = len;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (type == EX_READ) {
6562306a36Sopenharmony_ci		ei->blk = blk;
6662306a36Sopenharmony_ci		if (keep_clen)
6762306a36Sopenharmony_ci			return;
6862306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION
6962306a36Sopenharmony_ci		ei->c_len = 0;
7062306a36Sopenharmony_ci#endif
7162306a36Sopenharmony_ci	} else if (type == EX_BLOCK_AGE) {
7262306a36Sopenharmony_ci		ei->age = age;
7362306a36Sopenharmony_ci		ei->last_blocks = last_blocks;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic bool __init_may_extent_tree(struct inode *inode, enum extent_type type)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	if (type == EX_READ)
8062306a36Sopenharmony_ci		return test_opt(F2FS_I_SB(inode), READ_EXTENT_CACHE) &&
8162306a36Sopenharmony_ci			S_ISREG(inode->i_mode);
8262306a36Sopenharmony_ci	if (type == EX_BLOCK_AGE)
8362306a36Sopenharmony_ci		return test_opt(F2FS_I_SB(inode), AGE_EXTENT_CACHE) &&
8462306a36Sopenharmony_ci			(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode));
8562306a36Sopenharmony_ci	return false;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic bool __may_extent_tree(struct inode *inode, enum extent_type type)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	/*
9162306a36Sopenharmony_ci	 * for recovered files during mount do not create extents
9262306a36Sopenharmony_ci	 * if shrinker is not registered.
9362306a36Sopenharmony_ci	 */
9462306a36Sopenharmony_ci	if (list_empty(&F2FS_I_SB(inode)->s_list))
9562306a36Sopenharmony_ci		return false;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (!__init_may_extent_tree(inode, type))
9862306a36Sopenharmony_ci		return false;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (type == EX_READ) {
10162306a36Sopenharmony_ci		if (is_inode_flag_set(inode, FI_NO_EXTENT))
10262306a36Sopenharmony_ci			return false;
10362306a36Sopenharmony_ci		if (is_inode_flag_set(inode, FI_COMPRESSED_FILE) &&
10462306a36Sopenharmony_ci				 !f2fs_sb_has_readonly(F2FS_I_SB(inode)))
10562306a36Sopenharmony_ci			return false;
10662306a36Sopenharmony_ci	} else if (type == EX_BLOCK_AGE) {
10762306a36Sopenharmony_ci		if (is_inode_flag_set(inode, FI_COMPRESSED_FILE))
10862306a36Sopenharmony_ci			return false;
10962306a36Sopenharmony_ci		if (file_is_cold(inode))
11062306a36Sopenharmony_ci			return false;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	return true;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic void __try_update_largest_extent(struct extent_tree *et,
11662306a36Sopenharmony_ci						struct extent_node *en)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	if (et->type != EX_READ)
11962306a36Sopenharmony_ci		return;
12062306a36Sopenharmony_ci	if (en->ei.len <= et->largest.len)
12162306a36Sopenharmony_ci		return;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	et->largest = en->ei;
12462306a36Sopenharmony_ci	et->largest_updated = true;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic bool __is_extent_mergeable(struct extent_info *back,
12862306a36Sopenharmony_ci		struct extent_info *front, enum extent_type type)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	if (type == EX_READ) {
13162306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION
13262306a36Sopenharmony_ci		if (back->c_len && back->len != back->c_len)
13362306a36Sopenharmony_ci			return false;
13462306a36Sopenharmony_ci		if (front->c_len && front->len != front->c_len)
13562306a36Sopenharmony_ci			return false;
13662306a36Sopenharmony_ci#endif
13762306a36Sopenharmony_ci		return (back->fofs + back->len == front->fofs &&
13862306a36Sopenharmony_ci				back->blk + back->len == front->blk);
13962306a36Sopenharmony_ci	} else if (type == EX_BLOCK_AGE) {
14062306a36Sopenharmony_ci		return (back->fofs + back->len == front->fofs &&
14162306a36Sopenharmony_ci			abs(back->age - front->age) <= SAME_AGE_REGION &&
14262306a36Sopenharmony_ci			abs(back->last_blocks - front->last_blocks) <=
14362306a36Sopenharmony_ci							SAME_AGE_REGION);
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci	return false;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic bool __is_back_mergeable(struct extent_info *cur,
14962306a36Sopenharmony_ci		struct extent_info *back, enum extent_type type)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	return __is_extent_mergeable(back, cur, type);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic bool __is_front_mergeable(struct extent_info *cur,
15562306a36Sopenharmony_ci		struct extent_info *front, enum extent_type type)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	return __is_extent_mergeable(cur, front, type);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic struct extent_node *__lookup_extent_node(struct rb_root_cached *root,
16162306a36Sopenharmony_ci			struct extent_node *cached_en, unsigned int fofs)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct rb_node *node = root->rb_root.rb_node;
16462306a36Sopenharmony_ci	struct extent_node *en;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* check a cached entry */
16762306a36Sopenharmony_ci	if (cached_en && cached_en->ei.fofs <= fofs &&
16862306a36Sopenharmony_ci			cached_en->ei.fofs + cached_en->ei.len > fofs)
16962306a36Sopenharmony_ci		return cached_en;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* check rb_tree */
17262306a36Sopenharmony_ci	while (node) {
17362306a36Sopenharmony_ci		en = rb_entry(node, struct extent_node, rb_node);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		if (fofs < en->ei.fofs)
17662306a36Sopenharmony_ci			node = node->rb_left;
17762306a36Sopenharmony_ci		else if (fofs >= en->ei.fofs + en->ei.len)
17862306a36Sopenharmony_ci			node = node->rb_right;
17962306a36Sopenharmony_ci		else
18062306a36Sopenharmony_ci			return en;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci	return NULL;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci * lookup rb entry in position of @fofs in rb-tree,
18762306a36Sopenharmony_ci * if hit, return the entry, otherwise, return NULL
18862306a36Sopenharmony_ci * @prev_ex: extent before fofs
18962306a36Sopenharmony_ci * @next_ex: extent after fofs
19062306a36Sopenharmony_ci * @insert_p: insert point for new extent at fofs
19162306a36Sopenharmony_ci * in order to simplify the insertion after.
19262306a36Sopenharmony_ci * tree must stay unchanged between lookup and insertion.
19362306a36Sopenharmony_ci */
19462306a36Sopenharmony_cistatic struct extent_node *__lookup_extent_node_ret(struct rb_root_cached *root,
19562306a36Sopenharmony_ci				struct extent_node *cached_en,
19662306a36Sopenharmony_ci				unsigned int fofs,
19762306a36Sopenharmony_ci				struct extent_node **prev_entry,
19862306a36Sopenharmony_ci				struct extent_node **next_entry,
19962306a36Sopenharmony_ci				struct rb_node ***insert_p,
20062306a36Sopenharmony_ci				struct rb_node **insert_parent,
20162306a36Sopenharmony_ci				bool *leftmost)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct rb_node **pnode = &root->rb_root.rb_node;
20462306a36Sopenharmony_ci	struct rb_node *parent = NULL, *tmp_node;
20562306a36Sopenharmony_ci	struct extent_node *en = cached_en;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	*insert_p = NULL;
20862306a36Sopenharmony_ci	*insert_parent = NULL;
20962306a36Sopenharmony_ci	*prev_entry = NULL;
21062306a36Sopenharmony_ci	*next_entry = NULL;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (RB_EMPTY_ROOT(&root->rb_root))
21362306a36Sopenharmony_ci		return NULL;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (en && en->ei.fofs <= fofs && en->ei.fofs + en->ei.len > fofs)
21662306a36Sopenharmony_ci		goto lookup_neighbors;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	*leftmost = true;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	while (*pnode) {
22162306a36Sopenharmony_ci		parent = *pnode;
22262306a36Sopenharmony_ci		en = rb_entry(*pnode, struct extent_node, rb_node);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		if (fofs < en->ei.fofs) {
22562306a36Sopenharmony_ci			pnode = &(*pnode)->rb_left;
22662306a36Sopenharmony_ci		} else if (fofs >= en->ei.fofs + en->ei.len) {
22762306a36Sopenharmony_ci			pnode = &(*pnode)->rb_right;
22862306a36Sopenharmony_ci			*leftmost = false;
22962306a36Sopenharmony_ci		} else {
23062306a36Sopenharmony_ci			goto lookup_neighbors;
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	*insert_p = pnode;
23562306a36Sopenharmony_ci	*insert_parent = parent;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	en = rb_entry(parent, struct extent_node, rb_node);
23862306a36Sopenharmony_ci	tmp_node = parent;
23962306a36Sopenharmony_ci	if (parent && fofs > en->ei.fofs)
24062306a36Sopenharmony_ci		tmp_node = rb_next(parent);
24162306a36Sopenharmony_ci	*next_entry = rb_entry_safe(tmp_node, struct extent_node, rb_node);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	tmp_node = parent;
24462306a36Sopenharmony_ci	if (parent && fofs < en->ei.fofs)
24562306a36Sopenharmony_ci		tmp_node = rb_prev(parent);
24662306a36Sopenharmony_ci	*prev_entry = rb_entry_safe(tmp_node, struct extent_node, rb_node);
24762306a36Sopenharmony_ci	return NULL;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cilookup_neighbors:
25062306a36Sopenharmony_ci	if (fofs == en->ei.fofs) {
25162306a36Sopenharmony_ci		/* lookup prev node for merging backward later */
25262306a36Sopenharmony_ci		tmp_node = rb_prev(&en->rb_node);
25362306a36Sopenharmony_ci		*prev_entry = rb_entry_safe(tmp_node,
25462306a36Sopenharmony_ci					struct extent_node, rb_node);
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci	if (fofs == en->ei.fofs + en->ei.len - 1) {
25762306a36Sopenharmony_ci		/* lookup next node for merging frontward later */
25862306a36Sopenharmony_ci		tmp_node = rb_next(&en->rb_node);
25962306a36Sopenharmony_ci		*next_entry = rb_entry_safe(tmp_node,
26062306a36Sopenharmony_ci					struct extent_node, rb_node);
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci	return en;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic struct kmem_cache *extent_tree_slab;
26662306a36Sopenharmony_cistatic struct kmem_cache *extent_node_slab;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic struct extent_node *__attach_extent_node(struct f2fs_sb_info *sbi,
26962306a36Sopenharmony_ci				struct extent_tree *et, struct extent_info *ei,
27062306a36Sopenharmony_ci				struct rb_node *parent, struct rb_node **p,
27162306a36Sopenharmony_ci				bool leftmost)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
27462306a36Sopenharmony_ci	struct extent_node *en;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	en = f2fs_kmem_cache_alloc(extent_node_slab, GFP_ATOMIC, false, sbi);
27762306a36Sopenharmony_ci	if (!en)
27862306a36Sopenharmony_ci		return NULL;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	en->ei = *ei;
28162306a36Sopenharmony_ci	INIT_LIST_HEAD(&en->list);
28262306a36Sopenharmony_ci	en->et = et;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	rb_link_node(&en->rb_node, parent, p);
28562306a36Sopenharmony_ci	rb_insert_color_cached(&en->rb_node, &et->root, leftmost);
28662306a36Sopenharmony_ci	atomic_inc(&et->node_cnt);
28762306a36Sopenharmony_ci	atomic_inc(&eti->total_ext_node);
28862306a36Sopenharmony_ci	return en;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic void __detach_extent_node(struct f2fs_sb_info *sbi,
29262306a36Sopenharmony_ci				struct extent_tree *et, struct extent_node *en)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	rb_erase_cached(&en->rb_node, &et->root);
29762306a36Sopenharmony_ci	atomic_dec(&et->node_cnt);
29862306a36Sopenharmony_ci	atomic_dec(&eti->total_ext_node);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (et->cached_en == en)
30162306a36Sopenharmony_ci		et->cached_en = NULL;
30262306a36Sopenharmony_ci	kmem_cache_free(extent_node_slab, en);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci/*
30662306a36Sopenharmony_ci * Flow to release an extent_node:
30762306a36Sopenharmony_ci * 1. list_del_init
30862306a36Sopenharmony_ci * 2. __detach_extent_node
30962306a36Sopenharmony_ci * 3. kmem_cache_free.
31062306a36Sopenharmony_ci */
31162306a36Sopenharmony_cistatic void __release_extent_node(struct f2fs_sb_info *sbi,
31262306a36Sopenharmony_ci			struct extent_tree *et, struct extent_node *en)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	spin_lock(&eti->extent_lock);
31762306a36Sopenharmony_ci	f2fs_bug_on(sbi, list_empty(&en->list));
31862306a36Sopenharmony_ci	list_del_init(&en->list);
31962306a36Sopenharmony_ci	spin_unlock(&eti->extent_lock);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	__detach_extent_node(sbi, et, en);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic struct extent_tree *__grab_extent_tree(struct inode *inode,
32562306a36Sopenharmony_ci						enum extent_type type)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
32862306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[type];
32962306a36Sopenharmony_ci	struct extent_tree *et;
33062306a36Sopenharmony_ci	nid_t ino = inode->i_ino;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	mutex_lock(&eti->extent_tree_lock);
33362306a36Sopenharmony_ci	et = radix_tree_lookup(&eti->extent_tree_root, ino);
33462306a36Sopenharmony_ci	if (!et) {
33562306a36Sopenharmony_ci		et = f2fs_kmem_cache_alloc(extent_tree_slab,
33662306a36Sopenharmony_ci					GFP_NOFS, true, NULL);
33762306a36Sopenharmony_ci		f2fs_radix_tree_insert(&eti->extent_tree_root, ino, et);
33862306a36Sopenharmony_ci		memset(et, 0, sizeof(struct extent_tree));
33962306a36Sopenharmony_ci		et->ino = ino;
34062306a36Sopenharmony_ci		et->type = type;
34162306a36Sopenharmony_ci		et->root = RB_ROOT_CACHED;
34262306a36Sopenharmony_ci		et->cached_en = NULL;
34362306a36Sopenharmony_ci		rwlock_init(&et->lock);
34462306a36Sopenharmony_ci		INIT_LIST_HEAD(&et->list);
34562306a36Sopenharmony_ci		atomic_set(&et->node_cnt, 0);
34662306a36Sopenharmony_ci		atomic_inc(&eti->total_ext_tree);
34762306a36Sopenharmony_ci	} else {
34862306a36Sopenharmony_ci		atomic_dec(&eti->total_zombie_tree);
34962306a36Sopenharmony_ci		list_del_init(&et->list);
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci	mutex_unlock(&eti->extent_tree_lock);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* never died until evict_inode */
35462306a36Sopenharmony_ci	F2FS_I(inode)->extent_tree[type] = et;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return et;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic unsigned int __free_extent_tree(struct f2fs_sb_info *sbi,
36062306a36Sopenharmony_ci					struct extent_tree *et)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct rb_node *node, *next;
36362306a36Sopenharmony_ci	struct extent_node *en;
36462306a36Sopenharmony_ci	unsigned int count = atomic_read(&et->node_cnt);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	node = rb_first_cached(&et->root);
36762306a36Sopenharmony_ci	while (node) {
36862306a36Sopenharmony_ci		next = rb_next(node);
36962306a36Sopenharmony_ci		en = rb_entry(node, struct extent_node, rb_node);
37062306a36Sopenharmony_ci		__release_extent_node(sbi, et, en);
37162306a36Sopenharmony_ci		node = next;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	return count - atomic_read(&et->node_cnt);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic void __drop_largest_extent(struct extent_tree *et,
37862306a36Sopenharmony_ci					pgoff_t fofs, unsigned int len)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	if (fofs < et->largest.fofs + et->largest.len &&
38162306a36Sopenharmony_ci			fofs + len > et->largest.fofs) {
38262306a36Sopenharmony_ci		et->largest.len = 0;
38362306a36Sopenharmony_ci		et->largest_updated = true;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_civoid f2fs_init_read_extent_tree(struct inode *inode, struct page *ipage)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
39062306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[EX_READ];
39162306a36Sopenharmony_ci	struct f2fs_extent *i_ext = &F2FS_INODE(ipage)->i_ext;
39262306a36Sopenharmony_ci	struct extent_tree *et;
39362306a36Sopenharmony_ci	struct extent_node *en;
39462306a36Sopenharmony_ci	struct extent_info ei;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (!__may_extent_tree(inode, EX_READ)) {
39762306a36Sopenharmony_ci		/* drop largest read extent */
39862306a36Sopenharmony_ci		if (i_ext && i_ext->len) {
39962306a36Sopenharmony_ci			f2fs_wait_on_page_writeback(ipage, NODE, true, true);
40062306a36Sopenharmony_ci			i_ext->len = 0;
40162306a36Sopenharmony_ci			set_page_dirty(ipage);
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci		goto out;
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	et = __grab_extent_tree(inode, EX_READ);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (!i_ext || !i_ext->len)
40962306a36Sopenharmony_ci		goto out;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	get_read_extent_info(&ei, i_ext);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	write_lock(&et->lock);
41462306a36Sopenharmony_ci	if (atomic_read(&et->node_cnt))
41562306a36Sopenharmony_ci		goto unlock_out;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	en = __attach_extent_node(sbi, et, &ei, NULL,
41862306a36Sopenharmony_ci				&et->root.rb_root.rb_node, true);
41962306a36Sopenharmony_ci	if (en) {
42062306a36Sopenharmony_ci		et->largest = en->ei;
42162306a36Sopenharmony_ci		et->cached_en = en;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		spin_lock(&eti->extent_lock);
42462306a36Sopenharmony_ci		list_add_tail(&en->list, &eti->extent_list);
42562306a36Sopenharmony_ci		spin_unlock(&eti->extent_lock);
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ciunlock_out:
42862306a36Sopenharmony_ci	write_unlock(&et->lock);
42962306a36Sopenharmony_ciout:
43062306a36Sopenharmony_ci	if (!F2FS_I(inode)->extent_tree[EX_READ])
43162306a36Sopenharmony_ci		set_inode_flag(inode, FI_NO_EXTENT);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_civoid f2fs_init_age_extent_tree(struct inode *inode)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	if (!__init_may_extent_tree(inode, EX_BLOCK_AGE))
43762306a36Sopenharmony_ci		return;
43862306a36Sopenharmony_ci	__grab_extent_tree(inode, EX_BLOCK_AGE);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_civoid f2fs_init_extent_tree(struct inode *inode)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	/* initialize read cache */
44462306a36Sopenharmony_ci	if (__init_may_extent_tree(inode, EX_READ))
44562306a36Sopenharmony_ci		__grab_extent_tree(inode, EX_READ);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* initialize block age cache */
44862306a36Sopenharmony_ci	if (__init_may_extent_tree(inode, EX_BLOCK_AGE))
44962306a36Sopenharmony_ci		__grab_extent_tree(inode, EX_BLOCK_AGE);
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic bool __lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
45362306a36Sopenharmony_ci			struct extent_info *ei, enum extent_type type)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
45662306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[type];
45762306a36Sopenharmony_ci	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
45862306a36Sopenharmony_ci	struct extent_node *en;
45962306a36Sopenharmony_ci	bool ret = false;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (!et)
46262306a36Sopenharmony_ci		return false;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	trace_f2fs_lookup_extent_tree_start(inode, pgofs, type);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	read_lock(&et->lock);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (type == EX_READ &&
46962306a36Sopenharmony_ci			et->largest.fofs <= pgofs &&
47062306a36Sopenharmony_ci			et->largest.fofs + et->largest.len > pgofs) {
47162306a36Sopenharmony_ci		*ei = et->largest;
47262306a36Sopenharmony_ci		ret = true;
47362306a36Sopenharmony_ci		stat_inc_largest_node_hit(sbi);
47462306a36Sopenharmony_ci		goto out;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	en = __lookup_extent_node(&et->root, et->cached_en, pgofs);
47862306a36Sopenharmony_ci	if (!en)
47962306a36Sopenharmony_ci		goto out;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (en == et->cached_en)
48262306a36Sopenharmony_ci		stat_inc_cached_node_hit(sbi, type);
48362306a36Sopenharmony_ci	else
48462306a36Sopenharmony_ci		stat_inc_rbtree_node_hit(sbi, type);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	*ei = en->ei;
48762306a36Sopenharmony_ci	spin_lock(&eti->extent_lock);
48862306a36Sopenharmony_ci	if (!list_empty(&en->list)) {
48962306a36Sopenharmony_ci		list_move_tail(&en->list, &eti->extent_list);
49062306a36Sopenharmony_ci		et->cached_en = en;
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci	spin_unlock(&eti->extent_lock);
49362306a36Sopenharmony_ci	ret = true;
49462306a36Sopenharmony_ciout:
49562306a36Sopenharmony_ci	stat_inc_total_hit(sbi, type);
49662306a36Sopenharmony_ci	read_unlock(&et->lock);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (type == EX_READ)
49962306a36Sopenharmony_ci		trace_f2fs_lookup_read_extent_tree_end(inode, pgofs, ei);
50062306a36Sopenharmony_ci	else if (type == EX_BLOCK_AGE)
50162306a36Sopenharmony_ci		trace_f2fs_lookup_age_extent_tree_end(inode, pgofs, ei);
50262306a36Sopenharmony_ci	return ret;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic struct extent_node *__try_merge_extent_node(struct f2fs_sb_info *sbi,
50662306a36Sopenharmony_ci				struct extent_tree *et, struct extent_info *ei,
50762306a36Sopenharmony_ci				struct extent_node *prev_ex,
50862306a36Sopenharmony_ci				struct extent_node *next_ex)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
51162306a36Sopenharmony_ci	struct extent_node *en = NULL;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (prev_ex && __is_back_mergeable(ei, &prev_ex->ei, et->type)) {
51462306a36Sopenharmony_ci		prev_ex->ei.len += ei->len;
51562306a36Sopenharmony_ci		ei = &prev_ex->ei;
51662306a36Sopenharmony_ci		en = prev_ex;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (next_ex && __is_front_mergeable(ei, &next_ex->ei, et->type)) {
52062306a36Sopenharmony_ci		next_ex->ei.fofs = ei->fofs;
52162306a36Sopenharmony_ci		next_ex->ei.len += ei->len;
52262306a36Sopenharmony_ci		if (et->type == EX_READ)
52362306a36Sopenharmony_ci			next_ex->ei.blk = ei->blk;
52462306a36Sopenharmony_ci		if (en)
52562306a36Sopenharmony_ci			__release_extent_node(sbi, et, prev_ex);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		en = next_ex;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (!en)
53162306a36Sopenharmony_ci		return NULL;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	__try_update_largest_extent(et, en);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	spin_lock(&eti->extent_lock);
53662306a36Sopenharmony_ci	if (!list_empty(&en->list)) {
53762306a36Sopenharmony_ci		list_move_tail(&en->list, &eti->extent_list);
53862306a36Sopenharmony_ci		et->cached_en = en;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci	spin_unlock(&eti->extent_lock);
54162306a36Sopenharmony_ci	return en;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic struct extent_node *__insert_extent_tree(struct f2fs_sb_info *sbi,
54562306a36Sopenharmony_ci				struct extent_tree *et, struct extent_info *ei,
54662306a36Sopenharmony_ci				struct rb_node **insert_p,
54762306a36Sopenharmony_ci				struct rb_node *insert_parent,
54862306a36Sopenharmony_ci				bool leftmost)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[et->type];
55162306a36Sopenharmony_ci	struct rb_node **p = &et->root.rb_root.rb_node;
55262306a36Sopenharmony_ci	struct rb_node *parent = NULL;
55362306a36Sopenharmony_ci	struct extent_node *en = NULL;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (insert_p && insert_parent) {
55662306a36Sopenharmony_ci		parent = insert_parent;
55762306a36Sopenharmony_ci		p = insert_p;
55862306a36Sopenharmony_ci		goto do_insert;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	leftmost = true;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/* look up extent_node in the rb tree */
56462306a36Sopenharmony_ci	while (*p) {
56562306a36Sopenharmony_ci		parent = *p;
56662306a36Sopenharmony_ci		en = rb_entry(parent, struct extent_node, rb_node);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		if (ei->fofs < en->ei.fofs) {
56962306a36Sopenharmony_ci			p = &(*p)->rb_left;
57062306a36Sopenharmony_ci		} else if (ei->fofs >= en->ei.fofs + en->ei.len) {
57162306a36Sopenharmony_ci			p = &(*p)->rb_right;
57262306a36Sopenharmony_ci			leftmost = false;
57362306a36Sopenharmony_ci		} else {
57462306a36Sopenharmony_ci			f2fs_bug_on(sbi, 1);
57562306a36Sopenharmony_ci		}
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cido_insert:
57962306a36Sopenharmony_ci	en = __attach_extent_node(sbi, et, ei, parent, p, leftmost);
58062306a36Sopenharmony_ci	if (!en)
58162306a36Sopenharmony_ci		return NULL;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	__try_update_largest_extent(et, en);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* update in global extent list */
58662306a36Sopenharmony_ci	spin_lock(&eti->extent_lock);
58762306a36Sopenharmony_ci	list_add_tail(&en->list, &eti->extent_list);
58862306a36Sopenharmony_ci	et->cached_en = en;
58962306a36Sopenharmony_ci	spin_unlock(&eti->extent_lock);
59062306a36Sopenharmony_ci	return en;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic void __update_extent_tree_range(struct inode *inode,
59462306a36Sopenharmony_ci			struct extent_info *tei, enum extent_type type)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
59762306a36Sopenharmony_ci	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
59862306a36Sopenharmony_ci	struct extent_node *en = NULL, *en1 = NULL;
59962306a36Sopenharmony_ci	struct extent_node *prev_en = NULL, *next_en = NULL;
60062306a36Sopenharmony_ci	struct extent_info ei, dei, prev;
60162306a36Sopenharmony_ci	struct rb_node **insert_p = NULL, *insert_parent = NULL;
60262306a36Sopenharmony_ci	unsigned int fofs = tei->fofs, len = tei->len;
60362306a36Sopenharmony_ci	unsigned int end = fofs + len;
60462306a36Sopenharmony_ci	bool updated = false;
60562306a36Sopenharmony_ci	bool leftmost = false;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (!et)
60862306a36Sopenharmony_ci		return;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	if (type == EX_READ)
61162306a36Sopenharmony_ci		trace_f2fs_update_read_extent_tree_range(inode, fofs, len,
61262306a36Sopenharmony_ci						tei->blk, 0);
61362306a36Sopenharmony_ci	else if (type == EX_BLOCK_AGE)
61462306a36Sopenharmony_ci		trace_f2fs_update_age_extent_tree_range(inode, fofs, len,
61562306a36Sopenharmony_ci						tei->age, tei->last_blocks);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	write_lock(&et->lock);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (type == EX_READ) {
62062306a36Sopenharmony_ci		if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
62162306a36Sopenharmony_ci			write_unlock(&et->lock);
62262306a36Sopenharmony_ci			return;
62362306a36Sopenharmony_ci		}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		prev = et->largest;
62662306a36Sopenharmony_ci		dei.len = 0;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci		/*
62962306a36Sopenharmony_ci		 * drop largest extent before lookup, in case it's already
63062306a36Sopenharmony_ci		 * been shrunk from extent tree
63162306a36Sopenharmony_ci		 */
63262306a36Sopenharmony_ci		__drop_largest_extent(et, fofs, len);
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/* 1. lookup first extent node in range [fofs, fofs + len - 1] */
63662306a36Sopenharmony_ci	en = __lookup_extent_node_ret(&et->root,
63762306a36Sopenharmony_ci					et->cached_en, fofs,
63862306a36Sopenharmony_ci					&prev_en, &next_en,
63962306a36Sopenharmony_ci					&insert_p, &insert_parent,
64062306a36Sopenharmony_ci					&leftmost);
64162306a36Sopenharmony_ci	if (!en)
64262306a36Sopenharmony_ci		en = next_en;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	/* 2. invalidate all extent nodes in range [fofs, fofs + len - 1] */
64562306a36Sopenharmony_ci	while (en && en->ei.fofs < end) {
64662306a36Sopenharmony_ci		unsigned int org_end;
64762306a36Sopenharmony_ci		int parts = 0;	/* # of parts current extent split into */
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci		next_en = en1 = NULL;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		dei = en->ei;
65262306a36Sopenharmony_ci		org_end = dei.fofs + dei.len;
65362306a36Sopenharmony_ci		f2fs_bug_on(sbi, fofs >= org_end);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		if (fofs > dei.fofs && (type != EX_READ ||
65662306a36Sopenharmony_ci				fofs - dei.fofs >= F2FS_MIN_EXTENT_LEN)) {
65762306a36Sopenharmony_ci			en->ei.len = fofs - en->ei.fofs;
65862306a36Sopenharmony_ci			prev_en = en;
65962306a36Sopenharmony_ci			parts = 1;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		if (end < org_end && (type != EX_READ ||
66362306a36Sopenharmony_ci				org_end - end >= F2FS_MIN_EXTENT_LEN)) {
66462306a36Sopenharmony_ci			if (parts) {
66562306a36Sopenharmony_ci				__set_extent_info(&ei,
66662306a36Sopenharmony_ci					end, org_end - end,
66762306a36Sopenharmony_ci					end - dei.fofs + dei.blk, false,
66862306a36Sopenharmony_ci					dei.age, dei.last_blocks,
66962306a36Sopenharmony_ci					type);
67062306a36Sopenharmony_ci				en1 = __insert_extent_tree(sbi, et, &ei,
67162306a36Sopenharmony_ci							NULL, NULL, true);
67262306a36Sopenharmony_ci				next_en = en1;
67362306a36Sopenharmony_ci			} else {
67462306a36Sopenharmony_ci				__set_extent_info(&en->ei,
67562306a36Sopenharmony_ci					end, en->ei.len - (end - dei.fofs),
67662306a36Sopenharmony_ci					en->ei.blk + (end - dei.fofs), true,
67762306a36Sopenharmony_ci					dei.age, dei.last_blocks,
67862306a36Sopenharmony_ci					type);
67962306a36Sopenharmony_ci				next_en = en;
68062306a36Sopenharmony_ci			}
68162306a36Sopenharmony_ci			parts++;
68262306a36Sopenharmony_ci		}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		if (!next_en) {
68562306a36Sopenharmony_ci			struct rb_node *node = rb_next(&en->rb_node);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci			next_en = rb_entry_safe(node, struct extent_node,
68862306a36Sopenharmony_ci						rb_node);
68962306a36Sopenharmony_ci		}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		if (parts)
69262306a36Sopenharmony_ci			__try_update_largest_extent(et, en);
69362306a36Sopenharmony_ci		else
69462306a36Sopenharmony_ci			__release_extent_node(sbi, et, en);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		/*
69762306a36Sopenharmony_ci		 * if original extent is split into zero or two parts, extent
69862306a36Sopenharmony_ci		 * tree has been altered by deletion or insertion, therefore
69962306a36Sopenharmony_ci		 * invalidate pointers regard to tree.
70062306a36Sopenharmony_ci		 */
70162306a36Sopenharmony_ci		if (parts != 1) {
70262306a36Sopenharmony_ci			insert_p = NULL;
70362306a36Sopenharmony_ci			insert_parent = NULL;
70462306a36Sopenharmony_ci		}
70562306a36Sopenharmony_ci		en = next_en;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (type == EX_BLOCK_AGE)
70962306a36Sopenharmony_ci		goto update_age_extent_cache;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/* 3. update extent in read extent cache */
71262306a36Sopenharmony_ci	BUG_ON(type != EX_READ);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (tei->blk) {
71562306a36Sopenharmony_ci		__set_extent_info(&ei, fofs, len, tei->blk, false,
71662306a36Sopenharmony_ci				  0, 0, EX_READ);
71762306a36Sopenharmony_ci		if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
71862306a36Sopenharmony_ci			__insert_extent_tree(sbi, et, &ei,
71962306a36Sopenharmony_ci					insert_p, insert_parent, leftmost);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		/* give up extent_cache, if split and small updates happen */
72262306a36Sopenharmony_ci		if (dei.len >= 1 &&
72362306a36Sopenharmony_ci				prev.len < F2FS_MIN_EXTENT_LEN &&
72462306a36Sopenharmony_ci				et->largest.len < F2FS_MIN_EXTENT_LEN) {
72562306a36Sopenharmony_ci			et->largest.len = 0;
72662306a36Sopenharmony_ci			et->largest_updated = true;
72762306a36Sopenharmony_ci			set_inode_flag(inode, FI_NO_EXTENT);
72862306a36Sopenharmony_ci		}
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if (is_inode_flag_set(inode, FI_NO_EXTENT))
73262306a36Sopenharmony_ci		__free_extent_tree(sbi, et);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (et->largest_updated) {
73562306a36Sopenharmony_ci		et->largest_updated = false;
73662306a36Sopenharmony_ci		updated = true;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci	goto out_read_extent_cache;
73962306a36Sopenharmony_ciupdate_age_extent_cache:
74062306a36Sopenharmony_ci	if (!tei->last_blocks)
74162306a36Sopenharmony_ci		goto out_read_extent_cache;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	__set_extent_info(&ei, fofs, len, 0, false,
74462306a36Sopenharmony_ci			tei->age, tei->last_blocks, EX_BLOCK_AGE);
74562306a36Sopenharmony_ci	if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
74662306a36Sopenharmony_ci		__insert_extent_tree(sbi, et, &ei,
74762306a36Sopenharmony_ci					insert_p, insert_parent, leftmost);
74862306a36Sopenharmony_ciout_read_extent_cache:
74962306a36Sopenharmony_ci	write_unlock(&et->lock);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (updated)
75262306a36Sopenharmony_ci		f2fs_mark_inode_dirty_sync(inode, true);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION
75662306a36Sopenharmony_civoid f2fs_update_read_extent_tree_range_compressed(struct inode *inode,
75762306a36Sopenharmony_ci				pgoff_t fofs, block_t blkaddr, unsigned int llen,
75862306a36Sopenharmony_ci				unsigned int c_len)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
76162306a36Sopenharmony_ci	struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
76262306a36Sopenharmony_ci	struct extent_node *en = NULL;
76362306a36Sopenharmony_ci	struct extent_node *prev_en = NULL, *next_en = NULL;
76462306a36Sopenharmony_ci	struct extent_info ei;
76562306a36Sopenharmony_ci	struct rb_node **insert_p = NULL, *insert_parent = NULL;
76662306a36Sopenharmony_ci	bool leftmost = false;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	trace_f2fs_update_read_extent_tree_range(inode, fofs, llen,
76962306a36Sopenharmony_ci						blkaddr, c_len);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	/* it is safe here to check FI_NO_EXTENT w/o et->lock in ro image */
77262306a36Sopenharmony_ci	if (is_inode_flag_set(inode, FI_NO_EXTENT))
77362306a36Sopenharmony_ci		return;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	write_lock(&et->lock);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	en = __lookup_extent_node_ret(&et->root,
77862306a36Sopenharmony_ci					et->cached_en, fofs,
77962306a36Sopenharmony_ci					&prev_en, &next_en,
78062306a36Sopenharmony_ci					&insert_p, &insert_parent,
78162306a36Sopenharmony_ci					&leftmost);
78262306a36Sopenharmony_ci	if (en)
78362306a36Sopenharmony_ci		goto unlock_out;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	__set_extent_info(&ei, fofs, llen, blkaddr, true, 0, 0, EX_READ);
78662306a36Sopenharmony_ci	ei.c_len = c_len;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (!__try_merge_extent_node(sbi, et, &ei, prev_en, next_en))
78962306a36Sopenharmony_ci		__insert_extent_tree(sbi, et, &ei,
79062306a36Sopenharmony_ci				insert_p, insert_parent, leftmost);
79162306a36Sopenharmony_ciunlock_out:
79262306a36Sopenharmony_ci	write_unlock(&et->lock);
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci#endif
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic unsigned long long __calculate_block_age(struct f2fs_sb_info *sbi,
79762306a36Sopenharmony_ci						unsigned long long new,
79862306a36Sopenharmony_ci						unsigned long long old)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	unsigned int rem_old, rem_new;
80162306a36Sopenharmony_ci	unsigned long long res;
80262306a36Sopenharmony_ci	unsigned int weight = sbi->last_age_weight;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	res = div_u64_rem(new, 100, &rem_new) * (100 - weight)
80562306a36Sopenharmony_ci		+ div_u64_rem(old, 100, &rem_old) * weight;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	if (rem_new)
80862306a36Sopenharmony_ci		res += rem_new * (100 - weight) / 100;
80962306a36Sopenharmony_ci	if (rem_old)
81062306a36Sopenharmony_ci		res += rem_old * weight / 100;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	return res;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci/* This returns a new age and allocated blocks in ei */
81662306a36Sopenharmony_cistatic int __get_new_block_age(struct inode *inode, struct extent_info *ei,
81762306a36Sopenharmony_ci						block_t blkaddr)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
82062306a36Sopenharmony_ci	loff_t f_size = i_size_read(inode);
82162306a36Sopenharmony_ci	unsigned long long cur_blocks =
82262306a36Sopenharmony_ci				atomic64_read(&sbi->allocated_data_blocks);
82362306a36Sopenharmony_ci	struct extent_info tei = *ei;	/* only fofs and len are valid */
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	/*
82662306a36Sopenharmony_ci	 * When I/O is not aligned to a PAGE_SIZE, update will happen to the last
82762306a36Sopenharmony_ci	 * file block even in seq write. So don't record age for newly last file
82862306a36Sopenharmony_ci	 * block here.
82962306a36Sopenharmony_ci	 */
83062306a36Sopenharmony_ci	if ((f_size >> PAGE_SHIFT) == ei->fofs && f_size & (PAGE_SIZE - 1) &&
83162306a36Sopenharmony_ci			blkaddr == NEW_ADDR)
83262306a36Sopenharmony_ci		return -EINVAL;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	if (__lookup_extent_tree(inode, ei->fofs, &tei, EX_BLOCK_AGE)) {
83562306a36Sopenharmony_ci		unsigned long long cur_age;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		if (cur_blocks >= tei.last_blocks)
83862306a36Sopenharmony_ci			cur_age = cur_blocks - tei.last_blocks;
83962306a36Sopenharmony_ci		else
84062306a36Sopenharmony_ci			/* allocated_data_blocks overflow */
84162306a36Sopenharmony_ci			cur_age = ULLONG_MAX - tei.last_blocks + cur_blocks;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		if (tei.age)
84462306a36Sopenharmony_ci			ei->age = __calculate_block_age(sbi, cur_age, tei.age);
84562306a36Sopenharmony_ci		else
84662306a36Sopenharmony_ci			ei->age = cur_age;
84762306a36Sopenharmony_ci		ei->last_blocks = cur_blocks;
84862306a36Sopenharmony_ci		WARN_ON(ei->age > cur_blocks);
84962306a36Sopenharmony_ci		return 0;
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	f2fs_bug_on(sbi, blkaddr == NULL_ADDR);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	/* the data block was allocated for the first time */
85562306a36Sopenharmony_ci	if (blkaddr == NEW_ADDR)
85662306a36Sopenharmony_ci		goto out;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	if (__is_valid_data_blkaddr(blkaddr) &&
85962306a36Sopenharmony_ci	    !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
86062306a36Sopenharmony_ci		f2fs_bug_on(sbi, 1);
86162306a36Sopenharmony_ci		return -EINVAL;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ciout:
86462306a36Sopenharmony_ci	/*
86562306a36Sopenharmony_ci	 * init block age with zero, this can happen when the block age extent
86662306a36Sopenharmony_ci	 * was reclaimed due to memory constraint or system reboot
86762306a36Sopenharmony_ci	 */
86862306a36Sopenharmony_ci	ei->age = 0;
86962306a36Sopenharmony_ci	ei->last_blocks = cur_blocks;
87062306a36Sopenharmony_ci	return 0;
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cistatic void __update_extent_cache(struct dnode_of_data *dn, enum extent_type type)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci	struct extent_info ei = {};
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	if (!__may_extent_tree(dn->inode, type))
87862306a36Sopenharmony_ci		return;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	ei.fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
88162306a36Sopenharmony_ci								dn->ofs_in_node;
88262306a36Sopenharmony_ci	ei.len = 1;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	if (type == EX_READ) {
88562306a36Sopenharmony_ci		if (dn->data_blkaddr == NEW_ADDR)
88662306a36Sopenharmony_ci			ei.blk = NULL_ADDR;
88762306a36Sopenharmony_ci		else
88862306a36Sopenharmony_ci			ei.blk = dn->data_blkaddr;
88962306a36Sopenharmony_ci	} else if (type == EX_BLOCK_AGE) {
89062306a36Sopenharmony_ci		if (__get_new_block_age(dn->inode, &ei, dn->data_blkaddr))
89162306a36Sopenharmony_ci			return;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci	__update_extent_tree_range(dn->inode, &ei, type);
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_cistatic unsigned int __shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink,
89762306a36Sopenharmony_ci					enum extent_type type)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[type];
90062306a36Sopenharmony_ci	struct extent_tree *et, *next;
90162306a36Sopenharmony_ci	struct extent_node *en;
90262306a36Sopenharmony_ci	unsigned int node_cnt = 0, tree_cnt = 0;
90362306a36Sopenharmony_ci	int remained;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	if (!atomic_read(&eti->total_zombie_tree))
90662306a36Sopenharmony_ci		goto free_node;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	if (!mutex_trylock(&eti->extent_tree_lock))
90962306a36Sopenharmony_ci		goto out;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	/* 1. remove unreferenced extent tree */
91262306a36Sopenharmony_ci	list_for_each_entry_safe(et, next, &eti->zombie_list, list) {
91362306a36Sopenharmony_ci		if (atomic_read(&et->node_cnt)) {
91462306a36Sopenharmony_ci			write_lock(&et->lock);
91562306a36Sopenharmony_ci			node_cnt += __free_extent_tree(sbi, et);
91662306a36Sopenharmony_ci			write_unlock(&et->lock);
91762306a36Sopenharmony_ci		}
91862306a36Sopenharmony_ci		f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
91962306a36Sopenharmony_ci		list_del_init(&et->list);
92062306a36Sopenharmony_ci		radix_tree_delete(&eti->extent_tree_root, et->ino);
92162306a36Sopenharmony_ci		kmem_cache_free(extent_tree_slab, et);
92262306a36Sopenharmony_ci		atomic_dec(&eti->total_ext_tree);
92362306a36Sopenharmony_ci		atomic_dec(&eti->total_zombie_tree);
92462306a36Sopenharmony_ci		tree_cnt++;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci		if (node_cnt + tree_cnt >= nr_shrink)
92762306a36Sopenharmony_ci			goto unlock_out;
92862306a36Sopenharmony_ci		cond_resched();
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci	mutex_unlock(&eti->extent_tree_lock);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cifree_node:
93362306a36Sopenharmony_ci	/* 2. remove LRU extent entries */
93462306a36Sopenharmony_ci	if (!mutex_trylock(&eti->extent_tree_lock))
93562306a36Sopenharmony_ci		goto out;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	remained = nr_shrink - (node_cnt + tree_cnt);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	spin_lock(&eti->extent_lock);
94062306a36Sopenharmony_ci	for (; remained > 0; remained--) {
94162306a36Sopenharmony_ci		if (list_empty(&eti->extent_list))
94262306a36Sopenharmony_ci			break;
94362306a36Sopenharmony_ci		en = list_first_entry(&eti->extent_list,
94462306a36Sopenharmony_ci					struct extent_node, list);
94562306a36Sopenharmony_ci		et = en->et;
94662306a36Sopenharmony_ci		if (!write_trylock(&et->lock)) {
94762306a36Sopenharmony_ci			/* refresh this extent node's position in extent list */
94862306a36Sopenharmony_ci			list_move_tail(&en->list, &eti->extent_list);
94962306a36Sopenharmony_ci			continue;
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		list_del_init(&en->list);
95362306a36Sopenharmony_ci		spin_unlock(&eti->extent_lock);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci		__detach_extent_node(sbi, et, en);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci		write_unlock(&et->lock);
95862306a36Sopenharmony_ci		node_cnt++;
95962306a36Sopenharmony_ci		spin_lock(&eti->extent_lock);
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci	spin_unlock(&eti->extent_lock);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ciunlock_out:
96462306a36Sopenharmony_ci	mutex_unlock(&eti->extent_tree_lock);
96562306a36Sopenharmony_ciout:
96662306a36Sopenharmony_ci	trace_f2fs_shrink_extent_tree(sbi, node_cnt, tree_cnt, type);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	return node_cnt + tree_cnt;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci/* read extent cache operations */
97262306a36Sopenharmony_cibool f2fs_lookup_read_extent_cache(struct inode *inode, pgoff_t pgofs,
97362306a36Sopenharmony_ci				struct extent_info *ei)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	if (!__may_extent_tree(inode, EX_READ))
97662306a36Sopenharmony_ci		return false;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	return __lookup_extent_tree(inode, pgofs, ei, EX_READ);
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cibool f2fs_lookup_read_extent_cache_block(struct inode *inode, pgoff_t index,
98262306a36Sopenharmony_ci				block_t *blkaddr)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct extent_info ei = {};
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (!f2fs_lookup_read_extent_cache(inode, index, &ei))
98762306a36Sopenharmony_ci		return false;
98862306a36Sopenharmony_ci	*blkaddr = ei.blk + index - ei.fofs;
98962306a36Sopenharmony_ci	return true;
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_civoid f2fs_update_read_extent_cache(struct dnode_of_data *dn)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	return __update_extent_cache(dn, EX_READ);
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_civoid f2fs_update_read_extent_cache_range(struct dnode_of_data *dn,
99862306a36Sopenharmony_ci				pgoff_t fofs, block_t blkaddr, unsigned int len)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct extent_info ei = {
100162306a36Sopenharmony_ci		.fofs = fofs,
100262306a36Sopenharmony_ci		.len = len,
100362306a36Sopenharmony_ci		.blk = blkaddr,
100462306a36Sopenharmony_ci	};
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (!__may_extent_tree(dn->inode, EX_READ))
100762306a36Sopenharmony_ci		return;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	__update_extent_tree_range(dn->inode, &ei, EX_READ);
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ciunsigned int f2fs_shrink_read_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	if (!test_opt(sbi, READ_EXTENT_CACHE))
101562306a36Sopenharmony_ci		return 0;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	return __shrink_extent_tree(sbi, nr_shrink, EX_READ);
101862306a36Sopenharmony_ci}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci/* block age extent cache operations */
102162306a36Sopenharmony_cibool f2fs_lookup_age_extent_cache(struct inode *inode, pgoff_t pgofs,
102262306a36Sopenharmony_ci				struct extent_info *ei)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	if (!__may_extent_tree(inode, EX_BLOCK_AGE))
102562306a36Sopenharmony_ci		return false;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return __lookup_extent_tree(inode, pgofs, ei, EX_BLOCK_AGE);
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_civoid f2fs_update_age_extent_cache(struct dnode_of_data *dn)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	return __update_extent_cache(dn, EX_BLOCK_AGE);
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_civoid f2fs_update_age_extent_cache_range(struct dnode_of_data *dn,
103662306a36Sopenharmony_ci				pgoff_t fofs, unsigned int len)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	struct extent_info ei = {
103962306a36Sopenharmony_ci		.fofs = fofs,
104062306a36Sopenharmony_ci		.len = len,
104162306a36Sopenharmony_ci	};
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (!__may_extent_tree(dn->inode, EX_BLOCK_AGE))
104462306a36Sopenharmony_ci		return;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	__update_extent_tree_range(dn->inode, &ei, EX_BLOCK_AGE);
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ciunsigned int f2fs_shrink_age_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	if (!test_opt(sbi, AGE_EXTENT_CACHE))
105262306a36Sopenharmony_ci		return 0;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	return __shrink_extent_tree(sbi, nr_shrink, EX_BLOCK_AGE);
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_cistatic unsigned int __destroy_extent_node(struct inode *inode,
105862306a36Sopenharmony_ci					enum extent_type type)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
106162306a36Sopenharmony_ci	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
106262306a36Sopenharmony_ci	unsigned int node_cnt = 0;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	if (!et || !atomic_read(&et->node_cnt))
106562306a36Sopenharmony_ci		return 0;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	write_lock(&et->lock);
106862306a36Sopenharmony_ci	node_cnt = __free_extent_tree(sbi, et);
106962306a36Sopenharmony_ci	write_unlock(&et->lock);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	return node_cnt;
107262306a36Sopenharmony_ci}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_civoid f2fs_destroy_extent_node(struct inode *inode)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	__destroy_extent_node(inode, EX_READ);
107762306a36Sopenharmony_ci	__destroy_extent_node(inode, EX_BLOCK_AGE);
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic void __drop_extent_tree(struct inode *inode, enum extent_type type)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
108362306a36Sopenharmony_ci	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
108462306a36Sopenharmony_ci	bool updated = false;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (!__may_extent_tree(inode, type))
108762306a36Sopenharmony_ci		return;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	write_lock(&et->lock);
109062306a36Sopenharmony_ci	__free_extent_tree(sbi, et);
109162306a36Sopenharmony_ci	if (type == EX_READ) {
109262306a36Sopenharmony_ci		set_inode_flag(inode, FI_NO_EXTENT);
109362306a36Sopenharmony_ci		if (et->largest.len) {
109462306a36Sopenharmony_ci			et->largest.len = 0;
109562306a36Sopenharmony_ci			updated = true;
109662306a36Sopenharmony_ci		}
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci	write_unlock(&et->lock);
109962306a36Sopenharmony_ci	if (updated)
110062306a36Sopenharmony_ci		f2fs_mark_inode_dirty_sync(inode, true);
110162306a36Sopenharmony_ci}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_civoid f2fs_drop_extent_tree(struct inode *inode)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	__drop_extent_tree(inode, EX_READ);
110662306a36Sopenharmony_ci	__drop_extent_tree(inode, EX_BLOCK_AGE);
110762306a36Sopenharmony_ci}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_cistatic void __destroy_extent_tree(struct inode *inode, enum extent_type type)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
111262306a36Sopenharmony_ci	struct extent_tree_info *eti = &sbi->extent_tree[type];
111362306a36Sopenharmony_ci	struct extent_tree *et = F2FS_I(inode)->extent_tree[type];
111462306a36Sopenharmony_ci	unsigned int node_cnt = 0;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (!et)
111762306a36Sopenharmony_ci		return;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if (inode->i_nlink && !is_bad_inode(inode) &&
112062306a36Sopenharmony_ci					atomic_read(&et->node_cnt)) {
112162306a36Sopenharmony_ci		mutex_lock(&eti->extent_tree_lock);
112262306a36Sopenharmony_ci		list_add_tail(&et->list, &eti->zombie_list);
112362306a36Sopenharmony_ci		atomic_inc(&eti->total_zombie_tree);
112462306a36Sopenharmony_ci		mutex_unlock(&eti->extent_tree_lock);
112562306a36Sopenharmony_ci		return;
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	/* free all extent info belong to this extent tree */
112962306a36Sopenharmony_ci	node_cnt = __destroy_extent_node(inode, type);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* delete extent tree entry in radix tree */
113262306a36Sopenharmony_ci	mutex_lock(&eti->extent_tree_lock);
113362306a36Sopenharmony_ci	f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
113462306a36Sopenharmony_ci	radix_tree_delete(&eti->extent_tree_root, inode->i_ino);
113562306a36Sopenharmony_ci	kmem_cache_free(extent_tree_slab, et);
113662306a36Sopenharmony_ci	atomic_dec(&eti->total_ext_tree);
113762306a36Sopenharmony_ci	mutex_unlock(&eti->extent_tree_lock);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	F2FS_I(inode)->extent_tree[type] = NULL;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	trace_f2fs_destroy_extent_tree(inode, node_cnt, type);
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_civoid f2fs_destroy_extent_tree(struct inode *inode)
114562306a36Sopenharmony_ci{
114662306a36Sopenharmony_ci	__destroy_extent_tree(inode, EX_READ);
114762306a36Sopenharmony_ci	__destroy_extent_tree(inode, EX_BLOCK_AGE);
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic void __init_extent_tree_info(struct extent_tree_info *eti)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	INIT_RADIX_TREE(&eti->extent_tree_root, GFP_NOIO);
115362306a36Sopenharmony_ci	mutex_init(&eti->extent_tree_lock);
115462306a36Sopenharmony_ci	INIT_LIST_HEAD(&eti->extent_list);
115562306a36Sopenharmony_ci	spin_lock_init(&eti->extent_lock);
115662306a36Sopenharmony_ci	atomic_set(&eti->total_ext_tree, 0);
115762306a36Sopenharmony_ci	INIT_LIST_HEAD(&eti->zombie_list);
115862306a36Sopenharmony_ci	atomic_set(&eti->total_zombie_tree, 0);
115962306a36Sopenharmony_ci	atomic_set(&eti->total_ext_node, 0);
116062306a36Sopenharmony_ci}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_civoid f2fs_init_extent_cache_info(struct f2fs_sb_info *sbi)
116362306a36Sopenharmony_ci{
116462306a36Sopenharmony_ci	__init_extent_tree_info(&sbi->extent_tree[EX_READ]);
116562306a36Sopenharmony_ci	__init_extent_tree_info(&sbi->extent_tree[EX_BLOCK_AGE]);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	/* initialize for block age extents */
116862306a36Sopenharmony_ci	atomic64_set(&sbi->allocated_data_blocks, 0);
116962306a36Sopenharmony_ci	sbi->hot_data_age_threshold = DEF_HOT_DATA_AGE_THRESHOLD;
117062306a36Sopenharmony_ci	sbi->warm_data_age_threshold = DEF_WARM_DATA_AGE_THRESHOLD;
117162306a36Sopenharmony_ci	sbi->last_age_weight = LAST_AGE_WEIGHT;
117262306a36Sopenharmony_ci}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ciint __init f2fs_create_extent_cache(void)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	extent_tree_slab = f2fs_kmem_cache_create("f2fs_extent_tree",
117762306a36Sopenharmony_ci			sizeof(struct extent_tree));
117862306a36Sopenharmony_ci	if (!extent_tree_slab)
117962306a36Sopenharmony_ci		return -ENOMEM;
118062306a36Sopenharmony_ci	extent_node_slab = f2fs_kmem_cache_create("f2fs_extent_node",
118162306a36Sopenharmony_ci			sizeof(struct extent_node));
118262306a36Sopenharmony_ci	if (!extent_node_slab) {
118362306a36Sopenharmony_ci		kmem_cache_destroy(extent_tree_slab);
118462306a36Sopenharmony_ci		return -ENOMEM;
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci	return 0;
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_civoid f2fs_destroy_extent_cache(void)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	kmem_cache_destroy(extent_node_slab);
119262306a36Sopenharmony_ci	kmem_cache_destroy(extent_tree_slab);
119362306a36Sopenharmony_ci}
1194