162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/f2fs/checkpoint.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd. 662306a36Sopenharmony_ci * http://www.samsung.com/ 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/fs.h> 962306a36Sopenharmony_ci#include <linux/bio.h> 1062306a36Sopenharmony_ci#include <linux/mpage.h> 1162306a36Sopenharmony_ci#include <linux/writeback.h> 1262306a36Sopenharmony_ci#include <linux/blkdev.h> 1362306a36Sopenharmony_ci#include <linux/f2fs_fs.h> 1462306a36Sopenharmony_ci#include <linux/pagevec.h> 1562306a36Sopenharmony_ci#include <linux/swap.h> 1662306a36Sopenharmony_ci#include <linux/kthread.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "f2fs.h" 1962306a36Sopenharmony_ci#include "node.h" 2062306a36Sopenharmony_ci#include "segment.h" 2162306a36Sopenharmony_ci#include "iostat.h" 2262306a36Sopenharmony_ci#include <trace/events/f2fs.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define DEFAULT_CHECKPOINT_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3)) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic struct kmem_cache *ino_entry_slab; 2762306a36Sopenharmony_cistruct kmem_cache *f2fs_inode_entry_slab; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_civoid f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io, 3062306a36Sopenharmony_ci unsigned char reason) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci f2fs_build_fault_attr(sbi, 0, 0); 3362306a36Sopenharmony_ci if (!end_io) 3462306a36Sopenharmony_ci f2fs_flush_merged_writes(sbi); 3562306a36Sopenharmony_ci f2fs_handle_critical_error(sbi, reason, end_io); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * We guarantee no failure on the returned page. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_cistruct page *f2fs_grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct address_space *mapping = META_MAPPING(sbi); 4462306a36Sopenharmony_ci struct page *page; 4562306a36Sopenharmony_cirepeat: 4662306a36Sopenharmony_ci page = f2fs_grab_cache_page(mapping, index, false); 4762306a36Sopenharmony_ci if (!page) { 4862306a36Sopenharmony_ci cond_resched(); 4962306a36Sopenharmony_ci goto repeat; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci f2fs_wait_on_page_writeback(page, META, true, true); 5262306a36Sopenharmony_ci if (!PageUptodate(page)) 5362306a36Sopenharmony_ci SetPageUptodate(page); 5462306a36Sopenharmony_ci return page; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, 5862306a36Sopenharmony_ci bool is_meta) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct address_space *mapping = META_MAPPING(sbi); 6162306a36Sopenharmony_ci struct page *page; 6262306a36Sopenharmony_ci struct f2fs_io_info fio = { 6362306a36Sopenharmony_ci .sbi = sbi, 6462306a36Sopenharmony_ci .type = META, 6562306a36Sopenharmony_ci .op = REQ_OP_READ, 6662306a36Sopenharmony_ci .op_flags = REQ_META | REQ_PRIO, 6762306a36Sopenharmony_ci .old_blkaddr = index, 6862306a36Sopenharmony_ci .new_blkaddr = index, 6962306a36Sopenharmony_ci .encrypted_page = NULL, 7062306a36Sopenharmony_ci .is_por = !is_meta ? 1 : 0, 7162306a36Sopenharmony_ci }; 7262306a36Sopenharmony_ci int err; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (unlikely(!is_meta)) 7562306a36Sopenharmony_ci fio.op_flags &= ~REQ_META; 7662306a36Sopenharmony_cirepeat: 7762306a36Sopenharmony_ci page = f2fs_grab_cache_page(mapping, index, false); 7862306a36Sopenharmony_ci if (!page) { 7962306a36Sopenharmony_ci cond_resched(); 8062306a36Sopenharmony_ci goto repeat; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci if (PageUptodate(page)) 8362306a36Sopenharmony_ci goto out; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci fio.page = page; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci err = f2fs_submit_page_bio(&fio); 8862306a36Sopenharmony_ci if (err) { 8962306a36Sopenharmony_ci f2fs_put_page(page, 1); 9062306a36Sopenharmony_ci return ERR_PTR(err); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci f2fs_update_iostat(sbi, NULL, FS_META_READ_IO, F2FS_BLKSIZE); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci lock_page(page); 9662306a36Sopenharmony_ci if (unlikely(page->mapping != mapping)) { 9762306a36Sopenharmony_ci f2fs_put_page(page, 1); 9862306a36Sopenharmony_ci goto repeat; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (unlikely(!PageUptodate(page))) { 10262306a36Sopenharmony_ci f2fs_handle_page_eio(sbi, page->index, META); 10362306a36Sopenharmony_ci f2fs_put_page(page, 1); 10462306a36Sopenharmony_ci return ERR_PTR(-EIO); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ciout: 10762306a36Sopenharmony_ci return page; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistruct page *f2fs_get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci return __get_meta_page(sbi, index, true); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistruct page *f2fs_get_meta_page_retry(struct f2fs_sb_info *sbi, pgoff_t index) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct page *page; 11862306a36Sopenharmony_ci int count = 0; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciretry: 12162306a36Sopenharmony_ci page = __get_meta_page(sbi, index, true); 12262306a36Sopenharmony_ci if (IS_ERR(page)) { 12362306a36Sopenharmony_ci if (PTR_ERR(page) == -EIO && 12462306a36Sopenharmony_ci ++count <= DEFAULT_RETRY_IO_COUNT) 12562306a36Sopenharmony_ci goto retry; 12662306a36Sopenharmony_ci f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_META_PAGE); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci return page; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* for POR only */ 13262306a36Sopenharmony_cistruct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return __get_meta_page(sbi, index, false); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr, 13862306a36Sopenharmony_ci int type) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct seg_entry *se; 14162306a36Sopenharmony_ci unsigned int segno, offset; 14262306a36Sopenharmony_ci bool exist; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (type == DATA_GENERIC) 14562306a36Sopenharmony_ci return true; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci segno = GET_SEGNO(sbi, blkaddr); 14862306a36Sopenharmony_ci offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); 14962306a36Sopenharmony_ci se = get_seg_entry(sbi, segno); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci exist = f2fs_test_bit(offset, se->cur_valid_map); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* skip data, if we already have an error in checkpoint. */ 15462306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) 15562306a36Sopenharmony_ci return exist; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (exist && type == DATA_GENERIC_ENHANCE_UPDATE) { 15862306a36Sopenharmony_ci f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d", 15962306a36Sopenharmony_ci blkaddr, exist); 16062306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 16162306a36Sopenharmony_ci return exist; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (!exist && type == DATA_GENERIC_ENHANCE) { 16562306a36Sopenharmony_ci f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d", 16662306a36Sopenharmony_ci blkaddr, exist); 16762306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 16862306a36Sopenharmony_ci dump_stack(); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci return exist; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cibool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, 17462306a36Sopenharmony_ci block_t blkaddr, int type) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci if (time_to_inject(sbi, FAULT_BLKADDR)) 17762306a36Sopenharmony_ci return false; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci switch (type) { 18062306a36Sopenharmony_ci case META_NAT: 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci case META_SIT: 18362306a36Sopenharmony_ci if (unlikely(blkaddr >= SIT_BLK_CNT(sbi))) 18462306a36Sopenharmony_ci return false; 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci case META_SSA: 18762306a36Sopenharmony_ci if (unlikely(blkaddr >= MAIN_BLKADDR(sbi) || 18862306a36Sopenharmony_ci blkaddr < SM_I(sbi)->ssa_blkaddr)) 18962306a36Sopenharmony_ci return false; 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci case META_CP: 19262306a36Sopenharmony_ci if (unlikely(blkaddr >= SIT_I(sbi)->sit_base_addr || 19362306a36Sopenharmony_ci blkaddr < __start_cp_addr(sbi))) 19462306a36Sopenharmony_ci return false; 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci case META_POR: 19762306a36Sopenharmony_ci if (unlikely(blkaddr >= MAX_BLKADDR(sbi) || 19862306a36Sopenharmony_ci blkaddr < MAIN_BLKADDR(sbi))) 19962306a36Sopenharmony_ci return false; 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci case DATA_GENERIC: 20262306a36Sopenharmony_ci case DATA_GENERIC_ENHANCE: 20362306a36Sopenharmony_ci case DATA_GENERIC_ENHANCE_READ: 20462306a36Sopenharmony_ci case DATA_GENERIC_ENHANCE_UPDATE: 20562306a36Sopenharmony_ci if (unlikely(blkaddr >= MAX_BLKADDR(sbi) || 20662306a36Sopenharmony_ci blkaddr < MAIN_BLKADDR(sbi))) { 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Skip to emit an error message. */ 20962306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) 21062306a36Sopenharmony_ci return false; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci f2fs_warn(sbi, "access invalid blkaddr:%u", 21362306a36Sopenharmony_ci blkaddr); 21462306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 21562306a36Sopenharmony_ci dump_stack(); 21662306a36Sopenharmony_ci return false; 21762306a36Sopenharmony_ci } else { 21862306a36Sopenharmony_ci return __is_bitmap_valid(sbi, blkaddr, type); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci case META_GENERIC: 22262306a36Sopenharmony_ci if (unlikely(blkaddr < SEG0_BLKADDR(sbi) || 22362306a36Sopenharmony_ci blkaddr >= MAIN_BLKADDR(sbi))) 22462306a36Sopenharmony_ci return false; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci default: 22762306a36Sopenharmony_ci BUG(); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return true; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* 23462306a36Sopenharmony_ci * Readahead CP/NAT/SIT/SSA/POR pages 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ciint f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, 23762306a36Sopenharmony_ci int type, bool sync) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct page *page; 24062306a36Sopenharmony_ci block_t blkno = start; 24162306a36Sopenharmony_ci struct f2fs_io_info fio = { 24262306a36Sopenharmony_ci .sbi = sbi, 24362306a36Sopenharmony_ci .type = META, 24462306a36Sopenharmony_ci .op = REQ_OP_READ, 24562306a36Sopenharmony_ci .op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD, 24662306a36Sopenharmony_ci .encrypted_page = NULL, 24762306a36Sopenharmony_ci .in_list = 0, 24862306a36Sopenharmony_ci .is_por = (type == META_POR) ? 1 : 0, 24962306a36Sopenharmony_ci }; 25062306a36Sopenharmony_ci struct blk_plug plug; 25162306a36Sopenharmony_ci int err; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (unlikely(type == META_POR)) 25462306a36Sopenharmony_ci fio.op_flags &= ~REQ_META; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci blk_start_plug(&plug); 25762306a36Sopenharmony_ci for (; nrpages-- > 0; blkno++) { 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (!f2fs_is_valid_blkaddr(sbi, blkno, type)) 26062306a36Sopenharmony_ci goto out; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci switch (type) { 26362306a36Sopenharmony_ci case META_NAT: 26462306a36Sopenharmony_ci if (unlikely(blkno >= 26562306a36Sopenharmony_ci NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid))) 26662306a36Sopenharmony_ci blkno = 0; 26762306a36Sopenharmony_ci /* get nat block addr */ 26862306a36Sopenharmony_ci fio.new_blkaddr = current_nat_addr(sbi, 26962306a36Sopenharmony_ci blkno * NAT_ENTRY_PER_BLOCK); 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci case META_SIT: 27262306a36Sopenharmony_ci if (unlikely(blkno >= TOTAL_SEGS(sbi))) 27362306a36Sopenharmony_ci goto out; 27462306a36Sopenharmony_ci /* get sit block addr */ 27562306a36Sopenharmony_ci fio.new_blkaddr = current_sit_addr(sbi, 27662306a36Sopenharmony_ci blkno * SIT_ENTRY_PER_BLOCK); 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci case META_SSA: 27962306a36Sopenharmony_ci case META_CP: 28062306a36Sopenharmony_ci case META_POR: 28162306a36Sopenharmony_ci fio.new_blkaddr = blkno; 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci default: 28462306a36Sopenharmony_ci BUG(); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci page = f2fs_grab_cache_page(META_MAPPING(sbi), 28862306a36Sopenharmony_ci fio.new_blkaddr, false); 28962306a36Sopenharmony_ci if (!page) 29062306a36Sopenharmony_ci continue; 29162306a36Sopenharmony_ci if (PageUptodate(page)) { 29262306a36Sopenharmony_ci f2fs_put_page(page, 1); 29362306a36Sopenharmony_ci continue; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci fio.page = page; 29762306a36Sopenharmony_ci err = f2fs_submit_page_bio(&fio); 29862306a36Sopenharmony_ci f2fs_put_page(page, err ? 1 : 0); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!err) 30162306a36Sopenharmony_ci f2fs_update_iostat(sbi, NULL, FS_META_READ_IO, 30262306a36Sopenharmony_ci F2FS_BLKSIZE); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ciout: 30562306a36Sopenharmony_ci blk_finish_plug(&plug); 30662306a36Sopenharmony_ci return blkno - start; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_civoid f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index, 31062306a36Sopenharmony_ci unsigned int ra_blocks) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct page *page; 31362306a36Sopenharmony_ci bool readahead = false; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (ra_blocks == RECOVERY_MIN_RA_BLOCKS) 31662306a36Sopenharmony_ci return; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci page = find_get_page(META_MAPPING(sbi), index); 31962306a36Sopenharmony_ci if (!page || !PageUptodate(page)) 32062306a36Sopenharmony_ci readahead = true; 32162306a36Sopenharmony_ci f2fs_put_page(page, 0); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (readahead) 32462306a36Sopenharmony_ci f2fs_ra_meta_pages(sbi, index, ra_blocks, META_POR, true); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int __f2fs_write_meta_page(struct page *page, 32862306a36Sopenharmony_ci struct writeback_control *wbc, 32962306a36Sopenharmony_ci enum iostat_type io_type) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_P_SB(page); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci trace_f2fs_writepage(page, META); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) { 33662306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_IS_CLOSE)) { 33762306a36Sopenharmony_ci ClearPageUptodate(page); 33862306a36Sopenharmony_ci dec_page_count(sbi, F2FS_DIRTY_META); 33962306a36Sopenharmony_ci unlock_page(page); 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci goto redirty_out; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) 34562306a36Sopenharmony_ci goto redirty_out; 34662306a36Sopenharmony_ci if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0)) 34762306a36Sopenharmony_ci goto redirty_out; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci f2fs_do_write_meta_page(sbi, page, io_type); 35062306a36Sopenharmony_ci dec_page_count(sbi, F2FS_DIRTY_META); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (wbc->for_reclaim) 35362306a36Sopenharmony_ci f2fs_submit_merged_write_cond(sbi, NULL, page, 0, META); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci unlock_page(page); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) 35862306a36Sopenharmony_ci f2fs_submit_merged_write(sbi, META); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ciredirty_out: 36362306a36Sopenharmony_ci redirty_page_for_writepage(wbc, page); 36462306a36Sopenharmony_ci return AOP_WRITEPAGE_ACTIVATE; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int f2fs_write_meta_page(struct page *page, 36862306a36Sopenharmony_ci struct writeback_control *wbc) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci return __f2fs_write_meta_page(page, wbc, FS_META_IO); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int f2fs_write_meta_pages(struct address_space *mapping, 37462306a36Sopenharmony_ci struct writeback_control *wbc) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); 37762306a36Sopenharmony_ci long diff, written; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) 38062306a36Sopenharmony_ci goto skip_write; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* collect a number of dirty meta pages and write together */ 38362306a36Sopenharmony_ci if (wbc->sync_mode != WB_SYNC_ALL && 38462306a36Sopenharmony_ci get_pages(sbi, F2FS_DIRTY_META) < 38562306a36Sopenharmony_ci nr_pages_to_skip(sbi, META)) 38662306a36Sopenharmony_ci goto skip_write; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* if locked failed, cp will flush dirty pages instead */ 38962306a36Sopenharmony_ci if (!f2fs_down_write_trylock(&sbi->cp_global_sem)) 39062306a36Sopenharmony_ci goto skip_write; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci trace_f2fs_writepages(mapping->host, wbc, META); 39362306a36Sopenharmony_ci diff = nr_pages_to_write(sbi, META, wbc); 39462306a36Sopenharmony_ci written = f2fs_sync_meta_pages(sbi, META, wbc->nr_to_write, FS_META_IO); 39562306a36Sopenharmony_ci f2fs_up_write(&sbi->cp_global_sem); 39662306a36Sopenharmony_ci wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff); 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ciskip_write: 40062306a36Sopenharmony_ci wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_META); 40162306a36Sopenharmony_ci trace_f2fs_writepages(mapping->host, wbc, META); 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cilong f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, 40662306a36Sopenharmony_ci long nr_to_write, enum iostat_type io_type) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct address_space *mapping = META_MAPPING(sbi); 40962306a36Sopenharmony_ci pgoff_t index = 0, prev = ULONG_MAX; 41062306a36Sopenharmony_ci struct folio_batch fbatch; 41162306a36Sopenharmony_ci long nwritten = 0; 41262306a36Sopenharmony_ci int nr_folios; 41362306a36Sopenharmony_ci struct writeback_control wbc = { 41462306a36Sopenharmony_ci .for_reclaim = 0, 41562306a36Sopenharmony_ci }; 41662306a36Sopenharmony_ci struct blk_plug plug; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci folio_batch_init(&fbatch); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci blk_start_plug(&plug); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci while ((nr_folios = filemap_get_folios_tag(mapping, &index, 42362306a36Sopenharmony_ci (pgoff_t)-1, 42462306a36Sopenharmony_ci PAGECACHE_TAG_DIRTY, &fbatch))) { 42562306a36Sopenharmony_ci int i; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci for (i = 0; i < nr_folios; i++) { 42862306a36Sopenharmony_ci struct folio *folio = fbatch.folios[i]; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (nr_to_write != LONG_MAX && i != 0 && 43162306a36Sopenharmony_ci folio->index != prev + 43262306a36Sopenharmony_ci folio_nr_pages(fbatch.folios[i-1])) { 43362306a36Sopenharmony_ci folio_batch_release(&fbatch); 43462306a36Sopenharmony_ci goto stop; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci folio_lock(folio); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (unlikely(folio->mapping != mapping)) { 44062306a36Sopenharmony_cicontinue_unlock: 44162306a36Sopenharmony_ci folio_unlock(folio); 44262306a36Sopenharmony_ci continue; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci if (!folio_test_dirty(folio)) { 44562306a36Sopenharmony_ci /* someone wrote it for us */ 44662306a36Sopenharmony_ci goto continue_unlock; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci f2fs_wait_on_page_writeback(&folio->page, META, 45062306a36Sopenharmony_ci true, true); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (!folio_clear_dirty_for_io(folio)) 45362306a36Sopenharmony_ci goto continue_unlock; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (__f2fs_write_meta_page(&folio->page, &wbc, 45662306a36Sopenharmony_ci io_type)) { 45762306a36Sopenharmony_ci folio_unlock(folio); 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci nwritten += folio_nr_pages(folio); 46162306a36Sopenharmony_ci prev = folio->index; 46262306a36Sopenharmony_ci if (unlikely(nwritten >= nr_to_write)) 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci folio_batch_release(&fbatch); 46662306a36Sopenharmony_ci cond_resched(); 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_cistop: 46962306a36Sopenharmony_ci if (nwritten) 47062306a36Sopenharmony_ci f2fs_submit_merged_write(sbi, type); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci blk_finish_plug(&plug); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return nwritten; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic bool f2fs_dirty_meta_folio(struct address_space *mapping, 47862306a36Sopenharmony_ci struct folio *folio) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci trace_f2fs_set_page_dirty(&folio->page, META); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (!folio_test_uptodate(folio)) 48362306a36Sopenharmony_ci folio_mark_uptodate(folio); 48462306a36Sopenharmony_ci if (filemap_dirty_folio(mapping, folio)) { 48562306a36Sopenharmony_ci inc_page_count(F2FS_M_SB(mapping), F2FS_DIRTY_META); 48662306a36Sopenharmony_ci set_page_private_reference(&folio->page); 48762306a36Sopenharmony_ci return true; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci return false; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ciconst struct address_space_operations f2fs_meta_aops = { 49362306a36Sopenharmony_ci .writepage = f2fs_write_meta_page, 49462306a36Sopenharmony_ci .writepages = f2fs_write_meta_pages, 49562306a36Sopenharmony_ci .dirty_folio = f2fs_dirty_meta_folio, 49662306a36Sopenharmony_ci .invalidate_folio = f2fs_invalidate_folio, 49762306a36Sopenharmony_ci .release_folio = f2fs_release_folio, 49862306a36Sopenharmony_ci .migrate_folio = filemap_migrate_folio, 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, 50262306a36Sopenharmony_ci unsigned int devidx, int type) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct inode_management *im = &sbi->im[type]; 50562306a36Sopenharmony_ci struct ino_entry *e = NULL, *new = NULL; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (type == FLUSH_INO) { 50862306a36Sopenharmony_ci rcu_read_lock(); 50962306a36Sopenharmony_ci e = radix_tree_lookup(&im->ino_root, ino); 51062306a36Sopenharmony_ci rcu_read_unlock(); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ciretry: 51462306a36Sopenharmony_ci if (!e) 51562306a36Sopenharmony_ci new = f2fs_kmem_cache_alloc(ino_entry_slab, 51662306a36Sopenharmony_ci GFP_NOFS, true, NULL); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci spin_lock(&im->ino_lock); 52162306a36Sopenharmony_ci e = radix_tree_lookup(&im->ino_root, ino); 52262306a36Sopenharmony_ci if (!e) { 52362306a36Sopenharmony_ci if (!new) { 52462306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 52562306a36Sopenharmony_ci radix_tree_preload_end(); 52662306a36Sopenharmony_ci goto retry; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci e = new; 52962306a36Sopenharmony_ci if (unlikely(radix_tree_insert(&im->ino_root, ino, e))) 53062306a36Sopenharmony_ci f2fs_bug_on(sbi, 1); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci memset(e, 0, sizeof(struct ino_entry)); 53362306a36Sopenharmony_ci e->ino = ino; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci list_add_tail(&e->list, &im->ino_list); 53662306a36Sopenharmony_ci if (type != ORPHAN_INO) 53762306a36Sopenharmony_ci im->ino_num++; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (type == FLUSH_INO) 54162306a36Sopenharmony_ci f2fs_set_bit(devidx, (char *)&e->dirty_device); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 54462306a36Sopenharmony_ci radix_tree_preload_end(); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (new && e != new) 54762306a36Sopenharmony_ci kmem_cache_free(ino_entry_slab, new); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct inode_management *im = &sbi->im[type]; 55362306a36Sopenharmony_ci struct ino_entry *e; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci spin_lock(&im->ino_lock); 55662306a36Sopenharmony_ci e = radix_tree_lookup(&im->ino_root, ino); 55762306a36Sopenharmony_ci if (e) { 55862306a36Sopenharmony_ci list_del(&e->list); 55962306a36Sopenharmony_ci radix_tree_delete(&im->ino_root, ino); 56062306a36Sopenharmony_ci im->ino_num--; 56162306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 56262306a36Sopenharmony_ci kmem_cache_free(ino_entry_slab, e); 56362306a36Sopenharmony_ci return; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_civoid f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci /* add new dirty ino entry into list */ 57162306a36Sopenharmony_ci __add_ino_entry(sbi, ino, 0, type); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_civoid f2fs_remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci /* remove dirty ino entry from list */ 57762306a36Sopenharmony_ci __remove_ino_entry(sbi, ino, type); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci/* mode should be APPEND_INO, UPDATE_INO or TRANS_DIR_INO */ 58162306a36Sopenharmony_cibool f2fs_exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct inode_management *im = &sbi->im[mode]; 58462306a36Sopenharmony_ci struct ino_entry *e; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci spin_lock(&im->ino_lock); 58762306a36Sopenharmony_ci e = radix_tree_lookup(&im->ino_root, ino); 58862306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 58962306a36Sopenharmony_ci return e ? true : false; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_civoid f2fs_release_ino_entry(struct f2fs_sb_info *sbi, bool all) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct ino_entry *e, *tmp; 59562306a36Sopenharmony_ci int i; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci for (i = all ? ORPHAN_INO : APPEND_INO; i < MAX_INO_ENTRY; i++) { 59862306a36Sopenharmony_ci struct inode_management *im = &sbi->im[i]; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci spin_lock(&im->ino_lock); 60162306a36Sopenharmony_ci list_for_each_entry_safe(e, tmp, &im->ino_list, list) { 60262306a36Sopenharmony_ci list_del(&e->list); 60362306a36Sopenharmony_ci radix_tree_delete(&im->ino_root, e->ino); 60462306a36Sopenharmony_ci kmem_cache_free(ino_entry_slab, e); 60562306a36Sopenharmony_ci im->ino_num--; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_civoid f2fs_set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino, 61262306a36Sopenharmony_ci unsigned int devidx, int type) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci __add_ino_entry(sbi, ino, devidx, type); 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cibool f2fs_is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino, 61862306a36Sopenharmony_ci unsigned int devidx, int type) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct inode_management *im = &sbi->im[type]; 62162306a36Sopenharmony_ci struct ino_entry *e; 62262306a36Sopenharmony_ci bool is_dirty = false; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci spin_lock(&im->ino_lock); 62562306a36Sopenharmony_ci e = radix_tree_lookup(&im->ino_root, ino); 62662306a36Sopenharmony_ci if (e && f2fs_test_bit(devidx, (char *)&e->dirty_device)) 62762306a36Sopenharmony_ci is_dirty = true; 62862306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 62962306a36Sopenharmony_ci return is_dirty; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ciint f2fs_acquire_orphan_inode(struct f2fs_sb_info *sbi) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct inode_management *im = &sbi->im[ORPHAN_INO]; 63562306a36Sopenharmony_ci int err = 0; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci spin_lock(&im->ino_lock); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (time_to_inject(sbi, FAULT_ORPHAN)) { 64062306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 64162306a36Sopenharmony_ci return -ENOSPC; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (unlikely(im->ino_num >= sbi->max_orphans)) 64562306a36Sopenharmony_ci err = -ENOSPC; 64662306a36Sopenharmony_ci else 64762306a36Sopenharmony_ci im->ino_num++; 64862306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci return err; 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_civoid f2fs_release_orphan_inode(struct f2fs_sb_info *sbi) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct inode_management *im = &sbi->im[ORPHAN_INO]; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci spin_lock(&im->ino_lock); 65862306a36Sopenharmony_ci f2fs_bug_on(sbi, im->ino_num == 0); 65962306a36Sopenharmony_ci im->ino_num--; 66062306a36Sopenharmony_ci spin_unlock(&im->ino_lock); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_civoid f2fs_add_orphan_inode(struct inode *inode) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci /* add new orphan ino entry into list */ 66662306a36Sopenharmony_ci __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, 0, ORPHAN_INO); 66762306a36Sopenharmony_ci f2fs_update_inode_page(inode); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_civoid f2fs_remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci /* remove orphan entry from orphan list */ 67362306a36Sopenharmony_ci __remove_ino_entry(sbi, ino, ORPHAN_INO); 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct inode *inode; 67962306a36Sopenharmony_ci struct node_info ni; 68062306a36Sopenharmony_ci int err; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci inode = f2fs_iget_retry(sbi->sb, ino); 68362306a36Sopenharmony_ci if (IS_ERR(inode)) { 68462306a36Sopenharmony_ci /* 68562306a36Sopenharmony_ci * there should be a bug that we can't find the entry 68662306a36Sopenharmony_ci * to orphan inode. 68762306a36Sopenharmony_ci */ 68862306a36Sopenharmony_ci f2fs_bug_on(sbi, PTR_ERR(inode) == -ENOENT); 68962306a36Sopenharmony_ci return PTR_ERR(inode); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci err = f2fs_dquot_initialize(inode); 69362306a36Sopenharmony_ci if (err) { 69462306a36Sopenharmony_ci iput(inode); 69562306a36Sopenharmony_ci goto err_out; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci clear_nlink(inode); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* truncate all the data during iput */ 70162306a36Sopenharmony_ci iput(inode); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci err = f2fs_get_node_info(sbi, ino, &ni, false); 70462306a36Sopenharmony_ci if (err) 70562306a36Sopenharmony_ci goto err_out; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* ENOMEM was fully retried in f2fs_evict_inode. */ 70862306a36Sopenharmony_ci if (ni.blk_addr != NULL_ADDR) { 70962306a36Sopenharmony_ci err = -EIO; 71062306a36Sopenharmony_ci goto err_out; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci return 0; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cierr_out: 71562306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 71662306a36Sopenharmony_ci f2fs_warn(sbi, "%s: orphan failed (ino=%x), run fsck to fix.", 71762306a36Sopenharmony_ci __func__, ino); 71862306a36Sopenharmony_ci return err; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ciint f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci block_t start_blk, orphan_blocks, i, j; 72462306a36Sopenharmony_ci int err = 0; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) 72762306a36Sopenharmony_ci return 0; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (f2fs_hw_is_readonly(sbi)) { 73062306a36Sopenharmony_ci f2fs_info(sbi, "write access unavailable, skipping orphan cleanup"); 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE)) 73562306a36Sopenharmony_ci f2fs_info(sbi, "orphan cleanup on readonly fs"); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi); 73862306a36Sopenharmony_ci orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci f2fs_ra_meta_pages(sbi, start_blk, orphan_blocks, META_CP, true); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci for (i = 0; i < orphan_blocks; i++) { 74362306a36Sopenharmony_ci struct page *page; 74462306a36Sopenharmony_ci struct f2fs_orphan_block *orphan_blk; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci page = f2fs_get_meta_page(sbi, start_blk + i); 74762306a36Sopenharmony_ci if (IS_ERR(page)) { 74862306a36Sopenharmony_ci err = PTR_ERR(page); 74962306a36Sopenharmony_ci goto out; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci orphan_blk = (struct f2fs_orphan_block *)page_address(page); 75362306a36Sopenharmony_ci for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) { 75462306a36Sopenharmony_ci nid_t ino = le32_to_cpu(orphan_blk->ino[j]); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci err = recover_orphan_inode(sbi, ino); 75762306a36Sopenharmony_ci if (err) { 75862306a36Sopenharmony_ci f2fs_put_page(page, 1); 75962306a36Sopenharmony_ci goto out; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci f2fs_put_page(page, 1); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci /* clear Orphan Flag */ 76562306a36Sopenharmony_ci clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG); 76662306a36Sopenharmony_ciout: 76762306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_RECOVERED); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci return err; 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct list_head *head; 77562306a36Sopenharmony_ci struct f2fs_orphan_block *orphan_blk = NULL; 77662306a36Sopenharmony_ci unsigned int nentries = 0; 77762306a36Sopenharmony_ci unsigned short index = 1; 77862306a36Sopenharmony_ci unsigned short orphan_blocks; 77962306a36Sopenharmony_ci struct page *page = NULL; 78062306a36Sopenharmony_ci struct ino_entry *orphan = NULL; 78162306a36Sopenharmony_ci struct inode_management *im = &sbi->im[ORPHAN_INO]; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci orphan_blocks = GET_ORPHAN_BLOCKS(im->ino_num); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* 78662306a36Sopenharmony_ci * we don't need to do spin_lock(&im->ino_lock) here, since all the 78762306a36Sopenharmony_ci * orphan inode operations are covered under f2fs_lock_op(). 78862306a36Sopenharmony_ci * And, spin_lock should be avoided due to page operations below. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci head = &im->ino_list; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* loop for each orphan inode entry and write them in journal block */ 79362306a36Sopenharmony_ci list_for_each_entry(orphan, head, list) { 79462306a36Sopenharmony_ci if (!page) { 79562306a36Sopenharmony_ci page = f2fs_grab_meta_page(sbi, start_blk++); 79662306a36Sopenharmony_ci orphan_blk = 79762306a36Sopenharmony_ci (struct f2fs_orphan_block *)page_address(page); 79862306a36Sopenharmony_ci memset(orphan_blk, 0, sizeof(*orphan_blk)); 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci orphan_blk->ino[nentries++] = cpu_to_le32(orphan->ino); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (nentries == F2FS_ORPHANS_PER_BLOCK) { 80462306a36Sopenharmony_ci /* 80562306a36Sopenharmony_ci * an orphan block is full of 1020 entries, 80662306a36Sopenharmony_ci * then we need to flush current orphan blocks 80762306a36Sopenharmony_ci * and bring another one in memory 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_ci orphan_blk->blk_addr = cpu_to_le16(index); 81062306a36Sopenharmony_ci orphan_blk->blk_count = cpu_to_le16(orphan_blocks); 81162306a36Sopenharmony_ci orphan_blk->entry_count = cpu_to_le32(nentries); 81262306a36Sopenharmony_ci set_page_dirty(page); 81362306a36Sopenharmony_ci f2fs_put_page(page, 1); 81462306a36Sopenharmony_ci index++; 81562306a36Sopenharmony_ci nentries = 0; 81662306a36Sopenharmony_ci page = NULL; 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (page) { 82162306a36Sopenharmony_ci orphan_blk->blk_addr = cpu_to_le16(index); 82262306a36Sopenharmony_ci orphan_blk->blk_count = cpu_to_le16(orphan_blocks); 82362306a36Sopenharmony_ci orphan_blk->entry_count = cpu_to_le32(nentries); 82462306a36Sopenharmony_ci set_page_dirty(page); 82562306a36Sopenharmony_ci f2fs_put_page(page, 1); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic __u32 f2fs_checkpoint_chksum(struct f2fs_sb_info *sbi, 83062306a36Sopenharmony_ci struct f2fs_checkpoint *ckpt) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci unsigned int chksum_ofs = le32_to_cpu(ckpt->checksum_offset); 83362306a36Sopenharmony_ci __u32 chksum; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci chksum = f2fs_crc32(sbi, ckpt, chksum_ofs); 83662306a36Sopenharmony_ci if (chksum_ofs < CP_CHKSUM_OFFSET) { 83762306a36Sopenharmony_ci chksum_ofs += sizeof(chksum); 83862306a36Sopenharmony_ci chksum = f2fs_chksum(sbi, chksum, (__u8 *)ckpt + chksum_ofs, 83962306a36Sopenharmony_ci F2FS_BLKSIZE - chksum_ofs); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci return chksum; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr, 84562306a36Sopenharmony_ci struct f2fs_checkpoint **cp_block, struct page **cp_page, 84662306a36Sopenharmony_ci unsigned long long *version) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci size_t crc_offset = 0; 84962306a36Sopenharmony_ci __u32 crc; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci *cp_page = f2fs_get_meta_page(sbi, cp_addr); 85262306a36Sopenharmony_ci if (IS_ERR(*cp_page)) 85362306a36Sopenharmony_ci return PTR_ERR(*cp_page); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci *cp_block = (struct f2fs_checkpoint *)page_address(*cp_page); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci crc_offset = le32_to_cpu((*cp_block)->checksum_offset); 85862306a36Sopenharmony_ci if (crc_offset < CP_MIN_CHKSUM_OFFSET || 85962306a36Sopenharmony_ci crc_offset > CP_CHKSUM_OFFSET) { 86062306a36Sopenharmony_ci f2fs_put_page(*cp_page, 1); 86162306a36Sopenharmony_ci f2fs_warn(sbi, "invalid crc_offset: %zu", crc_offset); 86262306a36Sopenharmony_ci return -EINVAL; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci crc = f2fs_checkpoint_chksum(sbi, *cp_block); 86662306a36Sopenharmony_ci if (crc != cur_cp_crc(*cp_block)) { 86762306a36Sopenharmony_ci f2fs_put_page(*cp_page, 1); 86862306a36Sopenharmony_ci f2fs_warn(sbi, "invalid crc value"); 86962306a36Sopenharmony_ci return -EINVAL; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci *version = cur_cp_version(*cp_block); 87362306a36Sopenharmony_ci return 0; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic struct page *validate_checkpoint(struct f2fs_sb_info *sbi, 87762306a36Sopenharmony_ci block_t cp_addr, unsigned long long *version) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct page *cp_page_1 = NULL, *cp_page_2 = NULL; 88062306a36Sopenharmony_ci struct f2fs_checkpoint *cp_block = NULL; 88162306a36Sopenharmony_ci unsigned long long cur_version = 0, pre_version = 0; 88262306a36Sopenharmony_ci unsigned int cp_blocks; 88362306a36Sopenharmony_ci int err; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci err = get_checkpoint_version(sbi, cp_addr, &cp_block, 88662306a36Sopenharmony_ci &cp_page_1, version); 88762306a36Sopenharmony_ci if (err) 88862306a36Sopenharmony_ci return NULL; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci cp_blocks = le32_to_cpu(cp_block->cp_pack_total_block_count); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (cp_blocks > sbi->blocks_per_seg || cp_blocks <= F2FS_CP_PACKS) { 89362306a36Sopenharmony_ci f2fs_warn(sbi, "invalid cp_pack_total_block_count:%u", 89462306a36Sopenharmony_ci le32_to_cpu(cp_block->cp_pack_total_block_count)); 89562306a36Sopenharmony_ci goto invalid_cp; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci pre_version = *version; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci cp_addr += cp_blocks - 1; 90062306a36Sopenharmony_ci err = get_checkpoint_version(sbi, cp_addr, &cp_block, 90162306a36Sopenharmony_ci &cp_page_2, version); 90262306a36Sopenharmony_ci if (err) 90362306a36Sopenharmony_ci goto invalid_cp; 90462306a36Sopenharmony_ci cur_version = *version; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (cur_version == pre_version) { 90762306a36Sopenharmony_ci *version = cur_version; 90862306a36Sopenharmony_ci f2fs_put_page(cp_page_2, 1); 90962306a36Sopenharmony_ci return cp_page_1; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci f2fs_put_page(cp_page_2, 1); 91262306a36Sopenharmony_ciinvalid_cp: 91362306a36Sopenharmony_ci f2fs_put_page(cp_page_1, 1); 91462306a36Sopenharmony_ci return NULL; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ciint f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci struct f2fs_checkpoint *cp_block; 92062306a36Sopenharmony_ci struct f2fs_super_block *fsb = sbi->raw_super; 92162306a36Sopenharmony_ci struct page *cp1, *cp2, *cur_page; 92262306a36Sopenharmony_ci unsigned long blk_size = sbi->blocksize; 92362306a36Sopenharmony_ci unsigned long long cp1_version = 0, cp2_version = 0; 92462306a36Sopenharmony_ci unsigned long long cp_start_blk_no; 92562306a36Sopenharmony_ci unsigned int cp_blks = 1 + __cp_payload(sbi); 92662306a36Sopenharmony_ci block_t cp_blk_no; 92762306a36Sopenharmony_ci int i; 92862306a36Sopenharmony_ci int err; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci sbi->ckpt = f2fs_kvzalloc(sbi, array_size(blk_size, cp_blks), 93162306a36Sopenharmony_ci GFP_KERNEL); 93262306a36Sopenharmony_ci if (!sbi->ckpt) 93362306a36Sopenharmony_ci return -ENOMEM; 93462306a36Sopenharmony_ci /* 93562306a36Sopenharmony_ci * Finding out valid cp block involves read both 93662306a36Sopenharmony_ci * sets( cp pack 1 and cp pack 2) 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_ci cp_start_blk_no = le32_to_cpu(fsb->cp_blkaddr); 93962306a36Sopenharmony_ci cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* The second checkpoint pack should start at the next segment */ 94262306a36Sopenharmony_ci cp_start_blk_no += ((unsigned long long)1) << 94362306a36Sopenharmony_ci le32_to_cpu(fsb->log_blocks_per_seg); 94462306a36Sopenharmony_ci cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (cp1 && cp2) { 94762306a36Sopenharmony_ci if (ver_after(cp2_version, cp1_version)) 94862306a36Sopenharmony_ci cur_page = cp2; 94962306a36Sopenharmony_ci else 95062306a36Sopenharmony_ci cur_page = cp1; 95162306a36Sopenharmony_ci } else if (cp1) { 95262306a36Sopenharmony_ci cur_page = cp1; 95362306a36Sopenharmony_ci } else if (cp2) { 95462306a36Sopenharmony_ci cur_page = cp2; 95562306a36Sopenharmony_ci } else { 95662306a36Sopenharmony_ci err = -EFSCORRUPTED; 95762306a36Sopenharmony_ci goto fail_no_cp; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci cp_block = (struct f2fs_checkpoint *)page_address(cur_page); 96162306a36Sopenharmony_ci memcpy(sbi->ckpt, cp_block, blk_size); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (cur_page == cp1) 96462306a36Sopenharmony_ci sbi->cur_cp_pack = 1; 96562306a36Sopenharmony_ci else 96662306a36Sopenharmony_ci sbi->cur_cp_pack = 2; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* Sanity checking of checkpoint */ 96962306a36Sopenharmony_ci if (f2fs_sanity_check_ckpt(sbi)) { 97062306a36Sopenharmony_ci err = -EFSCORRUPTED; 97162306a36Sopenharmony_ci goto free_fail_no_cp; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (cp_blks <= 1) 97562306a36Sopenharmony_ci goto done; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci cp_blk_no = le32_to_cpu(fsb->cp_blkaddr); 97862306a36Sopenharmony_ci if (cur_page == cp2) 97962306a36Sopenharmony_ci cp_blk_no += BIT(le32_to_cpu(fsb->log_blocks_per_seg)); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci for (i = 1; i < cp_blks; i++) { 98262306a36Sopenharmony_ci void *sit_bitmap_ptr; 98362306a36Sopenharmony_ci unsigned char *ckpt = (unsigned char *)sbi->ckpt; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci cur_page = f2fs_get_meta_page(sbi, cp_blk_no + i); 98662306a36Sopenharmony_ci if (IS_ERR(cur_page)) { 98762306a36Sopenharmony_ci err = PTR_ERR(cur_page); 98862306a36Sopenharmony_ci goto free_fail_no_cp; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci sit_bitmap_ptr = page_address(cur_page); 99162306a36Sopenharmony_ci memcpy(ckpt + i * blk_size, sit_bitmap_ptr, blk_size); 99262306a36Sopenharmony_ci f2fs_put_page(cur_page, 1); 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_cidone: 99562306a36Sopenharmony_ci f2fs_put_page(cp1, 1); 99662306a36Sopenharmony_ci f2fs_put_page(cp2, 1); 99762306a36Sopenharmony_ci return 0; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cifree_fail_no_cp: 100062306a36Sopenharmony_ci f2fs_put_page(cp1, 1); 100162306a36Sopenharmony_ci f2fs_put_page(cp2, 1); 100262306a36Sopenharmony_cifail_no_cp: 100362306a36Sopenharmony_ci kvfree(sbi->ckpt); 100462306a36Sopenharmony_ci return err; 100562306a36Sopenharmony_ci} 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_cistatic void __add_dirty_inode(struct inode *inode, enum inode_type type) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 101062306a36Sopenharmony_ci int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (is_inode_flag_set(inode, flag)) 101362306a36Sopenharmony_ci return; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci set_inode_flag(inode, flag); 101662306a36Sopenharmony_ci list_add_tail(&F2FS_I(inode)->dirty_list, &sbi->inode_list[type]); 101762306a36Sopenharmony_ci stat_inc_dirty_inode(sbi, type); 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_cistatic void __remove_dirty_inode(struct inode *inode, enum inode_type type) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (get_dirty_pages(inode) || !is_inode_flag_set(inode, flag)) 102562306a36Sopenharmony_ci return; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci list_del_init(&F2FS_I(inode)->dirty_list); 102862306a36Sopenharmony_ci clear_inode_flag(inode, flag); 102962306a36Sopenharmony_ci stat_dec_dirty_inode(F2FS_I_SB(inode), type); 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_civoid f2fs_update_dirty_folio(struct inode *inode, struct folio *folio) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 103562306a36Sopenharmony_ci enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && 103862306a36Sopenharmony_ci !S_ISLNK(inode->i_mode)) 103962306a36Sopenharmony_ci return; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci spin_lock(&sbi->inode_lock[type]); 104262306a36Sopenharmony_ci if (type != FILE_INODE || test_opt(sbi, DATA_FLUSH)) 104362306a36Sopenharmony_ci __add_dirty_inode(inode, type); 104462306a36Sopenharmony_ci inode_inc_dirty_pages(inode); 104562306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[type]); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci set_page_private_reference(&folio->page); 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_civoid f2fs_remove_dirty_inode(struct inode *inode) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 105362306a36Sopenharmony_ci enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && 105662306a36Sopenharmony_ci !S_ISLNK(inode->i_mode)) 105762306a36Sopenharmony_ci return; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (type == FILE_INODE && !test_opt(sbi, DATA_FLUSH)) 106062306a36Sopenharmony_ci return; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci spin_lock(&sbi->inode_lock[type]); 106362306a36Sopenharmony_ci __remove_dirty_inode(inode, type); 106462306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[type]); 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ciint f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type, 106862306a36Sopenharmony_ci bool from_cp) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct list_head *head; 107162306a36Sopenharmony_ci struct inode *inode; 107262306a36Sopenharmony_ci struct f2fs_inode_info *fi; 107362306a36Sopenharmony_ci bool is_dir = (type == DIR_INODE); 107462306a36Sopenharmony_ci unsigned long ino = 0; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci trace_f2fs_sync_dirty_inodes_enter(sbi->sb, is_dir, 107762306a36Sopenharmony_ci get_pages(sbi, is_dir ? 107862306a36Sopenharmony_ci F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA)); 107962306a36Sopenharmony_ciretry: 108062306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) { 108162306a36Sopenharmony_ci trace_f2fs_sync_dirty_inodes_exit(sbi->sb, is_dir, 108262306a36Sopenharmony_ci get_pages(sbi, is_dir ? 108362306a36Sopenharmony_ci F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA)); 108462306a36Sopenharmony_ci return -EIO; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci spin_lock(&sbi->inode_lock[type]); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci head = &sbi->inode_list[type]; 109062306a36Sopenharmony_ci if (list_empty(head)) { 109162306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[type]); 109262306a36Sopenharmony_ci trace_f2fs_sync_dirty_inodes_exit(sbi->sb, is_dir, 109362306a36Sopenharmony_ci get_pages(sbi, is_dir ? 109462306a36Sopenharmony_ci F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA)); 109562306a36Sopenharmony_ci return 0; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci fi = list_first_entry(head, struct f2fs_inode_info, dirty_list); 109862306a36Sopenharmony_ci inode = igrab(&fi->vfs_inode); 109962306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[type]); 110062306a36Sopenharmony_ci if (inode) { 110162306a36Sopenharmony_ci unsigned long cur_ino = inode->i_ino; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (from_cp) 110462306a36Sopenharmony_ci F2FS_I(inode)->cp_task = current; 110562306a36Sopenharmony_ci F2FS_I(inode)->wb_task = current; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci filemap_fdatawrite(inode->i_mapping); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci F2FS_I(inode)->wb_task = NULL; 111062306a36Sopenharmony_ci if (from_cp) 111162306a36Sopenharmony_ci F2FS_I(inode)->cp_task = NULL; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci iput(inode); 111462306a36Sopenharmony_ci /* We need to give cpu to another writers. */ 111562306a36Sopenharmony_ci if (ino == cur_ino) 111662306a36Sopenharmony_ci cond_resched(); 111762306a36Sopenharmony_ci else 111862306a36Sopenharmony_ci ino = cur_ino; 111962306a36Sopenharmony_ci } else { 112062306a36Sopenharmony_ci /* 112162306a36Sopenharmony_ci * We should submit bio, since it exists several 112262306a36Sopenharmony_ci * writebacking dentry pages in the freeing inode. 112362306a36Sopenharmony_ci */ 112462306a36Sopenharmony_ci f2fs_submit_merged_write(sbi, DATA); 112562306a36Sopenharmony_ci cond_resched(); 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci goto retry; 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci struct list_head *head = &sbi->inode_list[DIRTY_META]; 113362306a36Sopenharmony_ci struct inode *inode; 113462306a36Sopenharmony_ci struct f2fs_inode_info *fi; 113562306a36Sopenharmony_ci s64 total = get_pages(sbi, F2FS_DIRTY_IMETA); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci while (total--) { 113862306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) 113962306a36Sopenharmony_ci return -EIO; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci spin_lock(&sbi->inode_lock[DIRTY_META]); 114262306a36Sopenharmony_ci if (list_empty(head)) { 114362306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[DIRTY_META]); 114462306a36Sopenharmony_ci return 0; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci fi = list_first_entry(head, struct f2fs_inode_info, 114762306a36Sopenharmony_ci gdirty_list); 114862306a36Sopenharmony_ci inode = igrab(&fi->vfs_inode); 114962306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[DIRTY_META]); 115062306a36Sopenharmony_ci if (inode) { 115162306a36Sopenharmony_ci sync_inode_metadata(inode, 0); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci /* it's on eviction */ 115462306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_DIRTY_INODE)) 115562306a36Sopenharmony_ci f2fs_update_inode_page(inode); 115662306a36Sopenharmony_ci iput(inode); 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci return 0; 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_cistatic void __prepare_cp_block(struct f2fs_sb_info *sbi) 116362306a36Sopenharmony_ci{ 116462306a36Sopenharmony_ci struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 116562306a36Sopenharmony_ci struct f2fs_nm_info *nm_i = NM_I(sbi); 116662306a36Sopenharmony_ci nid_t last_nid = nm_i->next_scan_nid; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci next_free_nid(sbi, &last_nid); 116962306a36Sopenharmony_ci ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi)); 117062306a36Sopenharmony_ci ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi)); 117162306a36Sopenharmony_ci ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi)); 117262306a36Sopenharmony_ci ckpt->next_free_nid = cpu_to_le32(last_nid); 117362306a36Sopenharmony_ci} 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_cistatic bool __need_flush_quota(struct f2fs_sb_info *sbi) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci bool ret = false; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci if (!is_journalled_quota(sbi)) 118062306a36Sopenharmony_ci return false; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (!f2fs_down_write_trylock(&sbi->quota_sem)) 118362306a36Sopenharmony_ci return true; 118462306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) { 118562306a36Sopenharmony_ci ret = false; 118662306a36Sopenharmony_ci } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) { 118762306a36Sopenharmony_ci ret = false; 118862306a36Sopenharmony_ci } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH)) { 118962306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); 119062306a36Sopenharmony_ci ret = true; 119162306a36Sopenharmony_ci } else if (get_pages(sbi, F2FS_DIRTY_QDATA)) { 119262306a36Sopenharmony_ci ret = true; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci f2fs_up_write(&sbi->quota_sem); 119562306a36Sopenharmony_ci return ret; 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci/* 119962306a36Sopenharmony_ci * Freeze all the FS-operations for checkpoint. 120062306a36Sopenharmony_ci */ 120162306a36Sopenharmony_cistatic int block_operations(struct f2fs_sb_info *sbi) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci struct writeback_control wbc = { 120462306a36Sopenharmony_ci .sync_mode = WB_SYNC_ALL, 120562306a36Sopenharmony_ci .nr_to_write = LONG_MAX, 120662306a36Sopenharmony_ci .for_reclaim = 0, 120762306a36Sopenharmony_ci }; 120862306a36Sopenharmony_ci int err = 0, cnt = 0; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* 121162306a36Sopenharmony_ci * Let's flush inline_data in dirty node pages. 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_ci f2fs_flush_inline_data(sbi); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ciretry_flush_quotas: 121662306a36Sopenharmony_ci f2fs_lock_all(sbi); 121762306a36Sopenharmony_ci if (__need_flush_quota(sbi)) { 121862306a36Sopenharmony_ci int locked; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (++cnt > DEFAULT_RETRY_QUOTA_FLUSH_COUNT) { 122162306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_SKIP_FLUSH); 122262306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); 122362306a36Sopenharmony_ci goto retry_flush_dents; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci f2fs_unlock_all(sbi); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* only failed during mount/umount/freeze/quotactl */ 122862306a36Sopenharmony_ci locked = down_read_trylock(&sbi->sb->s_umount); 122962306a36Sopenharmony_ci f2fs_quota_sync(sbi->sb, -1); 123062306a36Sopenharmony_ci if (locked) 123162306a36Sopenharmony_ci up_read(&sbi->sb->s_umount); 123262306a36Sopenharmony_ci cond_resched(); 123362306a36Sopenharmony_ci goto retry_flush_quotas; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ciretry_flush_dents: 123762306a36Sopenharmony_ci /* write all the dirty dentry pages */ 123862306a36Sopenharmony_ci if (get_pages(sbi, F2FS_DIRTY_DENTS)) { 123962306a36Sopenharmony_ci f2fs_unlock_all(sbi); 124062306a36Sopenharmony_ci err = f2fs_sync_dirty_inodes(sbi, DIR_INODE, true); 124162306a36Sopenharmony_ci if (err) 124262306a36Sopenharmony_ci return err; 124362306a36Sopenharmony_ci cond_resched(); 124462306a36Sopenharmony_ci goto retry_flush_quotas; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci /* 124862306a36Sopenharmony_ci * POR: we should ensure that there are no dirty node pages 124962306a36Sopenharmony_ci * until finishing nat/sit flush. inode->i_blocks can be updated. 125062306a36Sopenharmony_ci */ 125162306a36Sopenharmony_ci f2fs_down_write(&sbi->node_change); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (get_pages(sbi, F2FS_DIRTY_IMETA)) { 125462306a36Sopenharmony_ci f2fs_up_write(&sbi->node_change); 125562306a36Sopenharmony_ci f2fs_unlock_all(sbi); 125662306a36Sopenharmony_ci err = f2fs_sync_inode_meta(sbi); 125762306a36Sopenharmony_ci if (err) 125862306a36Sopenharmony_ci return err; 125962306a36Sopenharmony_ci cond_resched(); 126062306a36Sopenharmony_ci goto retry_flush_quotas; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ciretry_flush_nodes: 126462306a36Sopenharmony_ci f2fs_down_write(&sbi->node_write); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci if (get_pages(sbi, F2FS_DIRTY_NODES)) { 126762306a36Sopenharmony_ci f2fs_up_write(&sbi->node_write); 126862306a36Sopenharmony_ci atomic_inc(&sbi->wb_sync_req[NODE]); 126962306a36Sopenharmony_ci err = f2fs_sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO); 127062306a36Sopenharmony_ci atomic_dec(&sbi->wb_sync_req[NODE]); 127162306a36Sopenharmony_ci if (err) { 127262306a36Sopenharmony_ci f2fs_up_write(&sbi->node_change); 127362306a36Sopenharmony_ci f2fs_unlock_all(sbi); 127462306a36Sopenharmony_ci return err; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci cond_resched(); 127762306a36Sopenharmony_ci goto retry_flush_nodes; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci /* 128162306a36Sopenharmony_ci * sbi->node_change is used only for AIO write_begin path which produces 128262306a36Sopenharmony_ci * dirty node blocks and some checkpoint values by block allocation. 128362306a36Sopenharmony_ci */ 128462306a36Sopenharmony_ci __prepare_cp_block(sbi); 128562306a36Sopenharmony_ci f2fs_up_write(&sbi->node_change); 128662306a36Sopenharmony_ci return err; 128762306a36Sopenharmony_ci} 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_cistatic void unblock_operations(struct f2fs_sb_info *sbi) 129062306a36Sopenharmony_ci{ 129162306a36Sopenharmony_ci f2fs_up_write(&sbi->node_write); 129262306a36Sopenharmony_ci f2fs_unlock_all(sbi); 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_civoid f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci DEFINE_WAIT(wait); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci for (;;) { 130062306a36Sopenharmony_ci if (!get_pages(sbi, type)) 130162306a36Sopenharmony_ci break; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi) && 130462306a36Sopenharmony_ci !is_sbi_flag_set(sbi, SBI_IS_CLOSE))) 130562306a36Sopenharmony_ci break; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (type == F2FS_DIRTY_META) 130862306a36Sopenharmony_ci f2fs_sync_meta_pages(sbi, META, LONG_MAX, 130962306a36Sopenharmony_ci FS_CP_META_IO); 131062306a36Sopenharmony_ci else if (type == F2FS_WB_CP_DATA) 131162306a36Sopenharmony_ci f2fs_submit_merged_write(sbi, DATA); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE); 131462306a36Sopenharmony_ci io_schedule_timeout(DEFAULT_IO_TIMEOUT); 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci finish_wait(&sbi->cp_wait, &wait); 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_cistatic void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num; 132262306a36Sopenharmony_ci struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 132362306a36Sopenharmony_ci unsigned long flags; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci if (cpc->reason & CP_UMOUNT) { 132662306a36Sopenharmony_ci if (le32_to_cpu(ckpt->cp_pack_total_block_count) + 132762306a36Sopenharmony_ci NM_I(sbi)->nat_bits_blocks > sbi->blocks_per_seg) { 132862306a36Sopenharmony_ci clear_ckpt_flags(sbi, CP_NAT_BITS_FLAG); 132962306a36Sopenharmony_ci f2fs_notice(sbi, "Disable nat_bits due to no space"); 133062306a36Sopenharmony_ci } else if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG) && 133162306a36Sopenharmony_ci f2fs_nat_bitmap_enabled(sbi)) { 133262306a36Sopenharmony_ci f2fs_enable_nat_bits(sbi); 133362306a36Sopenharmony_ci set_ckpt_flags(sbi, CP_NAT_BITS_FLAG); 133462306a36Sopenharmony_ci f2fs_notice(sbi, "Rebuild and enable nat_bits"); 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci spin_lock_irqsave(&sbi->cp_lock, flags); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci if (cpc->reason & CP_TRIMMED) 134162306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_TRIMMED_FLAG); 134262306a36Sopenharmony_ci else 134362306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_TRIMMED_FLAG); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (cpc->reason & CP_UMOUNT) 134662306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); 134762306a36Sopenharmony_ci else 134862306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci if (cpc->reason & CP_FASTBOOT) 135162306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); 135262306a36Sopenharmony_ci else 135362306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci if (orphan_num) 135662306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); 135762306a36Sopenharmony_ci else 135862306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) 136162306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_FSCK_FLAG); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_IS_RESIZEFS)) 136462306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_RESIZEFS_FLAG); 136562306a36Sopenharmony_ci else 136662306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_RESIZEFS_FLAG); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_CP_DISABLED)) 136962306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_DISABLED_FLAG); 137062306a36Sopenharmony_ci else 137162306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_DISABLED_FLAG); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK)) 137462306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_DISABLED_QUICK_FLAG); 137562306a36Sopenharmony_ci else 137662306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_DISABLED_QUICK_FLAG); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) 137962306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_QUOTA_NEED_FSCK_FLAG); 138062306a36Sopenharmony_ci else 138162306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_QUOTA_NEED_FSCK_FLAG); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) 138462306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_QUOTA_NEED_FSCK_FLAG); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* set this flag to activate crc|cp_ver for recovery */ 138762306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG); 138862306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci spin_unlock_irqrestore(&sbi->cp_lock, flags); 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_cistatic void commit_checkpoint(struct f2fs_sb_info *sbi, 139462306a36Sopenharmony_ci void *src, block_t blk_addr) 139562306a36Sopenharmony_ci{ 139662306a36Sopenharmony_ci struct writeback_control wbc = { 139762306a36Sopenharmony_ci .for_reclaim = 0, 139862306a36Sopenharmony_ci }; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* 140162306a36Sopenharmony_ci * filemap_get_folios_tag and lock_page again will take 140262306a36Sopenharmony_ci * some extra time. Therefore, f2fs_update_meta_pages and 140362306a36Sopenharmony_ci * f2fs_sync_meta_pages are combined in this function. 140462306a36Sopenharmony_ci */ 140562306a36Sopenharmony_ci struct page *page = f2fs_grab_meta_page(sbi, blk_addr); 140662306a36Sopenharmony_ci int err; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci f2fs_wait_on_page_writeback(page, META, true, true); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci memcpy(page_address(page), src, PAGE_SIZE); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci set_page_dirty(page); 141362306a36Sopenharmony_ci if (unlikely(!clear_page_dirty_for_io(page))) 141462306a36Sopenharmony_ci f2fs_bug_on(sbi, 1); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* writeout cp pack 2 page */ 141762306a36Sopenharmony_ci err = __f2fs_write_meta_page(page, &wbc, FS_CP_META_IO); 141862306a36Sopenharmony_ci if (unlikely(err && f2fs_cp_error(sbi))) { 141962306a36Sopenharmony_ci f2fs_put_page(page, 1); 142062306a36Sopenharmony_ci return; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci f2fs_bug_on(sbi, err); 142462306a36Sopenharmony_ci f2fs_put_page(page, 0); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci /* submit checkpoint (with barrier if NOBARRIER is not set) */ 142762306a36Sopenharmony_ci f2fs_submit_merged_write(sbi, META_FLUSH); 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_cistatic inline u64 get_sectors_written(struct block_device *bdev) 143162306a36Sopenharmony_ci{ 143262306a36Sopenharmony_ci return (u64)part_stat_read(bdev, sectors[STAT_WRITE]); 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ciu64 f2fs_get_sectors_written(struct f2fs_sb_info *sbi) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci if (f2fs_is_multi_device(sbi)) { 143862306a36Sopenharmony_ci u64 sectors = 0; 143962306a36Sopenharmony_ci int i; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci for (i = 0; i < sbi->s_ndevs; i++) 144262306a36Sopenharmony_ci sectors += get_sectors_written(FDEV(i).bdev); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci return sectors; 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci return get_sectors_written(sbi->sb->s_bdev); 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_cistatic int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 145362306a36Sopenharmony_ci struct f2fs_nm_info *nm_i = NM_I(sbi); 145462306a36Sopenharmony_ci unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num, flags; 145562306a36Sopenharmony_ci block_t start_blk; 145662306a36Sopenharmony_ci unsigned int data_sum_blocks, orphan_blocks; 145762306a36Sopenharmony_ci __u32 crc32 = 0; 145862306a36Sopenharmony_ci int i; 145962306a36Sopenharmony_ci int cp_payload_blks = __cp_payload(sbi); 146062306a36Sopenharmony_ci struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); 146162306a36Sopenharmony_ci u64 kbytes_written; 146262306a36Sopenharmony_ci int err; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci /* Flush all the NAT/SIT pages */ 146562306a36Sopenharmony_ci f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* start to update checkpoint, cp ver is already updated previously */ 146862306a36Sopenharmony_ci ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi, true)); 146962306a36Sopenharmony_ci ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); 147062306a36Sopenharmony_ci for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { 147162306a36Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, i + CURSEG_HOT_NODE); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci ckpt->cur_node_segno[i] = cpu_to_le32(curseg->segno); 147462306a36Sopenharmony_ci ckpt->cur_node_blkoff[i] = cpu_to_le16(curseg->next_blkoff); 147562306a36Sopenharmony_ci ckpt->alloc_type[i + CURSEG_HOT_NODE] = curseg->alloc_type; 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { 147862306a36Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, i + CURSEG_HOT_DATA); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci ckpt->cur_data_segno[i] = cpu_to_le32(curseg->segno); 148162306a36Sopenharmony_ci ckpt->cur_data_blkoff[i] = cpu_to_le16(curseg->next_blkoff); 148262306a36Sopenharmony_ci ckpt->alloc_type[i + CURSEG_HOT_DATA] = curseg->alloc_type; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci /* 2 cp + n data seg summary + orphan inode blocks */ 148662306a36Sopenharmony_ci data_sum_blocks = f2fs_npages_for_summary_flush(sbi, false); 148762306a36Sopenharmony_ci spin_lock_irqsave(&sbi->cp_lock, flags); 148862306a36Sopenharmony_ci if (data_sum_blocks < NR_CURSEG_DATA_TYPE) 148962306a36Sopenharmony_ci __set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); 149062306a36Sopenharmony_ci else 149162306a36Sopenharmony_ci __clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG); 149262306a36Sopenharmony_ci spin_unlock_irqrestore(&sbi->cp_lock, flags); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num); 149562306a36Sopenharmony_ci ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks + 149662306a36Sopenharmony_ci orphan_blocks); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci if (__remain_node_summaries(cpc->reason)) 149962306a36Sopenharmony_ci ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS + 150062306a36Sopenharmony_ci cp_payload_blks + data_sum_blocks + 150162306a36Sopenharmony_ci orphan_blocks + NR_CURSEG_NODE_TYPE); 150262306a36Sopenharmony_ci else 150362306a36Sopenharmony_ci ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS + 150462306a36Sopenharmony_ci cp_payload_blks + data_sum_blocks + 150562306a36Sopenharmony_ci orphan_blocks); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci /* update ckpt flag for checkpoint */ 150862306a36Sopenharmony_ci update_ckpt_flags(sbi, cpc); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci /* update SIT/NAT bitmap */ 151162306a36Sopenharmony_ci get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP)); 151262306a36Sopenharmony_ci get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP)); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci crc32 = f2fs_checkpoint_chksum(sbi, ckpt); 151562306a36Sopenharmony_ci *((__le32 *)((unsigned char *)ckpt + 151662306a36Sopenharmony_ci le32_to_cpu(ckpt->checksum_offset))) 151762306a36Sopenharmony_ci = cpu_to_le32(crc32); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci start_blk = __start_cp_next_addr(sbi); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* write nat bits */ 152262306a36Sopenharmony_ci if ((cpc->reason & CP_UMOUNT) && 152362306a36Sopenharmony_ci is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG)) { 152462306a36Sopenharmony_ci __u64 cp_ver = cur_cp_version(ckpt); 152562306a36Sopenharmony_ci block_t blk; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci cp_ver |= ((__u64)crc32 << 32); 152862306a36Sopenharmony_ci *(__le64 *)nm_i->nat_bits = cpu_to_le64(cp_ver); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci blk = start_blk + sbi->blocks_per_seg - nm_i->nat_bits_blocks; 153162306a36Sopenharmony_ci for (i = 0; i < nm_i->nat_bits_blocks; i++) 153262306a36Sopenharmony_ci f2fs_update_meta_page(sbi, nm_i->nat_bits + 153362306a36Sopenharmony_ci (i << F2FS_BLKSIZE_BITS), blk + i); 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci /* write out checkpoint buffer at block 0 */ 153762306a36Sopenharmony_ci f2fs_update_meta_page(sbi, ckpt, start_blk++); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci for (i = 1; i < 1 + cp_payload_blks; i++) 154062306a36Sopenharmony_ci f2fs_update_meta_page(sbi, (char *)ckpt + i * F2FS_BLKSIZE, 154162306a36Sopenharmony_ci start_blk++); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (orphan_num) { 154462306a36Sopenharmony_ci write_orphan_inodes(sbi, start_blk); 154562306a36Sopenharmony_ci start_blk += orphan_blocks; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci f2fs_write_data_summaries(sbi, start_blk); 154962306a36Sopenharmony_ci start_blk += data_sum_blocks; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* Record write statistics in the hot node summary */ 155262306a36Sopenharmony_ci kbytes_written = sbi->kbytes_written; 155362306a36Sopenharmony_ci kbytes_written += (f2fs_get_sectors_written(sbi) - 155462306a36Sopenharmony_ci sbi->sectors_written_start) >> 1; 155562306a36Sopenharmony_ci seg_i->journal->info.kbytes_written = cpu_to_le64(kbytes_written); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if (__remain_node_summaries(cpc->reason)) { 155862306a36Sopenharmony_ci f2fs_write_node_summaries(sbi, start_blk); 155962306a36Sopenharmony_ci start_blk += NR_CURSEG_NODE_TYPE; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci /* update user_block_counts */ 156362306a36Sopenharmony_ci sbi->last_valid_block_count = sbi->total_valid_block_count; 156462306a36Sopenharmony_ci percpu_counter_set(&sbi->alloc_valid_block_count, 0); 156562306a36Sopenharmony_ci percpu_counter_set(&sbi->rf_node_block_count, 0); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci /* Here, we have one bio having CP pack except cp pack 2 page */ 156862306a36Sopenharmony_ci f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); 156962306a36Sopenharmony_ci /* Wait for all dirty meta pages to be submitted for IO */ 157062306a36Sopenharmony_ci f2fs_wait_on_all_pages(sbi, F2FS_DIRTY_META); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci /* wait for previous submitted meta pages writeback */ 157362306a36Sopenharmony_ci f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci /* flush all device cache */ 157662306a36Sopenharmony_ci err = f2fs_flush_device_cache(sbi); 157762306a36Sopenharmony_ci if (err) 157862306a36Sopenharmony_ci return err; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* barrier and flush checkpoint cp pack 2 page if it can */ 158162306a36Sopenharmony_ci commit_checkpoint(sbi, ckpt, start_blk); 158262306a36Sopenharmony_ci f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci /* 158562306a36Sopenharmony_ci * invalidate intermediate page cache borrowed from meta inode which are 158662306a36Sopenharmony_ci * used for migration of encrypted, verity or compressed inode's blocks. 158762306a36Sopenharmony_ci */ 158862306a36Sopenharmony_ci if (f2fs_sb_has_encrypt(sbi) || f2fs_sb_has_verity(sbi) || 158962306a36Sopenharmony_ci f2fs_sb_has_compression(sbi)) 159062306a36Sopenharmony_ci f2fs_bug_on(sbi, 159162306a36Sopenharmony_ci invalidate_inode_pages2_range(META_MAPPING(sbi), 159262306a36Sopenharmony_ci MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1)); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci f2fs_release_ino_entry(sbi, false); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci f2fs_reset_fsync_node_info(sbi); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_IS_DIRTY); 159962306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_NEED_CP); 160062306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_QUOTA_SKIP_FLUSH); 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci spin_lock(&sbi->stat_lock); 160362306a36Sopenharmony_ci sbi->unusable_block_count = 0; 160462306a36Sopenharmony_ci spin_unlock(&sbi->stat_lock); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci __set_cp_next_pack(sbi); 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci /* 160962306a36Sopenharmony_ci * redirty superblock if metadata like node page or inode cache is 161062306a36Sopenharmony_ci * updated during writing checkpoint. 161162306a36Sopenharmony_ci */ 161262306a36Sopenharmony_ci if (get_pages(sbi, F2FS_DIRTY_NODES) || 161362306a36Sopenharmony_ci get_pages(sbi, F2FS_DIRTY_IMETA)) 161462306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_DIRTY); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_DENTS)); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci return unlikely(f2fs_cp_error(sbi)) ? -EIO : 0; 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ciint f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 162462306a36Sopenharmony_ci unsigned long long ckpt_ver; 162562306a36Sopenharmony_ci int err = 0; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (f2fs_readonly(sbi->sb) || f2fs_hw_is_readonly(sbi)) 162862306a36Sopenharmony_ci return -EROFS; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { 163162306a36Sopenharmony_ci if (cpc->reason != CP_PAUSE) 163262306a36Sopenharmony_ci return 0; 163362306a36Sopenharmony_ci f2fs_warn(sbi, "Start checkpoint disabled!"); 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci if (cpc->reason != CP_RESIZE) 163662306a36Sopenharmony_ci f2fs_down_write(&sbi->cp_global_sem); 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && 163962306a36Sopenharmony_ci ((cpc->reason & CP_FASTBOOT) || (cpc->reason & CP_SYNC) || 164062306a36Sopenharmony_ci ((cpc->reason & CP_DISCARD) && !sbi->discard_blks))) 164162306a36Sopenharmony_ci goto out; 164262306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) { 164362306a36Sopenharmony_ci err = -EIO; 164462306a36Sopenharmony_ci goto out; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops"); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci err = block_operations(sbi); 165062306a36Sopenharmony_ci if (err) 165162306a36Sopenharmony_ci goto out; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops"); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci f2fs_flush_merged_writes(sbi); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci /* this is the case of multiple fstrims without any changes */ 165862306a36Sopenharmony_ci if (cpc->reason & CP_DISCARD) { 165962306a36Sopenharmony_ci if (!f2fs_exist_trim_candidates(sbi, cpc)) { 166062306a36Sopenharmony_ci unblock_operations(sbi); 166162306a36Sopenharmony_ci goto out; 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci if (NM_I(sbi)->nat_cnt[DIRTY_NAT] == 0 && 166562306a36Sopenharmony_ci SIT_I(sbi)->dirty_sentries == 0 && 166662306a36Sopenharmony_ci prefree_segments(sbi) == 0) { 166762306a36Sopenharmony_ci f2fs_flush_sit_entries(sbi, cpc); 166862306a36Sopenharmony_ci f2fs_clear_prefree_segments(sbi, cpc); 166962306a36Sopenharmony_ci unblock_operations(sbi); 167062306a36Sopenharmony_ci goto out; 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci /* 167562306a36Sopenharmony_ci * update checkpoint pack index 167662306a36Sopenharmony_ci * Increase the version number so that 167762306a36Sopenharmony_ci * SIT entries and seg summaries are written at correct place 167862306a36Sopenharmony_ci */ 167962306a36Sopenharmony_ci ckpt_ver = cur_cp_version(ckpt); 168062306a36Sopenharmony_ci ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci /* write cached NAT/SIT entries to NAT/SIT area */ 168362306a36Sopenharmony_ci err = f2fs_flush_nat_entries(sbi, cpc); 168462306a36Sopenharmony_ci if (err) { 168562306a36Sopenharmony_ci f2fs_err(sbi, "f2fs_flush_nat_entries failed err:%d, stop checkpoint", err); 168662306a36Sopenharmony_ci f2fs_bug_on(sbi, !f2fs_cp_error(sbi)); 168762306a36Sopenharmony_ci goto stop; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci f2fs_flush_sit_entries(sbi, cpc); 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci /* save inmem log status */ 169362306a36Sopenharmony_ci f2fs_save_inmem_curseg(sbi); 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci err = do_checkpoint(sbi, cpc); 169662306a36Sopenharmony_ci if (err) { 169762306a36Sopenharmony_ci f2fs_err(sbi, "do_checkpoint failed err:%d, stop checkpoint", err); 169862306a36Sopenharmony_ci f2fs_bug_on(sbi, !f2fs_cp_error(sbi)); 169962306a36Sopenharmony_ci f2fs_release_discard_addrs(sbi); 170062306a36Sopenharmony_ci } else { 170162306a36Sopenharmony_ci f2fs_clear_prefree_segments(sbi, cpc); 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci f2fs_restore_inmem_curseg(sbi); 170562306a36Sopenharmony_ci stat_inc_cp_count(sbi); 170662306a36Sopenharmony_cistop: 170762306a36Sopenharmony_ci unblock_operations(sbi); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci if (cpc->reason & CP_RECOVERY) 171062306a36Sopenharmony_ci f2fs_notice(sbi, "checkpoint: version = %llx", ckpt_ver); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci /* update CP_TIME to trigger checkpoint periodically */ 171362306a36Sopenharmony_ci f2fs_update_time(sbi, CP_TIME); 171462306a36Sopenharmony_ci trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint"); 171562306a36Sopenharmony_ciout: 171662306a36Sopenharmony_ci if (cpc->reason != CP_RESIZE) 171762306a36Sopenharmony_ci f2fs_up_write(&sbi->cp_global_sem); 171862306a36Sopenharmony_ci return err; 171962306a36Sopenharmony_ci} 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_civoid f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci int i; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci for (i = 0; i < MAX_INO_ENTRY; i++) { 172662306a36Sopenharmony_ci struct inode_management *im = &sbi->im[i]; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci INIT_RADIX_TREE(&im->ino_root, GFP_ATOMIC); 172962306a36Sopenharmony_ci spin_lock_init(&im->ino_lock); 173062306a36Sopenharmony_ci INIT_LIST_HEAD(&im->ino_list); 173162306a36Sopenharmony_ci im->ino_num = 0; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS - 173562306a36Sopenharmony_ci NR_CURSEG_PERSIST_TYPE - __cp_payload(sbi)) * 173662306a36Sopenharmony_ci F2FS_ORPHANS_PER_BLOCK; 173762306a36Sopenharmony_ci} 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ciint __init f2fs_create_checkpoint_caches(void) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci ino_entry_slab = f2fs_kmem_cache_create("f2fs_ino_entry", 174262306a36Sopenharmony_ci sizeof(struct ino_entry)); 174362306a36Sopenharmony_ci if (!ino_entry_slab) 174462306a36Sopenharmony_ci return -ENOMEM; 174562306a36Sopenharmony_ci f2fs_inode_entry_slab = f2fs_kmem_cache_create("f2fs_inode_entry", 174662306a36Sopenharmony_ci sizeof(struct inode_entry)); 174762306a36Sopenharmony_ci if (!f2fs_inode_entry_slab) { 174862306a36Sopenharmony_ci kmem_cache_destroy(ino_entry_slab); 174962306a36Sopenharmony_ci return -ENOMEM; 175062306a36Sopenharmony_ci } 175162306a36Sopenharmony_ci return 0; 175262306a36Sopenharmony_ci} 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_civoid f2fs_destroy_checkpoint_caches(void) 175562306a36Sopenharmony_ci{ 175662306a36Sopenharmony_ci kmem_cache_destroy(ino_entry_slab); 175762306a36Sopenharmony_ci kmem_cache_destroy(f2fs_inode_entry_slab); 175862306a36Sopenharmony_ci} 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_cistatic int __write_checkpoint_sync(struct f2fs_sb_info *sbi) 176162306a36Sopenharmony_ci{ 176262306a36Sopenharmony_ci struct cp_control cpc = { .reason = CP_SYNC, }; 176362306a36Sopenharmony_ci int err; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci f2fs_down_write(&sbi->gc_lock); 176662306a36Sopenharmony_ci err = f2fs_write_checkpoint(sbi, &cpc); 176762306a36Sopenharmony_ci f2fs_up_write(&sbi->gc_lock); 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci return err; 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_cistatic void __checkpoint_and_complete_reqs(struct f2fs_sb_info *sbi) 177362306a36Sopenharmony_ci{ 177462306a36Sopenharmony_ci struct ckpt_req_control *cprc = &sbi->cprc_info; 177562306a36Sopenharmony_ci struct ckpt_req *req, *next; 177662306a36Sopenharmony_ci struct llist_node *dispatch_list; 177762306a36Sopenharmony_ci u64 sum_diff = 0, diff, count = 0; 177862306a36Sopenharmony_ci int ret; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci dispatch_list = llist_del_all(&cprc->issue_list); 178162306a36Sopenharmony_ci if (!dispatch_list) 178262306a36Sopenharmony_ci return; 178362306a36Sopenharmony_ci dispatch_list = llist_reverse_order(dispatch_list); 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci ret = __write_checkpoint_sync(sbi); 178662306a36Sopenharmony_ci atomic_inc(&cprc->issued_ckpt); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci llist_for_each_entry_safe(req, next, dispatch_list, llnode) { 178962306a36Sopenharmony_ci diff = (u64)ktime_ms_delta(ktime_get(), req->queue_time); 179062306a36Sopenharmony_ci req->ret = ret; 179162306a36Sopenharmony_ci complete(&req->wait); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci sum_diff += diff; 179462306a36Sopenharmony_ci count++; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci atomic_sub(count, &cprc->queued_ckpt); 179762306a36Sopenharmony_ci atomic_add(count, &cprc->total_ckpt); 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci spin_lock(&cprc->stat_lock); 180062306a36Sopenharmony_ci cprc->cur_time = (unsigned int)div64_u64(sum_diff, count); 180162306a36Sopenharmony_ci if (cprc->peak_time < cprc->cur_time) 180262306a36Sopenharmony_ci cprc->peak_time = cprc->cur_time; 180362306a36Sopenharmony_ci spin_unlock(&cprc->stat_lock); 180462306a36Sopenharmony_ci} 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_cistatic int issue_checkpoint_thread(void *data) 180762306a36Sopenharmony_ci{ 180862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = data; 180962306a36Sopenharmony_ci struct ckpt_req_control *cprc = &sbi->cprc_info; 181062306a36Sopenharmony_ci wait_queue_head_t *q = &cprc->ckpt_wait_queue; 181162306a36Sopenharmony_cirepeat: 181262306a36Sopenharmony_ci if (kthread_should_stop()) 181362306a36Sopenharmony_ci return 0; 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci if (!llist_empty(&cprc->issue_list)) 181662306a36Sopenharmony_ci __checkpoint_and_complete_reqs(sbi); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci wait_event_interruptible(*q, 181962306a36Sopenharmony_ci kthread_should_stop() || !llist_empty(&cprc->issue_list)); 182062306a36Sopenharmony_ci goto repeat; 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_cistatic void flush_remained_ckpt_reqs(struct f2fs_sb_info *sbi, 182462306a36Sopenharmony_ci struct ckpt_req *wait_req) 182562306a36Sopenharmony_ci{ 182662306a36Sopenharmony_ci struct ckpt_req_control *cprc = &sbi->cprc_info; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (!llist_empty(&cprc->issue_list)) { 182962306a36Sopenharmony_ci __checkpoint_and_complete_reqs(sbi); 183062306a36Sopenharmony_ci } else { 183162306a36Sopenharmony_ci /* already dispatched by issue_checkpoint_thread */ 183262306a36Sopenharmony_ci if (wait_req) 183362306a36Sopenharmony_ci wait_for_completion(&wait_req->wait); 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci} 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_cistatic void init_ckpt_req(struct ckpt_req *req) 183862306a36Sopenharmony_ci{ 183962306a36Sopenharmony_ci memset(req, 0, sizeof(struct ckpt_req)); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci init_completion(&req->wait); 184262306a36Sopenharmony_ci req->queue_time = ktime_get(); 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ciint f2fs_issue_checkpoint(struct f2fs_sb_info *sbi) 184662306a36Sopenharmony_ci{ 184762306a36Sopenharmony_ci struct ckpt_req_control *cprc = &sbi->cprc_info; 184862306a36Sopenharmony_ci struct ckpt_req req; 184962306a36Sopenharmony_ci struct cp_control cpc; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci cpc.reason = __get_cp_reason(sbi); 185262306a36Sopenharmony_ci if (!test_opt(sbi, MERGE_CHECKPOINT) || cpc.reason != CP_SYNC) { 185362306a36Sopenharmony_ci int ret; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci f2fs_down_write(&sbi->gc_lock); 185662306a36Sopenharmony_ci ret = f2fs_write_checkpoint(sbi, &cpc); 185762306a36Sopenharmony_ci f2fs_up_write(&sbi->gc_lock); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci return ret; 186062306a36Sopenharmony_ci } 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci if (!cprc->f2fs_issue_ckpt) 186362306a36Sopenharmony_ci return __write_checkpoint_sync(sbi); 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci init_ckpt_req(&req); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci llist_add(&req.llnode, &cprc->issue_list); 186862306a36Sopenharmony_ci atomic_inc(&cprc->queued_ckpt); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci /* 187162306a36Sopenharmony_ci * update issue_list before we wake up issue_checkpoint thread, 187262306a36Sopenharmony_ci * this smp_mb() pairs with another barrier in ___wait_event(), 187362306a36Sopenharmony_ci * see more details in comments of waitqueue_active(). 187462306a36Sopenharmony_ci */ 187562306a36Sopenharmony_ci smp_mb(); 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci if (waitqueue_active(&cprc->ckpt_wait_queue)) 187862306a36Sopenharmony_ci wake_up(&cprc->ckpt_wait_queue); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (cprc->f2fs_issue_ckpt) 188162306a36Sopenharmony_ci wait_for_completion(&req.wait); 188262306a36Sopenharmony_ci else 188362306a36Sopenharmony_ci flush_remained_ckpt_reqs(sbi, &req); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci return req.ret; 188662306a36Sopenharmony_ci} 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ciint f2fs_start_ckpt_thread(struct f2fs_sb_info *sbi) 188962306a36Sopenharmony_ci{ 189062306a36Sopenharmony_ci dev_t dev = sbi->sb->s_bdev->bd_dev; 189162306a36Sopenharmony_ci struct ckpt_req_control *cprc = &sbi->cprc_info; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (cprc->f2fs_issue_ckpt) 189462306a36Sopenharmony_ci return 0; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci cprc->f2fs_issue_ckpt = kthread_run(issue_checkpoint_thread, sbi, 189762306a36Sopenharmony_ci "f2fs_ckpt-%u:%u", MAJOR(dev), MINOR(dev)); 189862306a36Sopenharmony_ci if (IS_ERR(cprc->f2fs_issue_ckpt)) { 189962306a36Sopenharmony_ci int err = PTR_ERR(cprc->f2fs_issue_ckpt); 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci cprc->f2fs_issue_ckpt = NULL; 190262306a36Sopenharmony_ci return err; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci set_task_ioprio(cprc->f2fs_issue_ckpt, cprc->ckpt_thread_ioprio); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci return 0; 190862306a36Sopenharmony_ci} 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_civoid f2fs_stop_ckpt_thread(struct f2fs_sb_info *sbi) 191162306a36Sopenharmony_ci{ 191262306a36Sopenharmony_ci struct ckpt_req_control *cprc = &sbi->cprc_info; 191362306a36Sopenharmony_ci struct task_struct *ckpt_task; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci if (!cprc->f2fs_issue_ckpt) 191662306a36Sopenharmony_ci return; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci ckpt_task = cprc->f2fs_issue_ckpt; 191962306a36Sopenharmony_ci cprc->f2fs_issue_ckpt = NULL; 192062306a36Sopenharmony_ci kthread_stop(ckpt_task); 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci f2fs_flush_ckpt_thread(sbi); 192362306a36Sopenharmony_ci} 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_civoid f2fs_flush_ckpt_thread(struct f2fs_sb_info *sbi) 192662306a36Sopenharmony_ci{ 192762306a36Sopenharmony_ci struct ckpt_req_control *cprc = &sbi->cprc_info; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci flush_remained_ckpt_reqs(sbi, NULL); 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci /* Let's wait for the previous dispatched checkpoint. */ 193262306a36Sopenharmony_ci while (atomic_read(&cprc->queued_ckpt)) 193362306a36Sopenharmony_ci io_schedule_timeout(DEFAULT_IO_TIMEOUT); 193462306a36Sopenharmony_ci} 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_civoid f2fs_init_ckpt_req_control(struct f2fs_sb_info *sbi) 193762306a36Sopenharmony_ci{ 193862306a36Sopenharmony_ci struct ckpt_req_control *cprc = &sbi->cprc_info; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci atomic_set(&cprc->issued_ckpt, 0); 194162306a36Sopenharmony_ci atomic_set(&cprc->total_ckpt, 0); 194262306a36Sopenharmony_ci atomic_set(&cprc->queued_ckpt, 0); 194362306a36Sopenharmony_ci cprc->ckpt_thread_ioprio = DEFAULT_CHECKPOINT_IOPRIO; 194462306a36Sopenharmony_ci init_waitqueue_head(&cprc->ckpt_wait_queue); 194562306a36Sopenharmony_ci init_llist_head(&cprc->issue_list); 194662306a36Sopenharmony_ci spin_lock_init(&cprc->stat_lock); 194762306a36Sopenharmony_ci} 1948