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