18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fs/f2fs/segment.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd. 68c2ecf20Sopenharmony_ci * http://www.samsung.com/ 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/fs.h> 98c2ecf20Sopenharmony_ci#include <linux/f2fs_fs.h> 108c2ecf20Sopenharmony_ci#include <linux/bio.h> 118c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 128c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 138c2ecf20Sopenharmony_ci#include <linux/kthread.h> 148c2ecf20Sopenharmony_ci#include <linux/swap.h> 158c2ecf20Sopenharmony_ci#include <linux/timer.h> 168c2ecf20Sopenharmony_ci#include <linux/freezer.h> 178c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "f2fs.h" 208c2ecf20Sopenharmony_ci#include "segment.h" 218c2ecf20Sopenharmony_ci#include "node.h" 228c2ecf20Sopenharmony_ci#include "gc.h" 238c2ecf20Sopenharmony_ci#include "trace.h" 248c2ecf20Sopenharmony_ci#include <trace/events/f2fs.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define __reverse_ffz(x) __reverse_ffs(~(x)) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct kmem_cache *discard_entry_slab; 298c2ecf20Sopenharmony_cistatic struct kmem_cache *discard_cmd_slab; 308c2ecf20Sopenharmony_cistatic struct kmem_cache *sit_entry_set_slab; 318c2ecf20Sopenharmony_cistatic struct kmem_cache *inmem_entry_slab; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct discard_policy dpolicys[MAX_DPOLICY] = { 348c2ecf20Sopenharmony_ci {DPOLICY_BG, 0, DEF_MID_DISCARD_ISSUE_TIME, DEF_MAX_DISCARD_ISSUE_TIME, 358c2ecf20Sopenharmony_ci MAX_PLIST_NUM, false, true, false, false, DISCARD_GRAN_BG, 368c2ecf20Sopenharmony_ci {{1, 0}, {0, 0}, {0, 0}}}, 378c2ecf20Sopenharmony_ci {DPOLICY_BALANCE, 0, DEF_MID_DISCARD_ISSUE_TIME, DEF_MAX_DISCARD_ISSUE_TIME, 388c2ecf20Sopenharmony_ci MAX_PLIST_NUM - 1, true, true, false, false, DISCARD_GRAN_BL, 398c2ecf20Sopenharmony_ci {{1, 0}, {2, 50}, {0, 0}}}, 408c2ecf20Sopenharmony_ci {DPOLICY_FORCE, 0, DEF_MID_DISCARD_ISSUE_TIME, DEF_MAX_DISCARD_ISSUE_TIME, 418c2ecf20Sopenharmony_ci MAX_PLIST_NUM - 1, true, true, false, false, DISCARD_GRAN_FORCE, 428c2ecf20Sopenharmony_ci {{1, 0}, {2, 50}, {4, 2000}}}, 438c2ecf20Sopenharmony_ci {DPOLICY_FSTRIM, 0, DEF_MID_DISCARD_ISSUE_TIME, DEF_MAX_DISCARD_ISSUE_TIME, 448c2ecf20Sopenharmony_ci MAX_PLIST_NUM, false, true, false, false, DISCARD_GRAN_FORCE, 458c2ecf20Sopenharmony_ci {{8, 0}, {8, 0}, {8, 0}}}, 468c2ecf20Sopenharmony_ci {DPOLICY_UMOUNT, 0, DEF_MID_DISCARD_ISSUE_TIME, DEF_MAX_DISCARD_ISSUE_TIME, 478c2ecf20Sopenharmony_ci MAX_PLIST_NUM, false, true, false, false, DISCARD_GRAN_BG, 488c2ecf20Sopenharmony_ci {{UINT_MAX, 0}, {0, 0}, {0, 0}}} 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic unsigned long __reverse_ulong(unsigned char *str) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci unsigned long tmp = 0; 548c2ecf20Sopenharmony_ci int shift = 24, idx = 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 64 578c2ecf20Sopenharmony_ci shift = 56; 588c2ecf20Sopenharmony_ci#endif 598c2ecf20Sopenharmony_ci while (shift >= 0) { 608c2ecf20Sopenharmony_ci tmp |= (unsigned long)str[idx++] << shift; 618c2ecf20Sopenharmony_ci shift -= BITS_PER_BYTE; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci return tmp; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* 678c2ecf20Sopenharmony_ci * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since 688c2ecf20Sopenharmony_ci * MSB and LSB are reversed in a byte by f2fs_set_bit. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistatic inline unsigned long __reverse_ffs(unsigned long word) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int num = 0; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 64 758c2ecf20Sopenharmony_ci if ((word & 0xffffffff00000000UL) == 0) 768c2ecf20Sopenharmony_ci num += 32; 778c2ecf20Sopenharmony_ci else 788c2ecf20Sopenharmony_ci word >>= 32; 798c2ecf20Sopenharmony_ci#endif 808c2ecf20Sopenharmony_ci if ((word & 0xffff0000) == 0) 818c2ecf20Sopenharmony_ci num += 16; 828c2ecf20Sopenharmony_ci else 838c2ecf20Sopenharmony_ci word >>= 16; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if ((word & 0xff00) == 0) 868c2ecf20Sopenharmony_ci num += 8; 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci word >>= 8; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if ((word & 0xf0) == 0) 918c2ecf20Sopenharmony_ci num += 4; 928c2ecf20Sopenharmony_ci else 938c2ecf20Sopenharmony_ci word >>= 4; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if ((word & 0xc) == 0) 968c2ecf20Sopenharmony_ci num += 2; 978c2ecf20Sopenharmony_ci else 988c2ecf20Sopenharmony_ci word >>= 2; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if ((word & 0x2) == 0) 1018c2ecf20Sopenharmony_ci num += 1; 1028c2ecf20Sopenharmony_ci return num; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because 1078c2ecf20Sopenharmony_ci * f2fs_set_bit makes MSB and LSB reversed in a byte. 1088c2ecf20Sopenharmony_ci * @size must be integral times of unsigned long. 1098c2ecf20Sopenharmony_ci * Example: 1108c2ecf20Sopenharmony_ci * MSB <--> LSB 1118c2ecf20Sopenharmony_ci * f2fs_set_bit(0, bitmap) => 1000 0000 1128c2ecf20Sopenharmony_ci * f2fs_set_bit(7, bitmap) => 0000 0001 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ciunsigned long find_rev_next_bit(const unsigned long *addr, 1158c2ecf20Sopenharmony_ci unsigned long size, unsigned long offset) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci const unsigned long *p = addr + BIT_WORD(offset); 1188c2ecf20Sopenharmony_ci unsigned long result = size; 1198c2ecf20Sopenharmony_ci unsigned long tmp; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (offset >= size) 1228c2ecf20Sopenharmony_ci return size; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci size -= (offset & ~(BITS_PER_LONG - 1)); 1258c2ecf20Sopenharmony_ci offset %= BITS_PER_LONG; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci while (1) { 1288c2ecf20Sopenharmony_ci if (*p == 0) 1298c2ecf20Sopenharmony_ci goto pass; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci tmp = __reverse_ulong((unsigned char *)p); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci tmp &= ~0UL >> offset; 1348c2ecf20Sopenharmony_ci if (size < BITS_PER_LONG) 1358c2ecf20Sopenharmony_ci tmp &= (~0UL << (BITS_PER_LONG - size)); 1368c2ecf20Sopenharmony_ci if (tmp) 1378c2ecf20Sopenharmony_ci goto found; 1388c2ecf20Sopenharmony_cipass: 1398c2ecf20Sopenharmony_ci if (size <= BITS_PER_LONG) 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci size -= BITS_PER_LONG; 1428c2ecf20Sopenharmony_ci offset = 0; 1438c2ecf20Sopenharmony_ci p++; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci return result; 1468c2ecf20Sopenharmony_cifound: 1478c2ecf20Sopenharmony_ci return result - size + __reverse_ffs(tmp); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ciunsigned long find_rev_next_zero_bit(const unsigned long *addr, 1518c2ecf20Sopenharmony_ci unsigned long size, unsigned long offset) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci const unsigned long *p = addr + BIT_WORD(offset); 1548c2ecf20Sopenharmony_ci unsigned long result = size; 1558c2ecf20Sopenharmony_ci unsigned long tmp; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (offset >= size) 1588c2ecf20Sopenharmony_ci return size; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci size -= (offset & ~(BITS_PER_LONG - 1)); 1618c2ecf20Sopenharmony_ci offset %= BITS_PER_LONG; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci while (1) { 1648c2ecf20Sopenharmony_ci if (*p == ~0UL) 1658c2ecf20Sopenharmony_ci goto pass; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci tmp = __reverse_ulong((unsigned char *)p); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (offset) 1708c2ecf20Sopenharmony_ci tmp |= ~0UL << (BITS_PER_LONG - offset); 1718c2ecf20Sopenharmony_ci if (size < BITS_PER_LONG) 1728c2ecf20Sopenharmony_ci tmp |= ~0UL >> size; 1738c2ecf20Sopenharmony_ci if (tmp != ~0UL) 1748c2ecf20Sopenharmony_ci goto found; 1758c2ecf20Sopenharmony_cipass: 1768c2ecf20Sopenharmony_ci if (size <= BITS_PER_LONG) 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci size -= BITS_PER_LONG; 1798c2ecf20Sopenharmony_ci offset = 0; 1808c2ecf20Sopenharmony_ci p++; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci return result; 1838c2ecf20Sopenharmony_cifound: 1848c2ecf20Sopenharmony_ci return result - size + __reverse_ffz(tmp); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cibool f2fs_need_SSR(struct f2fs_sb_info *sbi) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); 1908c2ecf20Sopenharmony_ci int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); 1918c2ecf20Sopenharmony_ci int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (f2fs_lfs_mode(sbi)) 1948c2ecf20Sopenharmony_ci return false; 1958c2ecf20Sopenharmony_ci if (sbi->gc_mode == GC_URGENT_HIGH) 1968c2ecf20Sopenharmony_ci return true; 1978c2ecf20Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) 1988c2ecf20Sopenharmony_ci return true; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs + 2018c2ecf20Sopenharmony_ci SM_I(sbi)->min_ssr_sections + reserved_sections(sbi)); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_GRADING_SSR 2058c2ecf20Sopenharmony_cistatic bool need_ssr_by_type(struct f2fs_sb_info *sbi, int type, int contig_level) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); 2088c2ecf20Sopenharmony_ci int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); 2098c2ecf20Sopenharmony_ci int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA); 2108c2ecf20Sopenharmony_ci u64 valid_blocks = sbi->total_valid_block_count; 2118c2ecf20Sopenharmony_ci u64 total_blocks = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg; 2128c2ecf20Sopenharmony_ci u64 left_space = (total_blocks - valid_blocks) << 2; 2138c2ecf20Sopenharmony_ci unsigned int free_segs = free_segments(sbi); 2148c2ecf20Sopenharmony_ci unsigned int ovp_segments = overprovision_segments(sbi); 2158c2ecf20Sopenharmony_ci unsigned int lower_limit = 0; 2168c2ecf20Sopenharmony_ci unsigned int waterline = 0; 2178c2ecf20Sopenharmony_ci int dirty_sum = node_secs + 2 * dent_secs + imeta_secs; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (sbi->hot_cold_params.enable == GRADING_SSR_OFF) 2208c2ecf20Sopenharmony_ci return f2fs_need_SSR(sbi); 2218c2ecf20Sopenharmony_ci if (f2fs_lfs_mode(sbi)) 2228c2ecf20Sopenharmony_ci return false; 2238c2ecf20Sopenharmony_ci if (sbi->gc_mode == GC_URGENT_HIGH) 2248c2ecf20Sopenharmony_ci return true; 2258c2ecf20Sopenharmony_ci if (contig_level == SEQ_256BLKS && type == CURSEG_WARM_DATA && 2268c2ecf20Sopenharmony_ci free_sections(sbi) > dirty_sum + 3 * reserved_sections(sbi) / 2) 2278c2ecf20Sopenharmony_ci return false; 2288c2ecf20Sopenharmony_ci if (free_sections(sbi) <= (unsigned int)(dirty_sum + 2 * reserved_sections(sbi))) 2298c2ecf20Sopenharmony_ci return true; 2308c2ecf20Sopenharmony_ci if (contig_level >= SEQ_32BLKS || total_blocks <= SSR_MIN_BLKS_LIMIT) 2318c2ecf20Sopenharmony_ci return false; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci left_space -= ovp_segments * KBS_PER_SEGMENT; 2348c2ecf20Sopenharmony_ci if (unlikely(left_space == 0)) 2358c2ecf20Sopenharmony_ci return false; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci switch (type) { 2388c2ecf20Sopenharmony_ci case CURSEG_HOT_DATA: 2398c2ecf20Sopenharmony_ci lower_limit = sbi->hot_cold_params.hot_data_lower_limit; 2408c2ecf20Sopenharmony_ci waterline = sbi->hot_cold_params.hot_data_waterline; 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci case CURSEG_WARM_DATA: 2438c2ecf20Sopenharmony_ci lower_limit = sbi->hot_cold_params.warm_data_lower_limit; 2448c2ecf20Sopenharmony_ci waterline = sbi->hot_cold_params.warm_data_waterline; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci case CURSEG_HOT_NODE: 2478c2ecf20Sopenharmony_ci lower_limit = sbi->hot_cold_params.hot_node_lower_limit; 2488c2ecf20Sopenharmony_ci waterline = sbi->hot_cold_params.hot_node_waterline; 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci case CURSEG_WARM_NODE: 2518c2ecf20Sopenharmony_ci lower_limit = sbi->hot_cold_params.warm_node_lower_limit; 2528c2ecf20Sopenharmony_ci waterline = sbi->hot_cold_params.warm_node_waterline; 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci default: 2558c2ecf20Sopenharmony_ci return false; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (left_space > lower_limit) 2598c2ecf20Sopenharmony_ci return false; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (div_u64((free_segs - ovp_segments) * 100, (left_space / KBS_PER_SEGMENT)) 2628c2ecf20Sopenharmony_ci <= waterline) { 2638c2ecf20Sopenharmony_ci trace_f2fs_grading_ssr_allocate( 2648c2ecf20Sopenharmony_ci (le64_to_cpu(sbi->raw_super->block_count) - sbi->total_valid_block_count), 2658c2ecf20Sopenharmony_ci free_segments(sbi), contig_level); 2668c2ecf20Sopenharmony_ci return true; 2678c2ecf20Sopenharmony_ci } else { 2688c2ecf20Sopenharmony_ci return false; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci#endif 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_civoid f2fs_register_inmem_page(struct inode *inode, struct page *page) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct inmem_pages *new; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci f2fs_trace_pid(page); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci f2fs_set_page_private(page, ATOMIC_WRITTEN_PAGE); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* add atomic page indices to the list */ 2848c2ecf20Sopenharmony_ci new->page = page; 2858c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&new->list); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* increase reference count with clean state */ 2888c2ecf20Sopenharmony_ci get_page(page); 2898c2ecf20Sopenharmony_ci mutex_lock(&F2FS_I(inode)->inmem_lock); 2908c2ecf20Sopenharmony_ci list_add_tail(&new->list, &F2FS_I(inode)->inmem_pages); 2918c2ecf20Sopenharmony_ci inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); 2928c2ecf20Sopenharmony_ci mutex_unlock(&F2FS_I(inode)->inmem_lock); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci trace_f2fs_register_inmem_page(page, INMEM); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int __revoke_inmem_pages(struct inode *inode, 2988c2ecf20Sopenharmony_ci struct list_head *head, bool drop, bool recover, 2998c2ecf20Sopenharmony_ci bool trylock) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 3028c2ecf20Sopenharmony_ci struct inmem_pages *cur, *tmp; 3038c2ecf20Sopenharmony_ci int err = 0; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci list_for_each_entry_safe(cur, tmp, head, list) { 3068c2ecf20Sopenharmony_ci struct page *page = cur->page; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (drop) 3098c2ecf20Sopenharmony_ci trace_f2fs_commit_inmem_page(page, INMEM_DROP); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (trylock) { 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * to avoid deadlock in between page lock and 3148c2ecf20Sopenharmony_ci * inmem_lock. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci if (!trylock_page(page)) 3178c2ecf20Sopenharmony_ci continue; 3188c2ecf20Sopenharmony_ci } else { 3198c2ecf20Sopenharmony_ci lock_page(page); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci f2fs_wait_on_page_writeback(page, DATA, true, true); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (recover) { 3258c2ecf20Sopenharmony_ci struct dnode_of_data dn; 3268c2ecf20Sopenharmony_ci struct node_info ni; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci trace_f2fs_commit_inmem_page(page, INMEM_REVOKE); 3298c2ecf20Sopenharmony_ciretry: 3308c2ecf20Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 3318c2ecf20Sopenharmony_ci err = f2fs_get_dnode_of_data(&dn, page->index, 3328c2ecf20Sopenharmony_ci LOOKUP_NODE); 3338c2ecf20Sopenharmony_ci if (err) { 3348c2ecf20Sopenharmony_ci if (err == -ENOMEM) { 3358c2ecf20Sopenharmony_ci congestion_wait(BLK_RW_ASYNC, 3368c2ecf20Sopenharmony_ci DEFAULT_IO_TIMEOUT); 3378c2ecf20Sopenharmony_ci cond_resched(); 3388c2ecf20Sopenharmony_ci goto retry; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci err = -EAGAIN; 3418c2ecf20Sopenharmony_ci goto next; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci err = f2fs_get_node_info(sbi, dn.nid, &ni); 3458c2ecf20Sopenharmony_ci if (err) { 3468c2ecf20Sopenharmony_ci f2fs_put_dnode(&dn); 3478c2ecf20Sopenharmony_ci return err; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (cur->old_addr == NEW_ADDR) { 3518c2ecf20Sopenharmony_ci f2fs_invalidate_blocks(sbi, dn.data_blkaddr); 3528c2ecf20Sopenharmony_ci f2fs_update_data_blkaddr(&dn, NEW_ADDR); 3538c2ecf20Sopenharmony_ci } else 3548c2ecf20Sopenharmony_ci f2fs_replace_block(sbi, &dn, dn.data_blkaddr, 3558c2ecf20Sopenharmony_ci cur->old_addr, ni.version, true, true); 3568c2ecf20Sopenharmony_ci f2fs_put_dnode(&dn); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_cinext: 3598c2ecf20Sopenharmony_ci /* we don't need to invalidate this in the sccessful status */ 3608c2ecf20Sopenharmony_ci if (drop || recover) { 3618c2ecf20Sopenharmony_ci ClearPageUptodate(page); 3628c2ecf20Sopenharmony_ci clear_cold_data(page); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci f2fs_clear_page_private(page); 3658c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci list_del(&cur->list); 3688c2ecf20Sopenharmony_ci kmem_cache_free(inmem_entry_slab, cur); 3698c2ecf20Sopenharmony_ci dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci return err; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_civoid f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct list_head *head = &sbi->inode_list[ATOMIC_FILE]; 3778c2ecf20Sopenharmony_ci struct inode *inode; 3788c2ecf20Sopenharmony_ci struct f2fs_inode_info *fi; 3798c2ecf20Sopenharmony_ci unsigned int count = sbi->atomic_files; 3808c2ecf20Sopenharmony_ci unsigned int looped = 0; 3818c2ecf20Sopenharmony_cinext: 3828c2ecf20Sopenharmony_ci spin_lock(&sbi->inode_lock[ATOMIC_FILE]); 3838c2ecf20Sopenharmony_ci if (list_empty(head)) { 3848c2ecf20Sopenharmony_ci spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); 3858c2ecf20Sopenharmony_ci return; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci fi = list_first_entry(head, struct f2fs_inode_info, inmem_ilist); 3888c2ecf20Sopenharmony_ci inode = igrab(&fi->vfs_inode); 3898c2ecf20Sopenharmony_ci if (inode) 3908c2ecf20Sopenharmony_ci list_move_tail(&fi->inmem_ilist, head); 3918c2ecf20Sopenharmony_ci spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (inode) { 3948c2ecf20Sopenharmony_ci if (gc_failure) { 3958c2ecf20Sopenharmony_ci if (!fi->i_gc_failures[GC_FAILURE_ATOMIC]) 3968c2ecf20Sopenharmony_ci goto skip; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci set_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); 3998c2ecf20Sopenharmony_ci f2fs_drop_inmem_pages(inode); 4008c2ecf20Sopenharmony_ciskip: 4018c2ecf20Sopenharmony_ci iput(inode); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); 4048c2ecf20Sopenharmony_ci cond_resched(); 4058c2ecf20Sopenharmony_ci if (gc_failure) { 4068c2ecf20Sopenharmony_ci if (++looped >= count) 4078c2ecf20Sopenharmony_ci return; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci goto next; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_civoid f2fs_drop_inmem_pages(struct inode *inode) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 4158c2ecf20Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci do { 4188c2ecf20Sopenharmony_ci mutex_lock(&fi->inmem_lock); 4198c2ecf20Sopenharmony_ci if (list_empty(&fi->inmem_pages)) { 4208c2ecf20Sopenharmony_ci fi->i_gc_failures[GC_FAILURE_ATOMIC] = 0; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci spin_lock(&sbi->inode_lock[ATOMIC_FILE]); 4238c2ecf20Sopenharmony_ci if (!list_empty(&fi->inmem_ilist)) 4248c2ecf20Sopenharmony_ci list_del_init(&fi->inmem_ilist); 4258c2ecf20Sopenharmony_ci if (f2fs_is_atomic_file(inode)) { 4268c2ecf20Sopenharmony_ci clear_inode_flag(inode, FI_ATOMIC_FILE); 4278c2ecf20Sopenharmony_ci sbi->atomic_files--; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci mutex_unlock(&fi->inmem_lock); 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci __revoke_inmem_pages(inode, &fi->inmem_pages, 4358c2ecf20Sopenharmony_ci true, false, true); 4368c2ecf20Sopenharmony_ci mutex_unlock(&fi->inmem_lock); 4378c2ecf20Sopenharmony_ci } while (1); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_civoid f2fs_drop_inmem_page(struct inode *inode, struct page *page) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 4438c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 4448c2ecf20Sopenharmony_ci struct list_head *head = &fi->inmem_pages; 4458c2ecf20Sopenharmony_ci struct inmem_pages *cur = NULL; 4468c2ecf20Sopenharmony_ci struct inmem_pages *tmp; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !IS_ATOMIC_WRITTEN_PAGE(page)); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci mutex_lock(&fi->inmem_lock); 4518c2ecf20Sopenharmony_ci list_for_each_entry(tmp, head, list) { 4528c2ecf20Sopenharmony_ci if (tmp->page == page) { 4538c2ecf20Sopenharmony_ci cur = tmp; 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !cur); 4598c2ecf20Sopenharmony_ci list_del(&cur->list); 4608c2ecf20Sopenharmony_ci mutex_unlock(&fi->inmem_lock); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci dec_page_count(sbi, F2FS_INMEM_PAGES); 4638c2ecf20Sopenharmony_ci kmem_cache_free(inmem_entry_slab, cur); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci ClearPageUptodate(page); 4668c2ecf20Sopenharmony_ci f2fs_clear_page_private(page); 4678c2ecf20Sopenharmony_ci f2fs_put_page(page, 0); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int __f2fs_commit_inmem_pages(struct inode *inode) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 4758c2ecf20Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 4768c2ecf20Sopenharmony_ci struct inmem_pages *cur, *tmp; 4778c2ecf20Sopenharmony_ci struct f2fs_io_info fio = { 4788c2ecf20Sopenharmony_ci .sbi = sbi, 4798c2ecf20Sopenharmony_ci .ino = inode->i_ino, 4808c2ecf20Sopenharmony_ci .type = DATA, 4818c2ecf20Sopenharmony_ci .op = REQ_OP_WRITE, 4828c2ecf20Sopenharmony_ci .op_flags = REQ_SYNC | REQ_PRIO, 4838c2ecf20Sopenharmony_ci .io_type = FS_DATA_IO, 4848c2ecf20Sopenharmony_ci }; 4858c2ecf20Sopenharmony_ci struct list_head revoke_list; 4868c2ecf20Sopenharmony_ci bool submit_bio = false; 4878c2ecf20Sopenharmony_ci int err = 0; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&revoke_list); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) { 4928c2ecf20Sopenharmony_ci struct page *page = cur->page; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci lock_page(page); 4958c2ecf20Sopenharmony_ci if (page->mapping == inode->i_mapping) { 4968c2ecf20Sopenharmony_ci trace_f2fs_commit_inmem_page(page, INMEM); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci f2fs_wait_on_page_writeback(page, DATA, true, true); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci set_page_dirty(page); 5018c2ecf20Sopenharmony_ci if (clear_page_dirty_for_io(page)) { 5028c2ecf20Sopenharmony_ci inode_dec_dirty_pages(inode); 5038c2ecf20Sopenharmony_ci f2fs_remove_dirty_inode(inode); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ciretry: 5068c2ecf20Sopenharmony_ci fio.page = page; 5078c2ecf20Sopenharmony_ci fio.old_blkaddr = NULL_ADDR; 5088c2ecf20Sopenharmony_ci fio.encrypted_page = NULL; 5098c2ecf20Sopenharmony_ci fio.need_lock = LOCK_DONE; 5108c2ecf20Sopenharmony_ci err = f2fs_do_write_data_page(&fio); 5118c2ecf20Sopenharmony_ci if (err) { 5128c2ecf20Sopenharmony_ci if (err == -ENOMEM) { 5138c2ecf20Sopenharmony_ci congestion_wait(BLK_RW_ASYNC, 5148c2ecf20Sopenharmony_ci DEFAULT_IO_TIMEOUT); 5158c2ecf20Sopenharmony_ci cond_resched(); 5168c2ecf20Sopenharmony_ci goto retry; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci unlock_page(page); 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci /* record old blkaddr for revoking */ 5228c2ecf20Sopenharmony_ci cur->old_addr = fio.old_blkaddr; 5238c2ecf20Sopenharmony_ci submit_bio = true; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci unlock_page(page); 5268c2ecf20Sopenharmony_ci list_move_tail(&cur->list, &revoke_list); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (submit_bio) 5308c2ecf20Sopenharmony_ci f2fs_submit_merged_write_cond(sbi, inode, NULL, 0, DATA); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (err) { 5338c2ecf20Sopenharmony_ci /* 5348c2ecf20Sopenharmony_ci * try to revoke all committed pages, but still we could fail 5358c2ecf20Sopenharmony_ci * due to no memory or other reason, if that happened, EAGAIN 5368c2ecf20Sopenharmony_ci * will be returned, which means in such case, transaction is 5378c2ecf20Sopenharmony_ci * already not integrity, caller should use journal to do the 5388c2ecf20Sopenharmony_ci * recovery or rewrite & commit last transaction. For other 5398c2ecf20Sopenharmony_ci * error number, revoking was done by filesystem itself. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_ci err = __revoke_inmem_pages(inode, &revoke_list, 5428c2ecf20Sopenharmony_ci false, true, false); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* drop all uncommitted pages */ 5458c2ecf20Sopenharmony_ci __revoke_inmem_pages(inode, &fi->inmem_pages, 5468c2ecf20Sopenharmony_ci true, false, false); 5478c2ecf20Sopenharmony_ci } else { 5488c2ecf20Sopenharmony_ci __revoke_inmem_pages(inode, &revoke_list, 5498c2ecf20Sopenharmony_ci false, false, false); 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return err; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ciint f2fs_commit_inmem_pages(struct inode *inode) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 5588c2ecf20Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 5598c2ecf20Sopenharmony_ci int err; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci f2fs_balance_fs(sbi, true); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci down_write(&fi->i_gc_rwsem[WRITE]); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci f2fs_lock_op(sbi); 5668c2ecf20Sopenharmony_ci set_inode_flag(inode, FI_ATOMIC_COMMIT); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci mutex_lock(&fi->inmem_lock); 5698c2ecf20Sopenharmony_ci err = __f2fs_commit_inmem_pages(inode); 5708c2ecf20Sopenharmony_ci mutex_unlock(&fi->inmem_lock); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci clear_inode_flag(inode, FI_ATOMIC_COMMIT); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci f2fs_unlock_op(sbi); 5758c2ecf20Sopenharmony_ci up_write(&fi->i_gc_rwsem[WRITE]); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return err; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/* 5818c2ecf20Sopenharmony_ci * This function balances dirty node and dentry pages. 5828c2ecf20Sopenharmony_ci * In addition, it controls garbage collection. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_civoid f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci if (time_to_inject(sbi, FAULT_CHECKPOINT)) { 5878c2ecf20Sopenharmony_ci f2fs_show_injection_info(sbi, FAULT_CHECKPOINT); 5888c2ecf20Sopenharmony_ci f2fs_stop_checkpoint(sbi, false); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* balance_fs_bg is able to be pending */ 5928c2ecf20Sopenharmony_ci if (need && excess_cached_nats(sbi)) 5938c2ecf20Sopenharmony_ci f2fs_balance_fs_bg(sbi, false); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (!f2fs_is_checkpoint_ready(sbi)) 5968c2ecf20Sopenharmony_ci return; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* 5998c2ecf20Sopenharmony_ci * We should do GC or end up with checkpoint, if there are so many dirty 6008c2ecf20Sopenharmony_ci * dir/node pages without enough free segments. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_ci if (has_not_enough_free_secs(sbi, 0, 0)) { 6038c2ecf20Sopenharmony_ci if (test_opt(sbi, GC_MERGE) && sbi->gc_thread && 6048c2ecf20Sopenharmony_ci sbi->gc_thread->f2fs_gc_task) { 6058c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci prepare_to_wait(&sbi->gc_thread->fggc_wq, &wait, 6088c2ecf20Sopenharmony_ci TASK_UNINTERRUPTIBLE); 6098c2ecf20Sopenharmony_ci wake_up(&sbi->gc_thread->gc_wait_queue_head); 6108c2ecf20Sopenharmony_ci io_schedule(); 6118c2ecf20Sopenharmony_ci finish_wait(&sbi->gc_thread->fggc_wq, &wait); 6128c2ecf20Sopenharmony_ci } else { 6138c2ecf20Sopenharmony_ci down_write(&sbi->gc_lock); 6148c2ecf20Sopenharmony_ci f2fs_gc(sbi, false, false, false, NULL_SEGNO); 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_civoid f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) 6228c2ecf20Sopenharmony_ci return; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* try to shrink extent cache when there is no enough memory */ 6258c2ecf20Sopenharmony_ci if (!f2fs_available_free_memory(sbi, EXTENT_CACHE)) 6268c2ecf20Sopenharmony_ci f2fs_shrink_extent_tree(sbi, EXTENT_CACHE_SHRINK_NUMBER); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* check the # of cached NAT entries */ 6298c2ecf20Sopenharmony_ci if (!f2fs_available_free_memory(sbi, NAT_ENTRIES)) 6308c2ecf20Sopenharmony_ci f2fs_try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (!f2fs_available_free_memory(sbi, FREE_NIDS)) 6338c2ecf20Sopenharmony_ci f2fs_try_to_free_nids(sbi, MAX_FREE_NIDS); 6348c2ecf20Sopenharmony_ci else 6358c2ecf20Sopenharmony_ci f2fs_build_free_nids(sbi, false, false); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (excess_dirty_nats(sbi) || excess_dirty_nodes(sbi) || 6388c2ecf20Sopenharmony_ci excess_prefree_segs(sbi)) 6398c2ecf20Sopenharmony_ci goto do_sync; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* there is background inflight IO or foreground operation recently */ 6428c2ecf20Sopenharmony_ci if (is_inflight_io(sbi, REQ_TIME) || 6438c2ecf20Sopenharmony_ci (!f2fs_time_over(sbi, REQ_TIME) && rwsem_is_locked(&sbi->cp_rwsem))) 6448c2ecf20Sopenharmony_ci return; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* exceed periodical checkpoint timeout threshold */ 6478c2ecf20Sopenharmony_ci if (f2fs_time_over(sbi, CP_TIME)) 6488c2ecf20Sopenharmony_ci goto do_sync; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* checkpoint is the only way to shrink partial cached entries */ 6518c2ecf20Sopenharmony_ci if (f2fs_available_free_memory(sbi, NAT_ENTRIES) && 6528c2ecf20Sopenharmony_ci f2fs_available_free_memory(sbi, INO_ENTRIES)) 6538c2ecf20Sopenharmony_ci return; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cido_sync: 6568c2ecf20Sopenharmony_ci if (test_opt(sbi, DATA_FLUSH) && from_bg) { 6578c2ecf20Sopenharmony_ci struct blk_plug plug; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci mutex_lock(&sbi->flush_lock); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci blk_start_plug(&plug); 6628c2ecf20Sopenharmony_ci f2fs_sync_dirty_inodes(sbi, FILE_INODE, false); 6638c2ecf20Sopenharmony_ci blk_finish_plug(&plug); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci mutex_unlock(&sbi->flush_lock); 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci f2fs_sync_fs(sbi->sb, true); 6688c2ecf20Sopenharmony_ci stat_inc_bg_cp_count(sbi->stat_info); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int __submit_flush_wait(struct f2fs_sb_info *sbi, 6728c2ecf20Sopenharmony_ci struct block_device *bdev) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct bio *bio; 6758c2ecf20Sopenharmony_ci int ret; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci bio = f2fs_bio_alloc(sbi, 0, false); 6788c2ecf20Sopenharmony_ci if (!bio) 6798c2ecf20Sopenharmony_ci return -ENOMEM; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH; 6828c2ecf20Sopenharmony_ci bio_set_dev(bio, bdev); 6838c2ecf20Sopenharmony_ci ret = submit_bio_wait(bio); 6848c2ecf20Sopenharmony_ci bio_put(bio); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci trace_f2fs_issue_flush(bdev, test_opt(sbi, NOBARRIER), 6878c2ecf20Sopenharmony_ci test_opt(sbi, FLUSH_MERGE), ret); 6888c2ecf20Sopenharmony_ci return ret; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int submit_flush_wait(struct f2fs_sb_info *sbi, nid_t ino) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci int ret = 0; 6948c2ecf20Sopenharmony_ci int i; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (!f2fs_is_multi_device(sbi)) 6978c2ecf20Sopenharmony_ci return __submit_flush_wait(sbi, sbi->sb->s_bdev); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_ndevs; i++) { 7008c2ecf20Sopenharmony_ci if (!f2fs_is_dirty_device(sbi, ino, i, FLUSH_INO)) 7018c2ecf20Sopenharmony_ci continue; 7028c2ecf20Sopenharmony_ci ret = __submit_flush_wait(sbi, FDEV(i).bdev); 7038c2ecf20Sopenharmony_ci if (ret) 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci return ret; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic int issue_flush_thread(void *data) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = data; 7128c2ecf20Sopenharmony_ci struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info; 7138c2ecf20Sopenharmony_ci wait_queue_head_t *q = &fcc->flush_wait_queue; 7148c2ecf20Sopenharmony_cirepeat: 7158c2ecf20Sopenharmony_ci if (kthread_should_stop()) 7168c2ecf20Sopenharmony_ci return 0; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci sb_start_intwrite(sbi->sb); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (!llist_empty(&fcc->issue_list)) { 7218c2ecf20Sopenharmony_ci struct flush_cmd *cmd, *next; 7228c2ecf20Sopenharmony_ci int ret; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci fcc->dispatch_list = llist_del_all(&fcc->issue_list); 7258c2ecf20Sopenharmony_ci fcc->dispatch_list = llist_reverse_order(fcc->dispatch_list); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci cmd = llist_entry(fcc->dispatch_list, struct flush_cmd, llnode); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci ret = submit_flush_wait(sbi, cmd->ino); 7308c2ecf20Sopenharmony_ci atomic_inc(&fcc->issued_flush); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci llist_for_each_entry_safe(cmd, next, 7338c2ecf20Sopenharmony_ci fcc->dispatch_list, llnode) { 7348c2ecf20Sopenharmony_ci cmd->ret = ret; 7358c2ecf20Sopenharmony_ci complete(&cmd->wait); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci fcc->dispatch_list = NULL; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci sb_end_intwrite(sbi->sb); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci wait_event_interruptible(*q, 7438c2ecf20Sopenharmony_ci kthread_should_stop() || !llist_empty(&fcc->issue_list)); 7448c2ecf20Sopenharmony_ci goto repeat; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ciint f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info; 7508c2ecf20Sopenharmony_ci struct flush_cmd cmd; 7518c2ecf20Sopenharmony_ci int ret; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (test_opt(sbi, NOBARRIER)) 7548c2ecf20Sopenharmony_ci return 0; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (!test_opt(sbi, FLUSH_MERGE)) { 7578c2ecf20Sopenharmony_ci atomic_inc(&fcc->queued_flush); 7588c2ecf20Sopenharmony_ci ret = submit_flush_wait(sbi, ino); 7598c2ecf20Sopenharmony_ci atomic_dec(&fcc->queued_flush); 7608c2ecf20Sopenharmony_ci atomic_inc(&fcc->issued_flush); 7618c2ecf20Sopenharmony_ci return ret; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (atomic_inc_return(&fcc->queued_flush) == 1 || 7658c2ecf20Sopenharmony_ci f2fs_is_multi_device(sbi)) { 7668c2ecf20Sopenharmony_ci ret = submit_flush_wait(sbi, ino); 7678c2ecf20Sopenharmony_ci atomic_dec(&fcc->queued_flush); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci atomic_inc(&fcc->issued_flush); 7708c2ecf20Sopenharmony_ci return ret; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci cmd.ino = ino; 7748c2ecf20Sopenharmony_ci init_completion(&cmd.wait); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci llist_add(&cmd.llnode, &fcc->issue_list); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* update issue_list before we wake up issue_flush thread */ 7798c2ecf20Sopenharmony_ci smp_mb(); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (waitqueue_active(&fcc->flush_wait_queue)) 7828c2ecf20Sopenharmony_ci wake_up(&fcc->flush_wait_queue); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (fcc->f2fs_issue_flush) { 7858c2ecf20Sopenharmony_ci wait_for_completion(&cmd.wait); 7868c2ecf20Sopenharmony_ci atomic_dec(&fcc->queued_flush); 7878c2ecf20Sopenharmony_ci } else { 7888c2ecf20Sopenharmony_ci struct llist_node *list; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci list = llist_del_all(&fcc->issue_list); 7918c2ecf20Sopenharmony_ci if (!list) { 7928c2ecf20Sopenharmony_ci wait_for_completion(&cmd.wait); 7938c2ecf20Sopenharmony_ci atomic_dec(&fcc->queued_flush); 7948c2ecf20Sopenharmony_ci } else { 7958c2ecf20Sopenharmony_ci struct flush_cmd *tmp, *next; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci ret = submit_flush_wait(sbi, ino); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci llist_for_each_entry_safe(tmp, next, list, llnode) { 8008c2ecf20Sopenharmony_ci if (tmp == &cmd) { 8018c2ecf20Sopenharmony_ci cmd.ret = ret; 8028c2ecf20Sopenharmony_ci atomic_dec(&fcc->queued_flush); 8038c2ecf20Sopenharmony_ci continue; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci tmp->ret = ret; 8068c2ecf20Sopenharmony_ci complete(&tmp->wait); 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci return cmd.ret; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ciint f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci dev_t dev = sbi->sb->s_bdev->bd_dev; 8178c2ecf20Sopenharmony_ci struct flush_cmd_control *fcc; 8188c2ecf20Sopenharmony_ci int err = 0; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (SM_I(sbi)->fcc_info) { 8218c2ecf20Sopenharmony_ci fcc = SM_I(sbi)->fcc_info; 8228c2ecf20Sopenharmony_ci if (fcc->f2fs_issue_flush) 8238c2ecf20Sopenharmony_ci return err; 8248c2ecf20Sopenharmony_ci goto init_thread; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci fcc = f2fs_kzalloc(sbi, sizeof(struct flush_cmd_control), GFP_KERNEL); 8288c2ecf20Sopenharmony_ci if (!fcc) 8298c2ecf20Sopenharmony_ci return -ENOMEM; 8308c2ecf20Sopenharmony_ci atomic_set(&fcc->issued_flush, 0); 8318c2ecf20Sopenharmony_ci atomic_set(&fcc->queued_flush, 0); 8328c2ecf20Sopenharmony_ci init_waitqueue_head(&fcc->flush_wait_queue); 8338c2ecf20Sopenharmony_ci init_llist_head(&fcc->issue_list); 8348c2ecf20Sopenharmony_ci SM_I(sbi)->fcc_info = fcc; 8358c2ecf20Sopenharmony_ci if (!test_opt(sbi, FLUSH_MERGE)) 8368c2ecf20Sopenharmony_ci return err; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ciinit_thread: 8398c2ecf20Sopenharmony_ci fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi, 8408c2ecf20Sopenharmony_ci "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); 8418c2ecf20Sopenharmony_ci if (IS_ERR(fcc->f2fs_issue_flush)) { 8428c2ecf20Sopenharmony_ci err = PTR_ERR(fcc->f2fs_issue_flush); 8438c2ecf20Sopenharmony_ci kfree(fcc); 8448c2ecf20Sopenharmony_ci SM_I(sbi)->fcc_info = NULL; 8458c2ecf20Sopenharmony_ci return err; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci return err; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_civoid f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (fcc && fcc->f2fs_issue_flush) { 8568c2ecf20Sopenharmony_ci struct task_struct *flush_thread = fcc->f2fs_issue_flush; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci fcc->f2fs_issue_flush = NULL; 8598c2ecf20Sopenharmony_ci kthread_stop(flush_thread); 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci if (free) { 8628c2ecf20Sopenharmony_ci kfree(fcc); 8638c2ecf20Sopenharmony_ci SM_I(sbi)->fcc_info = NULL; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ciint f2fs_flush_device_cache(struct f2fs_sb_info *sbi) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci int ret = 0, i; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (!f2fs_is_multi_device(sbi)) 8728c2ecf20Sopenharmony_ci return 0; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (test_opt(sbi, NOBARRIER)) 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci for (i = 1; i < sbi->s_ndevs; i++) { 8788c2ecf20Sopenharmony_ci if (!f2fs_test_bit(i, (char *)&sbi->dirty_device)) 8798c2ecf20Sopenharmony_ci continue; 8808c2ecf20Sopenharmony_ci ret = __submit_flush_wait(sbi, FDEV(i).bdev); 8818c2ecf20Sopenharmony_ci if (ret) 8828c2ecf20Sopenharmony_ci break; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci spin_lock(&sbi->dev_lock); 8858c2ecf20Sopenharmony_ci f2fs_clear_bit(i, (char *)&sbi->dirty_device); 8868c2ecf20Sopenharmony_ci spin_unlock(&sbi->dev_lock); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci return ret; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, 8938c2ecf20Sopenharmony_ci enum dirty_type dirty_type) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* need not be added */ 8988c2ecf20Sopenharmony_ci if (IS_CURSEG(sbi, segno)) 8998c2ecf20Sopenharmony_ci return; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type])) 9028c2ecf20Sopenharmony_ci dirty_i->nr_dirty[dirty_type]++; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (dirty_type == DIRTY) { 9058c2ecf20Sopenharmony_ci struct seg_entry *sentry = get_seg_entry(sbi, segno); 9068c2ecf20Sopenharmony_ci enum dirty_type t = sentry->type; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (unlikely(t >= DIRTY)) { 9098c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, 1); 9108c2ecf20Sopenharmony_ci return; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t])) 9138c2ecf20Sopenharmony_ci dirty_i->nr_dirty[t]++; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) { 9168c2ecf20Sopenharmony_ci unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); 9178c2ecf20Sopenharmony_ci block_t valid_blocks = 9188c2ecf20Sopenharmony_ci get_valid_blocks(sbi, segno, true); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, unlikely(!valid_blocks || 9218c2ecf20Sopenharmony_ci valid_blocks == BLKS_PER_SEC(sbi))); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (!IS_CURSEC(sbi, secno)) 9248c2ecf20Sopenharmony_ci set_bit(secno, dirty_i->dirty_secmap); 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, 9308c2ecf20Sopenharmony_ci enum dirty_type dirty_type) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 9338c2ecf20Sopenharmony_ci block_t valid_blocks; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type])) 9368c2ecf20Sopenharmony_ci dirty_i->nr_dirty[dirty_type]--; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (dirty_type == DIRTY) { 9398c2ecf20Sopenharmony_ci struct seg_entry *sentry = get_seg_entry(sbi, segno); 9408c2ecf20Sopenharmony_ci enum dirty_type t = sentry->type; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t])) 9438c2ecf20Sopenharmony_ci dirty_i->nr_dirty[t]--; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci valid_blocks = get_valid_blocks(sbi, segno, true); 9468c2ecf20Sopenharmony_ci if (valid_blocks == 0) { 9478c2ecf20Sopenharmony_ci clear_bit(GET_SEC_FROM_SEG(sbi, segno), 9488c2ecf20Sopenharmony_ci dirty_i->victim_secmap); 9498c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 9508c2ecf20Sopenharmony_ci clear_bit(segno, SIT_I(sbi)->invalid_segmap); 9518c2ecf20Sopenharmony_ci#endif 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) { 9548c2ecf20Sopenharmony_ci unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (!valid_blocks || 9578c2ecf20Sopenharmony_ci valid_blocks == BLKS_PER_SEC(sbi)) { 9588c2ecf20Sopenharmony_ci clear_bit(secno, dirty_i->dirty_secmap); 9598c2ecf20Sopenharmony_ci return; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (!IS_CURSEC(sbi, secno)) 9638c2ecf20Sopenharmony_ci set_bit(secno, dirty_i->dirty_secmap); 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci/* 9698c2ecf20Sopenharmony_ci * Should not occur error such as -ENOMEM. 9708c2ecf20Sopenharmony_ci * Adding dirty entry into seglist is not critical operation. 9718c2ecf20Sopenharmony_ci * If a given segment is one of current working segments, it won't be added. 9728c2ecf20Sopenharmony_ci */ 9738c2ecf20Sopenharmony_cistatic void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 9768c2ecf20Sopenharmony_ci unsigned short valid_blocks, ckpt_valid_blocks; 9778c2ecf20Sopenharmony_ci unsigned int usable_blocks; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno)) 9808c2ecf20Sopenharmony_ci return; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci usable_blocks = f2fs_usable_blks_in_seg(sbi, segno); 9838c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci valid_blocks = get_valid_blocks(sbi, segno, false); 9868c2ecf20Sopenharmony_ci ckpt_valid_blocks = get_ckpt_valid_blocks(sbi, segno, false); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci if (valid_blocks == 0 && (!is_sbi_flag_set(sbi, SBI_CP_DISABLED) || 9898c2ecf20Sopenharmony_ci ckpt_valid_blocks == usable_blocks)) { 9908c2ecf20Sopenharmony_ci __locate_dirty_segment(sbi, segno, PRE); 9918c2ecf20Sopenharmony_ci __remove_dirty_segment(sbi, segno, DIRTY); 9928c2ecf20Sopenharmony_ci } else if (valid_blocks < usable_blocks) { 9938c2ecf20Sopenharmony_ci __locate_dirty_segment(sbi, segno, DIRTY); 9948c2ecf20Sopenharmony_ci } else { 9958c2ecf20Sopenharmony_ci /* Recovery routine with SSR needs this */ 9968c2ecf20Sopenharmony_ci __remove_dirty_segment(sbi, segno, DIRTY); 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci/* This moves currently empty dirty blocks to prefree. Must hold seglist_lock */ 10038c2ecf20Sopenharmony_civoid f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 10068c2ecf20Sopenharmony_ci unsigned int segno; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 10098c2ecf20Sopenharmony_ci for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) { 10108c2ecf20Sopenharmony_ci if (get_valid_blocks(sbi, segno, false)) 10118c2ecf20Sopenharmony_ci continue; 10128c2ecf20Sopenharmony_ci if (IS_CURSEG(sbi, segno)) 10138c2ecf20Sopenharmony_ci continue; 10148c2ecf20Sopenharmony_ci __locate_dirty_segment(sbi, segno, PRE); 10158c2ecf20Sopenharmony_ci __remove_dirty_segment(sbi, segno, DIRTY); 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ciblock_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci int ovp_hole_segs = 10238c2ecf20Sopenharmony_ci (overprovision_segments(sbi) - reserved_segments(sbi)); 10248c2ecf20Sopenharmony_ci block_t ovp_holes = ovp_hole_segs << sbi->log_blocks_per_seg; 10258c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 10268c2ecf20Sopenharmony_ci block_t holes[2] = {0, 0}; /* DATA and NODE */ 10278c2ecf20Sopenharmony_ci block_t unusable; 10288c2ecf20Sopenharmony_ci struct seg_entry *se; 10298c2ecf20Sopenharmony_ci unsigned int segno; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 10328c2ecf20Sopenharmony_ci for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) { 10338c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, segno); 10348c2ecf20Sopenharmony_ci if (IS_NODESEG(se->type)) 10358c2ecf20Sopenharmony_ci holes[NODE] += f2fs_usable_blks_in_seg(sbi, segno) - 10368c2ecf20Sopenharmony_ci se->valid_blocks; 10378c2ecf20Sopenharmony_ci else 10388c2ecf20Sopenharmony_ci holes[DATA] += f2fs_usable_blks_in_seg(sbi, segno) - 10398c2ecf20Sopenharmony_ci se->valid_blocks; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci unusable = holes[DATA] > holes[NODE] ? holes[DATA] : holes[NODE]; 10448c2ecf20Sopenharmony_ci if (unusable > ovp_holes) 10458c2ecf20Sopenharmony_ci return unusable - ovp_holes; 10468c2ecf20Sopenharmony_ci return 0; 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ciint f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci int ovp_hole_segs = 10528c2ecf20Sopenharmony_ci (overprovision_segments(sbi) - reserved_segments(sbi)); 10538c2ecf20Sopenharmony_ci if (unusable > F2FS_OPTION(sbi).unusable_cap) 10548c2ecf20Sopenharmony_ci return -EAGAIN; 10558c2ecf20Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) && 10568c2ecf20Sopenharmony_ci dirty_segments(sbi) > ovp_hole_segs) 10578c2ecf20Sopenharmony_ci return -EAGAIN; 10588c2ecf20Sopenharmony_ci return 0; 10598c2ecf20Sopenharmony_ci} 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci/* This is only used by SBI_CP_DISABLED */ 10628c2ecf20Sopenharmony_cistatic unsigned int get_free_segment(struct f2fs_sb_info *sbi) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 10658c2ecf20Sopenharmony_ci unsigned int segno = 0; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 10688c2ecf20Sopenharmony_ci for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) { 10698c2ecf20Sopenharmony_ci if (get_valid_blocks(sbi, segno, false)) 10708c2ecf20Sopenharmony_ci continue; 10718c2ecf20Sopenharmony_ci if (get_ckpt_valid_blocks(sbi, segno, false)) 10728c2ecf20Sopenharmony_ci continue; 10738c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 10748c2ecf20Sopenharmony_ci return segno; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 10778c2ecf20Sopenharmony_ci return NULL_SEGNO; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi, 10818c2ecf20Sopenharmony_ci struct block_device *bdev, block_t lstart, 10828c2ecf20Sopenharmony_ci block_t start, block_t len) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 10858c2ecf20Sopenharmony_ci struct list_head *pend_list; 10868c2ecf20Sopenharmony_ci struct discard_cmd *dc; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !len); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci pend_list = &dcc->pend_list[plist_idx(len)]; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS); 10938c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dc->list); 10948c2ecf20Sopenharmony_ci dc->bdev = bdev; 10958c2ecf20Sopenharmony_ci dc->lstart = lstart; 10968c2ecf20Sopenharmony_ci dc->start = start; 10978c2ecf20Sopenharmony_ci dc->len = len; 10988c2ecf20Sopenharmony_ci dc->ref = 0; 10998c2ecf20Sopenharmony_ci dc->state = D_PREP; 11008c2ecf20Sopenharmony_ci dc->queued = 0; 11018c2ecf20Sopenharmony_ci dc->error = 0; 11028c2ecf20Sopenharmony_ci init_completion(&dc->wait); 11038c2ecf20Sopenharmony_ci list_add_tail(&dc->list, pend_list); 11048c2ecf20Sopenharmony_ci spin_lock_init(&dc->lock); 11058c2ecf20Sopenharmony_ci dc->bio_ref = 0; 11068c2ecf20Sopenharmony_ci atomic_inc(&dcc->discard_cmd_cnt); 11078c2ecf20Sopenharmony_ci dcc->undiscard_blks += len; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci return dc; 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic struct discard_cmd *__attach_discard_cmd(struct f2fs_sb_info *sbi, 11138c2ecf20Sopenharmony_ci struct block_device *bdev, block_t lstart, 11148c2ecf20Sopenharmony_ci block_t start, block_t len, 11158c2ecf20Sopenharmony_ci struct rb_node *parent, struct rb_node **p, 11168c2ecf20Sopenharmony_ci bool leftmost) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 11198c2ecf20Sopenharmony_ci struct discard_cmd *dc; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci dc = __create_discard_cmd(sbi, bdev, lstart, start, len); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci rb_link_node(&dc->rb_node, parent, p); 11248c2ecf20Sopenharmony_ci rb_insert_color_cached(&dc->rb_node, &dcc->root, leftmost); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci return dc; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic void __detach_discard_cmd(struct discard_cmd_control *dcc, 11308c2ecf20Sopenharmony_ci struct discard_cmd *dc) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci if (dc->state == D_DONE) 11338c2ecf20Sopenharmony_ci atomic_sub(dc->queued, &dcc->queued_discard); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci list_del(&dc->list); 11368c2ecf20Sopenharmony_ci rb_erase_cached(&dc->rb_node, &dcc->root); 11378c2ecf20Sopenharmony_ci dcc->undiscard_blks -= dc->len; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci kmem_cache_free(discard_cmd_slab, dc); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci atomic_dec(&dcc->discard_cmd_cnt); 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic void __remove_discard_cmd(struct f2fs_sb_info *sbi, 11458c2ecf20Sopenharmony_ci struct discard_cmd *dc) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 11488c2ecf20Sopenharmony_ci unsigned long flags; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci trace_f2fs_remove_discard(dc->bdev, dc->start, dc->len); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci spin_lock_irqsave(&dc->lock, flags); 11538c2ecf20Sopenharmony_ci if (dc->bio_ref) { 11548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dc->lock, flags); 11558c2ecf20Sopenharmony_ci return; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dc->lock, flags); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, dc->ref); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (dc->error == -EOPNOTSUPP) 11628c2ecf20Sopenharmony_ci dc->error = 0; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (dc->error) 11658c2ecf20Sopenharmony_ci printk_ratelimited( 11668c2ecf20Sopenharmony_ci "%sF2FS-fs (%s): Issue discard(%u, %u, %u) failed, ret: %d", 11678c2ecf20Sopenharmony_ci KERN_INFO, sbi->sb->s_id, 11688c2ecf20Sopenharmony_ci dc->lstart, dc->start, dc->len, dc->error); 11698c2ecf20Sopenharmony_ci __detach_discard_cmd(dcc, dc); 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic void f2fs_submit_discard_endio(struct bio *bio) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private; 11758c2ecf20Sopenharmony_ci unsigned long flags; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci spin_lock_irqsave(&dc->lock, flags); 11788c2ecf20Sopenharmony_ci if (!dc->error) 11798c2ecf20Sopenharmony_ci dc->error = blk_status_to_errno(bio->bi_status); 11808c2ecf20Sopenharmony_ci dc->bio_ref--; 11818c2ecf20Sopenharmony_ci if (!dc->bio_ref && dc->state == D_SUBMIT) { 11828c2ecf20Sopenharmony_ci dc->state = D_DONE; 11838c2ecf20Sopenharmony_ci complete_all(&dc->wait); 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dc->lock, flags); 11868c2ecf20Sopenharmony_ci bio_put(bio); 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cistatic void __check_sit_bitmap(struct f2fs_sb_info *sbi, 11908c2ecf20Sopenharmony_ci block_t start, block_t end) 11918c2ecf20Sopenharmony_ci{ 11928c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 11938c2ecf20Sopenharmony_ci struct seg_entry *sentry; 11948c2ecf20Sopenharmony_ci unsigned int segno; 11958c2ecf20Sopenharmony_ci block_t blk = start; 11968c2ecf20Sopenharmony_ci unsigned long offset, size, max_blocks = sbi->blocks_per_seg; 11978c2ecf20Sopenharmony_ci unsigned long *map; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci while (blk < end) { 12008c2ecf20Sopenharmony_ci segno = GET_SEGNO(sbi, blk); 12018c2ecf20Sopenharmony_ci sentry = get_seg_entry(sbi, segno); 12028c2ecf20Sopenharmony_ci offset = GET_BLKOFF_FROM_SEG0(sbi, blk); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (end < START_BLOCK(sbi, segno + 1)) 12058c2ecf20Sopenharmony_ci size = GET_BLKOFF_FROM_SEG0(sbi, end); 12068c2ecf20Sopenharmony_ci else 12078c2ecf20Sopenharmony_ci size = max_blocks; 12088c2ecf20Sopenharmony_ci map = (unsigned long *)(sentry->cur_valid_map); 12098c2ecf20Sopenharmony_ci offset = find_rev_next_bit(map, size, offset); 12108c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, offset != size); 12118c2ecf20Sopenharmony_ci blk = START_BLOCK(sbi, segno + 1); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci#endif 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic void __init_discard_policy(struct f2fs_sb_info *sbi, 12178c2ecf20Sopenharmony_ci struct discard_policy *policy, 12188c2ecf20Sopenharmony_ci int discard_type, unsigned int granularity) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (discard_type == DPOLICY_BG) { 12238c2ecf20Sopenharmony_ci *policy = dpolicys[DPOLICY_BG]; 12248c2ecf20Sopenharmony_ci } else if (discard_type == DPOLICY_BALANCE) { 12258c2ecf20Sopenharmony_ci *policy = dpolicys[DPOLICY_BALANCE]; 12268c2ecf20Sopenharmony_ci } else if (discard_type == DPOLICY_FORCE) { 12278c2ecf20Sopenharmony_ci *policy = dpolicys[DPOLICY_FORCE]; 12288c2ecf20Sopenharmony_ci } else if (discard_type == DPOLICY_FSTRIM) { 12298c2ecf20Sopenharmony_ci *policy = dpolicys[DPOLICY_FSTRIM]; 12308c2ecf20Sopenharmony_ci if (policy->granularity != granularity) 12318c2ecf20Sopenharmony_ci policy->granularity = granularity; 12328c2ecf20Sopenharmony_ci } else if (discard_type == DPOLICY_UMOUNT) { 12338c2ecf20Sopenharmony_ci *policy = dpolicys[DPOLICY_UMOUNT]; 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci dcc->discard_type = discard_type; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic void select_sub_discard_policy(struct discard_sub_policy **spolicy, 12398c2ecf20Sopenharmony_ci int index, struct discard_policy *dpolicy) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci if (dpolicy->type == DPOLICY_FSTRIM) { 12428c2ecf20Sopenharmony_ci *spolicy = &dpolicy->sub_policy[SUB_POLICY_BIG]; 12438c2ecf20Sopenharmony_ci return; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if ((index + 1) >= DISCARD_GRAN_BG) 12478c2ecf20Sopenharmony_ci *spolicy = &dpolicy->sub_policy[SUB_POLICY_BIG]; 12488c2ecf20Sopenharmony_ci else if ((index + 1) >= DISCARD_GRAN_BL) 12498c2ecf20Sopenharmony_ci *spolicy = &dpolicy->sub_policy[SUB_POLICY_MID]; 12508c2ecf20Sopenharmony_ci else 12518c2ecf20Sopenharmony_ci *spolicy = &dpolicy->sub_policy[SUB_POLICY_SMALL]; 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic void __update_discard_tree_range(struct f2fs_sb_info *sbi, 12558c2ecf20Sopenharmony_ci struct block_device *bdev, block_t lstart, 12568c2ecf20Sopenharmony_ci block_t start, block_t len); 12578c2ecf20Sopenharmony_ci/* this function is copied from blkdev_issue_discard from block/blk-lib.c */ 12588c2ecf20Sopenharmony_cistatic int __submit_discard_cmd(struct f2fs_sb_info *sbi, 12598c2ecf20Sopenharmony_ci struct discard_policy *dpolicy, 12608c2ecf20Sopenharmony_ci int spolicy_index, 12618c2ecf20Sopenharmony_ci struct discard_cmd *dc, 12628c2ecf20Sopenharmony_ci unsigned int *issued) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci struct block_device *bdev = dc->bdev; 12658c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(bdev); 12668c2ecf20Sopenharmony_ci unsigned int max_discard_blocks = 12678c2ecf20Sopenharmony_ci SECTOR_TO_BLOCK(q->limits.max_discard_sectors); 12688c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 12698c2ecf20Sopenharmony_ci struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ? 12708c2ecf20Sopenharmony_ci &(dcc->fstrim_list) : &(dcc->wait_list); 12718c2ecf20Sopenharmony_ci int flag = dpolicy->sync ? REQ_SYNC : 0; 12728c2ecf20Sopenharmony_ci struct discard_sub_policy *spolicy = NULL; 12738c2ecf20Sopenharmony_ci block_t lstart, start, len, total_len; 12748c2ecf20Sopenharmony_ci int err = 0; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci select_sub_discard_policy(&spolicy, spolicy_index, dpolicy); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (dc->state != D_PREP) 12798c2ecf20Sopenharmony_ci return 0; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) 12828c2ecf20Sopenharmony_ci return 0; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci trace_f2fs_issue_discard(bdev, dc->start, dc->len); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci lstart = dc->lstart; 12878c2ecf20Sopenharmony_ci start = dc->start; 12888c2ecf20Sopenharmony_ci len = dc->len; 12898c2ecf20Sopenharmony_ci total_len = len; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci dc->len = 0; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci while (total_len && *issued < spolicy->max_requests && !err) { 12948c2ecf20Sopenharmony_ci struct bio *bio = NULL; 12958c2ecf20Sopenharmony_ci unsigned long flags; 12968c2ecf20Sopenharmony_ci bool last = true; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci if (len > max_discard_blocks) { 12998c2ecf20Sopenharmony_ci len = max_discard_blocks; 13008c2ecf20Sopenharmony_ci last = false; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci (*issued)++; 13048c2ecf20Sopenharmony_ci if (*issued == spolicy->max_requests) 13058c2ecf20Sopenharmony_ci last = true; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci dc->len += len; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (time_to_inject(sbi, FAULT_DISCARD)) { 13108c2ecf20Sopenharmony_ci f2fs_show_injection_info(sbi, FAULT_DISCARD); 13118c2ecf20Sopenharmony_ci err = -EIO; 13128c2ecf20Sopenharmony_ci goto submit; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci err = __blkdev_issue_discard(bdev, 13158c2ecf20Sopenharmony_ci SECTOR_FROM_BLOCK(start), 13168c2ecf20Sopenharmony_ci SECTOR_FROM_BLOCK(len), 13178c2ecf20Sopenharmony_ci GFP_NOFS, 0, &bio); 13188c2ecf20Sopenharmony_cisubmit: 13198c2ecf20Sopenharmony_ci if (err) { 13208c2ecf20Sopenharmony_ci spin_lock_irqsave(&dc->lock, flags); 13218c2ecf20Sopenharmony_ci if (dc->state == D_PARTIAL) 13228c2ecf20Sopenharmony_ci dc->state = D_SUBMIT; 13238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dc->lock, flags); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci break; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !bio); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci /* 13318c2ecf20Sopenharmony_ci * should keep before submission to avoid D_DONE 13328c2ecf20Sopenharmony_ci * right away 13338c2ecf20Sopenharmony_ci */ 13348c2ecf20Sopenharmony_ci spin_lock_irqsave(&dc->lock, flags); 13358c2ecf20Sopenharmony_ci if (last) 13368c2ecf20Sopenharmony_ci dc->state = D_SUBMIT; 13378c2ecf20Sopenharmony_ci else 13388c2ecf20Sopenharmony_ci dc->state = D_PARTIAL; 13398c2ecf20Sopenharmony_ci dc->bio_ref++; 13408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dc->lock, flags); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci atomic_inc(&dcc->queued_discard); 13438c2ecf20Sopenharmony_ci dc->queued++; 13448c2ecf20Sopenharmony_ci list_move_tail(&dc->list, wait_list); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* sanity check on discard range */ 13478c2ecf20Sopenharmony_ci __check_sit_bitmap(sbi, lstart, lstart + len); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci bio->bi_private = dc; 13508c2ecf20Sopenharmony_ci bio->bi_end_io = f2fs_submit_discard_endio; 13518c2ecf20Sopenharmony_ci bio->bi_opf |= flag; 13528c2ecf20Sopenharmony_ci submit_bio(bio); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci atomic_inc(&dcc->issued_discard); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci f2fs_update_iostat(sbi, FS_DISCARD, 1); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci lstart += len; 13598c2ecf20Sopenharmony_ci start += len; 13608c2ecf20Sopenharmony_ci total_len -= len; 13618c2ecf20Sopenharmony_ci len = total_len; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci if (!err && len) { 13658c2ecf20Sopenharmony_ci dcc->undiscard_blks -= len; 13668c2ecf20Sopenharmony_ci __update_discard_tree_range(sbi, bdev, lstart, start, len); 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci return err; 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic void __insert_discard_tree(struct f2fs_sb_info *sbi, 13728c2ecf20Sopenharmony_ci struct block_device *bdev, block_t lstart, 13738c2ecf20Sopenharmony_ci block_t start, block_t len, 13748c2ecf20Sopenharmony_ci struct rb_node **insert_p, 13758c2ecf20Sopenharmony_ci struct rb_node *insert_parent) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 13788c2ecf20Sopenharmony_ci struct rb_node **p; 13798c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 13808c2ecf20Sopenharmony_ci bool leftmost = true; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (insert_p && insert_parent) { 13838c2ecf20Sopenharmony_ci parent = insert_parent; 13848c2ecf20Sopenharmony_ci p = insert_p; 13858c2ecf20Sopenharmony_ci goto do_insert; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci p = f2fs_lookup_rb_tree_for_insert(sbi, &dcc->root, &parent, 13898c2ecf20Sopenharmony_ci lstart, &leftmost); 13908c2ecf20Sopenharmony_cido_insert: 13918c2ecf20Sopenharmony_ci __attach_discard_cmd(sbi, bdev, lstart, start, len, parent, 13928c2ecf20Sopenharmony_ci p, leftmost); 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_cistatic void __relocate_discard_cmd(struct discard_cmd_control *dcc, 13968c2ecf20Sopenharmony_ci struct discard_cmd *dc) 13978c2ecf20Sopenharmony_ci{ 13988c2ecf20Sopenharmony_ci list_move_tail(&dc->list, &dcc->pend_list[plist_idx(dc->len)]); 13998c2ecf20Sopenharmony_ci} 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_cistatic void __punch_discard_cmd(struct f2fs_sb_info *sbi, 14028c2ecf20Sopenharmony_ci struct discard_cmd *dc, block_t blkaddr) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 14058c2ecf20Sopenharmony_ci struct discard_info di = dc->di; 14068c2ecf20Sopenharmony_ci bool modified = false; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (dc->state == D_DONE || dc->len == 1) { 14098c2ecf20Sopenharmony_ci __remove_discard_cmd(sbi, dc); 14108c2ecf20Sopenharmony_ci return; 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci dcc->undiscard_blks -= di.len; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (blkaddr > di.lstart) { 14168c2ecf20Sopenharmony_ci dc->len = blkaddr - dc->lstart; 14178c2ecf20Sopenharmony_ci dcc->undiscard_blks += dc->len; 14188c2ecf20Sopenharmony_ci __relocate_discard_cmd(dcc, dc); 14198c2ecf20Sopenharmony_ci modified = true; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (blkaddr < di.lstart + di.len - 1) { 14238c2ecf20Sopenharmony_ci if (modified) { 14248c2ecf20Sopenharmony_ci __insert_discard_tree(sbi, dc->bdev, blkaddr + 1, 14258c2ecf20Sopenharmony_ci di.start + blkaddr + 1 - di.lstart, 14268c2ecf20Sopenharmony_ci di.lstart + di.len - 1 - blkaddr, 14278c2ecf20Sopenharmony_ci NULL, NULL); 14288c2ecf20Sopenharmony_ci } else { 14298c2ecf20Sopenharmony_ci dc->lstart++; 14308c2ecf20Sopenharmony_ci dc->len--; 14318c2ecf20Sopenharmony_ci dc->start++; 14328c2ecf20Sopenharmony_ci dcc->undiscard_blks += dc->len; 14338c2ecf20Sopenharmony_ci __relocate_discard_cmd(dcc, dc); 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic void __update_discard_tree_range(struct f2fs_sb_info *sbi, 14398c2ecf20Sopenharmony_ci struct block_device *bdev, block_t lstart, 14408c2ecf20Sopenharmony_ci block_t start, block_t len) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 14438c2ecf20Sopenharmony_ci struct discard_cmd *prev_dc = NULL, *next_dc = NULL; 14448c2ecf20Sopenharmony_ci struct discard_cmd *dc; 14458c2ecf20Sopenharmony_ci struct discard_info di = {0}; 14468c2ecf20Sopenharmony_ci struct rb_node **insert_p = NULL, *insert_parent = NULL; 14478c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(bdev); 14488c2ecf20Sopenharmony_ci unsigned int max_discard_blocks = 14498c2ecf20Sopenharmony_ci SECTOR_TO_BLOCK(q->limits.max_discard_sectors); 14508c2ecf20Sopenharmony_ci block_t end = lstart + len; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root, 14538c2ecf20Sopenharmony_ci NULL, lstart, 14548c2ecf20Sopenharmony_ci (struct rb_entry **)&prev_dc, 14558c2ecf20Sopenharmony_ci (struct rb_entry **)&next_dc, 14568c2ecf20Sopenharmony_ci &insert_p, &insert_parent, true, NULL); 14578c2ecf20Sopenharmony_ci if (dc) 14588c2ecf20Sopenharmony_ci prev_dc = dc; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci if (!prev_dc) { 14618c2ecf20Sopenharmony_ci di.lstart = lstart; 14628c2ecf20Sopenharmony_ci di.len = next_dc ? next_dc->lstart - lstart : len; 14638c2ecf20Sopenharmony_ci di.len = min(di.len, len); 14648c2ecf20Sopenharmony_ci di.start = start; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci while (1) { 14688c2ecf20Sopenharmony_ci struct rb_node *node; 14698c2ecf20Sopenharmony_ci bool merged = false; 14708c2ecf20Sopenharmony_ci struct discard_cmd *tdc = NULL; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (prev_dc) { 14738c2ecf20Sopenharmony_ci di.lstart = prev_dc->lstart + prev_dc->len; 14748c2ecf20Sopenharmony_ci if (di.lstart < lstart) 14758c2ecf20Sopenharmony_ci di.lstart = lstart; 14768c2ecf20Sopenharmony_ci if (di.lstart >= end) 14778c2ecf20Sopenharmony_ci break; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (!next_dc || next_dc->lstart > end) 14808c2ecf20Sopenharmony_ci di.len = end - di.lstart; 14818c2ecf20Sopenharmony_ci else 14828c2ecf20Sopenharmony_ci di.len = next_dc->lstart - di.lstart; 14838c2ecf20Sopenharmony_ci di.start = start + di.lstart - lstart; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (!di.len) 14878c2ecf20Sopenharmony_ci goto next; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci if (prev_dc && prev_dc->state == D_PREP && 14908c2ecf20Sopenharmony_ci prev_dc->bdev == bdev && 14918c2ecf20Sopenharmony_ci __is_discard_back_mergeable(&di, &prev_dc->di, 14928c2ecf20Sopenharmony_ci max_discard_blocks)) { 14938c2ecf20Sopenharmony_ci prev_dc->di.len += di.len; 14948c2ecf20Sopenharmony_ci dcc->undiscard_blks += di.len; 14958c2ecf20Sopenharmony_ci __relocate_discard_cmd(dcc, prev_dc); 14968c2ecf20Sopenharmony_ci di = prev_dc->di; 14978c2ecf20Sopenharmony_ci tdc = prev_dc; 14988c2ecf20Sopenharmony_ci merged = true; 14998c2ecf20Sopenharmony_ci } 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (next_dc && next_dc->state == D_PREP && 15028c2ecf20Sopenharmony_ci next_dc->bdev == bdev && 15038c2ecf20Sopenharmony_ci __is_discard_front_mergeable(&di, &next_dc->di, 15048c2ecf20Sopenharmony_ci max_discard_blocks)) { 15058c2ecf20Sopenharmony_ci next_dc->di.lstart = di.lstart; 15068c2ecf20Sopenharmony_ci next_dc->di.len += di.len; 15078c2ecf20Sopenharmony_ci next_dc->di.start = di.start; 15088c2ecf20Sopenharmony_ci dcc->undiscard_blks += di.len; 15098c2ecf20Sopenharmony_ci __relocate_discard_cmd(dcc, next_dc); 15108c2ecf20Sopenharmony_ci if (tdc) 15118c2ecf20Sopenharmony_ci __remove_discard_cmd(sbi, tdc); 15128c2ecf20Sopenharmony_ci merged = true; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (!merged) { 15168c2ecf20Sopenharmony_ci __insert_discard_tree(sbi, bdev, di.lstart, di.start, 15178c2ecf20Sopenharmony_ci di.len, NULL, NULL); 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci next: 15208c2ecf20Sopenharmony_ci prev_dc = next_dc; 15218c2ecf20Sopenharmony_ci if (!prev_dc) 15228c2ecf20Sopenharmony_ci break; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci node = rb_next(&prev_dc->rb_node); 15258c2ecf20Sopenharmony_ci next_dc = rb_entry_safe(node, struct discard_cmd, rb_node); 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic int __queue_discard_cmd(struct f2fs_sb_info *sbi, 15308c2ecf20Sopenharmony_ci struct block_device *bdev, block_t blkstart, block_t blklen) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci block_t lblkstart = blkstart; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (!f2fs_bdev_support_discard(bdev)) 15358c2ecf20Sopenharmony_ci return 0; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci trace_f2fs_queue_discard(bdev, blkstart, blklen); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (f2fs_is_multi_device(sbi)) { 15408c2ecf20Sopenharmony_ci int devi = f2fs_target_device_index(sbi, blkstart); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci blkstart -= FDEV(devi).start_blk; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci mutex_lock(&SM_I(sbi)->dcc_info->cmd_lock); 15458c2ecf20Sopenharmony_ci __update_discard_tree_range(sbi, bdev, lblkstart, blkstart, blklen); 15468c2ecf20Sopenharmony_ci mutex_unlock(&SM_I(sbi)->dcc_info->cmd_lock); 15478c2ecf20Sopenharmony_ci return 0; 15488c2ecf20Sopenharmony_ci} 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_cistatic unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, 15518c2ecf20Sopenharmony_ci struct discard_policy *dpolicy, 15528c2ecf20Sopenharmony_ci int spolicy_index) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 15558c2ecf20Sopenharmony_ci struct discard_cmd *prev_dc = NULL, *next_dc = NULL; 15568c2ecf20Sopenharmony_ci struct rb_node **insert_p = NULL, *insert_parent = NULL; 15578c2ecf20Sopenharmony_ci struct discard_cmd *dc; 15588c2ecf20Sopenharmony_ci struct blk_plug plug; 15598c2ecf20Sopenharmony_ci unsigned int pos = dcc->next_pos; 15608c2ecf20Sopenharmony_ci unsigned int issued = 0; 15618c2ecf20Sopenharmony_ci bool io_interrupted = false; 15628c2ecf20Sopenharmony_ci struct discard_sub_policy *spolicy = NULL; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci select_sub_discard_policy(&spolicy, spolicy_index, dpolicy); 15658c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root, 15688c2ecf20Sopenharmony_ci NULL, pos, 15698c2ecf20Sopenharmony_ci (struct rb_entry **)&prev_dc, 15708c2ecf20Sopenharmony_ci (struct rb_entry **)&next_dc, 15718c2ecf20Sopenharmony_ci &insert_p, &insert_parent, true, NULL); 15728c2ecf20Sopenharmony_ci if (!dc) 15738c2ecf20Sopenharmony_ci dc = next_dc; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci blk_start_plug(&plug); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci while (dc) { 15788c2ecf20Sopenharmony_ci struct rb_node *node; 15798c2ecf20Sopenharmony_ci int err = 0; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci if (dc->state != D_PREP) 15828c2ecf20Sopenharmony_ci goto next; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci if (dpolicy->io_aware && !is_idle(sbi, DISCARD_TIME)) { 15858c2ecf20Sopenharmony_ci io_interrupted = true; 15868c2ecf20Sopenharmony_ci break; 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci dcc->next_pos = dc->lstart + dc->len; 15908c2ecf20Sopenharmony_ci err = __submit_discard_cmd(sbi, dpolicy, spolicy_index, dc, &issued); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (issued >= spolicy->max_requests) 15938c2ecf20Sopenharmony_ci break; 15948c2ecf20Sopenharmony_cinext: 15958c2ecf20Sopenharmony_ci node = rb_next(&dc->rb_node); 15968c2ecf20Sopenharmony_ci if (err) 15978c2ecf20Sopenharmony_ci __remove_discard_cmd(sbi, dc); 15988c2ecf20Sopenharmony_ci dc = rb_entry_safe(node, struct discard_cmd, rb_node); 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci blk_finish_plug(&plug); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (!dc) 16048c2ecf20Sopenharmony_ci dcc->next_pos = 0; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (!issued && io_interrupted) 16098c2ecf20Sopenharmony_ci issued = -1; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci return issued; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_cistatic unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi, 16148c2ecf20Sopenharmony_ci struct discard_policy *dpolicy); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_cistatic int __issue_discard_cmd(struct f2fs_sb_info *sbi, 16178c2ecf20Sopenharmony_ci struct discard_policy *dpolicy) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 16208c2ecf20Sopenharmony_ci struct list_head *pend_list; 16218c2ecf20Sopenharmony_ci struct discard_cmd *dc, *tmp; 16228c2ecf20Sopenharmony_ci struct blk_plug plug; 16238c2ecf20Sopenharmony_ci int i, issued; 16248c2ecf20Sopenharmony_ci bool io_interrupted = false; 16258c2ecf20Sopenharmony_ci struct discard_sub_policy *spolicy = NULL; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (dpolicy->timeout) 16288c2ecf20Sopenharmony_ci f2fs_update_time(sbi, UMOUNT_DISCARD_TIMEOUT); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* only do this check in CHECK_FS, may be time consumed */ 16318c2ecf20Sopenharmony_ci if (unlikely(dcc->rbtree_check)) { 16328c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 16338c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi, &dcc->root, false)); 16348c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ciretry: 16378c2ecf20Sopenharmony_ci blk_start_plug(&plug); 16388c2ecf20Sopenharmony_ci issued = 0; 16398c2ecf20Sopenharmony_ci for (i = MAX_PLIST_NUM - 1; i >= 0; i--) { 16408c2ecf20Sopenharmony_ci if (dpolicy->timeout && 16418c2ecf20Sopenharmony_ci f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT)) 16428c2ecf20Sopenharmony_ci break; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (i + 1 < dpolicy->granularity) 16458c2ecf20Sopenharmony_ci break; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci select_sub_discard_policy(&spolicy, i, dpolicy); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (i + 1 < DEFAULT_DISCARD_GRANULARITY && dpolicy->ordered) { 16508c2ecf20Sopenharmony_ci issued = __issue_discard_cmd_orderly(sbi, dpolicy, i); 16518c2ecf20Sopenharmony_ci blk_finish_plug(&plug); 16528c2ecf20Sopenharmony_ci return issued; 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci pend_list = &dcc->pend_list[i]; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 16588c2ecf20Sopenharmony_ci if (list_empty(pend_list)) 16598c2ecf20Sopenharmony_ci goto next; 16608c2ecf20Sopenharmony_ci if (unlikely(dcc->rbtree_check)) 16618c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi, 16628c2ecf20Sopenharmony_ci &dcc->root, false)); 16638c2ecf20Sopenharmony_ci list_for_each_entry_safe(dc, tmp, pend_list, list) { 16648c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, dc->state != D_PREP); 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci if (dpolicy->timeout && 16678c2ecf20Sopenharmony_ci f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT)) 16688c2ecf20Sopenharmony_ci break; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci if (dpolicy->io_aware && i < dpolicy->io_aware_gran && 16718c2ecf20Sopenharmony_ci !is_idle(sbi, DISCARD_TIME)) { 16728c2ecf20Sopenharmony_ci io_interrupted = true; 16738c2ecf20Sopenharmony_ci goto skip; 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci __submit_discard_cmd(sbi, dpolicy, i, dc, &issued); 16768c2ecf20Sopenharmony_ciskip: 16778c2ecf20Sopenharmony_ci if (issued >= spolicy->max_requests) 16788c2ecf20Sopenharmony_ci break; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_cinext: 16818c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci if (issued >= spolicy->max_requests || io_interrupted) 16848c2ecf20Sopenharmony_ci break; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci blk_finish_plug(&plug); 16888c2ecf20Sopenharmony_ci if (spolicy) 16898c2ecf20Sopenharmony_ci dpolicy->min_interval = spolicy->interval; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (dpolicy->type == DPOLICY_UMOUNT && issued) { 16928c2ecf20Sopenharmony_ci __wait_all_discard_cmd(sbi, dpolicy); 16938c2ecf20Sopenharmony_ci goto retry; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci if (!issued && io_interrupted) 16978c2ecf20Sopenharmony_ci issued = -1; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci return issued; 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic bool __drop_discard_cmd(struct f2fs_sb_info *sbi) 17038c2ecf20Sopenharmony_ci{ 17048c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 17058c2ecf20Sopenharmony_ci struct list_head *pend_list; 17068c2ecf20Sopenharmony_ci struct discard_cmd *dc, *tmp; 17078c2ecf20Sopenharmony_ci int i; 17088c2ecf20Sopenharmony_ci bool dropped = false; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 17118c2ecf20Sopenharmony_ci for (i = MAX_PLIST_NUM - 1; i >= 0; i--) { 17128c2ecf20Sopenharmony_ci pend_list = &dcc->pend_list[i]; 17138c2ecf20Sopenharmony_ci list_for_each_entry_safe(dc, tmp, pend_list, list) { 17148c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, dc->state != D_PREP); 17158c2ecf20Sopenharmony_ci __remove_discard_cmd(sbi, dc); 17168c2ecf20Sopenharmony_ci dropped = true; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci return dropped; 17228c2ecf20Sopenharmony_ci} 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_civoid f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi) 17258c2ecf20Sopenharmony_ci{ 17268c2ecf20Sopenharmony_ci __drop_discard_cmd(sbi); 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic unsigned int __wait_one_discard_bio(struct f2fs_sb_info *sbi, 17308c2ecf20Sopenharmony_ci struct discard_cmd *dc) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 17338c2ecf20Sopenharmony_ci unsigned int len = 0; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci wait_for_completion_io(&dc->wait); 17368c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 17378c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, dc->state != D_DONE); 17388c2ecf20Sopenharmony_ci dc->ref--; 17398c2ecf20Sopenharmony_ci if (!dc->ref) { 17408c2ecf20Sopenharmony_ci if (!dc->error) 17418c2ecf20Sopenharmony_ci len = dc->len; 17428c2ecf20Sopenharmony_ci __remove_discard_cmd(sbi, dc); 17438c2ecf20Sopenharmony_ci } 17448c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci return len; 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic unsigned int __wait_discard_cmd_range(struct f2fs_sb_info *sbi, 17508c2ecf20Sopenharmony_ci struct discard_policy *dpolicy, 17518c2ecf20Sopenharmony_ci block_t start, block_t end) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 17548c2ecf20Sopenharmony_ci struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ? 17558c2ecf20Sopenharmony_ci &(dcc->fstrim_list) : &(dcc->wait_list); 17568c2ecf20Sopenharmony_ci struct discard_cmd *dc, *tmp; 17578c2ecf20Sopenharmony_ci bool need_wait; 17588c2ecf20Sopenharmony_ci unsigned int trimmed = 0; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_cinext: 17618c2ecf20Sopenharmony_ci need_wait = false; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 17648c2ecf20Sopenharmony_ci list_for_each_entry_safe(dc, tmp, wait_list, list) { 17658c2ecf20Sopenharmony_ci if (dc->lstart + dc->len <= start || end <= dc->lstart) 17668c2ecf20Sopenharmony_ci continue; 17678c2ecf20Sopenharmony_ci if (dc->len < dpolicy->granularity) 17688c2ecf20Sopenharmony_ci continue; 17698c2ecf20Sopenharmony_ci if (dc->state == D_DONE && !dc->ref) { 17708c2ecf20Sopenharmony_ci wait_for_completion_io(&dc->wait); 17718c2ecf20Sopenharmony_ci if (!dc->error) 17728c2ecf20Sopenharmony_ci trimmed += dc->len; 17738c2ecf20Sopenharmony_ci __remove_discard_cmd(sbi, dc); 17748c2ecf20Sopenharmony_ci } else { 17758c2ecf20Sopenharmony_ci dc->ref++; 17768c2ecf20Sopenharmony_ci need_wait = true; 17778c2ecf20Sopenharmony_ci break; 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci if (need_wait) { 17838c2ecf20Sopenharmony_ci trimmed += __wait_one_discard_bio(sbi, dc); 17848c2ecf20Sopenharmony_ci goto next; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci return trimmed; 17888c2ecf20Sopenharmony_ci} 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_cistatic unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi, 17918c2ecf20Sopenharmony_ci struct discard_policy *dpolicy) 17928c2ecf20Sopenharmony_ci{ 17938c2ecf20Sopenharmony_ci struct discard_policy dp; 17948c2ecf20Sopenharmony_ci unsigned int discard_blks; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (dpolicy) 17978c2ecf20Sopenharmony_ci return __wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci /* wait all */ 18008c2ecf20Sopenharmony_ci __init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, 1); 18018c2ecf20Sopenharmony_ci discard_blks = __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); 18028c2ecf20Sopenharmony_ci __init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, 1); 18038c2ecf20Sopenharmony_ci discard_blks += __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci return discard_blks; 18068c2ecf20Sopenharmony_ci} 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci/* This should be covered by global mutex, &sit_i->sentry_lock */ 18098c2ecf20Sopenharmony_cistatic void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 18128c2ecf20Sopenharmony_ci struct discard_cmd *dc; 18138c2ecf20Sopenharmony_ci bool need_wait = false; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 18168c2ecf20Sopenharmony_ci dc = (struct discard_cmd *)f2fs_lookup_rb_tree(&dcc->root, 18178c2ecf20Sopenharmony_ci NULL, blkaddr); 18188c2ecf20Sopenharmony_ci if (dc) { 18198c2ecf20Sopenharmony_ci if (dc->state == D_PREP) { 18208c2ecf20Sopenharmony_ci __punch_discard_cmd(sbi, dc, blkaddr); 18218c2ecf20Sopenharmony_ci } else { 18228c2ecf20Sopenharmony_ci dc->ref++; 18238c2ecf20Sopenharmony_ci need_wait = true; 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci if (need_wait) 18298c2ecf20Sopenharmony_ci __wait_one_discard_bio(sbi, dc); 18308c2ecf20Sopenharmony_ci} 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_civoid f2fs_stop_discard_thread(struct f2fs_sb_info *sbi) 18338c2ecf20Sopenharmony_ci{ 18348c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci if (dcc && dcc->f2fs_issue_discard) { 18378c2ecf20Sopenharmony_ci struct task_struct *discard_thread = dcc->f2fs_issue_discard; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci dcc->f2fs_issue_discard = NULL; 18408c2ecf20Sopenharmony_ci kthread_stop(discard_thread); 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci/* This comes from f2fs_put_super */ 18458c2ecf20Sopenharmony_cibool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) 18468c2ecf20Sopenharmony_ci{ 18478c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 18488c2ecf20Sopenharmony_ci struct discard_policy dpolicy; 18498c2ecf20Sopenharmony_ci bool dropped; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, 0); 18528c2ecf20Sopenharmony_ci __issue_discard_cmd(sbi, &dpolicy); 18538c2ecf20Sopenharmony_ci dropped = __drop_discard_cmd(sbi); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* just to make sure there is no pending discard commands */ 18568c2ecf20Sopenharmony_ci __wait_all_discard_cmd(sbi, NULL); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt)); 18598c2ecf20Sopenharmony_ci return dropped; 18608c2ecf20Sopenharmony_ci} 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_cistatic int select_discard_type(struct f2fs_sb_info *sbi) 18638c2ecf20Sopenharmony_ci{ 18648c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 18658c2ecf20Sopenharmony_ci block_t user_block_count = sbi->user_block_count; 18668c2ecf20Sopenharmony_ci block_t ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg; 18678c2ecf20Sopenharmony_ci block_t fs_available_blocks = user_block_count - 18688c2ecf20Sopenharmony_ci valid_user_blocks(sbi) + ovp_count; 18698c2ecf20Sopenharmony_ci int discard_type; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (fs_available_blocks >= fs_free_space_threshold(sbi) && 18728c2ecf20Sopenharmony_ci fs_available_blocks - dcc->undiscard_blks >= 18738c2ecf20Sopenharmony_ci device_free_space_threshold(sbi)) { 18748c2ecf20Sopenharmony_ci discard_type = DPOLICY_BG; 18758c2ecf20Sopenharmony_ci } else if (fs_available_blocks < fs_free_space_threshold(sbi) && 18768c2ecf20Sopenharmony_ci fs_available_blocks - dcc->undiscard_blks < 18778c2ecf20Sopenharmony_ci device_free_space_threshold(sbi)) { 18788c2ecf20Sopenharmony_ci discard_type = DPOLICY_FORCE; 18798c2ecf20Sopenharmony_ci } else { 18808c2ecf20Sopenharmony_ci discard_type = DPOLICY_BALANCE; 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci return discard_type; 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_cistatic int issue_discard_thread(void *data) 18868c2ecf20Sopenharmony_ci{ 18878c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = data; 18888c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 18898c2ecf20Sopenharmony_ci wait_queue_head_t *q = &dcc->discard_wait_queue; 18908c2ecf20Sopenharmony_ci struct discard_policy dpolicy; 18918c2ecf20Sopenharmony_ci unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME; 18928c2ecf20Sopenharmony_ci int issued, discard_type; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci set_freezable(); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci do { 18978c2ecf20Sopenharmony_ci discard_type = select_discard_type(sbi); 18988c2ecf20Sopenharmony_ci __init_discard_policy(sbi, &dpolicy, discard_type, 0); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci wait_event_interruptible_timeout(*q, 19018c2ecf20Sopenharmony_ci kthread_should_stop() || freezing(current) || 19028c2ecf20Sopenharmony_ci dcc->discard_wake, 19038c2ecf20Sopenharmony_ci msecs_to_jiffies(wait_ms)); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (dcc->discard_wake) 19068c2ecf20Sopenharmony_ci dcc->discard_wake = 0; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci /* clean up pending candidates before going to sleep */ 19098c2ecf20Sopenharmony_ci if (atomic_read(&dcc->queued_discard)) 19108c2ecf20Sopenharmony_ci __wait_all_discard_cmd(sbi, NULL); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci if (try_to_freeze()) 19138c2ecf20Sopenharmony_ci continue; 19148c2ecf20Sopenharmony_ci if (f2fs_readonly(sbi->sb)) 19158c2ecf20Sopenharmony_ci continue; 19168c2ecf20Sopenharmony_ci if (kthread_should_stop()) 19178c2ecf20Sopenharmony_ci return 0; 19188c2ecf20Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { 19198c2ecf20Sopenharmony_ci wait_ms = dpolicy.max_interval; 19208c2ecf20Sopenharmony_ci continue; 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (sbi->gc_mode == GC_URGENT_HIGH) 19248c2ecf20Sopenharmony_ci __init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 0); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci sb_start_intwrite(sbi->sb); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci issued = __issue_discard_cmd(sbi, &dpolicy); 19298c2ecf20Sopenharmony_ci if (issued > 0) { 19308c2ecf20Sopenharmony_ci __wait_all_discard_cmd(sbi, &dpolicy); 19318c2ecf20Sopenharmony_ci wait_ms = dpolicy.min_interval; 19328c2ecf20Sopenharmony_ci } else if (issued == -1){ 19338c2ecf20Sopenharmony_ci wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME); 19348c2ecf20Sopenharmony_ci if (!wait_ms) 19358c2ecf20Sopenharmony_ci wait_ms = dpolicy.mid_interval; 19368c2ecf20Sopenharmony_ci } else { 19378c2ecf20Sopenharmony_ci wait_ms = dpolicy.max_interval; 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci sb_end_intwrite(sbi->sb); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci } while (!kthread_should_stop()); 19438c2ecf20Sopenharmony_ci return 0; 19448c2ecf20Sopenharmony_ci} 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 19478c2ecf20Sopenharmony_cistatic int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi, 19488c2ecf20Sopenharmony_ci struct block_device *bdev, block_t blkstart, block_t blklen) 19498c2ecf20Sopenharmony_ci{ 19508c2ecf20Sopenharmony_ci sector_t sector, nr_sects; 19518c2ecf20Sopenharmony_ci block_t lblkstart = blkstart; 19528c2ecf20Sopenharmony_ci int devi = 0; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci if (f2fs_is_multi_device(sbi)) { 19558c2ecf20Sopenharmony_ci devi = f2fs_target_device_index(sbi, blkstart); 19568c2ecf20Sopenharmony_ci if (blkstart < FDEV(devi).start_blk || 19578c2ecf20Sopenharmony_ci blkstart > FDEV(devi).end_blk) { 19588c2ecf20Sopenharmony_ci f2fs_err(sbi, "Invalid block %x", blkstart); 19598c2ecf20Sopenharmony_ci return -EIO; 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci blkstart -= FDEV(devi).start_blk; 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci /* For sequential zones, reset the zone write pointer */ 19658c2ecf20Sopenharmony_ci if (f2fs_blkz_is_seq(sbi, devi, blkstart)) { 19668c2ecf20Sopenharmony_ci sector = SECTOR_FROM_BLOCK(blkstart); 19678c2ecf20Sopenharmony_ci nr_sects = SECTOR_FROM_BLOCK(blklen); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci if (sector & (bdev_zone_sectors(bdev) - 1) || 19708c2ecf20Sopenharmony_ci nr_sects != bdev_zone_sectors(bdev)) { 19718c2ecf20Sopenharmony_ci f2fs_err(sbi, "(%d) %s: Unaligned zone reset attempted (block %x + %x)", 19728c2ecf20Sopenharmony_ci devi, sbi->s_ndevs ? FDEV(devi).path : "", 19738c2ecf20Sopenharmony_ci blkstart, blklen); 19748c2ecf20Sopenharmony_ci return -EIO; 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci trace_f2fs_issue_reset_zone(bdev, blkstart); 19778c2ecf20Sopenharmony_ci return blkdev_zone_mgmt(bdev, REQ_OP_ZONE_RESET, 19788c2ecf20Sopenharmony_ci sector, nr_sects, GFP_NOFS); 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci /* For conventional zones, use regular discard if supported */ 19828c2ecf20Sopenharmony_ci return __queue_discard_cmd(sbi, bdev, lblkstart, blklen); 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci#endif 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_cistatic int __issue_discard_async(struct f2fs_sb_info *sbi, 19878c2ecf20Sopenharmony_ci struct block_device *bdev, block_t blkstart, block_t blklen) 19888c2ecf20Sopenharmony_ci{ 19898c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 19908c2ecf20Sopenharmony_ci if (f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(bdev)) 19918c2ecf20Sopenharmony_ci return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen); 19928c2ecf20Sopenharmony_ci#endif 19938c2ecf20Sopenharmony_ci return __queue_discard_cmd(sbi, bdev, blkstart, blklen); 19948c2ecf20Sopenharmony_ci} 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_cistatic int f2fs_issue_discard(struct f2fs_sb_info *sbi, 19978c2ecf20Sopenharmony_ci block_t blkstart, block_t blklen) 19988c2ecf20Sopenharmony_ci{ 19998c2ecf20Sopenharmony_ci sector_t start = blkstart, len = 0; 20008c2ecf20Sopenharmony_ci struct block_device *bdev; 20018c2ecf20Sopenharmony_ci struct seg_entry *se; 20028c2ecf20Sopenharmony_ci unsigned int offset; 20038c2ecf20Sopenharmony_ci block_t i; 20048c2ecf20Sopenharmony_ci int err = 0; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci bdev = f2fs_target_device(sbi, blkstart, NULL); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci for (i = blkstart; i < blkstart + blklen; i++, len++) { 20098c2ecf20Sopenharmony_ci if (i != start) { 20108c2ecf20Sopenharmony_ci struct block_device *bdev2 = 20118c2ecf20Sopenharmony_ci f2fs_target_device(sbi, i, NULL); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci if (bdev2 != bdev) { 20148c2ecf20Sopenharmony_ci err = __issue_discard_async(sbi, bdev, 20158c2ecf20Sopenharmony_ci start, len); 20168c2ecf20Sopenharmony_ci if (err) 20178c2ecf20Sopenharmony_ci return err; 20188c2ecf20Sopenharmony_ci bdev = bdev2; 20198c2ecf20Sopenharmony_ci start = i; 20208c2ecf20Sopenharmony_ci len = 0; 20218c2ecf20Sopenharmony_ci } 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, GET_SEGNO(sbi, i)); 20258c2ecf20Sopenharmony_ci offset = GET_BLKOFF_FROM_SEG0(sbi, i); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (!f2fs_test_and_set_bit(offset, se->discard_map)) 20288c2ecf20Sopenharmony_ci sbi->discard_blks--; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci if (len) 20328c2ecf20Sopenharmony_ci err = __issue_discard_async(sbi, bdev, start, len); 20338c2ecf20Sopenharmony_ci return err; 20348c2ecf20Sopenharmony_ci} 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_cistatic bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, 20378c2ecf20Sopenharmony_ci bool check_only) 20388c2ecf20Sopenharmony_ci{ 20398c2ecf20Sopenharmony_ci int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); 20408c2ecf20Sopenharmony_ci int max_blocks = sbi->blocks_per_seg; 20418c2ecf20Sopenharmony_ci struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start); 20428c2ecf20Sopenharmony_ci unsigned long *cur_map = (unsigned long *)se->cur_valid_map; 20438c2ecf20Sopenharmony_ci unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; 20448c2ecf20Sopenharmony_ci unsigned long *discard_map = (unsigned long *)se->discard_map; 20458c2ecf20Sopenharmony_ci unsigned long *dmap = SIT_I(sbi)->tmp_map; 20468c2ecf20Sopenharmony_ci unsigned int start = 0, end = -1; 20478c2ecf20Sopenharmony_ci bool force = (cpc->reason & CP_DISCARD); 20488c2ecf20Sopenharmony_ci struct discard_entry *de = NULL; 20498c2ecf20Sopenharmony_ci struct list_head *head = &SM_I(sbi)->dcc_info->entry_list; 20508c2ecf20Sopenharmony_ci int i; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (se->valid_blocks == max_blocks || !f2fs_hw_support_discard(sbi)) 20538c2ecf20Sopenharmony_ci return false; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci if (!force) { 20568c2ecf20Sopenharmony_ci if (!f2fs_realtime_discard_enable(sbi) || !se->valid_blocks || 20578c2ecf20Sopenharmony_ci SM_I(sbi)->dcc_info->nr_discards >= 20588c2ecf20Sopenharmony_ci SM_I(sbi)->dcc_info->max_discards) 20598c2ecf20Sopenharmony_ci return false; 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci /* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */ 20638c2ecf20Sopenharmony_ci for (i = 0; i < entries; i++) 20648c2ecf20Sopenharmony_ci dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] : 20658c2ecf20Sopenharmony_ci (cur_map[i] ^ ckpt_map[i]) & ckpt_map[i]; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci while (force || SM_I(sbi)->dcc_info->nr_discards <= 20688c2ecf20Sopenharmony_ci SM_I(sbi)->dcc_info->max_discards) { 20698c2ecf20Sopenharmony_ci start = find_rev_next_bit(dmap, max_blocks, end + 1); 20708c2ecf20Sopenharmony_ci if (start >= max_blocks) 20718c2ecf20Sopenharmony_ci break; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci end = find_rev_next_zero_bit(dmap, max_blocks, start + 1); 20748c2ecf20Sopenharmony_ci if (force && start && end != max_blocks 20758c2ecf20Sopenharmony_ci && (end - start) < cpc->trim_minlen) 20768c2ecf20Sopenharmony_ci continue; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (check_only) 20798c2ecf20Sopenharmony_ci return true; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci if (!de) { 20828c2ecf20Sopenharmony_ci de = f2fs_kmem_cache_alloc(discard_entry_slab, 20838c2ecf20Sopenharmony_ci GFP_F2FS_ZERO); 20848c2ecf20Sopenharmony_ci de->start_blkaddr = START_BLOCK(sbi, cpc->trim_start); 20858c2ecf20Sopenharmony_ci list_add_tail(&de->list, head); 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci for (i = start; i < end; i++) 20898c2ecf20Sopenharmony_ci __set_bit_le(i, (void *)de->discard_map); 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci SM_I(sbi)->dcc_info->nr_discards += end - start; 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci return false; 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_cistatic void release_discard_addr(struct discard_entry *entry) 20978c2ecf20Sopenharmony_ci{ 20988c2ecf20Sopenharmony_ci list_del(&entry->list); 20998c2ecf20Sopenharmony_ci kmem_cache_free(discard_entry_slab, entry); 21008c2ecf20Sopenharmony_ci} 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_civoid f2fs_release_discard_addrs(struct f2fs_sb_info *sbi) 21038c2ecf20Sopenharmony_ci{ 21048c2ecf20Sopenharmony_ci struct list_head *head = &(SM_I(sbi)->dcc_info->entry_list); 21058c2ecf20Sopenharmony_ci struct discard_entry *entry, *this; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci /* drop caches */ 21088c2ecf20Sopenharmony_ci list_for_each_entry_safe(entry, this, head, list) 21098c2ecf20Sopenharmony_ci release_discard_addr(entry); 21108c2ecf20Sopenharmony_ci} 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci/* 21138c2ecf20Sopenharmony_ci * Should call f2fs_clear_prefree_segments after checkpoint is done. 21148c2ecf20Sopenharmony_ci */ 21158c2ecf20Sopenharmony_cistatic void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) 21168c2ecf20Sopenharmony_ci{ 21178c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 21188c2ecf20Sopenharmony_ci unsigned int segno; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 21218c2ecf20Sopenharmony_ci for_each_set_bit(segno, dirty_i->dirty_segmap[PRE], MAIN_SEGS(sbi)) 21228c2ecf20Sopenharmony_ci __set_test_and_free(sbi, segno, false); 21238c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_civoid f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, 21278c2ecf20Sopenharmony_ci struct cp_control *cpc) 21288c2ecf20Sopenharmony_ci{ 21298c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 21308c2ecf20Sopenharmony_ci struct list_head *head = &dcc->entry_list; 21318c2ecf20Sopenharmony_ci struct discard_entry *entry, *this; 21328c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 21338c2ecf20Sopenharmony_ci unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; 21348c2ecf20Sopenharmony_ci unsigned int start = 0, end = -1; 21358c2ecf20Sopenharmony_ci unsigned int secno, start_segno; 21368c2ecf20Sopenharmony_ci bool force = (cpc->reason & CP_DISCARD); 21378c2ecf20Sopenharmony_ci bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci while (1) { 21428c2ecf20Sopenharmony_ci int i; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci if (need_align && end != -1) 21458c2ecf20Sopenharmony_ci end--; 21468c2ecf20Sopenharmony_ci start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1); 21478c2ecf20Sopenharmony_ci if (start >= MAIN_SEGS(sbi)) 21488c2ecf20Sopenharmony_ci break; 21498c2ecf20Sopenharmony_ci end = find_next_zero_bit(prefree_map, MAIN_SEGS(sbi), 21508c2ecf20Sopenharmony_ci start + 1); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci if (need_align) { 21538c2ecf20Sopenharmony_ci start = rounddown(start, sbi->segs_per_sec); 21548c2ecf20Sopenharmony_ci end = roundup(end, sbi->segs_per_sec); 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci for (i = start; i < end; i++) { 21588c2ecf20Sopenharmony_ci if (test_and_clear_bit(i, prefree_map)) 21598c2ecf20Sopenharmony_ci dirty_i->nr_dirty[PRE]--; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci if (!f2fs_realtime_discard_enable(sbi)) 21638c2ecf20Sopenharmony_ci continue; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci if (force && start >= cpc->trim_start && 21668c2ecf20Sopenharmony_ci (end - 1) <= cpc->trim_end) 21678c2ecf20Sopenharmony_ci continue; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (!f2fs_lfs_mode(sbi) || !__is_large_section(sbi)) { 21708c2ecf20Sopenharmony_ci f2fs_issue_discard(sbi, START_BLOCK(sbi, start), 21718c2ecf20Sopenharmony_ci (end - start) << sbi->log_blocks_per_seg); 21728c2ecf20Sopenharmony_ci continue; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_cinext: 21758c2ecf20Sopenharmony_ci secno = GET_SEC_FROM_SEG(sbi, start); 21768c2ecf20Sopenharmony_ci start_segno = GET_SEG_FROM_SEC(sbi, secno); 21778c2ecf20Sopenharmony_ci if (!IS_CURSEC(sbi, secno) && 21788c2ecf20Sopenharmony_ci !get_valid_blocks(sbi, start, true)) 21798c2ecf20Sopenharmony_ci f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno), 21808c2ecf20Sopenharmony_ci sbi->segs_per_sec << sbi->log_blocks_per_seg); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci start = start_segno + sbi->segs_per_sec; 21838c2ecf20Sopenharmony_ci if (start < end) 21848c2ecf20Sopenharmony_ci goto next; 21858c2ecf20Sopenharmony_ci else 21868c2ecf20Sopenharmony_ci end = start - 1; 21878c2ecf20Sopenharmony_ci } 21888c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci /* send small discards */ 21918c2ecf20Sopenharmony_ci list_for_each_entry_safe(entry, this, head, list) { 21928c2ecf20Sopenharmony_ci unsigned int cur_pos = 0, next_pos, len, total_len = 0; 21938c2ecf20Sopenharmony_ci bool is_valid = test_bit_le(0, entry->discard_map); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_cifind_next: 21968c2ecf20Sopenharmony_ci if (is_valid) { 21978c2ecf20Sopenharmony_ci next_pos = find_next_zero_bit_le(entry->discard_map, 21988c2ecf20Sopenharmony_ci sbi->blocks_per_seg, cur_pos); 21998c2ecf20Sopenharmony_ci len = next_pos - cur_pos; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci if (f2fs_sb_has_blkzoned(sbi) || 22028c2ecf20Sopenharmony_ci (force && len < cpc->trim_minlen)) 22038c2ecf20Sopenharmony_ci goto skip; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci f2fs_issue_discard(sbi, entry->start_blkaddr + cur_pos, 22068c2ecf20Sopenharmony_ci len); 22078c2ecf20Sopenharmony_ci total_len += len; 22088c2ecf20Sopenharmony_ci } else { 22098c2ecf20Sopenharmony_ci next_pos = find_next_bit_le(entry->discard_map, 22108c2ecf20Sopenharmony_ci sbi->blocks_per_seg, cur_pos); 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ciskip: 22138c2ecf20Sopenharmony_ci cur_pos = next_pos; 22148c2ecf20Sopenharmony_ci is_valid = !is_valid; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci if (cur_pos < sbi->blocks_per_seg) 22178c2ecf20Sopenharmony_ci goto find_next; 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci release_discard_addr(entry); 22208c2ecf20Sopenharmony_ci dcc->nr_discards -= total_len; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci wake_up_discard_thread(sbi, false); 22248c2ecf20Sopenharmony_ci} 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_cistatic int create_discard_cmd_control(struct f2fs_sb_info *sbi) 22278c2ecf20Sopenharmony_ci{ 22288c2ecf20Sopenharmony_ci dev_t dev = sbi->sb->s_bdev->bd_dev; 22298c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc; 22308c2ecf20Sopenharmony_ci int err = 0, i; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci if (SM_I(sbi)->dcc_info) { 22338c2ecf20Sopenharmony_ci dcc = SM_I(sbi)->dcc_info; 22348c2ecf20Sopenharmony_ci goto init_thread; 22358c2ecf20Sopenharmony_ci } 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci dcc = f2fs_kzalloc(sbi, sizeof(struct discard_cmd_control), GFP_KERNEL); 22388c2ecf20Sopenharmony_ci if (!dcc) 22398c2ecf20Sopenharmony_ci return -ENOMEM; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci dcc->discard_granularity = DISCARD_GRAN_BG; 22428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dcc->entry_list); 22438c2ecf20Sopenharmony_ci for (i = 0; i < MAX_PLIST_NUM; i++) 22448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dcc->pend_list[i]); 22458c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dcc->wait_list); 22468c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dcc->fstrim_list); 22478c2ecf20Sopenharmony_ci mutex_init(&dcc->cmd_lock); 22488c2ecf20Sopenharmony_ci atomic_set(&dcc->issued_discard, 0); 22498c2ecf20Sopenharmony_ci atomic_set(&dcc->queued_discard, 0); 22508c2ecf20Sopenharmony_ci atomic_set(&dcc->discard_cmd_cnt, 0); 22518c2ecf20Sopenharmony_ci dcc->nr_discards = 0; 22528c2ecf20Sopenharmony_ci dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg; 22538c2ecf20Sopenharmony_ci dcc->undiscard_blks = 0; 22548c2ecf20Sopenharmony_ci dcc->next_pos = 0; 22558c2ecf20Sopenharmony_ci dcc->root = RB_ROOT_CACHED; 22568c2ecf20Sopenharmony_ci dcc->rbtree_check = false; 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci init_waitqueue_head(&dcc->discard_wait_queue); 22598c2ecf20Sopenharmony_ci SM_I(sbi)->dcc_info = dcc; 22608c2ecf20Sopenharmony_ciinit_thread: 22618c2ecf20Sopenharmony_ci dcc->f2fs_issue_discard = kthread_run(issue_discard_thread, sbi, 22628c2ecf20Sopenharmony_ci "f2fs_discard-%u:%u", MAJOR(dev), MINOR(dev)); 22638c2ecf20Sopenharmony_ci if (IS_ERR(dcc->f2fs_issue_discard)) { 22648c2ecf20Sopenharmony_ci err = PTR_ERR(dcc->f2fs_issue_discard); 22658c2ecf20Sopenharmony_ci kfree(dcc); 22668c2ecf20Sopenharmony_ci SM_I(sbi)->dcc_info = NULL; 22678c2ecf20Sopenharmony_ci return err; 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci return err; 22718c2ecf20Sopenharmony_ci} 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_cistatic void destroy_discard_cmd_control(struct f2fs_sb_info *sbi) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci if (!dcc) 22788c2ecf20Sopenharmony_ci return; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci f2fs_stop_discard_thread(sbi); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci /* 22838c2ecf20Sopenharmony_ci * Recovery can cache discard commands, so in error path of 22848c2ecf20Sopenharmony_ci * fill_super(), it needs to give a chance to handle them. 22858c2ecf20Sopenharmony_ci */ 22868c2ecf20Sopenharmony_ci if (unlikely(atomic_read(&dcc->discard_cmd_cnt))) 22878c2ecf20Sopenharmony_ci f2fs_issue_discard_timeout(sbi); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci kfree(dcc); 22908c2ecf20Sopenharmony_ci SM_I(sbi)->dcc_info = NULL; 22918c2ecf20Sopenharmony_ci} 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_cistatic bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno) 22948c2ecf20Sopenharmony_ci{ 22958c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap)) { 22988c2ecf20Sopenharmony_ci sit_i->dirty_sentries++; 22998c2ecf20Sopenharmony_ci return false; 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci return true; 23038c2ecf20Sopenharmony_ci} 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_cistatic void __set_sit_entry_type(struct f2fs_sb_info *sbi, int type, 23068c2ecf20Sopenharmony_ci unsigned int segno, int modified) 23078c2ecf20Sopenharmony_ci{ 23088c2ecf20Sopenharmony_ci struct seg_entry *se = get_seg_entry(sbi, segno); 23098c2ecf20Sopenharmony_ci se->type = type; 23108c2ecf20Sopenharmony_ci if (modified) 23118c2ecf20Sopenharmony_ci __mark_sit_entry_dirty(sbi, segno); 23128c2ecf20Sopenharmony_ci} 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_cistatic inline unsigned long long get_segment_mtime(struct f2fs_sb_info *sbi, 23158c2ecf20Sopenharmony_ci block_t blkaddr) 23168c2ecf20Sopenharmony_ci{ 23178c2ecf20Sopenharmony_ci unsigned int segno = GET_SEGNO(sbi, blkaddr); 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci if (segno == NULL_SEGNO) 23208c2ecf20Sopenharmony_ci return 0; 23218c2ecf20Sopenharmony_ci return get_seg_entry(sbi, segno)->mtime; 23228c2ecf20Sopenharmony_ci} 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_cistatic void update_segment_mtime(struct f2fs_sb_info *sbi, block_t blkaddr, 23258c2ecf20Sopenharmony_ci unsigned long long old_mtime) 23268c2ecf20Sopenharmony_ci{ 23278c2ecf20Sopenharmony_ci struct seg_entry *se; 23288c2ecf20Sopenharmony_ci unsigned int segno = GET_SEGNO(sbi, blkaddr); 23298c2ecf20Sopenharmony_ci unsigned long long ctime = get_mtime(sbi, false); 23308c2ecf20Sopenharmony_ci unsigned long long mtime = old_mtime ? old_mtime : ctime; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci if (segno == NULL_SEGNO) 23338c2ecf20Sopenharmony_ci return; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, segno); 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci if (!se->mtime) 23388c2ecf20Sopenharmony_ci se->mtime = mtime; 23398c2ecf20Sopenharmony_ci else 23408c2ecf20Sopenharmony_ci se->mtime = div_u64(se->mtime * se->valid_blocks + mtime, 23418c2ecf20Sopenharmony_ci se->valid_blocks + 1); 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci if (ctime > SIT_I(sbi)->max_mtime) 23448c2ecf20Sopenharmony_ci SIT_I(sbi)->max_mtime = ctime; 23458c2ecf20Sopenharmony_ci} 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_cistatic void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) 23488c2ecf20Sopenharmony_ci{ 23498c2ecf20Sopenharmony_ci struct seg_entry *se; 23508c2ecf20Sopenharmony_ci unsigned int segno, offset; 23518c2ecf20Sopenharmony_ci long int new_vblocks; 23528c2ecf20Sopenharmony_ci bool exist; 23538c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 23548c2ecf20Sopenharmony_ci bool mir_exist; 23558c2ecf20Sopenharmony_ci#endif 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci segno = GET_SEGNO(sbi, blkaddr); 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, segno); 23608c2ecf20Sopenharmony_ci new_vblocks = se->valid_blocks + del; 23618c2ecf20Sopenharmony_ci offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, (new_vblocks < 0 || 23648c2ecf20Sopenharmony_ci (new_vblocks > f2fs_usable_blks_in_seg(sbi, segno)))); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci se->valid_blocks = new_vblocks; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci /* Update valid block bitmap */ 23698c2ecf20Sopenharmony_ci if (del > 0) { 23708c2ecf20Sopenharmony_ci exist = f2fs_test_and_set_bit(offset, se->cur_valid_map); 23718c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 23728c2ecf20Sopenharmony_ci mir_exist = f2fs_test_and_set_bit(offset, 23738c2ecf20Sopenharmony_ci se->cur_valid_map_mir); 23748c2ecf20Sopenharmony_ci if (unlikely(exist != mir_exist)) { 23758c2ecf20Sopenharmony_ci f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d", 23768c2ecf20Sopenharmony_ci blkaddr, exist); 23778c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, 1); 23788c2ecf20Sopenharmony_ci } 23798c2ecf20Sopenharmony_ci#endif 23808c2ecf20Sopenharmony_ci if (unlikely(exist)) { 23818c2ecf20Sopenharmony_ci f2fs_err(sbi, "Bitmap was wrongly set, blk:%u", 23828c2ecf20Sopenharmony_ci blkaddr); 23838c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, 1); 23848c2ecf20Sopenharmony_ci se->valid_blocks--; 23858c2ecf20Sopenharmony_ci del = 0; 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci if (!f2fs_test_and_set_bit(offset, se->discard_map)) 23898c2ecf20Sopenharmony_ci sbi->discard_blks--; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci /* 23928c2ecf20Sopenharmony_ci * SSR should never reuse block which is checkpointed 23938c2ecf20Sopenharmony_ci * or newly invalidated. 23948c2ecf20Sopenharmony_ci */ 23958c2ecf20Sopenharmony_ci if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { 23968c2ecf20Sopenharmony_ci if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) 23978c2ecf20Sopenharmony_ci se->ckpt_valid_blocks++; 23988c2ecf20Sopenharmony_ci } 23998c2ecf20Sopenharmony_ci } else { 24008c2ecf20Sopenharmony_ci exist = f2fs_test_and_clear_bit(offset, se->cur_valid_map); 24018c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 24028c2ecf20Sopenharmony_ci mir_exist = f2fs_test_and_clear_bit(offset, 24038c2ecf20Sopenharmony_ci se->cur_valid_map_mir); 24048c2ecf20Sopenharmony_ci if (unlikely(exist != mir_exist)) { 24058c2ecf20Sopenharmony_ci f2fs_err(sbi, "Inconsistent error when clearing bitmap, blk:%u, old bit:%d", 24068c2ecf20Sopenharmony_ci blkaddr, exist); 24078c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, 1); 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci#endif 24108c2ecf20Sopenharmony_ci if (unlikely(!exist)) { 24118c2ecf20Sopenharmony_ci f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u", 24128c2ecf20Sopenharmony_ci blkaddr); 24138c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, 1); 24148c2ecf20Sopenharmony_ci se->valid_blocks++; 24158c2ecf20Sopenharmony_ci del = 0; 24168c2ecf20Sopenharmony_ci } else if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { 24178c2ecf20Sopenharmony_ci /* 24188c2ecf20Sopenharmony_ci * If checkpoints are off, we must not reuse data that 24198c2ecf20Sopenharmony_ci * was used in the previous checkpoint. If it was used 24208c2ecf20Sopenharmony_ci * before, we must track that to know how much space we 24218c2ecf20Sopenharmony_ci * really have. 24228c2ecf20Sopenharmony_ci */ 24238c2ecf20Sopenharmony_ci if (f2fs_test_bit(offset, se->ckpt_valid_map)) { 24248c2ecf20Sopenharmony_ci spin_lock(&sbi->stat_lock); 24258c2ecf20Sopenharmony_ci sbi->unusable_block_count++; 24268c2ecf20Sopenharmony_ci spin_unlock(&sbi->stat_lock); 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (f2fs_test_and_clear_bit(offset, se->discard_map)) 24318c2ecf20Sopenharmony_ci sbi->discard_blks++; 24328c2ecf20Sopenharmony_ci } 24338c2ecf20Sopenharmony_ci if (!f2fs_test_bit(offset, se->ckpt_valid_map)) 24348c2ecf20Sopenharmony_ci se->ckpt_valid_blocks += del; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci __mark_sit_entry_dirty(sbi, segno); 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci /* update total number of valid blocks to be written in ckpt area */ 24398c2ecf20Sopenharmony_ci SIT_I(sbi)->written_valid_blocks += del; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) 24428c2ecf20Sopenharmony_ci get_sec_entry(sbi, segno)->valid_blocks += del; 24438c2ecf20Sopenharmony_ci} 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_civoid f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) 24468c2ecf20Sopenharmony_ci{ 24478c2ecf20Sopenharmony_ci unsigned int segno = GET_SEGNO(sbi, addr); 24488c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, addr == NULL_ADDR); 24518c2ecf20Sopenharmony_ci if (addr == NEW_ADDR || addr == COMPRESS_ADDR) 24528c2ecf20Sopenharmony_ci return; 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci invalidate_mapping_pages(META_MAPPING(sbi), addr, addr); 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci /* add it into sit main buffer */ 24578c2ecf20Sopenharmony_ci down_write(&sit_i->sentry_lock); 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci update_segment_mtime(sbi, addr, 0); 24608c2ecf20Sopenharmony_ci update_sit_entry(sbi, addr, -1); 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci /* add it into dirty seglist */ 24638c2ecf20Sopenharmony_ci locate_dirty_segment(sbi, segno); 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci up_write(&sit_i->sentry_lock); 24668c2ecf20Sopenharmony_ci} 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_cibool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr) 24698c2ecf20Sopenharmony_ci{ 24708c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 24718c2ecf20Sopenharmony_ci unsigned int segno, offset; 24728c2ecf20Sopenharmony_ci struct seg_entry *se; 24738c2ecf20Sopenharmony_ci bool is_cp = false; 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci if (!__is_valid_data_blkaddr(blkaddr)) 24768c2ecf20Sopenharmony_ci return true; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci down_read(&sit_i->sentry_lock); 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci segno = GET_SEGNO(sbi, blkaddr); 24818c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, segno); 24828c2ecf20Sopenharmony_ci offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci if (f2fs_test_bit(offset, se->ckpt_valid_map)) 24858c2ecf20Sopenharmony_ci is_cp = true; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci up_read(&sit_i->sentry_lock); 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci return is_cp; 24908c2ecf20Sopenharmony_ci} 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci/* 24938c2ecf20Sopenharmony_ci * This function should be resided under the curseg_mutex lock 24948c2ecf20Sopenharmony_ci */ 24958c2ecf20Sopenharmony_cistatic void __add_sum_entry(struct f2fs_sb_info *sbi, int type, 24968c2ecf20Sopenharmony_ci struct f2fs_summary *sum) 24978c2ecf20Sopenharmony_ci{ 24988c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 24998c2ecf20Sopenharmony_ci void *addr = curseg->sum_blk; 25008c2ecf20Sopenharmony_ci addr += curseg->next_blkoff * sizeof(struct f2fs_summary); 25018c2ecf20Sopenharmony_ci memcpy(addr, sum, sizeof(struct f2fs_summary)); 25028c2ecf20Sopenharmony_ci} 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci/* 25058c2ecf20Sopenharmony_ci * Calculate the number of current summary pages for writing 25068c2ecf20Sopenharmony_ci */ 25078c2ecf20Sopenharmony_ciint f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra) 25088c2ecf20Sopenharmony_ci{ 25098c2ecf20Sopenharmony_ci int valid_sum_count = 0; 25108c2ecf20Sopenharmony_ci int i, sum_in_page; 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { 25138c2ecf20Sopenharmony_ci if (sbi->ckpt->alloc_type[i] == SSR) 25148c2ecf20Sopenharmony_ci valid_sum_count += sbi->blocks_per_seg; 25158c2ecf20Sopenharmony_ci else { 25168c2ecf20Sopenharmony_ci if (for_ra) 25178c2ecf20Sopenharmony_ci valid_sum_count += le16_to_cpu( 25188c2ecf20Sopenharmony_ci F2FS_CKPT(sbi)->cur_data_blkoff[i]); 25198c2ecf20Sopenharmony_ci else 25208c2ecf20Sopenharmony_ci valid_sum_count += curseg_blkoff(sbi, i); 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci sum_in_page = (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE - 25258c2ecf20Sopenharmony_ci SUM_FOOTER_SIZE) / SUMMARY_SIZE; 25268c2ecf20Sopenharmony_ci if (valid_sum_count <= sum_in_page) 25278c2ecf20Sopenharmony_ci return 1; 25288c2ecf20Sopenharmony_ci else if ((valid_sum_count - sum_in_page) <= 25298c2ecf20Sopenharmony_ci (PAGE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE) 25308c2ecf20Sopenharmony_ci return 2; 25318c2ecf20Sopenharmony_ci return 3; 25328c2ecf20Sopenharmony_ci} 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci/* 25358c2ecf20Sopenharmony_ci * Caller should put this summary page 25368c2ecf20Sopenharmony_ci */ 25378c2ecf20Sopenharmony_cistruct page *f2fs_get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno) 25388c2ecf20Sopenharmony_ci{ 25398c2ecf20Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) 25408c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 25418c2ecf20Sopenharmony_ci return f2fs_get_meta_page_retry(sbi, GET_SUM_BLOCK(sbi, segno)); 25428c2ecf20Sopenharmony_ci} 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_civoid f2fs_update_meta_page(struct f2fs_sb_info *sbi, 25458c2ecf20Sopenharmony_ci void *src, block_t blk_addr) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci struct page *page = f2fs_grab_meta_page(sbi, blk_addr); 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci memcpy(page_address(page), src, PAGE_SIZE); 25508c2ecf20Sopenharmony_ci set_page_dirty(page); 25518c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 25528c2ecf20Sopenharmony_ci} 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_cistatic void write_sum_page(struct f2fs_sb_info *sbi, 25558c2ecf20Sopenharmony_ci struct f2fs_summary_block *sum_blk, block_t blk_addr) 25568c2ecf20Sopenharmony_ci{ 25578c2ecf20Sopenharmony_ci f2fs_update_meta_page(sbi, (void *)sum_blk, blk_addr); 25588c2ecf20Sopenharmony_ci} 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_cistatic void write_current_sum_page(struct f2fs_sb_info *sbi, 25618c2ecf20Sopenharmony_ci int type, block_t blk_addr) 25628c2ecf20Sopenharmony_ci{ 25638c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 25648c2ecf20Sopenharmony_ci struct page *page = f2fs_grab_meta_page(sbi, blk_addr); 25658c2ecf20Sopenharmony_ci struct f2fs_summary_block *src = curseg->sum_blk; 25668c2ecf20Sopenharmony_ci struct f2fs_summary_block *dst; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci dst = (struct f2fs_summary_block *)page_address(page); 25698c2ecf20Sopenharmony_ci memset(dst, 0, PAGE_SIZE); 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci mutex_lock(&curseg->curseg_mutex); 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci down_read(&curseg->journal_rwsem); 25748c2ecf20Sopenharmony_ci memcpy(&dst->journal, curseg->journal, SUM_JOURNAL_SIZE); 25758c2ecf20Sopenharmony_ci up_read(&curseg->journal_rwsem); 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE); 25788c2ecf20Sopenharmony_ci memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci mutex_unlock(&curseg->curseg_mutex); 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci set_page_dirty(page); 25838c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 25848c2ecf20Sopenharmony_ci} 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_cistatic int is_next_segment_free(struct f2fs_sb_info *sbi, 25878c2ecf20Sopenharmony_ci struct curseg_info *curseg, int type) 25888c2ecf20Sopenharmony_ci{ 25898c2ecf20Sopenharmony_ci unsigned int segno = curseg->segno + 1; 25908c2ecf20Sopenharmony_ci struct free_segmap_info *free_i = FREE_I(sbi); 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci if (segno < MAIN_SEGS(sbi) && segno % sbi->segs_per_sec) 25938c2ecf20Sopenharmony_ci return !test_bit(segno, free_i->free_segmap); 25948c2ecf20Sopenharmony_ci return 0; 25958c2ecf20Sopenharmony_ci} 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci/* 25988c2ecf20Sopenharmony_ci * Find a new segment from the free segments bitmap to right order 25998c2ecf20Sopenharmony_ci * This function should be returned with success, otherwise BUG 26008c2ecf20Sopenharmony_ci */ 26018c2ecf20Sopenharmony_cistatic void get_new_segment(struct f2fs_sb_info *sbi, 26028c2ecf20Sopenharmony_ci unsigned int *newseg, bool new_sec, int dir) 26038c2ecf20Sopenharmony_ci{ 26048c2ecf20Sopenharmony_ci struct free_segmap_info *free_i = FREE_I(sbi); 26058c2ecf20Sopenharmony_ci unsigned int segno, secno, zoneno; 26068c2ecf20Sopenharmony_ci unsigned int total_zones = MAIN_SECS(sbi) / sbi->secs_per_zone; 26078c2ecf20Sopenharmony_ci unsigned int hint = GET_SEC_FROM_SEG(sbi, *newseg); 26088c2ecf20Sopenharmony_ci unsigned int old_zoneno = GET_ZONE_FROM_SEG(sbi, *newseg); 26098c2ecf20Sopenharmony_ci unsigned int left_start = hint; 26108c2ecf20Sopenharmony_ci bool init = true; 26118c2ecf20Sopenharmony_ci int go_left = 0; 26128c2ecf20Sopenharmony_ci int i; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci spin_lock(&free_i->segmap_lock); 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) { 26178c2ecf20Sopenharmony_ci segno = find_next_zero_bit(free_i->free_segmap, 26188c2ecf20Sopenharmony_ci GET_SEG_FROM_SEC(sbi, hint + 1), *newseg + 1); 26198c2ecf20Sopenharmony_ci if (segno < GET_SEG_FROM_SEC(sbi, hint + 1)) 26208c2ecf20Sopenharmony_ci goto got_it; 26218c2ecf20Sopenharmony_ci } 26228c2ecf20Sopenharmony_cifind_other_zone: 26238c2ecf20Sopenharmony_ci secno = find_next_zero_bit(free_i->free_secmap, MAIN_SECS(sbi), hint); 26248c2ecf20Sopenharmony_ci if (secno >= MAIN_SECS(sbi)) { 26258c2ecf20Sopenharmony_ci if (dir == ALLOC_RIGHT) { 26268c2ecf20Sopenharmony_ci secno = find_next_zero_bit(free_i->free_secmap, 26278c2ecf20Sopenharmony_ci MAIN_SECS(sbi), 0); 26288c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi)); 26298c2ecf20Sopenharmony_ci } else { 26308c2ecf20Sopenharmony_ci go_left = 1; 26318c2ecf20Sopenharmony_ci left_start = hint - 1; 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci } 26348c2ecf20Sopenharmony_ci if (go_left == 0) 26358c2ecf20Sopenharmony_ci goto skip_left; 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci while (test_bit(left_start, free_i->free_secmap)) { 26388c2ecf20Sopenharmony_ci if (left_start > 0) { 26398c2ecf20Sopenharmony_ci left_start--; 26408c2ecf20Sopenharmony_ci continue; 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci left_start = find_next_zero_bit(free_i->free_secmap, 26438c2ecf20Sopenharmony_ci MAIN_SECS(sbi), 0); 26448c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi)); 26458c2ecf20Sopenharmony_ci break; 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci secno = left_start; 26488c2ecf20Sopenharmony_ciskip_left: 26498c2ecf20Sopenharmony_ci segno = GET_SEG_FROM_SEC(sbi, secno); 26508c2ecf20Sopenharmony_ci zoneno = GET_ZONE_FROM_SEC(sbi, secno); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci /* give up on finding another zone */ 26538c2ecf20Sopenharmony_ci if (!init) 26548c2ecf20Sopenharmony_ci goto got_it; 26558c2ecf20Sopenharmony_ci if (sbi->secs_per_zone == 1) 26568c2ecf20Sopenharmony_ci goto got_it; 26578c2ecf20Sopenharmony_ci if (zoneno == old_zoneno) 26588c2ecf20Sopenharmony_ci goto got_it; 26598c2ecf20Sopenharmony_ci if (dir == ALLOC_LEFT) { 26608c2ecf20Sopenharmony_ci if (!go_left && zoneno + 1 >= total_zones) 26618c2ecf20Sopenharmony_ci goto got_it; 26628c2ecf20Sopenharmony_ci if (go_left && zoneno == 0) 26638c2ecf20Sopenharmony_ci goto got_it; 26648c2ecf20Sopenharmony_ci } 26658c2ecf20Sopenharmony_ci for (i = 0; i < NR_CURSEG_TYPE; i++) 26668c2ecf20Sopenharmony_ci if (CURSEG_I(sbi, i)->zone == zoneno) 26678c2ecf20Sopenharmony_ci break; 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci if (i < NR_CURSEG_TYPE) { 26708c2ecf20Sopenharmony_ci /* zone is in user, try another */ 26718c2ecf20Sopenharmony_ci if (go_left) 26728c2ecf20Sopenharmony_ci hint = zoneno * sbi->secs_per_zone - 1; 26738c2ecf20Sopenharmony_ci else if (zoneno + 1 >= total_zones) 26748c2ecf20Sopenharmony_ci hint = 0; 26758c2ecf20Sopenharmony_ci else 26768c2ecf20Sopenharmony_ci hint = (zoneno + 1) * sbi->secs_per_zone; 26778c2ecf20Sopenharmony_ci init = false; 26788c2ecf20Sopenharmony_ci goto find_other_zone; 26798c2ecf20Sopenharmony_ci } 26808c2ecf20Sopenharmony_cigot_it: 26818c2ecf20Sopenharmony_ci /* set it as dirty segment in free segmap */ 26828c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap)); 26838c2ecf20Sopenharmony_ci __set_inuse(sbi, segno); 26848c2ecf20Sopenharmony_ci *newseg = segno; 26858c2ecf20Sopenharmony_ci spin_unlock(&free_i->segmap_lock); 26868c2ecf20Sopenharmony_ci} 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_cistatic void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) 26898c2ecf20Sopenharmony_ci{ 26908c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 26918c2ecf20Sopenharmony_ci struct summary_footer *sum_footer; 26928c2ecf20Sopenharmony_ci unsigned short seg_type = curseg->seg_type; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci curseg->inited = true; 26958c2ecf20Sopenharmony_ci curseg->segno = curseg->next_segno; 26968c2ecf20Sopenharmony_ci curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno); 26978c2ecf20Sopenharmony_ci curseg->next_blkoff = 0; 26988c2ecf20Sopenharmony_ci curseg->next_segno = NULL_SEGNO; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci sum_footer = &(curseg->sum_blk->footer); 27018c2ecf20Sopenharmony_ci memset(sum_footer, 0, sizeof(struct summary_footer)); 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci sanity_check_seg_type(sbi, seg_type); 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci if (IS_DATASEG(seg_type)) 27068c2ecf20Sopenharmony_ci SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA); 27078c2ecf20Sopenharmony_ci if (IS_NODESEG(seg_type)) 27088c2ecf20Sopenharmony_ci SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE); 27098c2ecf20Sopenharmony_ci __set_sit_entry_type(sbi, seg_type, curseg->segno, modified); 27108c2ecf20Sopenharmony_ci} 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_cistatic unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) 27138c2ecf20Sopenharmony_ci{ 27148c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 27158c2ecf20Sopenharmony_ci unsigned short seg_type = curseg->seg_type; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci sanity_check_seg_type(sbi, seg_type); 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci /* if segs_per_sec is large than 1, we need to keep original policy. */ 27208c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) 27218c2ecf20Sopenharmony_ci return curseg->segno; 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci /* inmem log may not locate on any segment after mount */ 27248c2ecf20Sopenharmony_ci if (!curseg->inited) 27258c2ecf20Sopenharmony_ci return 0; 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) 27288c2ecf20Sopenharmony_ci return 0; 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci if (test_opt(sbi, NOHEAP) && 27318c2ecf20Sopenharmony_ci (seg_type == CURSEG_HOT_DATA || IS_NODESEG(seg_type))) 27328c2ecf20Sopenharmony_ci return 0; 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci if (SIT_I(sbi)->last_victim[ALLOC_NEXT]) 27358c2ecf20Sopenharmony_ci return SIT_I(sbi)->last_victim[ALLOC_NEXT]; 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci /* find segments from 0 to reuse freed segments */ 27388c2ecf20Sopenharmony_ci if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE) 27398c2ecf20Sopenharmony_ci return 0; 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci return curseg->segno; 27428c2ecf20Sopenharmony_ci} 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci/* 27458c2ecf20Sopenharmony_ci * Allocate a current working segment. 27468c2ecf20Sopenharmony_ci * This function always allocates a free segment in LFS manner. 27478c2ecf20Sopenharmony_ci */ 27488c2ecf20Sopenharmony_cistatic void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) 27498c2ecf20Sopenharmony_ci{ 27508c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 27518c2ecf20Sopenharmony_ci unsigned short seg_type = curseg->seg_type; 27528c2ecf20Sopenharmony_ci unsigned int segno = curseg->segno; 27538c2ecf20Sopenharmony_ci int dir = ALLOC_LEFT; 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci if (curseg->inited) 27568c2ecf20Sopenharmony_ci write_sum_page(sbi, curseg->sum_blk, 27578c2ecf20Sopenharmony_ci GET_SUM_BLOCK(sbi, segno)); 27588c2ecf20Sopenharmony_ci if (seg_type == CURSEG_WARM_DATA || seg_type == CURSEG_COLD_DATA) 27598c2ecf20Sopenharmony_ci dir = ALLOC_RIGHT; 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci if (test_opt(sbi, NOHEAP)) 27628c2ecf20Sopenharmony_ci dir = ALLOC_RIGHT; 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci segno = __get_next_segno(sbi, type); 27658c2ecf20Sopenharmony_ci get_new_segment(sbi, &segno, new_sec, dir); 27668c2ecf20Sopenharmony_ci curseg->next_segno = segno; 27678c2ecf20Sopenharmony_ci reset_curseg(sbi, type, 1); 27688c2ecf20Sopenharmony_ci curseg->alloc_type = LFS; 27698c2ecf20Sopenharmony_ci} 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_cistatic void __next_free_blkoff(struct f2fs_sb_info *sbi, 27728c2ecf20Sopenharmony_ci struct curseg_info *seg, block_t start) 27738c2ecf20Sopenharmony_ci{ 27748c2ecf20Sopenharmony_ci struct seg_entry *se = get_seg_entry(sbi, seg->segno); 27758c2ecf20Sopenharmony_ci int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); 27768c2ecf20Sopenharmony_ci unsigned long *target_map = SIT_I(sbi)->tmp_map; 27778c2ecf20Sopenharmony_ci unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; 27788c2ecf20Sopenharmony_ci unsigned long *cur_map = (unsigned long *)se->cur_valid_map; 27798c2ecf20Sopenharmony_ci int i, pos; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci for (i = 0; i < entries; i++) 27828c2ecf20Sopenharmony_ci target_map[i] = ckpt_map[i] | cur_map[i]; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci pos = find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start); 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci seg->next_blkoff = pos; 27878c2ecf20Sopenharmony_ci} 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci/* 27908c2ecf20Sopenharmony_ci * If a segment is written by LFS manner, next block offset is just obtained 27918c2ecf20Sopenharmony_ci * by increasing the current block offset. However, if a segment is written by 27928c2ecf20Sopenharmony_ci * SSR manner, next block offset obtained by calling __next_free_blkoff 27938c2ecf20Sopenharmony_ci */ 27948c2ecf20Sopenharmony_cistatic void __refresh_next_blkoff(struct f2fs_sb_info *sbi, 27958c2ecf20Sopenharmony_ci struct curseg_info *seg) 27968c2ecf20Sopenharmony_ci{ 27978c2ecf20Sopenharmony_ci if (seg->alloc_type == SSR) 27988c2ecf20Sopenharmony_ci __next_free_blkoff(sbi, seg, seg->next_blkoff + 1); 27998c2ecf20Sopenharmony_ci else 28008c2ecf20Sopenharmony_ci seg->next_blkoff++; 28018c2ecf20Sopenharmony_ci} 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_cibool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) 28048c2ecf20Sopenharmony_ci{ 28058c2ecf20Sopenharmony_ci struct seg_entry *se = get_seg_entry(sbi, segno); 28068c2ecf20Sopenharmony_ci int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long); 28078c2ecf20Sopenharmony_ci unsigned long *target_map = SIT_I(sbi)->tmp_map; 28088c2ecf20Sopenharmony_ci unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; 28098c2ecf20Sopenharmony_ci unsigned long *cur_map = (unsigned long *)se->cur_valid_map; 28108c2ecf20Sopenharmony_ci int i, pos; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci for (i = 0; i < entries; i++) 28138c2ecf20Sopenharmony_ci target_map[i] = ckpt_map[i] | cur_map[i]; 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci pos = find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, 0); 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci return pos < sbi->blocks_per_seg; 28188c2ecf20Sopenharmony_ci} 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci/* 28218c2ecf20Sopenharmony_ci * This function always allocates a used segment(from dirty seglist) by SSR 28228c2ecf20Sopenharmony_ci * manner, so it should recover the existing segment information of valid blocks 28238c2ecf20Sopenharmony_ci */ 28248c2ecf20Sopenharmony_cistatic void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush) 28258c2ecf20Sopenharmony_ci{ 28268c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 28278c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 28288c2ecf20Sopenharmony_ci unsigned int new_segno = curseg->next_segno; 28298c2ecf20Sopenharmony_ci struct f2fs_summary_block *sum_node; 28308c2ecf20Sopenharmony_ci struct page *sum_page; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci if (flush) 28338c2ecf20Sopenharmony_ci write_sum_page(sbi, curseg->sum_blk, 28348c2ecf20Sopenharmony_ci GET_SUM_BLOCK(sbi, curseg->segno)); 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci __set_test_and_inuse(sbi, new_segno); 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 28398c2ecf20Sopenharmony_ci __remove_dirty_segment(sbi, new_segno, PRE); 28408c2ecf20Sopenharmony_ci __remove_dirty_segment(sbi, new_segno, DIRTY); 28418c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci reset_curseg(sbi, type, 1); 28448c2ecf20Sopenharmony_ci curseg->alloc_type = SSR; 28458c2ecf20Sopenharmony_ci __next_free_blkoff(sbi, curseg, 0); 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_ci sum_page = f2fs_get_sum_page(sbi, new_segno); 28488c2ecf20Sopenharmony_ci if (IS_ERR(sum_page)) { 28498c2ecf20Sopenharmony_ci /* GC won't be able to use stale summary pages by cp_error */ 28508c2ecf20Sopenharmony_ci memset(curseg->sum_blk, 0, SUM_ENTRY_SIZE); 28518c2ecf20Sopenharmony_ci return; 28528c2ecf20Sopenharmony_ci } 28538c2ecf20Sopenharmony_ci sum_node = (struct f2fs_summary_block *)page_address(sum_page); 28548c2ecf20Sopenharmony_ci memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); 28558c2ecf20Sopenharmony_ci f2fs_put_page(sum_page, 1); 28568c2ecf20Sopenharmony_ci} 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_cistatic int get_ssr_segment(struct f2fs_sb_info *sbi, int type, 28598c2ecf20Sopenharmony_ci int alloc_mode, unsigned long long age); 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_cistatic void get_atssr_segment(struct f2fs_sb_info *sbi, int type, 28628c2ecf20Sopenharmony_ci int target_type, int alloc_mode, 28638c2ecf20Sopenharmony_ci unsigned long long age) 28648c2ecf20Sopenharmony_ci{ 28658c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci curseg->seg_type = target_type; 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci if (get_ssr_segment(sbi, type, alloc_mode, age)) { 28708c2ecf20Sopenharmony_ci struct seg_entry *se = get_seg_entry(sbi, curseg->next_segno); 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci curseg->seg_type = se->type; 28738c2ecf20Sopenharmony_ci change_curseg(sbi, type, true); 28748c2ecf20Sopenharmony_ci } else { 28758c2ecf20Sopenharmony_ci /* allocate cold segment by default */ 28768c2ecf20Sopenharmony_ci curseg->seg_type = CURSEG_COLD_DATA; 28778c2ecf20Sopenharmony_ci new_curseg(sbi, type, true); 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci stat_inc_seg_type(sbi, curseg); 28808c2ecf20Sopenharmony_ci} 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_cistatic void __f2fs_init_atgc_curseg(struct f2fs_sb_info *sbi) 28838c2ecf20Sopenharmony_ci{ 28848c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC); 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci if (!sbi->am.atgc_enabled) 28878c2ecf20Sopenharmony_ci return; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci down_read(&SM_I(sbi)->curseg_lock); 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci mutex_lock(&curseg->curseg_mutex); 28928c2ecf20Sopenharmony_ci down_write(&SIT_I(sbi)->sentry_lock); 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci get_atssr_segment(sbi, CURSEG_ALL_DATA_ATGC, CURSEG_COLD_DATA, SSR, 0); 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci up_write(&SIT_I(sbi)->sentry_lock); 28978c2ecf20Sopenharmony_ci mutex_unlock(&curseg->curseg_mutex); 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci up_read(&SM_I(sbi)->curseg_lock); 29008c2ecf20Sopenharmony_ci 29018c2ecf20Sopenharmony_ci} 29028c2ecf20Sopenharmony_civoid f2fs_init_inmem_curseg(struct f2fs_sb_info *sbi) 29038c2ecf20Sopenharmony_ci{ 29048c2ecf20Sopenharmony_ci __f2fs_init_atgc_curseg(sbi); 29058c2ecf20Sopenharmony_ci} 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_cistatic void __f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi, int type) 29088c2ecf20Sopenharmony_ci{ 29098c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci mutex_lock(&curseg->curseg_mutex); 29128c2ecf20Sopenharmony_ci if (!curseg->inited) 29138c2ecf20Sopenharmony_ci goto out; 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci if (get_valid_blocks(sbi, curseg->segno, false)) { 29168c2ecf20Sopenharmony_ci write_sum_page(sbi, curseg->sum_blk, 29178c2ecf20Sopenharmony_ci GET_SUM_BLOCK(sbi, curseg->segno)); 29188c2ecf20Sopenharmony_ci } else { 29198c2ecf20Sopenharmony_ci mutex_lock(&DIRTY_I(sbi)->seglist_lock); 29208c2ecf20Sopenharmony_ci __set_test_and_free(sbi, curseg->segno, true); 29218c2ecf20Sopenharmony_ci mutex_unlock(&DIRTY_I(sbi)->seglist_lock); 29228c2ecf20Sopenharmony_ci } 29238c2ecf20Sopenharmony_ciout: 29248c2ecf20Sopenharmony_ci mutex_unlock(&curseg->curseg_mutex); 29258c2ecf20Sopenharmony_ci} 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_civoid f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi) 29288c2ecf20Sopenharmony_ci{ 29298c2ecf20Sopenharmony_ci __f2fs_save_inmem_curseg(sbi, CURSEG_COLD_DATA_PINNED); 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci if (sbi->am.atgc_enabled) 29328c2ecf20Sopenharmony_ci __f2fs_save_inmem_curseg(sbi, CURSEG_ALL_DATA_ATGC); 29338c2ecf20Sopenharmony_ci} 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_cistatic void __f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi, int type) 29368c2ecf20Sopenharmony_ci{ 29378c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci mutex_lock(&curseg->curseg_mutex); 29408c2ecf20Sopenharmony_ci if (!curseg->inited) 29418c2ecf20Sopenharmony_ci goto out; 29428c2ecf20Sopenharmony_ci if (get_valid_blocks(sbi, curseg->segno, false)) 29438c2ecf20Sopenharmony_ci goto out; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci mutex_lock(&DIRTY_I(sbi)->seglist_lock); 29468c2ecf20Sopenharmony_ci __set_test_and_inuse(sbi, curseg->segno); 29478c2ecf20Sopenharmony_ci mutex_unlock(&DIRTY_I(sbi)->seglist_lock); 29488c2ecf20Sopenharmony_ciout: 29498c2ecf20Sopenharmony_ci mutex_unlock(&curseg->curseg_mutex); 29508c2ecf20Sopenharmony_ci} 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_civoid f2fs_restore_inmem_curseg(struct f2fs_sb_info *sbi) 29538c2ecf20Sopenharmony_ci{ 29548c2ecf20Sopenharmony_ci __f2fs_restore_inmem_curseg(sbi, CURSEG_COLD_DATA_PINNED); 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci if (sbi->am.atgc_enabled) 29578c2ecf20Sopenharmony_ci __f2fs_restore_inmem_curseg(sbi, CURSEG_ALL_DATA_ATGC); 29588c2ecf20Sopenharmony_ci} 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_cistatic int get_ssr_segment(struct f2fs_sb_info *sbi, int type, 29618c2ecf20Sopenharmony_ci int alloc_mode, unsigned long long age) 29628c2ecf20Sopenharmony_ci{ 29638c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 29648c2ecf20Sopenharmony_ci const struct victim_selection *v_ops = DIRTY_I(sbi)->v_ops; 29658c2ecf20Sopenharmony_ci unsigned segno = NULL_SEGNO; 29668c2ecf20Sopenharmony_ci unsigned short seg_type = curseg->seg_type; 29678c2ecf20Sopenharmony_ci int i, cnt; 29688c2ecf20Sopenharmony_ci bool reversed = false; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci sanity_check_seg_type(sbi, seg_type); 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci /* f2fs_need_SSR() already forces to do this */ 29738c2ecf20Sopenharmony_ci if (!v_ops->get_victim(sbi, &segno, BG_GC, seg_type, alloc_mode, age)) { 29748c2ecf20Sopenharmony_ci curseg->next_segno = segno; 29758c2ecf20Sopenharmony_ci return 1; 29768c2ecf20Sopenharmony_ci } 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci /* For node segments, let's do SSR more intensively */ 29798c2ecf20Sopenharmony_ci if (IS_NODESEG(seg_type)) { 29808c2ecf20Sopenharmony_ci if (seg_type >= CURSEG_WARM_NODE) { 29818c2ecf20Sopenharmony_ci reversed = true; 29828c2ecf20Sopenharmony_ci i = CURSEG_COLD_NODE; 29838c2ecf20Sopenharmony_ci } else { 29848c2ecf20Sopenharmony_ci i = CURSEG_HOT_NODE; 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci cnt = NR_CURSEG_NODE_TYPE; 29878c2ecf20Sopenharmony_ci } else { 29888c2ecf20Sopenharmony_ci if (seg_type >= CURSEG_WARM_DATA) { 29898c2ecf20Sopenharmony_ci reversed = true; 29908c2ecf20Sopenharmony_ci i = CURSEG_COLD_DATA; 29918c2ecf20Sopenharmony_ci } else { 29928c2ecf20Sopenharmony_ci i = CURSEG_HOT_DATA; 29938c2ecf20Sopenharmony_ci } 29948c2ecf20Sopenharmony_ci cnt = NR_CURSEG_DATA_TYPE; 29958c2ecf20Sopenharmony_ci } 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci for (; cnt-- > 0; reversed ? i-- : i++) { 29988c2ecf20Sopenharmony_ci if (i == seg_type) 29998c2ecf20Sopenharmony_ci continue; 30008c2ecf20Sopenharmony_ci if (!v_ops->get_victim(sbi, &segno, BG_GC, i, alloc_mode, age)) { 30018c2ecf20Sopenharmony_ci curseg->next_segno = segno; 30028c2ecf20Sopenharmony_ci return 1; 30038c2ecf20Sopenharmony_ci } 30048c2ecf20Sopenharmony_ci } 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci /* find valid_blocks=0 in dirty list */ 30078c2ecf20Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { 30088c2ecf20Sopenharmony_ci segno = get_free_segment(sbi); 30098c2ecf20Sopenharmony_ci if (segno != NULL_SEGNO) { 30108c2ecf20Sopenharmony_ci curseg->next_segno = segno; 30118c2ecf20Sopenharmony_ci return 1; 30128c2ecf20Sopenharmony_ci } 30138c2ecf20Sopenharmony_ci } 30148c2ecf20Sopenharmony_ci return 0; 30158c2ecf20Sopenharmony_ci} 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci/* 30188c2ecf20Sopenharmony_ci * flush out current segment and replace it with new segment 30198c2ecf20Sopenharmony_ci * This function should be returned with success, otherwise BUG 30208c2ecf20Sopenharmony_ci */ 30218c2ecf20Sopenharmony_cistatic void allocate_segment_by_default(struct f2fs_sb_info *sbi, 30228c2ecf20Sopenharmony_ci int type, bool force, int contig_level) 30238c2ecf20Sopenharmony_ci{ 30248c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci if (force) 30278c2ecf20Sopenharmony_ci new_curseg(sbi, type, true); 30288c2ecf20Sopenharmony_ci else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) && 30298c2ecf20Sopenharmony_ci curseg->seg_type == CURSEG_WARM_NODE) 30308c2ecf20Sopenharmony_ci new_curseg(sbi, type, false); 30318c2ecf20Sopenharmony_ci else if (curseg->alloc_type == LFS && 30328c2ecf20Sopenharmony_ci is_next_segment_free(sbi, curseg, type) && 30338c2ecf20Sopenharmony_ci likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED))) 30348c2ecf20Sopenharmony_ci new_curseg(sbi, type, false); 30358c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_GRADING_SSR 30368c2ecf20Sopenharmony_ci else if (need_ssr_by_type(sbi, type, contig_level) && get_ssr_segment(sbi, type, SSR, 0)) 30378c2ecf20Sopenharmony_ci#else 30388c2ecf20Sopenharmony_ci else if (f2fs_need_SSR(sbi) && 30398c2ecf20Sopenharmony_ci get_ssr_segment(sbi, type, SSR, 0)) 30408c2ecf20Sopenharmony_ci#endif 30418c2ecf20Sopenharmony_ci change_curseg(sbi, type, true); 30428c2ecf20Sopenharmony_ci else 30438c2ecf20Sopenharmony_ci new_curseg(sbi, type, false); 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci stat_inc_seg_type(sbi, curseg); 30468c2ecf20Sopenharmony_ci} 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_civoid f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type, 30498c2ecf20Sopenharmony_ci unsigned int start, unsigned int end) 30508c2ecf20Sopenharmony_ci{ 30518c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 30528c2ecf20Sopenharmony_ci unsigned int segno; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci down_read(&SM_I(sbi)->curseg_lock); 30558c2ecf20Sopenharmony_ci mutex_lock(&curseg->curseg_mutex); 30568c2ecf20Sopenharmony_ci down_write(&SIT_I(sbi)->sentry_lock); 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci segno = CURSEG_I(sbi, type)->segno; 30598c2ecf20Sopenharmony_ci if (segno < start || segno > end) 30608c2ecf20Sopenharmony_ci goto unlock; 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0)) 30638c2ecf20Sopenharmony_ci change_curseg(sbi, type, true); 30648c2ecf20Sopenharmony_ci else 30658c2ecf20Sopenharmony_ci new_curseg(sbi, type, true); 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci stat_inc_seg_type(sbi, curseg); 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci locate_dirty_segment(sbi, segno); 30708c2ecf20Sopenharmony_ciunlock: 30718c2ecf20Sopenharmony_ci up_write(&SIT_I(sbi)->sentry_lock); 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci if (segno != curseg->segno) 30748c2ecf20Sopenharmony_ci f2fs_notice(sbi, "For resize: curseg of type %d: %u ==> %u", 30758c2ecf20Sopenharmony_ci type, segno, curseg->segno); 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci mutex_unlock(&curseg->curseg_mutex); 30788c2ecf20Sopenharmony_ci up_read(&SM_I(sbi)->curseg_lock); 30798c2ecf20Sopenharmony_ci} 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_cistatic void __allocate_new_segment(struct f2fs_sb_info *sbi, int type, 30828c2ecf20Sopenharmony_ci bool new_sec) 30838c2ecf20Sopenharmony_ci{ 30848c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 30858c2ecf20Sopenharmony_ci unsigned int old_segno; 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci if (!curseg->inited) 30888c2ecf20Sopenharmony_ci goto alloc; 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci if (curseg->next_blkoff || 30918c2ecf20Sopenharmony_ci get_valid_blocks(sbi, curseg->segno, new_sec)) 30928c2ecf20Sopenharmony_ci goto alloc; 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci if (!get_ckpt_valid_blocks(sbi, curseg->segno, new_sec)) 30958c2ecf20Sopenharmony_ci return; 30968c2ecf20Sopenharmony_cialloc: 30978c2ecf20Sopenharmony_ci old_segno = curseg->segno; 30988c2ecf20Sopenharmony_ci SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true, SEQ_NONE); 30998c2ecf20Sopenharmony_ci locate_dirty_segment(sbi, old_segno); 31008c2ecf20Sopenharmony_ci} 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_cistatic void __allocate_new_section(struct f2fs_sb_info *sbi, int type) 31038c2ecf20Sopenharmony_ci{ 31048c2ecf20Sopenharmony_ci __allocate_new_segment(sbi, type, true); 31058c2ecf20Sopenharmony_ci} 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_civoid f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type) 31088c2ecf20Sopenharmony_ci{ 31098c2ecf20Sopenharmony_ci down_read(&SM_I(sbi)->curseg_lock); 31108c2ecf20Sopenharmony_ci down_write(&SIT_I(sbi)->sentry_lock); 31118c2ecf20Sopenharmony_ci __allocate_new_section(sbi, type); 31128c2ecf20Sopenharmony_ci up_write(&SIT_I(sbi)->sentry_lock); 31138c2ecf20Sopenharmony_ci up_read(&SM_I(sbi)->curseg_lock); 31148c2ecf20Sopenharmony_ci} 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_civoid f2fs_allocate_new_segments(struct f2fs_sb_info *sbi) 31178c2ecf20Sopenharmony_ci{ 31188c2ecf20Sopenharmony_ci int i; 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci down_read(&SM_I(sbi)->curseg_lock); 31218c2ecf20Sopenharmony_ci down_write(&SIT_I(sbi)->sentry_lock); 31228c2ecf20Sopenharmony_ci for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) 31238c2ecf20Sopenharmony_ci __allocate_new_segment(sbi, i, false); 31248c2ecf20Sopenharmony_ci up_write(&SIT_I(sbi)->sentry_lock); 31258c2ecf20Sopenharmony_ci up_read(&SM_I(sbi)->curseg_lock); 31268c2ecf20Sopenharmony_ci} 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_cistatic const struct segment_allocation default_salloc_ops = { 31298c2ecf20Sopenharmony_ci .allocate_segment = allocate_segment_by_default, 31308c2ecf20Sopenharmony_ci}; 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_cibool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi, 31338c2ecf20Sopenharmony_ci struct cp_control *cpc) 31348c2ecf20Sopenharmony_ci{ 31358c2ecf20Sopenharmony_ci __u64 trim_start = cpc->trim_start; 31368c2ecf20Sopenharmony_ci bool has_candidate = false; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci down_write(&SIT_I(sbi)->sentry_lock); 31398c2ecf20Sopenharmony_ci for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++) { 31408c2ecf20Sopenharmony_ci if (add_discard_addrs(sbi, cpc, true)) { 31418c2ecf20Sopenharmony_ci has_candidate = true; 31428c2ecf20Sopenharmony_ci break; 31438c2ecf20Sopenharmony_ci } 31448c2ecf20Sopenharmony_ci } 31458c2ecf20Sopenharmony_ci up_write(&SIT_I(sbi)->sentry_lock); 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci cpc->trim_start = trim_start; 31488c2ecf20Sopenharmony_ci return has_candidate; 31498c2ecf20Sopenharmony_ci} 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_cistatic unsigned int __issue_discard_cmd_range(struct f2fs_sb_info *sbi, 31528c2ecf20Sopenharmony_ci struct discard_policy *dpolicy, 31538c2ecf20Sopenharmony_ci unsigned int start, unsigned int end) 31548c2ecf20Sopenharmony_ci{ 31558c2ecf20Sopenharmony_ci struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; 31568c2ecf20Sopenharmony_ci struct discard_cmd *prev_dc = NULL, *next_dc = NULL; 31578c2ecf20Sopenharmony_ci struct rb_node **insert_p = NULL, *insert_parent = NULL; 31588c2ecf20Sopenharmony_ci struct discard_cmd *dc; 31598c2ecf20Sopenharmony_ci struct blk_plug plug; 31608c2ecf20Sopenharmony_ci struct discard_sub_policy *spolicy = NULL; 31618c2ecf20Sopenharmony_ci int issued; 31628c2ecf20Sopenharmony_ci unsigned int trimmed = 0; 31638c2ecf20Sopenharmony_ci /* fstrim each time 8 discard without no interrupt */ 31648c2ecf20Sopenharmony_ci select_sub_discard_policy(&spolicy, 0, dpolicy); 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci if (dcc->rbtree_check) { 31678c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 31688c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi, &dcc->root, false)); 31698c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 31708c2ecf20Sopenharmony_ci } 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_cinext: 31738c2ecf20Sopenharmony_ci issued = 0; 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci mutex_lock(&dcc->cmd_lock); 31768c2ecf20Sopenharmony_ci if (unlikely(dcc->rbtree_check)) 31778c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi, 31788c2ecf20Sopenharmony_ci &dcc->root, false)); 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root, 31818c2ecf20Sopenharmony_ci NULL, start, 31828c2ecf20Sopenharmony_ci (struct rb_entry **)&prev_dc, 31838c2ecf20Sopenharmony_ci (struct rb_entry **)&next_dc, 31848c2ecf20Sopenharmony_ci &insert_p, &insert_parent, true, NULL); 31858c2ecf20Sopenharmony_ci if (!dc) 31868c2ecf20Sopenharmony_ci dc = next_dc; 31878c2ecf20Sopenharmony_ci 31888c2ecf20Sopenharmony_ci blk_start_plug(&plug); 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci while (dc && dc->lstart <= end) { 31918c2ecf20Sopenharmony_ci struct rb_node *node; 31928c2ecf20Sopenharmony_ci int err = 0; 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci if (dc->len < dpolicy->granularity) 31958c2ecf20Sopenharmony_ci goto skip; 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci if (dc->state != D_PREP) { 31988c2ecf20Sopenharmony_ci list_move_tail(&dc->list, &dcc->fstrim_list); 31998c2ecf20Sopenharmony_ci goto skip; 32008c2ecf20Sopenharmony_ci } 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci err = __submit_discard_cmd(sbi, dpolicy, 0, dc, &issued); 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci if (issued >= spolicy->max_requests) { 32058c2ecf20Sopenharmony_ci start = dc->lstart + dc->len; 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci if (err) 32088c2ecf20Sopenharmony_ci __remove_discard_cmd(sbi, dc); 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci blk_finish_plug(&plug); 32118c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 32128c2ecf20Sopenharmony_ci trimmed += __wait_all_discard_cmd(sbi, NULL); 32138c2ecf20Sopenharmony_ci congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT); 32148c2ecf20Sopenharmony_ci goto next; 32158c2ecf20Sopenharmony_ci } 32168c2ecf20Sopenharmony_ciskip: 32178c2ecf20Sopenharmony_ci node = rb_next(&dc->rb_node); 32188c2ecf20Sopenharmony_ci if (err) 32198c2ecf20Sopenharmony_ci __remove_discard_cmd(sbi, dc); 32208c2ecf20Sopenharmony_ci dc = rb_entry_safe(node, struct discard_cmd, rb_node); 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) 32238c2ecf20Sopenharmony_ci break; 32248c2ecf20Sopenharmony_ci } 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci blk_finish_plug(&plug); 32278c2ecf20Sopenharmony_ci mutex_unlock(&dcc->cmd_lock); 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci return trimmed; 32308c2ecf20Sopenharmony_ci} 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ciint f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) 32338c2ecf20Sopenharmony_ci{ 32348c2ecf20Sopenharmony_ci __u64 start = F2FS_BYTES_TO_BLK(range->start); 32358c2ecf20Sopenharmony_ci __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1; 32368c2ecf20Sopenharmony_ci unsigned int start_segno, end_segno; 32378c2ecf20Sopenharmony_ci block_t start_block, end_block; 32388c2ecf20Sopenharmony_ci struct cp_control cpc; 32398c2ecf20Sopenharmony_ci struct discard_policy dpolicy; 32408c2ecf20Sopenharmony_ci unsigned long long trimmed = 0; 32418c2ecf20Sopenharmony_ci int err = 0; 32428c2ecf20Sopenharmony_ci bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi); 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize) 32458c2ecf20Sopenharmony_ci return -EINVAL; 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci if (end < MAIN_BLKADDR(sbi)) 32488c2ecf20Sopenharmony_ci goto out; 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { 32518c2ecf20Sopenharmony_ci f2fs_warn(sbi, "Found FS corruption, run fsck to fix."); 32528c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 32538c2ecf20Sopenharmony_ci } 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci /* start/end segment number in main_area */ 32568c2ecf20Sopenharmony_ci start_segno = (start <= MAIN_BLKADDR(sbi)) ? 0 : GET_SEGNO(sbi, start); 32578c2ecf20Sopenharmony_ci end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 : 32588c2ecf20Sopenharmony_ci GET_SEGNO(sbi, end); 32598c2ecf20Sopenharmony_ci if (need_align) { 32608c2ecf20Sopenharmony_ci start_segno = rounddown(start_segno, sbi->segs_per_sec); 32618c2ecf20Sopenharmony_ci end_segno = roundup(end_segno + 1, sbi->segs_per_sec) - 1; 32628c2ecf20Sopenharmony_ci } 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci cpc.reason = CP_DISCARD; 32658c2ecf20Sopenharmony_ci cpc.trim_minlen = max_t(__u64, 1, F2FS_BYTES_TO_BLK(range->minlen)); 32668c2ecf20Sopenharmony_ci cpc.trim_start = start_segno; 32678c2ecf20Sopenharmony_ci cpc.trim_end = end_segno; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci if (sbi->discard_blks == 0) 32708c2ecf20Sopenharmony_ci goto out; 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci down_write(&sbi->gc_lock); 32738c2ecf20Sopenharmony_ci err = f2fs_write_checkpoint(sbi, &cpc); 32748c2ecf20Sopenharmony_ci up_write(&sbi->gc_lock); 32758c2ecf20Sopenharmony_ci if (err) 32768c2ecf20Sopenharmony_ci goto out; 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci /* 32798c2ecf20Sopenharmony_ci * We filed discard candidates, but actually we don't need to wait for 32808c2ecf20Sopenharmony_ci * all of them, since they'll be issued in idle time along with runtime 32818c2ecf20Sopenharmony_ci * discard option. User configuration looks like using runtime discard 32828c2ecf20Sopenharmony_ci * or periodic fstrim instead of it. 32838c2ecf20Sopenharmony_ci */ 32848c2ecf20Sopenharmony_ci if (f2fs_realtime_discard_enable(sbi)) 32858c2ecf20Sopenharmony_ci goto out; 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci start_block = START_BLOCK(sbi, start_segno); 32888c2ecf20Sopenharmony_ci end_block = START_BLOCK(sbi, end_segno + 1); 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci __init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen); 32918c2ecf20Sopenharmony_ci trimmed = __issue_discard_cmd_range(sbi, &dpolicy, 32928c2ecf20Sopenharmony_ci start_block, end_block); 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci trimmed += __wait_discard_cmd_range(sbi, &dpolicy, 32958c2ecf20Sopenharmony_ci start_block, end_block); 32968c2ecf20Sopenharmony_ciout: 32978c2ecf20Sopenharmony_ci if (!err) 32988c2ecf20Sopenharmony_ci range->len = F2FS_BLK_TO_BYTES(trimmed); 32998c2ecf20Sopenharmony_ci return err; 33008c2ecf20Sopenharmony_ci} 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_cistatic bool __has_curseg_space(struct f2fs_sb_info *sbi, 33038c2ecf20Sopenharmony_ci struct curseg_info *curseg) 33048c2ecf20Sopenharmony_ci{ 33058c2ecf20Sopenharmony_ci return curseg->next_blkoff < f2fs_usable_blks_in_seg(sbi, 33068c2ecf20Sopenharmony_ci curseg->segno); 33078c2ecf20Sopenharmony_ci} 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ciint f2fs_rw_hint_to_seg_type(enum rw_hint hint) 33108c2ecf20Sopenharmony_ci{ 33118c2ecf20Sopenharmony_ci switch (hint) { 33128c2ecf20Sopenharmony_ci case WRITE_LIFE_SHORT: 33138c2ecf20Sopenharmony_ci return CURSEG_HOT_DATA; 33148c2ecf20Sopenharmony_ci case WRITE_LIFE_EXTREME: 33158c2ecf20Sopenharmony_ci return CURSEG_COLD_DATA; 33168c2ecf20Sopenharmony_ci default: 33178c2ecf20Sopenharmony_ci return CURSEG_WARM_DATA; 33188c2ecf20Sopenharmony_ci } 33198c2ecf20Sopenharmony_ci} 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci/* This returns write hints for each segment type. This hints will be 33228c2ecf20Sopenharmony_ci * passed down to block layer. There are mapping tables which depend on 33238c2ecf20Sopenharmony_ci * the mount option 'whint_mode'. 33248c2ecf20Sopenharmony_ci * 33258c2ecf20Sopenharmony_ci * 1) whint_mode=off. F2FS only passes down WRITE_LIFE_NOT_SET. 33268c2ecf20Sopenharmony_ci * 33278c2ecf20Sopenharmony_ci * 2) whint_mode=user-based. F2FS tries to pass down hints given by users. 33288c2ecf20Sopenharmony_ci * 33298c2ecf20Sopenharmony_ci * User F2FS Block 33308c2ecf20Sopenharmony_ci * ---- ---- ----- 33318c2ecf20Sopenharmony_ci * META WRITE_LIFE_NOT_SET 33328c2ecf20Sopenharmony_ci * HOT_NODE " 33338c2ecf20Sopenharmony_ci * WARM_NODE " 33348c2ecf20Sopenharmony_ci * COLD_NODE " 33358c2ecf20Sopenharmony_ci * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME 33368c2ecf20Sopenharmony_ci * extension list " " 33378c2ecf20Sopenharmony_ci * 33388c2ecf20Sopenharmony_ci * -- buffered io 33398c2ecf20Sopenharmony_ci * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME 33408c2ecf20Sopenharmony_ci * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT 33418c2ecf20Sopenharmony_ci * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET 33428c2ecf20Sopenharmony_ci * WRITE_LIFE_NONE " " 33438c2ecf20Sopenharmony_ci * WRITE_LIFE_MEDIUM " " 33448c2ecf20Sopenharmony_ci * WRITE_LIFE_LONG " " 33458c2ecf20Sopenharmony_ci * 33468c2ecf20Sopenharmony_ci * -- direct io 33478c2ecf20Sopenharmony_ci * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME 33488c2ecf20Sopenharmony_ci * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT 33498c2ecf20Sopenharmony_ci * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET 33508c2ecf20Sopenharmony_ci * WRITE_LIFE_NONE " WRITE_LIFE_NONE 33518c2ecf20Sopenharmony_ci * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM 33528c2ecf20Sopenharmony_ci * WRITE_LIFE_LONG " WRITE_LIFE_LONG 33538c2ecf20Sopenharmony_ci * 33548c2ecf20Sopenharmony_ci * 3) whint_mode=fs-based. F2FS passes down hints with its policy. 33558c2ecf20Sopenharmony_ci * 33568c2ecf20Sopenharmony_ci * User F2FS Block 33578c2ecf20Sopenharmony_ci * ---- ---- ----- 33588c2ecf20Sopenharmony_ci * META WRITE_LIFE_MEDIUM; 33598c2ecf20Sopenharmony_ci * HOT_NODE WRITE_LIFE_NOT_SET 33608c2ecf20Sopenharmony_ci * WARM_NODE " 33618c2ecf20Sopenharmony_ci * COLD_NODE WRITE_LIFE_NONE 33628c2ecf20Sopenharmony_ci * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME 33638c2ecf20Sopenharmony_ci * extension list " " 33648c2ecf20Sopenharmony_ci * 33658c2ecf20Sopenharmony_ci * -- buffered io 33668c2ecf20Sopenharmony_ci * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME 33678c2ecf20Sopenharmony_ci * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT 33688c2ecf20Sopenharmony_ci * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_LONG 33698c2ecf20Sopenharmony_ci * WRITE_LIFE_NONE " " 33708c2ecf20Sopenharmony_ci * WRITE_LIFE_MEDIUM " " 33718c2ecf20Sopenharmony_ci * WRITE_LIFE_LONG " " 33728c2ecf20Sopenharmony_ci * 33738c2ecf20Sopenharmony_ci * -- direct io 33748c2ecf20Sopenharmony_ci * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME 33758c2ecf20Sopenharmony_ci * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT 33768c2ecf20Sopenharmony_ci * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET 33778c2ecf20Sopenharmony_ci * WRITE_LIFE_NONE " WRITE_LIFE_NONE 33788c2ecf20Sopenharmony_ci * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM 33798c2ecf20Sopenharmony_ci * WRITE_LIFE_LONG " WRITE_LIFE_LONG 33808c2ecf20Sopenharmony_ci */ 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_cienum rw_hint f2fs_io_type_to_rw_hint(struct f2fs_sb_info *sbi, 33838c2ecf20Sopenharmony_ci enum page_type type, enum temp_type temp) 33848c2ecf20Sopenharmony_ci{ 33858c2ecf20Sopenharmony_ci if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) { 33868c2ecf20Sopenharmony_ci if (type == DATA) { 33878c2ecf20Sopenharmony_ci if (temp == WARM) 33888c2ecf20Sopenharmony_ci return WRITE_LIFE_NOT_SET; 33898c2ecf20Sopenharmony_ci else if (temp == HOT) 33908c2ecf20Sopenharmony_ci return WRITE_LIFE_SHORT; 33918c2ecf20Sopenharmony_ci else if (temp == COLD) 33928c2ecf20Sopenharmony_ci return WRITE_LIFE_EXTREME; 33938c2ecf20Sopenharmony_ci } else { 33948c2ecf20Sopenharmony_ci return WRITE_LIFE_NOT_SET; 33958c2ecf20Sopenharmony_ci } 33968c2ecf20Sopenharmony_ci } else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) { 33978c2ecf20Sopenharmony_ci if (type == DATA) { 33988c2ecf20Sopenharmony_ci if (temp == WARM) 33998c2ecf20Sopenharmony_ci return WRITE_LIFE_LONG; 34008c2ecf20Sopenharmony_ci else if (temp == HOT) 34018c2ecf20Sopenharmony_ci return WRITE_LIFE_SHORT; 34028c2ecf20Sopenharmony_ci else if (temp == COLD) 34038c2ecf20Sopenharmony_ci return WRITE_LIFE_EXTREME; 34048c2ecf20Sopenharmony_ci } else if (type == NODE) { 34058c2ecf20Sopenharmony_ci if (temp == WARM || temp == HOT) 34068c2ecf20Sopenharmony_ci return WRITE_LIFE_NOT_SET; 34078c2ecf20Sopenharmony_ci else if (temp == COLD) 34088c2ecf20Sopenharmony_ci return WRITE_LIFE_NONE; 34098c2ecf20Sopenharmony_ci } else if (type == META) { 34108c2ecf20Sopenharmony_ci return WRITE_LIFE_MEDIUM; 34118c2ecf20Sopenharmony_ci } 34128c2ecf20Sopenharmony_ci } 34138c2ecf20Sopenharmony_ci return WRITE_LIFE_NOT_SET; 34148c2ecf20Sopenharmony_ci} 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_cistatic int __get_segment_type_2(struct f2fs_io_info *fio) 34178c2ecf20Sopenharmony_ci{ 34188c2ecf20Sopenharmony_ci if (fio->type == DATA) 34198c2ecf20Sopenharmony_ci return CURSEG_HOT_DATA; 34208c2ecf20Sopenharmony_ci else 34218c2ecf20Sopenharmony_ci return CURSEG_HOT_NODE; 34228c2ecf20Sopenharmony_ci} 34238c2ecf20Sopenharmony_ci 34248c2ecf20Sopenharmony_cistatic int __get_segment_type_4(struct f2fs_io_info *fio) 34258c2ecf20Sopenharmony_ci{ 34268c2ecf20Sopenharmony_ci if (fio->type == DATA) { 34278c2ecf20Sopenharmony_ci struct inode *inode = fio->page->mapping->host; 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 34308c2ecf20Sopenharmony_ci return CURSEG_HOT_DATA; 34318c2ecf20Sopenharmony_ci else 34328c2ecf20Sopenharmony_ci return CURSEG_COLD_DATA; 34338c2ecf20Sopenharmony_ci } else { 34348c2ecf20Sopenharmony_ci if (IS_DNODE(fio->page) && is_cold_node(fio->page)) 34358c2ecf20Sopenharmony_ci return CURSEG_WARM_NODE; 34368c2ecf20Sopenharmony_ci else 34378c2ecf20Sopenharmony_ci return CURSEG_COLD_NODE; 34388c2ecf20Sopenharmony_ci } 34398c2ecf20Sopenharmony_ci} 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_cistatic int __get_segment_type_6(struct f2fs_io_info *fio) 34428c2ecf20Sopenharmony_ci{ 34438c2ecf20Sopenharmony_ci if (fio->type == DATA) { 34448c2ecf20Sopenharmony_ci struct inode *inode = fio->page->mapping->host; 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci if (is_cold_data(fio->page)) { 34478c2ecf20Sopenharmony_ci if (fio->sbi->am.atgc_enabled) 34488c2ecf20Sopenharmony_ci return CURSEG_ALL_DATA_ATGC; 34498c2ecf20Sopenharmony_ci else 34508c2ecf20Sopenharmony_ci return CURSEG_COLD_DATA; 34518c2ecf20Sopenharmony_ci } 34528c2ecf20Sopenharmony_ci if (file_is_cold(inode) || f2fs_compressed_file(inode)) 34538c2ecf20Sopenharmony_ci return CURSEG_COLD_DATA; 34548c2ecf20Sopenharmony_ci if (file_is_hot(inode) || 34558c2ecf20Sopenharmony_ci is_inode_flag_set(inode, FI_HOT_DATA) || 34568c2ecf20Sopenharmony_ci f2fs_is_atomic_file(inode) || 34578c2ecf20Sopenharmony_ci f2fs_is_volatile_file(inode)) 34588c2ecf20Sopenharmony_ci return CURSEG_HOT_DATA; 34598c2ecf20Sopenharmony_ci return f2fs_rw_hint_to_seg_type(inode->i_write_hint); 34608c2ecf20Sopenharmony_ci } else { 34618c2ecf20Sopenharmony_ci if (IS_DNODE(fio->page)) 34628c2ecf20Sopenharmony_ci return is_cold_node(fio->page) ? CURSEG_WARM_NODE : 34638c2ecf20Sopenharmony_ci CURSEG_HOT_NODE; 34648c2ecf20Sopenharmony_ci return CURSEG_COLD_NODE; 34658c2ecf20Sopenharmony_ci } 34668c2ecf20Sopenharmony_ci} 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_cistatic int __get_segment_type(struct f2fs_io_info *fio) 34698c2ecf20Sopenharmony_ci{ 34708c2ecf20Sopenharmony_ci int type = 0; 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci switch (F2FS_OPTION(fio->sbi).active_logs) { 34738c2ecf20Sopenharmony_ci case 2: 34748c2ecf20Sopenharmony_ci type = __get_segment_type_2(fio); 34758c2ecf20Sopenharmony_ci break; 34768c2ecf20Sopenharmony_ci case 4: 34778c2ecf20Sopenharmony_ci type = __get_segment_type_4(fio); 34788c2ecf20Sopenharmony_ci break; 34798c2ecf20Sopenharmony_ci case 6: 34808c2ecf20Sopenharmony_ci type = __get_segment_type_6(fio); 34818c2ecf20Sopenharmony_ci break; 34828c2ecf20Sopenharmony_ci default: 34838c2ecf20Sopenharmony_ci f2fs_bug_on(fio->sbi, true); 34848c2ecf20Sopenharmony_ci } 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci if (IS_HOT(type)) 34878c2ecf20Sopenharmony_ci fio->temp = HOT; 34888c2ecf20Sopenharmony_ci else if (IS_WARM(type)) 34898c2ecf20Sopenharmony_ci fio->temp = WARM; 34908c2ecf20Sopenharmony_ci else 34918c2ecf20Sopenharmony_ci fio->temp = COLD; 34928c2ecf20Sopenharmony_ci return type; 34938c2ecf20Sopenharmony_ci} 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_civoid f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, 34968c2ecf20Sopenharmony_ci block_t old_blkaddr, block_t *new_blkaddr, 34978c2ecf20Sopenharmony_ci struct f2fs_summary *sum, int type, 34988c2ecf20Sopenharmony_ci struct f2fs_io_info *fio, int contig_level) 34998c2ecf20Sopenharmony_ci{ 35008c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 35018c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 35028c2ecf20Sopenharmony_ci unsigned long long old_mtime; 35038c2ecf20Sopenharmony_ci bool from_gc = (type == CURSEG_ALL_DATA_ATGC); 35048c2ecf20Sopenharmony_ci struct seg_entry *se = NULL; 35058c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_GRADING_SSR 35068c2ecf20Sopenharmony_ci struct inode *inode = NULL; 35078c2ecf20Sopenharmony_ci#endif 35088c2ecf20Sopenharmony_ci int contig = SEQ_NONE; 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci down_read(&SM_I(sbi)->curseg_lock); 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_ci mutex_lock(&curseg->curseg_mutex); 35138c2ecf20Sopenharmony_ci down_write(&sit_i->sentry_lock); 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci if (from_gc) { 35168c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, GET_SEGNO(sbi, old_blkaddr) == NULL_SEGNO); 35178c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, GET_SEGNO(sbi, old_blkaddr)); 35188c2ecf20Sopenharmony_ci sanity_check_seg_type(sbi, se->type); 35198c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, IS_NODESEG(se->type)); 35208c2ecf20Sopenharmony_ci } 35218c2ecf20Sopenharmony_ci *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, curseg->next_blkoff >= sbi->blocks_per_seg); 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci f2fs_wait_discard_bio(sbi, *new_blkaddr); 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci /* 35288c2ecf20Sopenharmony_ci * __add_sum_entry should be resided under the curseg_mutex 35298c2ecf20Sopenharmony_ci * because, this function updates a summary entry in the 35308c2ecf20Sopenharmony_ci * current summary block. 35318c2ecf20Sopenharmony_ci */ 35328c2ecf20Sopenharmony_ci __add_sum_entry(sbi, type, sum); 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci __refresh_next_blkoff(sbi, curseg); 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci stat_inc_block_count(sbi, curseg); 35378c2ecf20Sopenharmony_ci 35388c2ecf20Sopenharmony_ci if (from_gc) { 35398c2ecf20Sopenharmony_ci old_mtime = get_segment_mtime(sbi, old_blkaddr); 35408c2ecf20Sopenharmony_ci } else { 35418c2ecf20Sopenharmony_ci update_segment_mtime(sbi, old_blkaddr, 0); 35428c2ecf20Sopenharmony_ci old_mtime = 0; 35438c2ecf20Sopenharmony_ci } 35448c2ecf20Sopenharmony_ci update_segment_mtime(sbi, *new_blkaddr, old_mtime); 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_ci /* 35478c2ecf20Sopenharmony_ci * SIT information should be updated before segment allocation, 35488c2ecf20Sopenharmony_ci * since SSR needs latest valid block information. 35498c2ecf20Sopenharmony_ci */ 35508c2ecf20Sopenharmony_ci update_sit_entry(sbi, *new_blkaddr, 1); 35518c2ecf20Sopenharmony_ci if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) 35528c2ecf20Sopenharmony_ci update_sit_entry(sbi, old_blkaddr, -1); 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci if (!__has_curseg_space(sbi, curseg)) { 35558c2ecf20Sopenharmony_ci if (from_gc) { 35568c2ecf20Sopenharmony_ci get_atssr_segment(sbi, type, se->type, 35578c2ecf20Sopenharmony_ci AT_SSR, se->mtime); 35588c2ecf20Sopenharmony_ci } else { 35598c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_GRADING_SSR 35608c2ecf20Sopenharmony_ci if (contig_level != SEQ_NONE) { 35618c2ecf20Sopenharmony_ci contig = contig_level; 35628c2ecf20Sopenharmony_ci goto allocate_label; 35638c2ecf20Sopenharmony_ci } 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci if (page && page->mapping && page->mapping != NODE_MAPPING(sbi) && 35668c2ecf20Sopenharmony_ci page->mapping != META_MAPPING(sbi)) { 35678c2ecf20Sopenharmony_ci inode = page->mapping->host; 35688c2ecf20Sopenharmony_ci contig = check_io_seq(get_dirty_pages(inode)); 35698c2ecf20Sopenharmony_ci } 35708c2ecf20Sopenharmony_ciallocate_label: 35718c2ecf20Sopenharmony_ci#endif 35728c2ecf20Sopenharmony_ci sit_i->s_ops->allocate_segment(sbi, type, false, contig); 35738c2ecf20Sopenharmony_ci } 35748c2ecf20Sopenharmony_ci } 35758c2ecf20Sopenharmony_ci /* 35768c2ecf20Sopenharmony_ci * segment dirty status should be updated after segment allocation, 35778c2ecf20Sopenharmony_ci * so we just need to update status only one time after previous 35788c2ecf20Sopenharmony_ci * segment being closed. 35798c2ecf20Sopenharmony_ci */ 35808c2ecf20Sopenharmony_ci locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); 35818c2ecf20Sopenharmony_ci locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr)); 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci up_write(&sit_i->sentry_lock); 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci if (page && IS_NODESEG(type)) { 35868c2ecf20Sopenharmony_ci fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg)); 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci f2fs_inode_chksum_set(sbi, page); 35898c2ecf20Sopenharmony_ci } 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci if (fio) { 35928c2ecf20Sopenharmony_ci struct f2fs_bio_info *io; 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci if (F2FS_IO_ALIGNED(sbi)) 35958c2ecf20Sopenharmony_ci fio->retry = false; 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fio->list); 35988c2ecf20Sopenharmony_ci fio->in_list = true; 35998c2ecf20Sopenharmony_ci io = sbi->write_io[fio->type] + fio->temp; 36008c2ecf20Sopenharmony_ci spin_lock(&io->io_lock); 36018c2ecf20Sopenharmony_ci list_add_tail(&fio->list, &io->io_list); 36028c2ecf20Sopenharmony_ci spin_unlock(&io->io_lock); 36038c2ecf20Sopenharmony_ci } 36048c2ecf20Sopenharmony_ci 36058c2ecf20Sopenharmony_ci mutex_unlock(&curseg->curseg_mutex); 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_ci up_read(&SM_I(sbi)->curseg_lock); 36088c2ecf20Sopenharmony_ci} 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_cistatic void update_device_state(struct f2fs_io_info *fio) 36118c2ecf20Sopenharmony_ci{ 36128c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = fio->sbi; 36138c2ecf20Sopenharmony_ci unsigned int devidx; 36148c2ecf20Sopenharmony_ci 36158c2ecf20Sopenharmony_ci if (!f2fs_is_multi_device(sbi)) 36168c2ecf20Sopenharmony_ci return; 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_ci devidx = f2fs_target_device_index(sbi, fio->new_blkaddr); 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci /* update device state for fsync */ 36218c2ecf20Sopenharmony_ci f2fs_set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO); 36228c2ecf20Sopenharmony_ci 36238c2ecf20Sopenharmony_ci /* update device state for checkpoint */ 36248c2ecf20Sopenharmony_ci if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) { 36258c2ecf20Sopenharmony_ci spin_lock(&sbi->dev_lock); 36268c2ecf20Sopenharmony_ci f2fs_set_bit(devidx, (char *)&sbi->dirty_device); 36278c2ecf20Sopenharmony_ci spin_unlock(&sbi->dev_lock); 36288c2ecf20Sopenharmony_ci } 36298c2ecf20Sopenharmony_ci} 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_cistatic void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) 36328c2ecf20Sopenharmony_ci{ 36338c2ecf20Sopenharmony_ci int type = __get_segment_type(fio); 36348c2ecf20Sopenharmony_ci bool keep_order = (f2fs_lfs_mode(fio->sbi) && type == CURSEG_COLD_DATA); 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci if (keep_order) 36378c2ecf20Sopenharmony_ci down_read(&fio->sbi->io_order_lock); 36388c2ecf20Sopenharmony_cireallocate: 36398c2ecf20Sopenharmony_ci f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, 36408c2ecf20Sopenharmony_ci &fio->new_blkaddr, sum, type, fio, SEQ_NONE); 36418c2ecf20Sopenharmony_ci if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) 36428c2ecf20Sopenharmony_ci invalidate_mapping_pages(META_MAPPING(fio->sbi), 36438c2ecf20Sopenharmony_ci fio->old_blkaddr, fio->old_blkaddr); 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci /* writeout dirty page into bdev */ 36468c2ecf20Sopenharmony_ci f2fs_submit_page_write(fio); 36478c2ecf20Sopenharmony_ci if (fio->retry) { 36488c2ecf20Sopenharmony_ci fio->old_blkaddr = fio->new_blkaddr; 36498c2ecf20Sopenharmony_ci goto reallocate; 36508c2ecf20Sopenharmony_ci } 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci update_device_state(fio); 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_ci if (keep_order) 36558c2ecf20Sopenharmony_ci up_read(&fio->sbi->io_order_lock); 36568c2ecf20Sopenharmony_ci} 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_civoid f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, 36598c2ecf20Sopenharmony_ci enum iostat_type io_type) 36608c2ecf20Sopenharmony_ci{ 36618c2ecf20Sopenharmony_ci struct f2fs_io_info fio = { 36628c2ecf20Sopenharmony_ci .sbi = sbi, 36638c2ecf20Sopenharmony_ci .type = META, 36648c2ecf20Sopenharmony_ci .temp = HOT, 36658c2ecf20Sopenharmony_ci .op = REQ_OP_WRITE, 36668c2ecf20Sopenharmony_ci .op_flags = REQ_SYNC | REQ_META | REQ_PRIO, 36678c2ecf20Sopenharmony_ci .old_blkaddr = page->index, 36688c2ecf20Sopenharmony_ci .new_blkaddr = page->index, 36698c2ecf20Sopenharmony_ci .page = page, 36708c2ecf20Sopenharmony_ci .encrypted_page = NULL, 36718c2ecf20Sopenharmony_ci .in_list = false, 36728c2ecf20Sopenharmony_ci }; 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_ci if (unlikely(page->index >= MAIN_BLKADDR(sbi))) 36758c2ecf20Sopenharmony_ci fio.op_flags &= ~REQ_META; 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_ci set_page_writeback(page); 36788c2ecf20Sopenharmony_ci ClearPageError(page); 36798c2ecf20Sopenharmony_ci f2fs_submit_page_write(&fio); 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci stat_inc_meta_count(sbi, page->index); 36828c2ecf20Sopenharmony_ci f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE); 36838c2ecf20Sopenharmony_ci} 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_civoid f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio) 36868c2ecf20Sopenharmony_ci{ 36878c2ecf20Sopenharmony_ci struct f2fs_summary sum; 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_ci set_summary(&sum, nid, 0, 0); 36908c2ecf20Sopenharmony_ci do_write_page(&sum, fio); 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE); 36938c2ecf20Sopenharmony_ci} 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_civoid f2fs_outplace_write_data(struct dnode_of_data *dn, 36968c2ecf20Sopenharmony_ci struct f2fs_io_info *fio) 36978c2ecf20Sopenharmony_ci{ 36988c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = fio->sbi; 36998c2ecf20Sopenharmony_ci struct f2fs_summary sum; 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR); 37028c2ecf20Sopenharmony_ci set_summary(&sum, dn->nid, dn->ofs_in_node, fio->version); 37038c2ecf20Sopenharmony_ci do_write_page(&sum, fio); 37048c2ecf20Sopenharmony_ci f2fs_update_data_blkaddr(dn, fio->new_blkaddr); 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci f2fs_update_iostat(sbi, fio->io_type, F2FS_BLKSIZE); 37078c2ecf20Sopenharmony_ci} 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ciint f2fs_inplace_write_data(struct f2fs_io_info *fio) 37108c2ecf20Sopenharmony_ci{ 37118c2ecf20Sopenharmony_ci int err; 37128c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = fio->sbi; 37138c2ecf20Sopenharmony_ci unsigned int segno; 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_ci fio->new_blkaddr = fio->old_blkaddr; 37168c2ecf20Sopenharmony_ci /* i/o temperature is needed for passing down write hints */ 37178c2ecf20Sopenharmony_ci __get_segment_type(fio); 37188c2ecf20Sopenharmony_ci 37198c2ecf20Sopenharmony_ci segno = GET_SEGNO(sbi, fio->new_blkaddr); 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci if (!IS_DATASEG(get_seg_entry(sbi, segno)->type)) { 37228c2ecf20Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 37238c2ecf20Sopenharmony_ci f2fs_warn(sbi, "%s: incorrect segment(%u) type, run fsck to fix.", 37248c2ecf20Sopenharmony_ci __func__, segno); 37258c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 37268c2ecf20Sopenharmony_ci } 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci stat_inc_inplace_blocks(fio->sbi); 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_ci if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE))) 37318c2ecf20Sopenharmony_ci err = f2fs_merge_page_bio(fio); 37328c2ecf20Sopenharmony_ci else 37338c2ecf20Sopenharmony_ci err = f2fs_submit_page_bio(fio); 37348c2ecf20Sopenharmony_ci if (!err) { 37358c2ecf20Sopenharmony_ci update_device_state(fio); 37368c2ecf20Sopenharmony_ci f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE); 37378c2ecf20Sopenharmony_ci } 37388c2ecf20Sopenharmony_ci 37398c2ecf20Sopenharmony_ci return err; 37408c2ecf20Sopenharmony_ci} 37418c2ecf20Sopenharmony_ci 37428c2ecf20Sopenharmony_cistatic inline int __f2fs_get_curseg(struct f2fs_sb_info *sbi, 37438c2ecf20Sopenharmony_ci unsigned int segno) 37448c2ecf20Sopenharmony_ci{ 37458c2ecf20Sopenharmony_ci int i; 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci for (i = CURSEG_HOT_DATA; i < NO_CHECK_TYPE; i++) { 37488c2ecf20Sopenharmony_ci if (CURSEG_I(sbi, i)->segno == segno) 37498c2ecf20Sopenharmony_ci break; 37508c2ecf20Sopenharmony_ci } 37518c2ecf20Sopenharmony_ci return i; 37528c2ecf20Sopenharmony_ci} 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_civoid f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, 37558c2ecf20Sopenharmony_ci block_t old_blkaddr, block_t new_blkaddr, 37568c2ecf20Sopenharmony_ci bool recover_curseg, bool recover_newaddr, 37578c2ecf20Sopenharmony_ci bool from_gc) 37588c2ecf20Sopenharmony_ci{ 37598c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 37608c2ecf20Sopenharmony_ci struct curseg_info *curseg; 37618c2ecf20Sopenharmony_ci unsigned int segno, old_cursegno; 37628c2ecf20Sopenharmony_ci struct seg_entry *se; 37638c2ecf20Sopenharmony_ci int type; 37648c2ecf20Sopenharmony_ci unsigned short old_blkoff; 37658c2ecf20Sopenharmony_ci 37668c2ecf20Sopenharmony_ci segno = GET_SEGNO(sbi, new_blkaddr); 37678c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, segno); 37688c2ecf20Sopenharmony_ci type = se->type; 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci down_write(&SM_I(sbi)->curseg_lock); 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci if (!recover_curseg) { 37738c2ecf20Sopenharmony_ci /* for recovery flow */ 37748c2ecf20Sopenharmony_ci if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) { 37758c2ecf20Sopenharmony_ci if (old_blkaddr == NULL_ADDR) 37768c2ecf20Sopenharmony_ci type = CURSEG_COLD_DATA; 37778c2ecf20Sopenharmony_ci else 37788c2ecf20Sopenharmony_ci type = CURSEG_WARM_DATA; 37798c2ecf20Sopenharmony_ci } 37808c2ecf20Sopenharmony_ci } else { 37818c2ecf20Sopenharmony_ci if (IS_CURSEG(sbi, segno)) { 37828c2ecf20Sopenharmony_ci /* se->type is volatile as SSR allocation */ 37838c2ecf20Sopenharmony_ci type = __f2fs_get_curseg(sbi, segno); 37848c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, type == NO_CHECK_TYPE); 37858c2ecf20Sopenharmony_ci } else { 37868c2ecf20Sopenharmony_ci type = CURSEG_WARM_DATA; 37878c2ecf20Sopenharmony_ci } 37888c2ecf20Sopenharmony_ci } 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !IS_DATASEG(type)); 37918c2ecf20Sopenharmony_ci curseg = CURSEG_I(sbi, type); 37928c2ecf20Sopenharmony_ci 37938c2ecf20Sopenharmony_ci mutex_lock(&curseg->curseg_mutex); 37948c2ecf20Sopenharmony_ci down_write(&sit_i->sentry_lock); 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci old_cursegno = curseg->segno; 37978c2ecf20Sopenharmony_ci old_blkoff = curseg->next_blkoff; 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci /* change the current segment */ 38008c2ecf20Sopenharmony_ci if (segno != curseg->segno) { 38018c2ecf20Sopenharmony_ci curseg->next_segno = segno; 38028c2ecf20Sopenharmony_ci change_curseg(sbi, type, true); 38038c2ecf20Sopenharmony_ci } 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); 38068c2ecf20Sopenharmony_ci __add_sum_entry(sbi, type, sum); 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci if (!recover_curseg || recover_newaddr) { 38098c2ecf20Sopenharmony_ci if (!from_gc) 38108c2ecf20Sopenharmony_ci update_segment_mtime(sbi, new_blkaddr, 0); 38118c2ecf20Sopenharmony_ci update_sit_entry(sbi, new_blkaddr, 1); 38128c2ecf20Sopenharmony_ci } 38138c2ecf20Sopenharmony_ci if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) { 38148c2ecf20Sopenharmony_ci invalidate_mapping_pages(META_MAPPING(sbi), 38158c2ecf20Sopenharmony_ci old_blkaddr, old_blkaddr); 38168c2ecf20Sopenharmony_ci if (!from_gc) 38178c2ecf20Sopenharmony_ci update_segment_mtime(sbi, old_blkaddr, 0); 38188c2ecf20Sopenharmony_ci update_sit_entry(sbi, old_blkaddr, -1); 38198c2ecf20Sopenharmony_ci } 38208c2ecf20Sopenharmony_ci 38218c2ecf20Sopenharmony_ci locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); 38228c2ecf20Sopenharmony_ci locate_dirty_segment(sbi, GET_SEGNO(sbi, new_blkaddr)); 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci locate_dirty_segment(sbi, old_cursegno); 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_ci if (recover_curseg) { 38278c2ecf20Sopenharmony_ci if (old_cursegno != curseg->segno) { 38288c2ecf20Sopenharmony_ci curseg->next_segno = old_cursegno; 38298c2ecf20Sopenharmony_ci change_curseg(sbi, type, true); 38308c2ecf20Sopenharmony_ci } 38318c2ecf20Sopenharmony_ci curseg->next_blkoff = old_blkoff; 38328c2ecf20Sopenharmony_ci } 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci up_write(&sit_i->sentry_lock); 38358c2ecf20Sopenharmony_ci mutex_unlock(&curseg->curseg_mutex); 38368c2ecf20Sopenharmony_ci up_write(&SM_I(sbi)->curseg_lock); 38378c2ecf20Sopenharmony_ci} 38388c2ecf20Sopenharmony_ci 38398c2ecf20Sopenharmony_civoid f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, 38408c2ecf20Sopenharmony_ci block_t old_addr, block_t new_addr, 38418c2ecf20Sopenharmony_ci unsigned char version, bool recover_curseg, 38428c2ecf20Sopenharmony_ci bool recover_newaddr) 38438c2ecf20Sopenharmony_ci{ 38448c2ecf20Sopenharmony_ci struct f2fs_summary sum; 38458c2ecf20Sopenharmony_ci 38468c2ecf20Sopenharmony_ci set_summary(&sum, dn->nid, dn->ofs_in_node, version); 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_ci f2fs_do_replace_block(sbi, &sum, old_addr, new_addr, 38498c2ecf20Sopenharmony_ci recover_curseg, recover_newaddr, false); 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_ci f2fs_update_data_blkaddr(dn, new_addr); 38528c2ecf20Sopenharmony_ci} 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_civoid f2fs_wait_on_page_writeback(struct page *page, 38558c2ecf20Sopenharmony_ci enum page_type type, bool ordered, bool locked) 38568c2ecf20Sopenharmony_ci{ 38578c2ecf20Sopenharmony_ci if (PageWriteback(page)) { 38588c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_P_SB(page); 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci /* submit cached LFS IO */ 38618c2ecf20Sopenharmony_ci f2fs_submit_merged_write_cond(sbi, NULL, page, 0, type); 38628c2ecf20Sopenharmony_ci /* sbumit cached IPU IO */ 38638c2ecf20Sopenharmony_ci f2fs_submit_merged_ipu_write(sbi, NULL, page); 38648c2ecf20Sopenharmony_ci if (ordered) { 38658c2ecf20Sopenharmony_ci wait_on_page_writeback(page); 38668c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, locked && PageWriteback(page)); 38678c2ecf20Sopenharmony_ci } else { 38688c2ecf20Sopenharmony_ci wait_for_stable_page(page); 38698c2ecf20Sopenharmony_ci } 38708c2ecf20Sopenharmony_ci } 38718c2ecf20Sopenharmony_ci} 38728c2ecf20Sopenharmony_ci 38738c2ecf20Sopenharmony_civoid f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr) 38748c2ecf20Sopenharmony_ci{ 38758c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 38768c2ecf20Sopenharmony_ci struct page *cpage; 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci if (!f2fs_post_read_required(inode)) 38798c2ecf20Sopenharmony_ci return; 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci if (!__is_valid_data_blkaddr(blkaddr)) 38828c2ecf20Sopenharmony_ci return; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci cpage = find_lock_page(META_MAPPING(sbi), blkaddr); 38858c2ecf20Sopenharmony_ci if (cpage) { 38868c2ecf20Sopenharmony_ci f2fs_wait_on_page_writeback(cpage, DATA, true, true); 38878c2ecf20Sopenharmony_ci f2fs_put_page(cpage, 1); 38888c2ecf20Sopenharmony_ci } 38898c2ecf20Sopenharmony_ci} 38908c2ecf20Sopenharmony_ci 38918c2ecf20Sopenharmony_civoid f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr, 38928c2ecf20Sopenharmony_ci block_t len) 38938c2ecf20Sopenharmony_ci{ 38948c2ecf20Sopenharmony_ci block_t i; 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 38978c2ecf20Sopenharmony_ci f2fs_wait_on_block_writeback(inode, blkaddr + i); 38988c2ecf20Sopenharmony_ci} 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_cistatic int read_compacted_summaries(struct f2fs_sb_info *sbi) 39018c2ecf20Sopenharmony_ci{ 39028c2ecf20Sopenharmony_ci struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 39038c2ecf20Sopenharmony_ci struct curseg_info *seg_i; 39048c2ecf20Sopenharmony_ci unsigned char *kaddr; 39058c2ecf20Sopenharmony_ci struct page *page; 39068c2ecf20Sopenharmony_ci block_t start; 39078c2ecf20Sopenharmony_ci int i, j, offset; 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci start = start_sum_block(sbi); 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci page = f2fs_get_meta_page(sbi, start++); 39128c2ecf20Sopenharmony_ci if (IS_ERR(page)) 39138c2ecf20Sopenharmony_ci return PTR_ERR(page); 39148c2ecf20Sopenharmony_ci kaddr = (unsigned char *)page_address(page); 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci /* Step 1: restore nat cache */ 39178c2ecf20Sopenharmony_ci seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); 39188c2ecf20Sopenharmony_ci memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE); 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_ci /* Step 2: restore sit cache */ 39218c2ecf20Sopenharmony_ci seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); 39228c2ecf20Sopenharmony_ci memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); 39238c2ecf20Sopenharmony_ci offset = 2 * SUM_JOURNAL_SIZE; 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci /* Step 3: restore summary entries */ 39268c2ecf20Sopenharmony_ci for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { 39278c2ecf20Sopenharmony_ci unsigned short blk_off; 39288c2ecf20Sopenharmony_ci unsigned int segno; 39298c2ecf20Sopenharmony_ci 39308c2ecf20Sopenharmony_ci seg_i = CURSEG_I(sbi, i); 39318c2ecf20Sopenharmony_ci segno = le32_to_cpu(ckpt->cur_data_segno[i]); 39328c2ecf20Sopenharmony_ci blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); 39338c2ecf20Sopenharmony_ci seg_i->next_segno = segno; 39348c2ecf20Sopenharmony_ci reset_curseg(sbi, i, 0); 39358c2ecf20Sopenharmony_ci seg_i->alloc_type = ckpt->alloc_type[i]; 39368c2ecf20Sopenharmony_ci seg_i->next_blkoff = blk_off; 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci if (seg_i->alloc_type == SSR) 39398c2ecf20Sopenharmony_ci blk_off = sbi->blocks_per_seg; 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci for (j = 0; j < blk_off; j++) { 39428c2ecf20Sopenharmony_ci struct f2fs_summary *s; 39438c2ecf20Sopenharmony_ci s = (struct f2fs_summary *)(kaddr + offset); 39448c2ecf20Sopenharmony_ci seg_i->sum_blk->entries[j] = *s; 39458c2ecf20Sopenharmony_ci offset += SUMMARY_SIZE; 39468c2ecf20Sopenharmony_ci if (offset + SUMMARY_SIZE <= PAGE_SIZE - 39478c2ecf20Sopenharmony_ci SUM_FOOTER_SIZE) 39488c2ecf20Sopenharmony_ci continue; 39498c2ecf20Sopenharmony_ci 39508c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 39518c2ecf20Sopenharmony_ci page = NULL; 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci page = f2fs_get_meta_page(sbi, start++); 39548c2ecf20Sopenharmony_ci if (IS_ERR(page)) 39558c2ecf20Sopenharmony_ci return PTR_ERR(page); 39568c2ecf20Sopenharmony_ci kaddr = (unsigned char *)page_address(page); 39578c2ecf20Sopenharmony_ci offset = 0; 39588c2ecf20Sopenharmony_ci } 39598c2ecf20Sopenharmony_ci } 39608c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 39618c2ecf20Sopenharmony_ci return 0; 39628c2ecf20Sopenharmony_ci} 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_cistatic int read_normal_summaries(struct f2fs_sb_info *sbi, int type) 39658c2ecf20Sopenharmony_ci{ 39668c2ecf20Sopenharmony_ci struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 39678c2ecf20Sopenharmony_ci struct f2fs_summary_block *sum; 39688c2ecf20Sopenharmony_ci struct curseg_info *curseg; 39698c2ecf20Sopenharmony_ci struct page *new; 39708c2ecf20Sopenharmony_ci unsigned short blk_off; 39718c2ecf20Sopenharmony_ci unsigned int segno = 0; 39728c2ecf20Sopenharmony_ci block_t blk_addr = 0; 39738c2ecf20Sopenharmony_ci int err = 0; 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ci /* get segment number and block addr */ 39768c2ecf20Sopenharmony_ci if (IS_DATASEG(type)) { 39778c2ecf20Sopenharmony_ci segno = le32_to_cpu(ckpt->cur_data_segno[type]); 39788c2ecf20Sopenharmony_ci blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - 39798c2ecf20Sopenharmony_ci CURSEG_HOT_DATA]); 39808c2ecf20Sopenharmony_ci if (__exist_node_summaries(sbi)) 39818c2ecf20Sopenharmony_ci blk_addr = sum_blk_addr(sbi, NR_CURSEG_PERSIST_TYPE, type); 39828c2ecf20Sopenharmony_ci else 39838c2ecf20Sopenharmony_ci blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); 39848c2ecf20Sopenharmony_ci } else { 39858c2ecf20Sopenharmony_ci segno = le32_to_cpu(ckpt->cur_node_segno[type - 39868c2ecf20Sopenharmony_ci CURSEG_HOT_NODE]); 39878c2ecf20Sopenharmony_ci blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - 39888c2ecf20Sopenharmony_ci CURSEG_HOT_NODE]); 39898c2ecf20Sopenharmony_ci if (__exist_node_summaries(sbi)) 39908c2ecf20Sopenharmony_ci blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, 39918c2ecf20Sopenharmony_ci type - CURSEG_HOT_NODE); 39928c2ecf20Sopenharmony_ci else 39938c2ecf20Sopenharmony_ci blk_addr = GET_SUM_BLOCK(sbi, segno); 39948c2ecf20Sopenharmony_ci } 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci new = f2fs_get_meta_page(sbi, blk_addr); 39978c2ecf20Sopenharmony_ci if (IS_ERR(new)) 39988c2ecf20Sopenharmony_ci return PTR_ERR(new); 39998c2ecf20Sopenharmony_ci sum = (struct f2fs_summary_block *)page_address(new); 40008c2ecf20Sopenharmony_ci 40018c2ecf20Sopenharmony_ci if (IS_NODESEG(type)) { 40028c2ecf20Sopenharmony_ci if (__exist_node_summaries(sbi)) { 40038c2ecf20Sopenharmony_ci struct f2fs_summary *ns = &sum->entries[0]; 40048c2ecf20Sopenharmony_ci int i; 40058c2ecf20Sopenharmony_ci for (i = 0; i < sbi->blocks_per_seg; i++, ns++) { 40068c2ecf20Sopenharmony_ci ns->version = 0; 40078c2ecf20Sopenharmony_ci ns->ofs_in_node = 0; 40088c2ecf20Sopenharmony_ci } 40098c2ecf20Sopenharmony_ci } else { 40108c2ecf20Sopenharmony_ci err = f2fs_restore_node_summary(sbi, segno, sum); 40118c2ecf20Sopenharmony_ci if (err) 40128c2ecf20Sopenharmony_ci goto out; 40138c2ecf20Sopenharmony_ci } 40148c2ecf20Sopenharmony_ci } 40158c2ecf20Sopenharmony_ci 40168c2ecf20Sopenharmony_ci /* set uncompleted segment to curseg */ 40178c2ecf20Sopenharmony_ci curseg = CURSEG_I(sbi, type); 40188c2ecf20Sopenharmony_ci mutex_lock(&curseg->curseg_mutex); 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci /* update journal info */ 40218c2ecf20Sopenharmony_ci down_write(&curseg->journal_rwsem); 40228c2ecf20Sopenharmony_ci memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE); 40238c2ecf20Sopenharmony_ci up_write(&curseg->journal_rwsem); 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE); 40268c2ecf20Sopenharmony_ci memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE); 40278c2ecf20Sopenharmony_ci curseg->next_segno = segno; 40288c2ecf20Sopenharmony_ci reset_curseg(sbi, type, 0); 40298c2ecf20Sopenharmony_ci curseg->alloc_type = ckpt->alloc_type[type]; 40308c2ecf20Sopenharmony_ci curseg->next_blkoff = blk_off; 40318c2ecf20Sopenharmony_ci mutex_unlock(&curseg->curseg_mutex); 40328c2ecf20Sopenharmony_ciout: 40338c2ecf20Sopenharmony_ci f2fs_put_page(new, 1); 40348c2ecf20Sopenharmony_ci return err; 40358c2ecf20Sopenharmony_ci} 40368c2ecf20Sopenharmony_ci 40378c2ecf20Sopenharmony_cistatic int restore_curseg_summaries(struct f2fs_sb_info *sbi) 40388c2ecf20Sopenharmony_ci{ 40398c2ecf20Sopenharmony_ci struct f2fs_journal *sit_j = CURSEG_I(sbi, CURSEG_COLD_DATA)->journal; 40408c2ecf20Sopenharmony_ci struct f2fs_journal *nat_j = CURSEG_I(sbi, CURSEG_HOT_DATA)->journal; 40418c2ecf20Sopenharmony_ci int type = CURSEG_HOT_DATA; 40428c2ecf20Sopenharmony_ci int err; 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) { 40458c2ecf20Sopenharmony_ci int npages = f2fs_npages_for_summary_flush(sbi, true); 40468c2ecf20Sopenharmony_ci 40478c2ecf20Sopenharmony_ci if (npages >= 2) 40488c2ecf20Sopenharmony_ci f2fs_ra_meta_pages(sbi, start_sum_block(sbi), npages, 40498c2ecf20Sopenharmony_ci META_CP, true); 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_ci /* restore for compacted data summary */ 40528c2ecf20Sopenharmony_ci err = read_compacted_summaries(sbi); 40538c2ecf20Sopenharmony_ci if (err) 40548c2ecf20Sopenharmony_ci return err; 40558c2ecf20Sopenharmony_ci type = CURSEG_HOT_NODE; 40568c2ecf20Sopenharmony_ci } 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci if (__exist_node_summaries(sbi)) 40598c2ecf20Sopenharmony_ci f2fs_ra_meta_pages(sbi, 40608c2ecf20Sopenharmony_ci sum_blk_addr(sbi, NR_CURSEG_PERSIST_TYPE, type), 40618c2ecf20Sopenharmony_ci NR_CURSEG_PERSIST_TYPE - type, META_CP, true); 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci for (; type <= CURSEG_COLD_NODE; type++) { 40648c2ecf20Sopenharmony_ci err = read_normal_summaries(sbi, type); 40658c2ecf20Sopenharmony_ci if (err) 40668c2ecf20Sopenharmony_ci return err; 40678c2ecf20Sopenharmony_ci } 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci /* sanity check for summary blocks */ 40708c2ecf20Sopenharmony_ci if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES || 40718c2ecf20Sopenharmony_ci sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) { 40728c2ecf20Sopenharmony_ci f2fs_err(sbi, "invalid journal entries nats %u sits %u\n", 40738c2ecf20Sopenharmony_ci nats_in_cursum(nat_j), sits_in_cursum(sit_j)); 40748c2ecf20Sopenharmony_ci return -EINVAL; 40758c2ecf20Sopenharmony_ci } 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_ci return 0; 40788c2ecf20Sopenharmony_ci} 40798c2ecf20Sopenharmony_ci 40808c2ecf20Sopenharmony_cistatic void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) 40818c2ecf20Sopenharmony_ci{ 40828c2ecf20Sopenharmony_ci struct page *page; 40838c2ecf20Sopenharmony_ci unsigned char *kaddr; 40848c2ecf20Sopenharmony_ci struct f2fs_summary *summary; 40858c2ecf20Sopenharmony_ci struct curseg_info *seg_i; 40868c2ecf20Sopenharmony_ci int written_size = 0; 40878c2ecf20Sopenharmony_ci int i, j; 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_ci page = f2fs_grab_meta_page(sbi, blkaddr++); 40908c2ecf20Sopenharmony_ci kaddr = (unsigned char *)page_address(page); 40918c2ecf20Sopenharmony_ci memset(kaddr, 0, PAGE_SIZE); 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ci /* Step 1: write nat cache */ 40948c2ecf20Sopenharmony_ci seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); 40958c2ecf20Sopenharmony_ci memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE); 40968c2ecf20Sopenharmony_ci written_size += SUM_JOURNAL_SIZE; 40978c2ecf20Sopenharmony_ci 40988c2ecf20Sopenharmony_ci /* Step 2: write sit cache */ 40998c2ecf20Sopenharmony_ci seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); 41008c2ecf20Sopenharmony_ci memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE); 41018c2ecf20Sopenharmony_ci written_size += SUM_JOURNAL_SIZE; 41028c2ecf20Sopenharmony_ci 41038c2ecf20Sopenharmony_ci /* Step 3: write summary entries */ 41048c2ecf20Sopenharmony_ci for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { 41058c2ecf20Sopenharmony_ci unsigned short blkoff; 41068c2ecf20Sopenharmony_ci seg_i = CURSEG_I(sbi, i); 41078c2ecf20Sopenharmony_ci if (sbi->ckpt->alloc_type[i] == SSR) 41088c2ecf20Sopenharmony_ci blkoff = sbi->blocks_per_seg; 41098c2ecf20Sopenharmony_ci else 41108c2ecf20Sopenharmony_ci blkoff = curseg_blkoff(sbi, i); 41118c2ecf20Sopenharmony_ci 41128c2ecf20Sopenharmony_ci for (j = 0; j < blkoff; j++) { 41138c2ecf20Sopenharmony_ci if (!page) { 41148c2ecf20Sopenharmony_ci page = f2fs_grab_meta_page(sbi, blkaddr++); 41158c2ecf20Sopenharmony_ci kaddr = (unsigned char *)page_address(page); 41168c2ecf20Sopenharmony_ci memset(kaddr, 0, PAGE_SIZE); 41178c2ecf20Sopenharmony_ci written_size = 0; 41188c2ecf20Sopenharmony_ci } 41198c2ecf20Sopenharmony_ci summary = (struct f2fs_summary *)(kaddr + written_size); 41208c2ecf20Sopenharmony_ci *summary = seg_i->sum_blk->entries[j]; 41218c2ecf20Sopenharmony_ci written_size += SUMMARY_SIZE; 41228c2ecf20Sopenharmony_ci 41238c2ecf20Sopenharmony_ci if (written_size + SUMMARY_SIZE <= PAGE_SIZE - 41248c2ecf20Sopenharmony_ci SUM_FOOTER_SIZE) 41258c2ecf20Sopenharmony_ci continue; 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_ci set_page_dirty(page); 41288c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 41298c2ecf20Sopenharmony_ci page = NULL; 41308c2ecf20Sopenharmony_ci } 41318c2ecf20Sopenharmony_ci } 41328c2ecf20Sopenharmony_ci if (page) { 41338c2ecf20Sopenharmony_ci set_page_dirty(page); 41348c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 41358c2ecf20Sopenharmony_ci } 41368c2ecf20Sopenharmony_ci} 41378c2ecf20Sopenharmony_ci 41388c2ecf20Sopenharmony_cistatic void write_normal_summaries(struct f2fs_sb_info *sbi, 41398c2ecf20Sopenharmony_ci block_t blkaddr, int type) 41408c2ecf20Sopenharmony_ci{ 41418c2ecf20Sopenharmony_ci int i, end; 41428c2ecf20Sopenharmony_ci if (IS_DATASEG(type)) 41438c2ecf20Sopenharmony_ci end = type + NR_CURSEG_DATA_TYPE; 41448c2ecf20Sopenharmony_ci else 41458c2ecf20Sopenharmony_ci end = type + NR_CURSEG_NODE_TYPE; 41468c2ecf20Sopenharmony_ci 41478c2ecf20Sopenharmony_ci for (i = type; i < end; i++) 41488c2ecf20Sopenharmony_ci write_current_sum_page(sbi, i, blkaddr + (i - type)); 41498c2ecf20Sopenharmony_ci} 41508c2ecf20Sopenharmony_ci 41518c2ecf20Sopenharmony_civoid f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk) 41528c2ecf20Sopenharmony_ci{ 41538c2ecf20Sopenharmony_ci if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) 41548c2ecf20Sopenharmony_ci write_compacted_summaries(sbi, start_blk); 41558c2ecf20Sopenharmony_ci else 41568c2ecf20Sopenharmony_ci write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA); 41578c2ecf20Sopenharmony_ci} 41588c2ecf20Sopenharmony_ci 41598c2ecf20Sopenharmony_civoid f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) 41608c2ecf20Sopenharmony_ci{ 41618c2ecf20Sopenharmony_ci write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); 41628c2ecf20Sopenharmony_ci} 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_ciint f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type, 41658c2ecf20Sopenharmony_ci unsigned int val, int alloc) 41668c2ecf20Sopenharmony_ci{ 41678c2ecf20Sopenharmony_ci int i; 41688c2ecf20Sopenharmony_ci 41698c2ecf20Sopenharmony_ci if (type == NAT_JOURNAL) { 41708c2ecf20Sopenharmony_ci for (i = 0; i < nats_in_cursum(journal); i++) { 41718c2ecf20Sopenharmony_ci if (le32_to_cpu(nid_in_journal(journal, i)) == val) 41728c2ecf20Sopenharmony_ci return i; 41738c2ecf20Sopenharmony_ci } 41748c2ecf20Sopenharmony_ci if (alloc && __has_cursum_space(journal, 1, NAT_JOURNAL)) 41758c2ecf20Sopenharmony_ci return update_nats_in_cursum(journal, 1); 41768c2ecf20Sopenharmony_ci } else if (type == SIT_JOURNAL) { 41778c2ecf20Sopenharmony_ci for (i = 0; i < sits_in_cursum(journal); i++) 41788c2ecf20Sopenharmony_ci if (le32_to_cpu(segno_in_journal(journal, i)) == val) 41798c2ecf20Sopenharmony_ci return i; 41808c2ecf20Sopenharmony_ci if (alloc && __has_cursum_space(journal, 1, SIT_JOURNAL)) 41818c2ecf20Sopenharmony_ci return update_sits_in_cursum(journal, 1); 41828c2ecf20Sopenharmony_ci } 41838c2ecf20Sopenharmony_ci return -1; 41848c2ecf20Sopenharmony_ci} 41858c2ecf20Sopenharmony_ci 41868c2ecf20Sopenharmony_cistatic struct page *get_current_sit_page(struct f2fs_sb_info *sbi, 41878c2ecf20Sopenharmony_ci unsigned int segno) 41888c2ecf20Sopenharmony_ci{ 41898c2ecf20Sopenharmony_ci return f2fs_get_meta_page(sbi, current_sit_addr(sbi, segno)); 41908c2ecf20Sopenharmony_ci} 41918c2ecf20Sopenharmony_ci 41928c2ecf20Sopenharmony_cistatic struct page *get_next_sit_page(struct f2fs_sb_info *sbi, 41938c2ecf20Sopenharmony_ci unsigned int start) 41948c2ecf20Sopenharmony_ci{ 41958c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 41968c2ecf20Sopenharmony_ci struct page *page; 41978c2ecf20Sopenharmony_ci pgoff_t src_off, dst_off; 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_ci src_off = current_sit_addr(sbi, start); 42008c2ecf20Sopenharmony_ci dst_off = next_sit_addr(sbi, src_off); 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci page = f2fs_grab_meta_page(sbi, dst_off); 42038c2ecf20Sopenharmony_ci seg_info_to_sit_page(sbi, page, start); 42048c2ecf20Sopenharmony_ci 42058c2ecf20Sopenharmony_ci set_page_dirty(page); 42068c2ecf20Sopenharmony_ci set_to_next_sit(sit_i, start); 42078c2ecf20Sopenharmony_ci 42088c2ecf20Sopenharmony_ci return page; 42098c2ecf20Sopenharmony_ci} 42108c2ecf20Sopenharmony_ci 42118c2ecf20Sopenharmony_cistatic struct sit_entry_set *grab_sit_entry_set(void) 42128c2ecf20Sopenharmony_ci{ 42138c2ecf20Sopenharmony_ci struct sit_entry_set *ses = 42148c2ecf20Sopenharmony_ci f2fs_kmem_cache_alloc(sit_entry_set_slab, GFP_NOFS); 42158c2ecf20Sopenharmony_ci 42168c2ecf20Sopenharmony_ci ses->entry_cnt = 0; 42178c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ses->set_list); 42188c2ecf20Sopenharmony_ci return ses; 42198c2ecf20Sopenharmony_ci} 42208c2ecf20Sopenharmony_ci 42218c2ecf20Sopenharmony_cistatic void release_sit_entry_set(struct sit_entry_set *ses) 42228c2ecf20Sopenharmony_ci{ 42238c2ecf20Sopenharmony_ci list_del(&ses->set_list); 42248c2ecf20Sopenharmony_ci kmem_cache_free(sit_entry_set_slab, ses); 42258c2ecf20Sopenharmony_ci} 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_cistatic void adjust_sit_entry_set(struct sit_entry_set *ses, 42288c2ecf20Sopenharmony_ci struct list_head *head) 42298c2ecf20Sopenharmony_ci{ 42308c2ecf20Sopenharmony_ci struct sit_entry_set *next = ses; 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci if (list_is_last(&ses->set_list, head)) 42338c2ecf20Sopenharmony_ci return; 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ci list_for_each_entry_continue(next, head, set_list) 42368c2ecf20Sopenharmony_ci if (ses->entry_cnt <= next->entry_cnt) 42378c2ecf20Sopenharmony_ci break; 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci list_move_tail(&ses->set_list, &next->set_list); 42408c2ecf20Sopenharmony_ci} 42418c2ecf20Sopenharmony_ci 42428c2ecf20Sopenharmony_cistatic void add_sit_entry(unsigned int segno, struct list_head *head) 42438c2ecf20Sopenharmony_ci{ 42448c2ecf20Sopenharmony_ci struct sit_entry_set *ses; 42458c2ecf20Sopenharmony_ci unsigned int start_segno = START_SEGNO(segno); 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci list_for_each_entry(ses, head, set_list) { 42488c2ecf20Sopenharmony_ci if (ses->start_segno == start_segno) { 42498c2ecf20Sopenharmony_ci ses->entry_cnt++; 42508c2ecf20Sopenharmony_ci adjust_sit_entry_set(ses, head); 42518c2ecf20Sopenharmony_ci return; 42528c2ecf20Sopenharmony_ci } 42538c2ecf20Sopenharmony_ci } 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci ses = grab_sit_entry_set(); 42568c2ecf20Sopenharmony_ci 42578c2ecf20Sopenharmony_ci ses->start_segno = start_segno; 42588c2ecf20Sopenharmony_ci ses->entry_cnt++; 42598c2ecf20Sopenharmony_ci list_add(&ses->set_list, head); 42608c2ecf20Sopenharmony_ci} 42618c2ecf20Sopenharmony_ci 42628c2ecf20Sopenharmony_cistatic void add_sits_in_set(struct f2fs_sb_info *sbi) 42638c2ecf20Sopenharmony_ci{ 42648c2ecf20Sopenharmony_ci struct f2fs_sm_info *sm_info = SM_I(sbi); 42658c2ecf20Sopenharmony_ci struct list_head *set_list = &sm_info->sit_entry_set; 42668c2ecf20Sopenharmony_ci unsigned long *bitmap = SIT_I(sbi)->dirty_sentries_bitmap; 42678c2ecf20Sopenharmony_ci unsigned int segno; 42688c2ecf20Sopenharmony_ci 42698c2ecf20Sopenharmony_ci for_each_set_bit(segno, bitmap, MAIN_SEGS(sbi)) 42708c2ecf20Sopenharmony_ci add_sit_entry(segno, set_list); 42718c2ecf20Sopenharmony_ci} 42728c2ecf20Sopenharmony_ci 42738c2ecf20Sopenharmony_cistatic void remove_sits_in_journal(struct f2fs_sb_info *sbi) 42748c2ecf20Sopenharmony_ci{ 42758c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); 42768c2ecf20Sopenharmony_ci struct f2fs_journal *journal = curseg->journal; 42778c2ecf20Sopenharmony_ci int i; 42788c2ecf20Sopenharmony_ci 42798c2ecf20Sopenharmony_ci down_write(&curseg->journal_rwsem); 42808c2ecf20Sopenharmony_ci for (i = 0; i < sits_in_cursum(journal); i++) { 42818c2ecf20Sopenharmony_ci unsigned int segno; 42828c2ecf20Sopenharmony_ci bool dirtied; 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_ci segno = le32_to_cpu(segno_in_journal(journal, i)); 42858c2ecf20Sopenharmony_ci dirtied = __mark_sit_entry_dirty(sbi, segno); 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_ci if (!dirtied) 42888c2ecf20Sopenharmony_ci add_sit_entry(segno, &SM_I(sbi)->sit_entry_set); 42898c2ecf20Sopenharmony_ci } 42908c2ecf20Sopenharmony_ci update_sits_in_cursum(journal, -i); 42918c2ecf20Sopenharmony_ci up_write(&curseg->journal_rwsem); 42928c2ecf20Sopenharmony_ci} 42938c2ecf20Sopenharmony_ci 42948c2ecf20Sopenharmony_ci/* 42958c2ecf20Sopenharmony_ci * CP calls this function, which flushes SIT entries including sit_journal, 42968c2ecf20Sopenharmony_ci * and moves prefree segs to free segs. 42978c2ecf20Sopenharmony_ci */ 42988c2ecf20Sopenharmony_civoid f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) 42998c2ecf20Sopenharmony_ci{ 43008c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 43018c2ecf20Sopenharmony_ci unsigned long *bitmap = sit_i->dirty_sentries_bitmap; 43028c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); 43038c2ecf20Sopenharmony_ci struct f2fs_journal *journal = curseg->journal; 43048c2ecf20Sopenharmony_ci struct sit_entry_set *ses, *tmp; 43058c2ecf20Sopenharmony_ci struct list_head *head = &SM_I(sbi)->sit_entry_set; 43068c2ecf20Sopenharmony_ci bool to_journal = !is_sbi_flag_set(sbi, SBI_IS_RESIZEFS); 43078c2ecf20Sopenharmony_ci struct seg_entry *se; 43088c2ecf20Sopenharmony_ci 43098c2ecf20Sopenharmony_ci down_write(&sit_i->sentry_lock); 43108c2ecf20Sopenharmony_ci 43118c2ecf20Sopenharmony_ci if (!sit_i->dirty_sentries) 43128c2ecf20Sopenharmony_ci goto out; 43138c2ecf20Sopenharmony_ci 43148c2ecf20Sopenharmony_ci /* 43158c2ecf20Sopenharmony_ci * add and account sit entries of dirty bitmap in sit entry 43168c2ecf20Sopenharmony_ci * set temporarily 43178c2ecf20Sopenharmony_ci */ 43188c2ecf20Sopenharmony_ci add_sits_in_set(sbi); 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci /* 43218c2ecf20Sopenharmony_ci * if there are no enough space in journal to store dirty sit 43228c2ecf20Sopenharmony_ci * entries, remove all entries from journal and add and account 43238c2ecf20Sopenharmony_ci * them in sit entry set. 43248c2ecf20Sopenharmony_ci */ 43258c2ecf20Sopenharmony_ci if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL) || 43268c2ecf20Sopenharmony_ci !to_journal) 43278c2ecf20Sopenharmony_ci remove_sits_in_journal(sbi); 43288c2ecf20Sopenharmony_ci 43298c2ecf20Sopenharmony_ci /* 43308c2ecf20Sopenharmony_ci * there are two steps to flush sit entries: 43318c2ecf20Sopenharmony_ci * #1, flush sit entries to journal in current cold data summary block. 43328c2ecf20Sopenharmony_ci * #2, flush sit entries to sit page. 43338c2ecf20Sopenharmony_ci */ 43348c2ecf20Sopenharmony_ci list_for_each_entry_safe(ses, tmp, head, set_list) { 43358c2ecf20Sopenharmony_ci struct page *page = NULL; 43368c2ecf20Sopenharmony_ci struct f2fs_sit_block *raw_sit = NULL; 43378c2ecf20Sopenharmony_ci unsigned int start_segno = ses->start_segno; 43388c2ecf20Sopenharmony_ci unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK, 43398c2ecf20Sopenharmony_ci (unsigned long)MAIN_SEGS(sbi)); 43408c2ecf20Sopenharmony_ci unsigned int segno = start_segno; 43418c2ecf20Sopenharmony_ci 43428c2ecf20Sopenharmony_ci if (to_journal && 43438c2ecf20Sopenharmony_ci !__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL)) 43448c2ecf20Sopenharmony_ci to_journal = false; 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_ci if (to_journal) { 43478c2ecf20Sopenharmony_ci down_write(&curseg->journal_rwsem); 43488c2ecf20Sopenharmony_ci } else { 43498c2ecf20Sopenharmony_ci page = get_next_sit_page(sbi, start_segno); 43508c2ecf20Sopenharmony_ci raw_sit = page_address(page); 43518c2ecf20Sopenharmony_ci } 43528c2ecf20Sopenharmony_ci 43538c2ecf20Sopenharmony_ci /* flush dirty sit entries in region of current sit set */ 43548c2ecf20Sopenharmony_ci for_each_set_bit_from(segno, bitmap, end) { 43558c2ecf20Sopenharmony_ci int offset, sit_offset; 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, segno); 43588c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 43598c2ecf20Sopenharmony_ci if (memcmp(se->cur_valid_map, se->cur_valid_map_mir, 43608c2ecf20Sopenharmony_ci SIT_VBLOCK_MAP_SIZE)) 43618c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, 1); 43628c2ecf20Sopenharmony_ci#endif 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_ci /* add discard candidates */ 43658c2ecf20Sopenharmony_ci if (!(cpc->reason & CP_DISCARD)) { 43668c2ecf20Sopenharmony_ci cpc->trim_start = segno; 43678c2ecf20Sopenharmony_ci add_discard_addrs(sbi, cpc, false); 43688c2ecf20Sopenharmony_ci } 43698c2ecf20Sopenharmony_ci 43708c2ecf20Sopenharmony_ci if (to_journal) { 43718c2ecf20Sopenharmony_ci offset = f2fs_lookup_journal_in_cursum(journal, 43728c2ecf20Sopenharmony_ci SIT_JOURNAL, segno, 1); 43738c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, offset < 0); 43748c2ecf20Sopenharmony_ci segno_in_journal(journal, offset) = 43758c2ecf20Sopenharmony_ci cpu_to_le32(segno); 43768c2ecf20Sopenharmony_ci seg_info_to_raw_sit(se, 43778c2ecf20Sopenharmony_ci &sit_in_journal(journal, offset)); 43788c2ecf20Sopenharmony_ci check_block_count(sbi, segno, 43798c2ecf20Sopenharmony_ci &sit_in_journal(journal, offset)); 43808c2ecf20Sopenharmony_ci } else { 43818c2ecf20Sopenharmony_ci sit_offset = SIT_ENTRY_OFFSET(sit_i, segno); 43828c2ecf20Sopenharmony_ci seg_info_to_raw_sit(se, 43838c2ecf20Sopenharmony_ci &raw_sit->entries[sit_offset]); 43848c2ecf20Sopenharmony_ci check_block_count(sbi, segno, 43858c2ecf20Sopenharmony_ci &raw_sit->entries[sit_offset]); 43868c2ecf20Sopenharmony_ci } 43878c2ecf20Sopenharmony_ci 43888c2ecf20Sopenharmony_ci __clear_bit(segno, bitmap); 43898c2ecf20Sopenharmony_ci sit_i->dirty_sentries--; 43908c2ecf20Sopenharmony_ci ses->entry_cnt--; 43918c2ecf20Sopenharmony_ci } 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_ci if (to_journal) 43948c2ecf20Sopenharmony_ci up_write(&curseg->journal_rwsem); 43958c2ecf20Sopenharmony_ci else 43968c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 43978c2ecf20Sopenharmony_ci 43988c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, ses->entry_cnt); 43998c2ecf20Sopenharmony_ci release_sit_entry_set(ses); 44008c2ecf20Sopenharmony_ci } 44018c2ecf20Sopenharmony_ci 44028c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !list_empty(head)); 44038c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, sit_i->dirty_sentries); 44048c2ecf20Sopenharmony_ciout: 44058c2ecf20Sopenharmony_ci if (cpc->reason & CP_DISCARD) { 44068c2ecf20Sopenharmony_ci __u64 trim_start = cpc->trim_start; 44078c2ecf20Sopenharmony_ci 44088c2ecf20Sopenharmony_ci for (; cpc->trim_start <= cpc->trim_end; cpc->trim_start++) 44098c2ecf20Sopenharmony_ci add_discard_addrs(sbi, cpc, false); 44108c2ecf20Sopenharmony_ci 44118c2ecf20Sopenharmony_ci cpc->trim_start = trim_start; 44128c2ecf20Sopenharmony_ci } 44138c2ecf20Sopenharmony_ci up_write(&sit_i->sentry_lock); 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_ci set_prefree_as_free_segments(sbi); 44168c2ecf20Sopenharmony_ci} 44178c2ecf20Sopenharmony_ci 44188c2ecf20Sopenharmony_cistatic int build_sit_info(struct f2fs_sb_info *sbi) 44198c2ecf20Sopenharmony_ci{ 44208c2ecf20Sopenharmony_ci struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); 44218c2ecf20Sopenharmony_ci struct sit_info *sit_i; 44228c2ecf20Sopenharmony_ci unsigned int sit_segs, start; 44238c2ecf20Sopenharmony_ci char *src_bitmap, *bitmap; 44248c2ecf20Sopenharmony_ci unsigned int bitmap_size, main_bitmap_size, sit_bitmap_size; 44258c2ecf20Sopenharmony_ci 44268c2ecf20Sopenharmony_ci /* allocate memory for SIT information */ 44278c2ecf20Sopenharmony_ci sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL); 44288c2ecf20Sopenharmony_ci if (!sit_i) 44298c2ecf20Sopenharmony_ci return -ENOMEM; 44308c2ecf20Sopenharmony_ci 44318c2ecf20Sopenharmony_ci SM_I(sbi)->sit_info = sit_i; 44328c2ecf20Sopenharmony_ci 44338c2ecf20Sopenharmony_ci sit_i->sentries = 44348c2ecf20Sopenharmony_ci f2fs_kvzalloc(sbi, array_size(sizeof(struct seg_entry), 44358c2ecf20Sopenharmony_ci MAIN_SEGS(sbi)), 44368c2ecf20Sopenharmony_ci GFP_KERNEL); 44378c2ecf20Sopenharmony_ci if (!sit_i->sentries) 44388c2ecf20Sopenharmony_ci return -ENOMEM; 44398c2ecf20Sopenharmony_ci 44408c2ecf20Sopenharmony_ci main_bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi)); 44418c2ecf20Sopenharmony_ci sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, main_bitmap_size, 44428c2ecf20Sopenharmony_ci GFP_KERNEL); 44438c2ecf20Sopenharmony_ci if (!sit_i->dirty_sentries_bitmap) 44448c2ecf20Sopenharmony_ci return -ENOMEM; 44458c2ecf20Sopenharmony_ci 44468c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 44478c2ecf20Sopenharmony_ci bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 4; 44488c2ecf20Sopenharmony_ci#else 44498c2ecf20Sopenharmony_ci bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 3; 44508c2ecf20Sopenharmony_ci#endif 44518c2ecf20Sopenharmony_ci sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL); 44528c2ecf20Sopenharmony_ci if (!sit_i->bitmap) 44538c2ecf20Sopenharmony_ci return -ENOMEM; 44548c2ecf20Sopenharmony_ci 44558c2ecf20Sopenharmony_ci bitmap = sit_i->bitmap; 44568c2ecf20Sopenharmony_ci 44578c2ecf20Sopenharmony_ci for (start = 0; start < MAIN_SEGS(sbi); start++) { 44588c2ecf20Sopenharmony_ci sit_i->sentries[start].cur_valid_map = bitmap; 44598c2ecf20Sopenharmony_ci bitmap += SIT_VBLOCK_MAP_SIZE; 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_ci sit_i->sentries[start].ckpt_valid_map = bitmap; 44628c2ecf20Sopenharmony_ci bitmap += SIT_VBLOCK_MAP_SIZE; 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 44658c2ecf20Sopenharmony_ci sit_i->sentries[start].cur_valid_map_mir = bitmap; 44668c2ecf20Sopenharmony_ci bitmap += SIT_VBLOCK_MAP_SIZE; 44678c2ecf20Sopenharmony_ci#endif 44688c2ecf20Sopenharmony_ci 44698c2ecf20Sopenharmony_ci sit_i->sentries[start].discard_map = bitmap; 44708c2ecf20Sopenharmony_ci bitmap += SIT_VBLOCK_MAP_SIZE; 44718c2ecf20Sopenharmony_ci } 44728c2ecf20Sopenharmony_ci 44738c2ecf20Sopenharmony_ci sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); 44748c2ecf20Sopenharmony_ci if (!sit_i->tmp_map) 44758c2ecf20Sopenharmony_ci return -ENOMEM; 44768c2ecf20Sopenharmony_ci 44778c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) { 44788c2ecf20Sopenharmony_ci sit_i->sec_entries = 44798c2ecf20Sopenharmony_ci f2fs_kvzalloc(sbi, array_size(sizeof(struct sec_entry), 44808c2ecf20Sopenharmony_ci MAIN_SECS(sbi)), 44818c2ecf20Sopenharmony_ci GFP_KERNEL); 44828c2ecf20Sopenharmony_ci if (!sit_i->sec_entries) 44838c2ecf20Sopenharmony_ci return -ENOMEM; 44848c2ecf20Sopenharmony_ci } 44858c2ecf20Sopenharmony_ci 44868c2ecf20Sopenharmony_ci /* get information related with SIT */ 44878c2ecf20Sopenharmony_ci sit_segs = le32_to_cpu(raw_super->segment_count_sit) >> 1; 44888c2ecf20Sopenharmony_ci 44898c2ecf20Sopenharmony_ci /* setup SIT bitmap from ckeckpoint pack */ 44908c2ecf20Sopenharmony_ci sit_bitmap_size = __bitmap_size(sbi, SIT_BITMAP); 44918c2ecf20Sopenharmony_ci src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP); 44928c2ecf20Sopenharmony_ci 44938c2ecf20Sopenharmony_ci sit_i->sit_bitmap = kmemdup(src_bitmap, sit_bitmap_size, GFP_KERNEL); 44948c2ecf20Sopenharmony_ci if (!sit_i->sit_bitmap) 44958c2ecf20Sopenharmony_ci return -ENOMEM; 44968c2ecf20Sopenharmony_ci 44978c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 44988c2ecf20Sopenharmony_ci sit_i->sit_bitmap_mir = kmemdup(src_bitmap, 44998c2ecf20Sopenharmony_ci sit_bitmap_size, GFP_KERNEL); 45008c2ecf20Sopenharmony_ci if (!sit_i->sit_bitmap_mir) 45018c2ecf20Sopenharmony_ci return -ENOMEM; 45028c2ecf20Sopenharmony_ci 45038c2ecf20Sopenharmony_ci sit_i->invalid_segmap = f2fs_kvzalloc(sbi, 45048c2ecf20Sopenharmony_ci main_bitmap_size, GFP_KERNEL); 45058c2ecf20Sopenharmony_ci if (!sit_i->invalid_segmap) 45068c2ecf20Sopenharmony_ci return -ENOMEM; 45078c2ecf20Sopenharmony_ci#endif 45088c2ecf20Sopenharmony_ci 45098c2ecf20Sopenharmony_ci /* init SIT information */ 45108c2ecf20Sopenharmony_ci sit_i->s_ops = &default_salloc_ops; 45118c2ecf20Sopenharmony_ci 45128c2ecf20Sopenharmony_ci sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr); 45138c2ecf20Sopenharmony_ci sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg; 45148c2ecf20Sopenharmony_ci sit_i->written_valid_blocks = 0; 45158c2ecf20Sopenharmony_ci sit_i->bitmap_size = sit_bitmap_size; 45168c2ecf20Sopenharmony_ci sit_i->dirty_sentries = 0; 45178c2ecf20Sopenharmony_ci sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK; 45188c2ecf20Sopenharmony_ci sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time); 45198c2ecf20Sopenharmony_ci sit_i->mounted_time = ktime_get_boottime_seconds(); 45208c2ecf20Sopenharmony_ci init_rwsem(&sit_i->sentry_lock); 45218c2ecf20Sopenharmony_ci return 0; 45228c2ecf20Sopenharmony_ci} 45238c2ecf20Sopenharmony_ci 45248c2ecf20Sopenharmony_cistatic int build_free_segmap(struct f2fs_sb_info *sbi) 45258c2ecf20Sopenharmony_ci{ 45268c2ecf20Sopenharmony_ci struct free_segmap_info *free_i; 45278c2ecf20Sopenharmony_ci unsigned int bitmap_size, sec_bitmap_size; 45288c2ecf20Sopenharmony_ci 45298c2ecf20Sopenharmony_ci /* allocate memory for free segmap information */ 45308c2ecf20Sopenharmony_ci free_i = f2fs_kzalloc(sbi, sizeof(struct free_segmap_info), GFP_KERNEL); 45318c2ecf20Sopenharmony_ci if (!free_i) 45328c2ecf20Sopenharmony_ci return -ENOMEM; 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci SM_I(sbi)->free_info = free_i; 45358c2ecf20Sopenharmony_ci 45368c2ecf20Sopenharmony_ci bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi)); 45378c2ecf20Sopenharmony_ci free_i->free_segmap = f2fs_kvmalloc(sbi, bitmap_size, GFP_KERNEL); 45388c2ecf20Sopenharmony_ci if (!free_i->free_segmap) 45398c2ecf20Sopenharmony_ci return -ENOMEM; 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci sec_bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi)); 45428c2ecf20Sopenharmony_ci free_i->free_secmap = f2fs_kvmalloc(sbi, sec_bitmap_size, GFP_KERNEL); 45438c2ecf20Sopenharmony_ci if (!free_i->free_secmap) 45448c2ecf20Sopenharmony_ci return -ENOMEM; 45458c2ecf20Sopenharmony_ci 45468c2ecf20Sopenharmony_ci /* set all segments as dirty temporarily */ 45478c2ecf20Sopenharmony_ci memset(free_i->free_segmap, 0xff, bitmap_size); 45488c2ecf20Sopenharmony_ci memset(free_i->free_secmap, 0xff, sec_bitmap_size); 45498c2ecf20Sopenharmony_ci 45508c2ecf20Sopenharmony_ci /* init free segmap information */ 45518c2ecf20Sopenharmony_ci free_i->start_segno = GET_SEGNO_FROM_SEG0(sbi, MAIN_BLKADDR(sbi)); 45528c2ecf20Sopenharmony_ci free_i->free_segments = 0; 45538c2ecf20Sopenharmony_ci free_i->free_sections = 0; 45548c2ecf20Sopenharmony_ci spin_lock_init(&free_i->segmap_lock); 45558c2ecf20Sopenharmony_ci return 0; 45568c2ecf20Sopenharmony_ci} 45578c2ecf20Sopenharmony_ci 45588c2ecf20Sopenharmony_cistatic int build_curseg(struct f2fs_sb_info *sbi) 45598c2ecf20Sopenharmony_ci{ 45608c2ecf20Sopenharmony_ci struct curseg_info *array; 45618c2ecf20Sopenharmony_ci int i; 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_ci array = f2fs_kzalloc(sbi, array_size(NR_CURSEG_TYPE, 45648c2ecf20Sopenharmony_ci sizeof(*array)), GFP_KERNEL); 45658c2ecf20Sopenharmony_ci if (!array) 45668c2ecf20Sopenharmony_ci return -ENOMEM; 45678c2ecf20Sopenharmony_ci 45688c2ecf20Sopenharmony_ci SM_I(sbi)->curseg_array = array; 45698c2ecf20Sopenharmony_ci 45708c2ecf20Sopenharmony_ci for (i = 0; i < NO_CHECK_TYPE; i++) { 45718c2ecf20Sopenharmony_ci mutex_init(&array[i].curseg_mutex); 45728c2ecf20Sopenharmony_ci array[i].sum_blk = f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL); 45738c2ecf20Sopenharmony_ci if (!array[i].sum_blk) 45748c2ecf20Sopenharmony_ci return -ENOMEM; 45758c2ecf20Sopenharmony_ci init_rwsem(&array[i].journal_rwsem); 45768c2ecf20Sopenharmony_ci array[i].journal = f2fs_kzalloc(sbi, 45778c2ecf20Sopenharmony_ci sizeof(struct f2fs_journal), GFP_KERNEL); 45788c2ecf20Sopenharmony_ci if (!array[i].journal) 45798c2ecf20Sopenharmony_ci return -ENOMEM; 45808c2ecf20Sopenharmony_ci if (i < NR_PERSISTENT_LOG) 45818c2ecf20Sopenharmony_ci array[i].seg_type = CURSEG_HOT_DATA + i; 45828c2ecf20Sopenharmony_ci else if (i == CURSEG_COLD_DATA_PINNED) 45838c2ecf20Sopenharmony_ci array[i].seg_type = CURSEG_COLD_DATA; 45848c2ecf20Sopenharmony_ci else if (i == CURSEG_ALL_DATA_ATGC) 45858c2ecf20Sopenharmony_ci array[i].seg_type = CURSEG_COLD_DATA; 45868c2ecf20Sopenharmony_ci array[i].segno = NULL_SEGNO; 45878c2ecf20Sopenharmony_ci array[i].next_blkoff = 0; 45888c2ecf20Sopenharmony_ci array[i].inited = false; 45898c2ecf20Sopenharmony_ci } 45908c2ecf20Sopenharmony_ci return restore_curseg_summaries(sbi); 45918c2ecf20Sopenharmony_ci} 45928c2ecf20Sopenharmony_ci 45938c2ecf20Sopenharmony_cistatic int build_sit_entries(struct f2fs_sb_info *sbi) 45948c2ecf20Sopenharmony_ci{ 45958c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 45968c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); 45978c2ecf20Sopenharmony_ci struct f2fs_journal *journal = curseg->journal; 45988c2ecf20Sopenharmony_ci struct seg_entry *se; 45998c2ecf20Sopenharmony_ci struct f2fs_sit_entry sit; 46008c2ecf20Sopenharmony_ci int sit_blk_cnt = SIT_BLK_CNT(sbi); 46018c2ecf20Sopenharmony_ci unsigned int i, start, end; 46028c2ecf20Sopenharmony_ci unsigned int readed, start_blk = 0; 46038c2ecf20Sopenharmony_ci int err = 0; 46048c2ecf20Sopenharmony_ci block_t sit_valid_blocks[2] = {0, 0}; 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci do { 46078c2ecf20Sopenharmony_ci readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES, 46088c2ecf20Sopenharmony_ci META_SIT, true); 46098c2ecf20Sopenharmony_ci 46108c2ecf20Sopenharmony_ci start = start_blk * sit_i->sents_per_block; 46118c2ecf20Sopenharmony_ci end = (start_blk + readed) * sit_i->sents_per_block; 46128c2ecf20Sopenharmony_ci 46138c2ecf20Sopenharmony_ci for (; start < end && start < MAIN_SEGS(sbi); start++) { 46148c2ecf20Sopenharmony_ci struct f2fs_sit_block *sit_blk; 46158c2ecf20Sopenharmony_ci struct page *page; 46168c2ecf20Sopenharmony_ci 46178c2ecf20Sopenharmony_ci se = &sit_i->sentries[start]; 46188c2ecf20Sopenharmony_ci page = get_current_sit_page(sbi, start); 46198c2ecf20Sopenharmony_ci if (IS_ERR(page)) 46208c2ecf20Sopenharmony_ci return PTR_ERR(page); 46218c2ecf20Sopenharmony_ci sit_blk = (struct f2fs_sit_block *)page_address(page); 46228c2ecf20Sopenharmony_ci sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)]; 46238c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci err = check_block_count(sbi, start, &sit); 46268c2ecf20Sopenharmony_ci if (err) 46278c2ecf20Sopenharmony_ci return err; 46288c2ecf20Sopenharmony_ci seg_info_from_raw_sit(se, &sit); 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_ci if (se->type >= NR_PERSISTENT_LOG) { 46318c2ecf20Sopenharmony_ci f2fs_err(sbi, "Invalid segment type: %u, segno: %u", 46328c2ecf20Sopenharmony_ci se->type, start); 46338c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 46348c2ecf20Sopenharmony_ci } 46358c2ecf20Sopenharmony_ci 46368c2ecf20Sopenharmony_ci sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks; 46378c2ecf20Sopenharmony_ci 46388c2ecf20Sopenharmony_ci /* build discard map only one time */ 46398c2ecf20Sopenharmony_ci if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) { 46408c2ecf20Sopenharmony_ci memset(se->discard_map, 0xff, 46418c2ecf20Sopenharmony_ci SIT_VBLOCK_MAP_SIZE); 46428c2ecf20Sopenharmony_ci } else { 46438c2ecf20Sopenharmony_ci memcpy(se->discard_map, 46448c2ecf20Sopenharmony_ci se->cur_valid_map, 46458c2ecf20Sopenharmony_ci SIT_VBLOCK_MAP_SIZE); 46468c2ecf20Sopenharmony_ci sbi->discard_blks += 46478c2ecf20Sopenharmony_ci sbi->blocks_per_seg - 46488c2ecf20Sopenharmony_ci se->valid_blocks; 46498c2ecf20Sopenharmony_ci } 46508c2ecf20Sopenharmony_ci 46518c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) 46528c2ecf20Sopenharmony_ci get_sec_entry(sbi, start)->valid_blocks += 46538c2ecf20Sopenharmony_ci se->valid_blocks; 46548c2ecf20Sopenharmony_ci } 46558c2ecf20Sopenharmony_ci start_blk += readed; 46568c2ecf20Sopenharmony_ci } while (start_blk < sit_blk_cnt); 46578c2ecf20Sopenharmony_ci 46588c2ecf20Sopenharmony_ci down_read(&curseg->journal_rwsem); 46598c2ecf20Sopenharmony_ci for (i = 0; i < sits_in_cursum(journal); i++) { 46608c2ecf20Sopenharmony_ci unsigned int old_valid_blocks; 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci start = le32_to_cpu(segno_in_journal(journal, i)); 46638c2ecf20Sopenharmony_ci if (start >= MAIN_SEGS(sbi)) { 46648c2ecf20Sopenharmony_ci f2fs_err(sbi, "Wrong journal entry on segno %u", 46658c2ecf20Sopenharmony_ci start); 46668c2ecf20Sopenharmony_ci err = -EFSCORRUPTED; 46678c2ecf20Sopenharmony_ci break; 46688c2ecf20Sopenharmony_ci } 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_ci se = &sit_i->sentries[start]; 46718c2ecf20Sopenharmony_ci sit = sit_in_journal(journal, i); 46728c2ecf20Sopenharmony_ci 46738c2ecf20Sopenharmony_ci old_valid_blocks = se->valid_blocks; 46748c2ecf20Sopenharmony_ci 46758c2ecf20Sopenharmony_ci sit_valid_blocks[SE_PAGETYPE(se)] -= old_valid_blocks; 46768c2ecf20Sopenharmony_ci 46778c2ecf20Sopenharmony_ci err = check_block_count(sbi, start, &sit); 46788c2ecf20Sopenharmony_ci if (err) 46798c2ecf20Sopenharmony_ci break; 46808c2ecf20Sopenharmony_ci seg_info_from_raw_sit(se, &sit); 46818c2ecf20Sopenharmony_ci 46828c2ecf20Sopenharmony_ci if (se->type >= NR_PERSISTENT_LOG) { 46838c2ecf20Sopenharmony_ci f2fs_err(sbi, "Invalid segment type: %u, segno: %u", 46848c2ecf20Sopenharmony_ci se->type, start); 46858c2ecf20Sopenharmony_ci err = -EFSCORRUPTED; 46868c2ecf20Sopenharmony_ci break; 46878c2ecf20Sopenharmony_ci } 46888c2ecf20Sopenharmony_ci 46898c2ecf20Sopenharmony_ci sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks; 46908c2ecf20Sopenharmony_ci 46918c2ecf20Sopenharmony_ci if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) { 46928c2ecf20Sopenharmony_ci memset(se->discard_map, 0xff, SIT_VBLOCK_MAP_SIZE); 46938c2ecf20Sopenharmony_ci } else { 46948c2ecf20Sopenharmony_ci memcpy(se->discard_map, se->cur_valid_map, 46958c2ecf20Sopenharmony_ci SIT_VBLOCK_MAP_SIZE); 46968c2ecf20Sopenharmony_ci sbi->discard_blks += old_valid_blocks; 46978c2ecf20Sopenharmony_ci sbi->discard_blks -= se->valid_blocks; 46988c2ecf20Sopenharmony_ci } 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) { 47018c2ecf20Sopenharmony_ci get_sec_entry(sbi, start)->valid_blocks += 47028c2ecf20Sopenharmony_ci se->valid_blocks; 47038c2ecf20Sopenharmony_ci get_sec_entry(sbi, start)->valid_blocks -= 47048c2ecf20Sopenharmony_ci old_valid_blocks; 47058c2ecf20Sopenharmony_ci } 47068c2ecf20Sopenharmony_ci } 47078c2ecf20Sopenharmony_ci up_read(&curseg->journal_rwsem); 47088c2ecf20Sopenharmony_ci 47098c2ecf20Sopenharmony_ci if (err) 47108c2ecf20Sopenharmony_ci return err; 47118c2ecf20Sopenharmony_ci 47128c2ecf20Sopenharmony_ci if (sit_valid_blocks[NODE] != valid_node_count(sbi)) { 47138c2ecf20Sopenharmony_ci f2fs_err(sbi, "SIT is corrupted node# %u vs %u", 47148c2ecf20Sopenharmony_ci sit_valid_blocks[NODE], valid_node_count(sbi)); 47158c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 47168c2ecf20Sopenharmony_ci } 47178c2ecf20Sopenharmony_ci 47188c2ecf20Sopenharmony_ci if (sit_valid_blocks[DATA] + sit_valid_blocks[NODE] > 47198c2ecf20Sopenharmony_ci valid_user_blocks(sbi)) { 47208c2ecf20Sopenharmony_ci f2fs_err(sbi, "SIT is corrupted data# %u %u vs %u", 47218c2ecf20Sopenharmony_ci sit_valid_blocks[DATA], sit_valid_blocks[NODE], 47228c2ecf20Sopenharmony_ci valid_user_blocks(sbi)); 47238c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 47248c2ecf20Sopenharmony_ci } 47258c2ecf20Sopenharmony_ci 47268c2ecf20Sopenharmony_ci return 0; 47278c2ecf20Sopenharmony_ci} 47288c2ecf20Sopenharmony_ci 47298c2ecf20Sopenharmony_cistatic void init_free_segmap(struct f2fs_sb_info *sbi) 47308c2ecf20Sopenharmony_ci{ 47318c2ecf20Sopenharmony_ci unsigned int start; 47328c2ecf20Sopenharmony_ci int type; 47338c2ecf20Sopenharmony_ci struct seg_entry *sentry; 47348c2ecf20Sopenharmony_ci 47358c2ecf20Sopenharmony_ci for (start = 0; start < MAIN_SEGS(sbi); start++) { 47368c2ecf20Sopenharmony_ci if (f2fs_usable_blks_in_seg(sbi, start) == 0) 47378c2ecf20Sopenharmony_ci continue; 47388c2ecf20Sopenharmony_ci sentry = get_seg_entry(sbi, start); 47398c2ecf20Sopenharmony_ci if (!sentry->valid_blocks) 47408c2ecf20Sopenharmony_ci __set_free(sbi, start); 47418c2ecf20Sopenharmony_ci else 47428c2ecf20Sopenharmony_ci SIT_I(sbi)->written_valid_blocks += 47438c2ecf20Sopenharmony_ci sentry->valid_blocks; 47448c2ecf20Sopenharmony_ci } 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci /* set use the current segments */ 47478c2ecf20Sopenharmony_ci for (type = CURSEG_HOT_DATA; type <= CURSEG_COLD_NODE; type++) { 47488c2ecf20Sopenharmony_ci struct curseg_info *curseg_t = CURSEG_I(sbi, type); 47498c2ecf20Sopenharmony_ci __set_test_and_inuse(sbi, curseg_t->segno); 47508c2ecf20Sopenharmony_ci } 47518c2ecf20Sopenharmony_ci} 47528c2ecf20Sopenharmony_ci 47538c2ecf20Sopenharmony_cistatic void init_dirty_segmap(struct f2fs_sb_info *sbi) 47548c2ecf20Sopenharmony_ci{ 47558c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 47568c2ecf20Sopenharmony_ci struct free_segmap_info *free_i = FREE_I(sbi); 47578c2ecf20Sopenharmony_ci unsigned int segno = 0, offset = 0, secno; 47588c2ecf20Sopenharmony_ci block_t valid_blocks, usable_blks_in_seg; 47598c2ecf20Sopenharmony_ci block_t blks_per_sec = BLKS_PER_SEC(sbi); 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci while (1) { 47628c2ecf20Sopenharmony_ci /* find dirty segment based on free segmap */ 47638c2ecf20Sopenharmony_ci segno = find_next_inuse(free_i, MAIN_SEGS(sbi), offset); 47648c2ecf20Sopenharmony_ci if (segno >= MAIN_SEGS(sbi)) 47658c2ecf20Sopenharmony_ci break; 47668c2ecf20Sopenharmony_ci offset = segno + 1; 47678c2ecf20Sopenharmony_ci valid_blocks = get_valid_blocks(sbi, segno, false); 47688c2ecf20Sopenharmony_ci usable_blks_in_seg = f2fs_usable_blks_in_seg(sbi, segno); 47698c2ecf20Sopenharmony_ci if (valid_blocks == usable_blks_in_seg || !valid_blocks) 47708c2ecf20Sopenharmony_ci continue; 47718c2ecf20Sopenharmony_ci if (valid_blocks > usable_blks_in_seg) { 47728c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, 1); 47738c2ecf20Sopenharmony_ci continue; 47748c2ecf20Sopenharmony_ci } 47758c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 47768c2ecf20Sopenharmony_ci __locate_dirty_segment(sbi, segno, DIRTY); 47778c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 47788c2ecf20Sopenharmony_ci } 47798c2ecf20Sopenharmony_ci 47808c2ecf20Sopenharmony_ci if (!__is_large_section(sbi)) 47818c2ecf20Sopenharmony_ci return; 47828c2ecf20Sopenharmony_ci 47838c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 47848c2ecf20Sopenharmony_ci for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { 47858c2ecf20Sopenharmony_ci valid_blocks = get_valid_blocks(sbi, segno, true); 47868c2ecf20Sopenharmony_ci secno = GET_SEC_FROM_SEG(sbi, segno); 47878c2ecf20Sopenharmony_ci 47888c2ecf20Sopenharmony_ci if (!valid_blocks || valid_blocks == blks_per_sec) 47898c2ecf20Sopenharmony_ci continue; 47908c2ecf20Sopenharmony_ci if (IS_CURSEC(sbi, secno)) 47918c2ecf20Sopenharmony_ci continue; 47928c2ecf20Sopenharmony_ci set_bit(secno, dirty_i->dirty_secmap); 47938c2ecf20Sopenharmony_ci } 47948c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 47958c2ecf20Sopenharmony_ci} 47968c2ecf20Sopenharmony_ci 47978c2ecf20Sopenharmony_cistatic int init_victim_secmap(struct f2fs_sb_info *sbi) 47988c2ecf20Sopenharmony_ci{ 47998c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 48008c2ecf20Sopenharmony_ci unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi)); 48018c2ecf20Sopenharmony_ci 48028c2ecf20Sopenharmony_ci dirty_i->victim_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL); 48038c2ecf20Sopenharmony_ci if (!dirty_i->victim_secmap) 48048c2ecf20Sopenharmony_ci return -ENOMEM; 48058c2ecf20Sopenharmony_ci return 0; 48068c2ecf20Sopenharmony_ci} 48078c2ecf20Sopenharmony_ci 48088c2ecf20Sopenharmony_cistatic int build_dirty_segmap(struct f2fs_sb_info *sbi) 48098c2ecf20Sopenharmony_ci{ 48108c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i; 48118c2ecf20Sopenharmony_ci unsigned int bitmap_size, i; 48128c2ecf20Sopenharmony_ci 48138c2ecf20Sopenharmony_ci /* allocate memory for dirty segments list information */ 48148c2ecf20Sopenharmony_ci dirty_i = f2fs_kzalloc(sbi, sizeof(struct dirty_seglist_info), 48158c2ecf20Sopenharmony_ci GFP_KERNEL); 48168c2ecf20Sopenharmony_ci if (!dirty_i) 48178c2ecf20Sopenharmony_ci return -ENOMEM; 48188c2ecf20Sopenharmony_ci 48198c2ecf20Sopenharmony_ci SM_I(sbi)->dirty_info = dirty_i; 48208c2ecf20Sopenharmony_ci mutex_init(&dirty_i->seglist_lock); 48218c2ecf20Sopenharmony_ci 48228c2ecf20Sopenharmony_ci bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi)); 48238c2ecf20Sopenharmony_ci 48248c2ecf20Sopenharmony_ci for (i = 0; i < NR_DIRTY_TYPE; i++) { 48258c2ecf20Sopenharmony_ci dirty_i->dirty_segmap[i] = f2fs_kvzalloc(sbi, bitmap_size, 48268c2ecf20Sopenharmony_ci GFP_KERNEL); 48278c2ecf20Sopenharmony_ci if (!dirty_i->dirty_segmap[i]) 48288c2ecf20Sopenharmony_ci return -ENOMEM; 48298c2ecf20Sopenharmony_ci } 48308c2ecf20Sopenharmony_ci 48318c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) { 48328c2ecf20Sopenharmony_ci bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi)); 48338c2ecf20Sopenharmony_ci dirty_i->dirty_secmap = f2fs_kvzalloc(sbi, 48348c2ecf20Sopenharmony_ci bitmap_size, GFP_KERNEL); 48358c2ecf20Sopenharmony_ci if (!dirty_i->dirty_secmap) 48368c2ecf20Sopenharmony_ci return -ENOMEM; 48378c2ecf20Sopenharmony_ci } 48388c2ecf20Sopenharmony_ci 48398c2ecf20Sopenharmony_ci init_dirty_segmap(sbi); 48408c2ecf20Sopenharmony_ci return init_victim_secmap(sbi); 48418c2ecf20Sopenharmony_ci} 48428c2ecf20Sopenharmony_ci 48438c2ecf20Sopenharmony_cistatic int sanity_check_curseg(struct f2fs_sb_info *sbi) 48448c2ecf20Sopenharmony_ci{ 48458c2ecf20Sopenharmony_ci int i; 48468c2ecf20Sopenharmony_ci 48478c2ecf20Sopenharmony_ci /* 48488c2ecf20Sopenharmony_ci * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr; 48498c2ecf20Sopenharmony_ci * In LFS curseg, all blkaddr after .next_blkoff should be unused. 48508c2ecf20Sopenharmony_ci */ 48518c2ecf20Sopenharmony_ci for (i = 0; i < NR_PERSISTENT_LOG; i++) { 48528c2ecf20Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, i); 48538c2ecf20Sopenharmony_ci struct seg_entry *se = get_seg_entry(sbi, curseg->segno); 48548c2ecf20Sopenharmony_ci unsigned int blkofs = curseg->next_blkoff; 48558c2ecf20Sopenharmony_ci 48568c2ecf20Sopenharmony_ci sanity_check_seg_type(sbi, curseg->seg_type); 48578c2ecf20Sopenharmony_ci 48588c2ecf20Sopenharmony_ci if (curseg->alloc_type != LFS && curseg->alloc_type != SSR) { 48598c2ecf20Sopenharmony_ci f2fs_err(sbi, 48608c2ecf20Sopenharmony_ci "Current segment has invalid alloc_type:%d", 48618c2ecf20Sopenharmony_ci curseg->alloc_type); 48628c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 48638c2ecf20Sopenharmony_ci } 48648c2ecf20Sopenharmony_ci 48658c2ecf20Sopenharmony_ci if (f2fs_test_bit(blkofs, se->cur_valid_map)) 48668c2ecf20Sopenharmony_ci goto out; 48678c2ecf20Sopenharmony_ci 48688c2ecf20Sopenharmony_ci if (curseg->alloc_type == SSR) 48698c2ecf20Sopenharmony_ci continue; 48708c2ecf20Sopenharmony_ci 48718c2ecf20Sopenharmony_ci for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) { 48728c2ecf20Sopenharmony_ci if (!f2fs_test_bit(blkofs, se->cur_valid_map)) 48738c2ecf20Sopenharmony_ci continue; 48748c2ecf20Sopenharmony_ciout: 48758c2ecf20Sopenharmony_ci f2fs_err(sbi, 48768c2ecf20Sopenharmony_ci "Current segment's next free block offset is inconsistent with bitmap, logtype:%u, segno:%u, type:%u, next_blkoff:%u, blkofs:%u", 48778c2ecf20Sopenharmony_ci i, curseg->segno, curseg->alloc_type, 48788c2ecf20Sopenharmony_ci curseg->next_blkoff, blkofs); 48798c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 48808c2ecf20Sopenharmony_ci } 48818c2ecf20Sopenharmony_ci } 48828c2ecf20Sopenharmony_ci return 0; 48838c2ecf20Sopenharmony_ci} 48848c2ecf20Sopenharmony_ci 48858c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_cistatic int check_zone_write_pointer(struct f2fs_sb_info *sbi, 48888c2ecf20Sopenharmony_ci struct f2fs_dev_info *fdev, 48898c2ecf20Sopenharmony_ci struct blk_zone *zone) 48908c2ecf20Sopenharmony_ci{ 48918c2ecf20Sopenharmony_ci unsigned int wp_segno, wp_blkoff, zone_secno, zone_segno, segno; 48928c2ecf20Sopenharmony_ci block_t zone_block, wp_block, last_valid_block; 48938c2ecf20Sopenharmony_ci unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; 48948c2ecf20Sopenharmony_ci int i, s, b, ret; 48958c2ecf20Sopenharmony_ci struct seg_entry *se; 48968c2ecf20Sopenharmony_ci 48978c2ecf20Sopenharmony_ci if (zone->type != BLK_ZONE_TYPE_SEQWRITE_REQ) 48988c2ecf20Sopenharmony_ci return 0; 48998c2ecf20Sopenharmony_ci 49008c2ecf20Sopenharmony_ci wp_block = fdev->start_blk + (zone->wp >> log_sectors_per_block); 49018c2ecf20Sopenharmony_ci wp_segno = GET_SEGNO(sbi, wp_block); 49028c2ecf20Sopenharmony_ci wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno); 49038c2ecf20Sopenharmony_ci zone_block = fdev->start_blk + (zone->start >> log_sectors_per_block); 49048c2ecf20Sopenharmony_ci zone_segno = GET_SEGNO(sbi, zone_block); 49058c2ecf20Sopenharmony_ci zone_secno = GET_SEC_FROM_SEG(sbi, zone_segno); 49068c2ecf20Sopenharmony_ci 49078c2ecf20Sopenharmony_ci if (zone_segno >= MAIN_SEGS(sbi)) 49088c2ecf20Sopenharmony_ci return 0; 49098c2ecf20Sopenharmony_ci 49108c2ecf20Sopenharmony_ci /* 49118c2ecf20Sopenharmony_ci * Skip check of zones cursegs point to, since 49128c2ecf20Sopenharmony_ci * fix_curseg_write_pointer() checks them. 49138c2ecf20Sopenharmony_ci */ 49148c2ecf20Sopenharmony_ci for (i = 0; i < NO_CHECK_TYPE; i++) 49158c2ecf20Sopenharmony_ci if (zone_secno == GET_SEC_FROM_SEG(sbi, 49168c2ecf20Sopenharmony_ci CURSEG_I(sbi, i)->segno)) 49178c2ecf20Sopenharmony_ci return 0; 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci /* 49208c2ecf20Sopenharmony_ci * Get last valid block of the zone. 49218c2ecf20Sopenharmony_ci */ 49228c2ecf20Sopenharmony_ci last_valid_block = zone_block - 1; 49238c2ecf20Sopenharmony_ci for (s = sbi->segs_per_sec - 1; s >= 0; s--) { 49248c2ecf20Sopenharmony_ci segno = zone_segno + s; 49258c2ecf20Sopenharmony_ci se = get_seg_entry(sbi, segno); 49268c2ecf20Sopenharmony_ci for (b = sbi->blocks_per_seg - 1; b >= 0; b--) 49278c2ecf20Sopenharmony_ci if (f2fs_test_bit(b, se->cur_valid_map)) { 49288c2ecf20Sopenharmony_ci last_valid_block = START_BLOCK(sbi, segno) + b; 49298c2ecf20Sopenharmony_ci break; 49308c2ecf20Sopenharmony_ci } 49318c2ecf20Sopenharmony_ci if (last_valid_block >= zone_block) 49328c2ecf20Sopenharmony_ci break; 49338c2ecf20Sopenharmony_ci } 49348c2ecf20Sopenharmony_ci 49358c2ecf20Sopenharmony_ci /* 49368c2ecf20Sopenharmony_ci * If last valid block is beyond the write pointer, report the 49378c2ecf20Sopenharmony_ci * inconsistency. This inconsistency does not cause write error 49388c2ecf20Sopenharmony_ci * because the zone will not be selected for write operation until 49398c2ecf20Sopenharmony_ci * it get discarded. Just report it. 49408c2ecf20Sopenharmony_ci */ 49418c2ecf20Sopenharmony_ci if (last_valid_block >= wp_block) { 49428c2ecf20Sopenharmony_ci f2fs_notice(sbi, "Valid block beyond write pointer: " 49438c2ecf20Sopenharmony_ci "valid block[0x%x,0x%x] wp[0x%x,0x%x]", 49448c2ecf20Sopenharmony_ci GET_SEGNO(sbi, last_valid_block), 49458c2ecf20Sopenharmony_ci GET_BLKOFF_FROM_SEG0(sbi, last_valid_block), 49468c2ecf20Sopenharmony_ci wp_segno, wp_blkoff); 49478c2ecf20Sopenharmony_ci return 0; 49488c2ecf20Sopenharmony_ci } 49498c2ecf20Sopenharmony_ci 49508c2ecf20Sopenharmony_ci /* 49518c2ecf20Sopenharmony_ci * If there is no valid block in the zone and if write pointer is 49528c2ecf20Sopenharmony_ci * not at zone start, reset the write pointer. 49538c2ecf20Sopenharmony_ci */ 49548c2ecf20Sopenharmony_ci if (last_valid_block + 1 == zone_block && zone->wp != zone->start) { 49558c2ecf20Sopenharmony_ci f2fs_notice(sbi, 49568c2ecf20Sopenharmony_ci "Zone without valid block has non-zero write " 49578c2ecf20Sopenharmony_ci "pointer. Reset the write pointer: wp[0x%x,0x%x]", 49588c2ecf20Sopenharmony_ci wp_segno, wp_blkoff); 49598c2ecf20Sopenharmony_ci ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block, 49608c2ecf20Sopenharmony_ci zone->len >> log_sectors_per_block); 49618c2ecf20Sopenharmony_ci if (ret) { 49628c2ecf20Sopenharmony_ci f2fs_err(sbi, "Discard zone failed: %s (errno=%d)", 49638c2ecf20Sopenharmony_ci fdev->path, ret); 49648c2ecf20Sopenharmony_ci return ret; 49658c2ecf20Sopenharmony_ci } 49668c2ecf20Sopenharmony_ci } 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_ci return 0; 49698c2ecf20Sopenharmony_ci} 49708c2ecf20Sopenharmony_ci 49718c2ecf20Sopenharmony_cistatic struct f2fs_dev_info *get_target_zoned_dev(struct f2fs_sb_info *sbi, 49728c2ecf20Sopenharmony_ci block_t zone_blkaddr) 49738c2ecf20Sopenharmony_ci{ 49748c2ecf20Sopenharmony_ci int i; 49758c2ecf20Sopenharmony_ci 49768c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_ndevs; i++) { 49778c2ecf20Sopenharmony_ci if (!bdev_is_zoned(FDEV(i).bdev)) 49788c2ecf20Sopenharmony_ci continue; 49798c2ecf20Sopenharmony_ci if (sbi->s_ndevs == 1 || (FDEV(i).start_blk <= zone_blkaddr && 49808c2ecf20Sopenharmony_ci zone_blkaddr <= FDEV(i).end_blk)) 49818c2ecf20Sopenharmony_ci return &FDEV(i); 49828c2ecf20Sopenharmony_ci } 49838c2ecf20Sopenharmony_ci 49848c2ecf20Sopenharmony_ci return NULL; 49858c2ecf20Sopenharmony_ci} 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_cistatic int report_one_zone_cb(struct blk_zone *zone, unsigned int idx, 49888c2ecf20Sopenharmony_ci void *data) { 49898c2ecf20Sopenharmony_ci memcpy(data, zone, sizeof(struct blk_zone)); 49908c2ecf20Sopenharmony_ci return 0; 49918c2ecf20Sopenharmony_ci} 49928c2ecf20Sopenharmony_ci 49938c2ecf20Sopenharmony_cistatic int fix_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) 49948c2ecf20Sopenharmony_ci{ 49958c2ecf20Sopenharmony_ci struct curseg_info *cs = CURSEG_I(sbi, type); 49968c2ecf20Sopenharmony_ci struct f2fs_dev_info *zbd; 49978c2ecf20Sopenharmony_ci struct blk_zone zone; 49988c2ecf20Sopenharmony_ci unsigned int cs_section, wp_segno, wp_blkoff, wp_sector_off; 49998c2ecf20Sopenharmony_ci block_t cs_zone_block, wp_block; 50008c2ecf20Sopenharmony_ci unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; 50018c2ecf20Sopenharmony_ci sector_t zone_sector; 50028c2ecf20Sopenharmony_ci int err; 50038c2ecf20Sopenharmony_ci 50048c2ecf20Sopenharmony_ci cs_section = GET_SEC_FROM_SEG(sbi, cs->segno); 50058c2ecf20Sopenharmony_ci cs_zone_block = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, cs_section)); 50068c2ecf20Sopenharmony_ci 50078c2ecf20Sopenharmony_ci zbd = get_target_zoned_dev(sbi, cs_zone_block); 50088c2ecf20Sopenharmony_ci if (!zbd) 50098c2ecf20Sopenharmony_ci return 0; 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ci /* report zone for the sector the curseg points to */ 50128c2ecf20Sopenharmony_ci zone_sector = (sector_t)(cs_zone_block - zbd->start_blk) 50138c2ecf20Sopenharmony_ci << log_sectors_per_block; 50148c2ecf20Sopenharmony_ci err = blkdev_report_zones(zbd->bdev, zone_sector, 1, 50158c2ecf20Sopenharmony_ci report_one_zone_cb, &zone); 50168c2ecf20Sopenharmony_ci if (err != 1) { 50178c2ecf20Sopenharmony_ci f2fs_err(sbi, "Report zone failed: %s errno=(%d)", 50188c2ecf20Sopenharmony_ci zbd->path, err); 50198c2ecf20Sopenharmony_ci return err; 50208c2ecf20Sopenharmony_ci } 50218c2ecf20Sopenharmony_ci 50228c2ecf20Sopenharmony_ci if (zone.type != BLK_ZONE_TYPE_SEQWRITE_REQ) 50238c2ecf20Sopenharmony_ci return 0; 50248c2ecf20Sopenharmony_ci 50258c2ecf20Sopenharmony_ci wp_block = zbd->start_blk + (zone.wp >> log_sectors_per_block); 50268c2ecf20Sopenharmony_ci wp_segno = GET_SEGNO(sbi, wp_block); 50278c2ecf20Sopenharmony_ci wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno); 50288c2ecf20Sopenharmony_ci wp_sector_off = zone.wp & GENMASK(log_sectors_per_block - 1, 0); 50298c2ecf20Sopenharmony_ci 50308c2ecf20Sopenharmony_ci if (cs->segno == wp_segno && cs->next_blkoff == wp_blkoff && 50318c2ecf20Sopenharmony_ci wp_sector_off == 0) 50328c2ecf20Sopenharmony_ci return 0; 50338c2ecf20Sopenharmony_ci 50348c2ecf20Sopenharmony_ci f2fs_notice(sbi, "Unaligned curseg[%d] with write pointer: " 50358c2ecf20Sopenharmony_ci "curseg[0x%x,0x%x] wp[0x%x,0x%x]", 50368c2ecf20Sopenharmony_ci type, cs->segno, cs->next_blkoff, wp_segno, wp_blkoff); 50378c2ecf20Sopenharmony_ci 50388c2ecf20Sopenharmony_ci f2fs_notice(sbi, "Assign new section to curseg[%d]: " 50398c2ecf20Sopenharmony_ci "curseg[0x%x,0x%x]", type, cs->segno, cs->next_blkoff); 50408c2ecf20Sopenharmony_ci allocate_segment_by_default(sbi, type, true, SEQ_NONE); 50418c2ecf20Sopenharmony_ci 50428c2ecf20Sopenharmony_ci /* check consistency of the zone curseg pointed to */ 50438c2ecf20Sopenharmony_ci if (check_zone_write_pointer(sbi, zbd, &zone)) 50448c2ecf20Sopenharmony_ci return -EIO; 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci /* check newly assigned zone */ 50478c2ecf20Sopenharmony_ci cs_section = GET_SEC_FROM_SEG(sbi, cs->segno); 50488c2ecf20Sopenharmony_ci cs_zone_block = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, cs_section)); 50498c2ecf20Sopenharmony_ci 50508c2ecf20Sopenharmony_ci zbd = get_target_zoned_dev(sbi, cs_zone_block); 50518c2ecf20Sopenharmony_ci if (!zbd) 50528c2ecf20Sopenharmony_ci return 0; 50538c2ecf20Sopenharmony_ci 50548c2ecf20Sopenharmony_ci zone_sector = (sector_t)(cs_zone_block - zbd->start_blk) 50558c2ecf20Sopenharmony_ci << log_sectors_per_block; 50568c2ecf20Sopenharmony_ci err = blkdev_report_zones(zbd->bdev, zone_sector, 1, 50578c2ecf20Sopenharmony_ci report_one_zone_cb, &zone); 50588c2ecf20Sopenharmony_ci if (err != 1) { 50598c2ecf20Sopenharmony_ci f2fs_err(sbi, "Report zone failed: %s errno=(%d)", 50608c2ecf20Sopenharmony_ci zbd->path, err); 50618c2ecf20Sopenharmony_ci return err; 50628c2ecf20Sopenharmony_ci } 50638c2ecf20Sopenharmony_ci 50648c2ecf20Sopenharmony_ci if (zone.type != BLK_ZONE_TYPE_SEQWRITE_REQ) 50658c2ecf20Sopenharmony_ci return 0; 50668c2ecf20Sopenharmony_ci 50678c2ecf20Sopenharmony_ci if (zone.wp != zone.start) { 50688c2ecf20Sopenharmony_ci f2fs_notice(sbi, 50698c2ecf20Sopenharmony_ci "New zone for curseg[%d] is not yet discarded. " 50708c2ecf20Sopenharmony_ci "Reset the zone: curseg[0x%x,0x%x]", 50718c2ecf20Sopenharmony_ci type, cs->segno, cs->next_blkoff); 50728c2ecf20Sopenharmony_ci err = __f2fs_issue_discard_zone(sbi, zbd->bdev, 50738c2ecf20Sopenharmony_ci zone_sector >> log_sectors_per_block, 50748c2ecf20Sopenharmony_ci zone.len >> log_sectors_per_block); 50758c2ecf20Sopenharmony_ci if (err) { 50768c2ecf20Sopenharmony_ci f2fs_err(sbi, "Discard zone failed: %s (errno=%d)", 50778c2ecf20Sopenharmony_ci zbd->path, err); 50788c2ecf20Sopenharmony_ci return err; 50798c2ecf20Sopenharmony_ci } 50808c2ecf20Sopenharmony_ci } 50818c2ecf20Sopenharmony_ci 50828c2ecf20Sopenharmony_ci return 0; 50838c2ecf20Sopenharmony_ci} 50848c2ecf20Sopenharmony_ci 50858c2ecf20Sopenharmony_ciint f2fs_fix_curseg_write_pointer(struct f2fs_sb_info *sbi) 50868c2ecf20Sopenharmony_ci{ 50878c2ecf20Sopenharmony_ci int i, ret; 50888c2ecf20Sopenharmony_ci 50898c2ecf20Sopenharmony_ci for (i = 0; i < NR_PERSISTENT_LOG; i++) { 50908c2ecf20Sopenharmony_ci ret = fix_curseg_write_pointer(sbi, i); 50918c2ecf20Sopenharmony_ci if (ret) 50928c2ecf20Sopenharmony_ci return ret; 50938c2ecf20Sopenharmony_ci } 50948c2ecf20Sopenharmony_ci 50958c2ecf20Sopenharmony_ci return 0; 50968c2ecf20Sopenharmony_ci} 50978c2ecf20Sopenharmony_ci 50988c2ecf20Sopenharmony_cistruct check_zone_write_pointer_args { 50998c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi; 51008c2ecf20Sopenharmony_ci struct f2fs_dev_info *fdev; 51018c2ecf20Sopenharmony_ci}; 51028c2ecf20Sopenharmony_ci 51038c2ecf20Sopenharmony_cistatic int check_zone_write_pointer_cb(struct blk_zone *zone, unsigned int idx, 51048c2ecf20Sopenharmony_ci void *data) { 51058c2ecf20Sopenharmony_ci struct check_zone_write_pointer_args *args; 51068c2ecf20Sopenharmony_ci args = (struct check_zone_write_pointer_args *)data; 51078c2ecf20Sopenharmony_ci 51088c2ecf20Sopenharmony_ci return check_zone_write_pointer(args->sbi, args->fdev, zone); 51098c2ecf20Sopenharmony_ci} 51108c2ecf20Sopenharmony_ci 51118c2ecf20Sopenharmony_ciint f2fs_check_write_pointer(struct f2fs_sb_info *sbi) 51128c2ecf20Sopenharmony_ci{ 51138c2ecf20Sopenharmony_ci int i, ret; 51148c2ecf20Sopenharmony_ci struct check_zone_write_pointer_args args; 51158c2ecf20Sopenharmony_ci 51168c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_ndevs; i++) { 51178c2ecf20Sopenharmony_ci if (!bdev_is_zoned(FDEV(i).bdev)) 51188c2ecf20Sopenharmony_ci continue; 51198c2ecf20Sopenharmony_ci 51208c2ecf20Sopenharmony_ci args.sbi = sbi; 51218c2ecf20Sopenharmony_ci args.fdev = &FDEV(i); 51228c2ecf20Sopenharmony_ci ret = blkdev_report_zones(FDEV(i).bdev, 0, BLK_ALL_ZONES, 51238c2ecf20Sopenharmony_ci check_zone_write_pointer_cb, &args); 51248c2ecf20Sopenharmony_ci if (ret < 0) 51258c2ecf20Sopenharmony_ci return ret; 51268c2ecf20Sopenharmony_ci } 51278c2ecf20Sopenharmony_ci 51288c2ecf20Sopenharmony_ci return 0; 51298c2ecf20Sopenharmony_ci} 51308c2ecf20Sopenharmony_ci 51318c2ecf20Sopenharmony_ci/* 51328c2ecf20Sopenharmony_ci * Return the number of usable blocks in a segment. The number of blocks 51338c2ecf20Sopenharmony_ci * returned is always equal to the number of blocks in a segment for 51348c2ecf20Sopenharmony_ci * segments fully contained within a sequential zone capacity or a 51358c2ecf20Sopenharmony_ci * conventional zone. For segments partially contained in a sequential 51368c2ecf20Sopenharmony_ci * zone capacity, the number of usable blocks up to the zone capacity 51378c2ecf20Sopenharmony_ci * is returned. 0 is returned in all other cases. 51388c2ecf20Sopenharmony_ci */ 51398c2ecf20Sopenharmony_cistatic inline unsigned int f2fs_usable_zone_blks_in_seg( 51408c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi, unsigned int segno) 51418c2ecf20Sopenharmony_ci{ 51428c2ecf20Sopenharmony_ci block_t seg_start, sec_start_blkaddr, sec_cap_blkaddr; 51438c2ecf20Sopenharmony_ci unsigned int secno; 51448c2ecf20Sopenharmony_ci 51458c2ecf20Sopenharmony_ci if (!sbi->unusable_blocks_per_sec) 51468c2ecf20Sopenharmony_ci return sbi->blocks_per_seg; 51478c2ecf20Sopenharmony_ci 51488c2ecf20Sopenharmony_ci secno = GET_SEC_FROM_SEG(sbi, segno); 51498c2ecf20Sopenharmony_ci seg_start = START_BLOCK(sbi, segno); 51508c2ecf20Sopenharmony_ci sec_start_blkaddr = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, secno)); 51518c2ecf20Sopenharmony_ci sec_cap_blkaddr = sec_start_blkaddr + CAP_BLKS_PER_SEC(sbi); 51528c2ecf20Sopenharmony_ci 51538c2ecf20Sopenharmony_ci /* 51548c2ecf20Sopenharmony_ci * If segment starts before zone capacity and spans beyond 51558c2ecf20Sopenharmony_ci * zone capacity, then usable blocks are from seg start to 51568c2ecf20Sopenharmony_ci * zone capacity. If the segment starts after the zone capacity, 51578c2ecf20Sopenharmony_ci * then there are no usable blocks. 51588c2ecf20Sopenharmony_ci */ 51598c2ecf20Sopenharmony_ci if (seg_start >= sec_cap_blkaddr) 51608c2ecf20Sopenharmony_ci return 0; 51618c2ecf20Sopenharmony_ci if (seg_start + sbi->blocks_per_seg > sec_cap_blkaddr) 51628c2ecf20Sopenharmony_ci return sec_cap_blkaddr - seg_start; 51638c2ecf20Sopenharmony_ci 51648c2ecf20Sopenharmony_ci return sbi->blocks_per_seg; 51658c2ecf20Sopenharmony_ci} 51668c2ecf20Sopenharmony_ci#else 51678c2ecf20Sopenharmony_ciint f2fs_fix_curseg_write_pointer(struct f2fs_sb_info *sbi) 51688c2ecf20Sopenharmony_ci{ 51698c2ecf20Sopenharmony_ci return 0; 51708c2ecf20Sopenharmony_ci} 51718c2ecf20Sopenharmony_ci 51728c2ecf20Sopenharmony_ciint f2fs_check_write_pointer(struct f2fs_sb_info *sbi) 51738c2ecf20Sopenharmony_ci{ 51748c2ecf20Sopenharmony_ci return 0; 51758c2ecf20Sopenharmony_ci} 51768c2ecf20Sopenharmony_ci 51778c2ecf20Sopenharmony_cistatic inline unsigned int f2fs_usable_zone_blks_in_seg(struct f2fs_sb_info *sbi, 51788c2ecf20Sopenharmony_ci unsigned int segno) 51798c2ecf20Sopenharmony_ci{ 51808c2ecf20Sopenharmony_ci return 0; 51818c2ecf20Sopenharmony_ci} 51828c2ecf20Sopenharmony_ci 51838c2ecf20Sopenharmony_ci#endif 51848c2ecf20Sopenharmony_ciunsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi, 51858c2ecf20Sopenharmony_ci unsigned int segno) 51868c2ecf20Sopenharmony_ci{ 51878c2ecf20Sopenharmony_ci if (f2fs_sb_has_blkzoned(sbi)) 51888c2ecf20Sopenharmony_ci return f2fs_usable_zone_blks_in_seg(sbi, segno); 51898c2ecf20Sopenharmony_ci 51908c2ecf20Sopenharmony_ci return sbi->blocks_per_seg; 51918c2ecf20Sopenharmony_ci} 51928c2ecf20Sopenharmony_ci 51938c2ecf20Sopenharmony_ciunsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi, 51948c2ecf20Sopenharmony_ci unsigned int segno) 51958c2ecf20Sopenharmony_ci{ 51968c2ecf20Sopenharmony_ci if (f2fs_sb_has_blkzoned(sbi)) 51978c2ecf20Sopenharmony_ci return CAP_SEGS_PER_SEC(sbi); 51988c2ecf20Sopenharmony_ci 51998c2ecf20Sopenharmony_ci return sbi->segs_per_sec; 52008c2ecf20Sopenharmony_ci} 52018c2ecf20Sopenharmony_ci 52028c2ecf20Sopenharmony_ci/* 52038c2ecf20Sopenharmony_ci * Update min, max modified time for cost-benefit GC algorithm 52048c2ecf20Sopenharmony_ci */ 52058c2ecf20Sopenharmony_cistatic void init_min_max_mtime(struct f2fs_sb_info *sbi) 52068c2ecf20Sopenharmony_ci{ 52078c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 52088c2ecf20Sopenharmony_ci unsigned int segno; 52098c2ecf20Sopenharmony_ci 52108c2ecf20Sopenharmony_ci down_write(&sit_i->sentry_lock); 52118c2ecf20Sopenharmony_ci 52128c2ecf20Sopenharmony_ci sit_i->min_mtime = ULLONG_MAX; 52138c2ecf20Sopenharmony_ci 52148c2ecf20Sopenharmony_ci for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { 52158c2ecf20Sopenharmony_ci unsigned int i; 52168c2ecf20Sopenharmony_ci unsigned long long mtime = 0; 52178c2ecf20Sopenharmony_ci 52188c2ecf20Sopenharmony_ci for (i = 0; i < sbi->segs_per_sec; i++) 52198c2ecf20Sopenharmony_ci mtime += get_seg_entry(sbi, segno + i)->mtime; 52208c2ecf20Sopenharmony_ci 52218c2ecf20Sopenharmony_ci mtime = div_u64(mtime, sbi->segs_per_sec); 52228c2ecf20Sopenharmony_ci 52238c2ecf20Sopenharmony_ci if (sit_i->min_mtime > mtime) 52248c2ecf20Sopenharmony_ci sit_i->min_mtime = mtime; 52258c2ecf20Sopenharmony_ci } 52268c2ecf20Sopenharmony_ci sit_i->max_mtime = get_mtime(sbi, false); 52278c2ecf20Sopenharmony_ci sit_i->dirty_max_mtime = 0; 52288c2ecf20Sopenharmony_ci up_write(&sit_i->sentry_lock); 52298c2ecf20Sopenharmony_ci} 52308c2ecf20Sopenharmony_ci 52318c2ecf20Sopenharmony_ciint f2fs_build_segment_manager(struct f2fs_sb_info *sbi) 52328c2ecf20Sopenharmony_ci{ 52338c2ecf20Sopenharmony_ci struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); 52348c2ecf20Sopenharmony_ci struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 52358c2ecf20Sopenharmony_ci struct f2fs_sm_info *sm_info; 52368c2ecf20Sopenharmony_ci int err; 52378c2ecf20Sopenharmony_ci 52388c2ecf20Sopenharmony_ci sm_info = f2fs_kzalloc(sbi, sizeof(struct f2fs_sm_info), GFP_KERNEL); 52398c2ecf20Sopenharmony_ci if (!sm_info) 52408c2ecf20Sopenharmony_ci return -ENOMEM; 52418c2ecf20Sopenharmony_ci 52428c2ecf20Sopenharmony_ci /* init sm info */ 52438c2ecf20Sopenharmony_ci sbi->sm_info = sm_info; 52448c2ecf20Sopenharmony_ci sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); 52458c2ecf20Sopenharmony_ci sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); 52468c2ecf20Sopenharmony_ci sm_info->segment_count = le32_to_cpu(raw_super->segment_count); 52478c2ecf20Sopenharmony_ci sm_info->reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count); 52488c2ecf20Sopenharmony_ci sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count); 52498c2ecf20Sopenharmony_ci sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main); 52508c2ecf20Sopenharmony_ci sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); 52518c2ecf20Sopenharmony_ci sm_info->rec_prefree_segments = sm_info->main_segments * 52528c2ecf20Sopenharmony_ci DEF_RECLAIM_PREFREE_SEGMENTS / 100; 52538c2ecf20Sopenharmony_ci if (sm_info->rec_prefree_segments > DEF_MAX_RECLAIM_PREFREE_SEGMENTS) 52548c2ecf20Sopenharmony_ci sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS; 52558c2ecf20Sopenharmony_ci 52568c2ecf20Sopenharmony_ci if (!f2fs_lfs_mode(sbi)) 52578c2ecf20Sopenharmony_ci sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC; 52588c2ecf20Sopenharmony_ci sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; 52598c2ecf20Sopenharmony_ci sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; 52608c2ecf20Sopenharmony_ci sm_info->min_seq_blocks = sbi->blocks_per_seg * sbi->segs_per_sec; 52618c2ecf20Sopenharmony_ci sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS; 52628c2ecf20Sopenharmony_ci sm_info->min_ssr_sections = reserved_sections(sbi); 52638c2ecf20Sopenharmony_ci 52648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sm_info->sit_entry_set); 52658c2ecf20Sopenharmony_ci 52668c2ecf20Sopenharmony_ci init_rwsem(&sm_info->curseg_lock); 52678c2ecf20Sopenharmony_ci 52688c2ecf20Sopenharmony_ci if (!f2fs_readonly(sbi->sb)) { 52698c2ecf20Sopenharmony_ci err = f2fs_create_flush_cmd_control(sbi); 52708c2ecf20Sopenharmony_ci if (err) 52718c2ecf20Sopenharmony_ci return err; 52728c2ecf20Sopenharmony_ci } 52738c2ecf20Sopenharmony_ci 52748c2ecf20Sopenharmony_ci err = create_discard_cmd_control(sbi); 52758c2ecf20Sopenharmony_ci if (err) 52768c2ecf20Sopenharmony_ci return err; 52778c2ecf20Sopenharmony_ci 52788c2ecf20Sopenharmony_ci err = build_sit_info(sbi); 52798c2ecf20Sopenharmony_ci if (err) 52808c2ecf20Sopenharmony_ci return err; 52818c2ecf20Sopenharmony_ci err = build_free_segmap(sbi); 52828c2ecf20Sopenharmony_ci if (err) 52838c2ecf20Sopenharmony_ci return err; 52848c2ecf20Sopenharmony_ci err = build_curseg(sbi); 52858c2ecf20Sopenharmony_ci if (err) 52868c2ecf20Sopenharmony_ci return err; 52878c2ecf20Sopenharmony_ci 52888c2ecf20Sopenharmony_ci /* reinit free segmap based on SIT */ 52898c2ecf20Sopenharmony_ci err = build_sit_entries(sbi); 52908c2ecf20Sopenharmony_ci if (err) 52918c2ecf20Sopenharmony_ci return err; 52928c2ecf20Sopenharmony_ci 52938c2ecf20Sopenharmony_ci init_free_segmap(sbi); 52948c2ecf20Sopenharmony_ci err = build_dirty_segmap(sbi); 52958c2ecf20Sopenharmony_ci if (err) 52968c2ecf20Sopenharmony_ci return err; 52978c2ecf20Sopenharmony_ci 52988c2ecf20Sopenharmony_ci err = sanity_check_curseg(sbi); 52998c2ecf20Sopenharmony_ci if (err) 53008c2ecf20Sopenharmony_ci return err; 53018c2ecf20Sopenharmony_ci 53028c2ecf20Sopenharmony_ci init_min_max_mtime(sbi); 53038c2ecf20Sopenharmony_ci return 0; 53048c2ecf20Sopenharmony_ci} 53058c2ecf20Sopenharmony_ci 53068c2ecf20Sopenharmony_cistatic void discard_dirty_segmap(struct f2fs_sb_info *sbi, 53078c2ecf20Sopenharmony_ci enum dirty_type dirty_type) 53088c2ecf20Sopenharmony_ci{ 53098c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 53108c2ecf20Sopenharmony_ci 53118c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 53128c2ecf20Sopenharmony_ci kvfree(dirty_i->dirty_segmap[dirty_type]); 53138c2ecf20Sopenharmony_ci dirty_i->nr_dirty[dirty_type] = 0; 53148c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 53158c2ecf20Sopenharmony_ci} 53168c2ecf20Sopenharmony_ci 53178c2ecf20Sopenharmony_cistatic void destroy_victim_secmap(struct f2fs_sb_info *sbi) 53188c2ecf20Sopenharmony_ci{ 53198c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 53208c2ecf20Sopenharmony_ci kvfree(dirty_i->victim_secmap); 53218c2ecf20Sopenharmony_ci} 53228c2ecf20Sopenharmony_ci 53238c2ecf20Sopenharmony_cistatic void destroy_dirty_segmap(struct f2fs_sb_info *sbi) 53248c2ecf20Sopenharmony_ci{ 53258c2ecf20Sopenharmony_ci struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 53268c2ecf20Sopenharmony_ci int i; 53278c2ecf20Sopenharmony_ci 53288c2ecf20Sopenharmony_ci if (!dirty_i) 53298c2ecf20Sopenharmony_ci return; 53308c2ecf20Sopenharmony_ci 53318c2ecf20Sopenharmony_ci /* discard pre-free/dirty segments list */ 53328c2ecf20Sopenharmony_ci for (i = 0; i < NR_DIRTY_TYPE; i++) 53338c2ecf20Sopenharmony_ci discard_dirty_segmap(sbi, i); 53348c2ecf20Sopenharmony_ci 53358c2ecf20Sopenharmony_ci if (__is_large_section(sbi)) { 53368c2ecf20Sopenharmony_ci mutex_lock(&dirty_i->seglist_lock); 53378c2ecf20Sopenharmony_ci kvfree(dirty_i->dirty_secmap); 53388c2ecf20Sopenharmony_ci mutex_unlock(&dirty_i->seglist_lock); 53398c2ecf20Sopenharmony_ci } 53408c2ecf20Sopenharmony_ci 53418c2ecf20Sopenharmony_ci destroy_victim_secmap(sbi); 53428c2ecf20Sopenharmony_ci SM_I(sbi)->dirty_info = NULL; 53438c2ecf20Sopenharmony_ci kfree(dirty_i); 53448c2ecf20Sopenharmony_ci} 53458c2ecf20Sopenharmony_ci 53468c2ecf20Sopenharmony_cistatic void destroy_curseg(struct f2fs_sb_info *sbi) 53478c2ecf20Sopenharmony_ci{ 53488c2ecf20Sopenharmony_ci struct curseg_info *array = SM_I(sbi)->curseg_array; 53498c2ecf20Sopenharmony_ci int i; 53508c2ecf20Sopenharmony_ci 53518c2ecf20Sopenharmony_ci if (!array) 53528c2ecf20Sopenharmony_ci return; 53538c2ecf20Sopenharmony_ci SM_I(sbi)->curseg_array = NULL; 53548c2ecf20Sopenharmony_ci for (i = 0; i < NR_CURSEG_TYPE; i++) { 53558c2ecf20Sopenharmony_ci kfree(array[i].sum_blk); 53568c2ecf20Sopenharmony_ci kfree(array[i].journal); 53578c2ecf20Sopenharmony_ci } 53588c2ecf20Sopenharmony_ci kfree(array); 53598c2ecf20Sopenharmony_ci} 53608c2ecf20Sopenharmony_ci 53618c2ecf20Sopenharmony_cistatic void destroy_free_segmap(struct f2fs_sb_info *sbi) 53628c2ecf20Sopenharmony_ci{ 53638c2ecf20Sopenharmony_ci struct free_segmap_info *free_i = SM_I(sbi)->free_info; 53648c2ecf20Sopenharmony_ci if (!free_i) 53658c2ecf20Sopenharmony_ci return; 53668c2ecf20Sopenharmony_ci SM_I(sbi)->free_info = NULL; 53678c2ecf20Sopenharmony_ci kvfree(free_i->free_segmap); 53688c2ecf20Sopenharmony_ci kvfree(free_i->free_secmap); 53698c2ecf20Sopenharmony_ci kfree(free_i); 53708c2ecf20Sopenharmony_ci} 53718c2ecf20Sopenharmony_ci 53728c2ecf20Sopenharmony_cistatic void destroy_sit_info(struct f2fs_sb_info *sbi) 53738c2ecf20Sopenharmony_ci{ 53748c2ecf20Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 53758c2ecf20Sopenharmony_ci 53768c2ecf20Sopenharmony_ci if (!sit_i) 53778c2ecf20Sopenharmony_ci return; 53788c2ecf20Sopenharmony_ci 53798c2ecf20Sopenharmony_ci if (sit_i->sentries) 53808c2ecf20Sopenharmony_ci kvfree(sit_i->bitmap); 53818c2ecf20Sopenharmony_ci kfree(sit_i->tmp_map); 53828c2ecf20Sopenharmony_ci 53838c2ecf20Sopenharmony_ci kvfree(sit_i->sentries); 53848c2ecf20Sopenharmony_ci kvfree(sit_i->sec_entries); 53858c2ecf20Sopenharmony_ci kvfree(sit_i->dirty_sentries_bitmap); 53868c2ecf20Sopenharmony_ci 53878c2ecf20Sopenharmony_ci SM_I(sbi)->sit_info = NULL; 53888c2ecf20Sopenharmony_ci kvfree(sit_i->sit_bitmap); 53898c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_CHECK_FS 53908c2ecf20Sopenharmony_ci kvfree(sit_i->sit_bitmap_mir); 53918c2ecf20Sopenharmony_ci kvfree(sit_i->invalid_segmap); 53928c2ecf20Sopenharmony_ci#endif 53938c2ecf20Sopenharmony_ci kfree(sit_i); 53948c2ecf20Sopenharmony_ci} 53958c2ecf20Sopenharmony_ci 53968c2ecf20Sopenharmony_civoid f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi) 53978c2ecf20Sopenharmony_ci{ 53988c2ecf20Sopenharmony_ci struct f2fs_sm_info *sm_info = SM_I(sbi); 53998c2ecf20Sopenharmony_ci 54008c2ecf20Sopenharmony_ci if (!sm_info) 54018c2ecf20Sopenharmony_ci return; 54028c2ecf20Sopenharmony_ci f2fs_destroy_flush_cmd_control(sbi, true); 54038c2ecf20Sopenharmony_ci destroy_discard_cmd_control(sbi); 54048c2ecf20Sopenharmony_ci destroy_dirty_segmap(sbi); 54058c2ecf20Sopenharmony_ci destroy_curseg(sbi); 54068c2ecf20Sopenharmony_ci destroy_free_segmap(sbi); 54078c2ecf20Sopenharmony_ci destroy_sit_info(sbi); 54088c2ecf20Sopenharmony_ci sbi->sm_info = NULL; 54098c2ecf20Sopenharmony_ci kfree(sm_info); 54108c2ecf20Sopenharmony_ci} 54118c2ecf20Sopenharmony_ci 54128c2ecf20Sopenharmony_ciint __init f2fs_create_segment_manager_caches(void) 54138c2ecf20Sopenharmony_ci{ 54148c2ecf20Sopenharmony_ci discard_entry_slab = f2fs_kmem_cache_create("f2fs_discard_entry", 54158c2ecf20Sopenharmony_ci sizeof(struct discard_entry)); 54168c2ecf20Sopenharmony_ci if (!discard_entry_slab) 54178c2ecf20Sopenharmony_ci goto fail; 54188c2ecf20Sopenharmony_ci 54198c2ecf20Sopenharmony_ci discard_cmd_slab = f2fs_kmem_cache_create("f2fs_discard_cmd", 54208c2ecf20Sopenharmony_ci sizeof(struct discard_cmd)); 54218c2ecf20Sopenharmony_ci if (!discard_cmd_slab) 54228c2ecf20Sopenharmony_ci goto destroy_discard_entry; 54238c2ecf20Sopenharmony_ci 54248c2ecf20Sopenharmony_ci sit_entry_set_slab = f2fs_kmem_cache_create("f2fs_sit_entry_set", 54258c2ecf20Sopenharmony_ci sizeof(struct sit_entry_set)); 54268c2ecf20Sopenharmony_ci if (!sit_entry_set_slab) 54278c2ecf20Sopenharmony_ci goto destroy_discard_cmd; 54288c2ecf20Sopenharmony_ci 54298c2ecf20Sopenharmony_ci inmem_entry_slab = f2fs_kmem_cache_create("f2fs_inmem_page_entry", 54308c2ecf20Sopenharmony_ci sizeof(struct inmem_pages)); 54318c2ecf20Sopenharmony_ci if (!inmem_entry_slab) 54328c2ecf20Sopenharmony_ci goto destroy_sit_entry_set; 54338c2ecf20Sopenharmony_ci return 0; 54348c2ecf20Sopenharmony_ci 54358c2ecf20Sopenharmony_cidestroy_sit_entry_set: 54368c2ecf20Sopenharmony_ci kmem_cache_destroy(sit_entry_set_slab); 54378c2ecf20Sopenharmony_cidestroy_discard_cmd: 54388c2ecf20Sopenharmony_ci kmem_cache_destroy(discard_cmd_slab); 54398c2ecf20Sopenharmony_cidestroy_discard_entry: 54408c2ecf20Sopenharmony_ci kmem_cache_destroy(discard_entry_slab); 54418c2ecf20Sopenharmony_cifail: 54428c2ecf20Sopenharmony_ci return -ENOMEM; 54438c2ecf20Sopenharmony_ci} 54448c2ecf20Sopenharmony_ci 54458c2ecf20Sopenharmony_civoid f2fs_destroy_segment_manager_caches(void) 54468c2ecf20Sopenharmony_ci{ 54478c2ecf20Sopenharmony_ci kmem_cache_destroy(sit_entry_set_slab); 54488c2ecf20Sopenharmony_ci kmem_cache_destroy(discard_cmd_slab); 54498c2ecf20Sopenharmony_ci kmem_cache_destroy(discard_entry_slab); 54508c2ecf20Sopenharmony_ci kmem_cache_destroy(inmem_entry_slab); 54518c2ecf20Sopenharmony_ci} 5452