cregit-Linux how code gets into the kernel

Release 4.10 fs/f2fs/checkpoint.c

Directory: fs/f2fs
/*
 * fs/f2fs/checkpoint.c
 *
 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
 *             http://www.samsung.com/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/fs.h>
#include <linux/bio.h>
#include <linux/mpage.h>
#include <linux/writeback.h>
#include <linux/blkdev.h>
#include <linux/f2fs_fs.h>
#include <linux/pagevec.h>
#include <linux/swap.h>

#include "f2fs.h"
#include "node.h"
#include "segment.h"
#include "trace.h"
#include <trace/events/f2fs.h>


static struct kmem_cache *ino_entry_slab;

struct kmem_cache *inode_entry_slab;


void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io) { set_ckpt_flags(sbi, CP_ERROR_FLAG); sbi->sb->s_flags |= MS_RDONLY; if (!end_io) f2fs_flush_merged_bios(sbi); }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim38100.00%1100.00%
Total38100.00%1100.00%

/* * We guarantee no failure on the returned page. */
struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) { struct address_space *mapping = META_MAPPING(sbi); struct page *page = NULL; repeat: page = f2fs_grab_cache_page(mapping, index, false); if (!page) { cond_resched(); goto repeat; } f2fs_wait_on_page_writeback(page, META, true); if (!PageUptodate(page)) SetPageUptodate(page); return page; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim8096.39%583.33%
gu zhenggu zheng33.61%116.67%
Total83100.00%6100.00%

/* * We guarantee no failure on the returned page. */
static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, bool is_meta) { struct address_space *mapping = META_MAPPING(sbi); struct page *page; struct f2fs_io_info fio = { .sbi = sbi, .type = META, .op = REQ_OP_READ, .op_flags = REQ_META | REQ_PRIO, .old_blkaddr = index, .new_blkaddr = index, .encrypted_page = NULL, }; if (unlikely(!is_meta)) fio.op_flags &= ~REQ_META; repeat: page = f2fs_grab_cache_page(mapping, index, false); if (!page) { cond_resched(); goto repeat; } if (PageUptodate(page)) goto out; fio.page = page; if (f2fs_submit_page_bio(&fio)) { f2fs_put_page(page, 1); goto repeat; } lock_page(page); if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); goto repeat; } /* * if there is any IO error when accessing device, make our filesystem * readonly and make sure do not write checkpoint with non-uptodate * meta page. */ if (unlikely(!PageUptodate(page))) f2fs_stop_checkpoint(sbi, false); out: return page; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim15474.76%1168.75%
chao yuchao yu4220.39%318.75%
michael christiemichael christie73.40%16.25%
gu zhenggu zheng31.46%16.25%
Total206100.00%16100.00%


struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index) { return __get_meta_page(sbi, index, true); }

Contributors

PersonTokensPropCommitsCommitProp
chao yuchao yu25100.00%1100.00%
Total25100.00%1100.00%

/* for POR only */
struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index) { return __get_meta_page(sbi, index, false); }

Contributors

PersonTokensPropCommitsCommitProp
chao yuchao yu25100.00%1100.00%
Total25100.00%1100.00%


bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type) { switch (type) { case META_NAT: break; case META_SIT: if (unlikely(blkaddr >= SIT_BLK_CNT(sbi))) return false; break; case META_SSA: if (unlikely(blkaddr >= MAIN_BLKADDR(sbi) || blkaddr < SM_I(sbi)->ssa_blkaddr)) return false; break; case META_CP: if (unlikely(blkaddr >= SIT_I(sbi)->sit_base_addr || blkaddr < __start_cp_addr(sbi))) return false; break; case META_POR: if (unlikely(blkaddr >= MAX_BLKADDR(sbi) || blkaddr < MAIN_BLKADDR(sbi))) return false; break; default: BUG(); } return true; }

Contributors

PersonTokensPropCommitsCommitProp
chao yuchao yu12694.03%466.67%
jaegeuk kimjaegeuk kim85.97%233.33%
Total134100.00%6100.00%

/* * Readahead CP/NAT/SIT/SSA pages */
int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type, bool sync) { struct page *page; block_t blkno = start; struct f2fs_io_info fio = { .sbi = sbi, .type = META, .op = REQ_OP_READ, .op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD, .encrypted_page = NULL, }; struct blk_plug plug; if (unlikely(type == META_POR)) fio.op_flags &= ~REQ_META; blk_start_plug(&plug); for (; nrpages-- > 0; blkno++) { if (!is_valid_blkaddr(sbi, blkno, type)) goto out; switch (type) { case META_NAT: if (unlikely(blkno >= NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid))) blkno = 0; /* get nat block addr */ fio.new_blkaddr = current_nat_addr(sbi, blkno * NAT_ENTRY_PER_BLOCK); break; case META_SIT: /* get sit block addr */ fio.new_blkaddr = current_sit_addr(sbi, blkno * SIT_ENTRY_PER_BLOCK); break; case META_SSA: case META_CP: case META_POR: fio.new_blkaddr = blkno; break; default: BUG(); } page = f2fs_grab_cache_page(META_MAPPING(sbi), fio.new_blkaddr, false); if (!page) continue; if (PageUptodate(page)) { f2fs_put_page(page, 1); continue; } fio.page = page; fio.old_blkaddr = fio.new_blkaddr; f2fs_submit_page_mbio(&fio); f2fs_put_page(page, 0); } out: f2fs_submit_merged_bio(sbi, META, READ); blk_finish_plug(&plug); return blkno - start; }

Contributors

PersonTokensPropCommitsCommitProp
chao yuchao yu25586.15%750.00%
jaegeuk kimjaegeuk kim3311.15%535.71%
michael christiemichael christie72.36%17.14%
christoph hellwigchristoph hellwig10.34%17.14%
Total296100.00%14100.00%


void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) { struct page *page; bool readahead = false; page = find_get_page(META_MAPPING(sbi), index); if (!page || !PageUptodate(page)) readahead = true; f2fs_put_page(page, 0); if (readahead) ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true); }

Contributors

PersonTokensPropCommitsCommitProp
chao yuchao yu7398.65%266.67%
jaegeuk kimjaegeuk kim11.35%133.33%
Total74100.00%3100.00%


static int f2fs_write_meta_page(struct page *page, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_P_SB(page); trace_f2fs_writepage(page, META); if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) goto redirty_out; if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0)) goto redirty_out; if (unlikely(f2fs_cp_error(sbi))) goto redirty_out; write_meta_page(sbi, page); dec_page_count(sbi, F2FS_DIRTY_META); if (wbc->for_reclaim) f2fs_submit_merged_bio_cond(sbi, NULL, page, 0, META, WRITE); unlock_page(page); if (unlikely(f2fs_cp_error(sbi))) f2fs_submit_merged_bio(sbi, META, WRITE); return 0; redirty_out: redirty_page_for_writepage(wbc, page); return AOP_WRITEPAGE_ACTIVATE; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim9963.87%1071.43%
chao yuchao yu5636.13%428.57%
Total155100.00%14100.00%


static int f2fs_write_meta_pages(struct address_space *mapping, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); long diff, written; /* collect a number of dirty meta pages and write together */ if (wbc->for_kupdate || get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META)) goto skip_write; trace_f2fs_writepages(mapping->host, wbc, META); /* if mounting is failed, skip writing node pages */ mutex_lock(&sbi->cp_mutex); diff = nr_pages_to_write(sbi, META, wbc); written = sync_meta_pages(sbi, META, wbc->nr_to_write); mutex_unlock(&sbi->cp_mutex); wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff); return 0; skip_write: wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_META); trace_f2fs_writepages(mapping->host, wbc, META); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim13585.99%583.33%
yunlei heyunlei he2214.01%116.67%
Total157100.00%6100.00%


long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long nr_to_write) { struct address_space *mapping = META_MAPPING(sbi); pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX; struct pagevec pvec; long nwritten = 0; struct writeback_control wbc = { .for_reclaim = 0, }; struct blk_plug plug; pagevec_init(&pvec, 0); blk_start_plug(&plug); while (index <= end) { int i, nr_pages; nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY, min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); if (unlikely(nr_pages == 0)) break; for (i = 0; i < nr_pages; i++) { struct page *page = pvec.pages[i]; if (prev == ULONG_MAX) prev = page->index - 1; if (nr_to_write != LONG_MAX && page->index != prev + 1) { pagevec_release(&pvec); goto stop; } lock_page(page); if (unlikely(page->mapping != mapping)) { continue_unlock: unlock_page(page); continue; } if (!PageDirty(page)) { /* someone wrote it for us */ goto continue_unlock; } f2fs_wait_on_page_writeback(page, META, true); BUG_ON(PageWriteback(page)); if (!clear_page_dirty_for_io(page)) goto continue_unlock; if (mapping->a_ops->writepage(page, &wbc)) { unlock_page(page); break; } nwritten++; prev = page->index; if (unlikely(nwritten >= nr_to_write)) break; } pagevec_release(&pvec); cond_resched(); } stop: if (nwritten) f2fs_submit_merged_bio(sbi, type, WRITE); blk_finish_plug(&plug); return nwritten; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim30489.41%654.55%
chao yuchao yu339.71%436.36%
gu zhenggu zheng30.88%19.09%
Total340100.00%11100.00%


static int f2fs_set_meta_page_dirty(struct page *page) { trace_f2fs_set_page_dirty(page, META); if (!PageUptodate(page)) SetPageUptodate(page); if (!PageDirty(page)) { f2fs_set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META); SetPagePrivate(page); f2fs_trace_pid(page); return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim6793.06%685.71%
chao yuchao yu56.94%114.29%
Total72100.00%7100.00%

const struct address_space_operations f2fs_meta_aops = { .writepage = f2fs_write_meta_page, .writepages = f2fs_write_meta_pages, .set_page_dirty = f2fs_set_meta_page_dirty, .invalidatepage = f2fs_invalidate_page, .releasepage = f2fs_release_page, #ifdef CONFIG_MIGRATION .migratepage = f2fs_migrate_page, #endif };
static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { struct inode_management *im = &sbi->im[type]; struct ino_entry *e, *tmp; tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS); retry: radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); spin_lock(&im->ino_lock); e = radix_tree_lookup(&im->ino_root, ino); if (!e) { e = tmp; if (radix_tree_insert(&im->ino_root, ino, e)) { spin_unlock(&im->ino_lock); radix_tree_preload_end(); goto retry; } memset(e, 0, sizeof(struct ino_entry)); e->ino = ino; list_add_tail(&e->list, &im->ino_list); if (type != ORPHAN_INO) im->ino_num++; } spin_unlock(&im->ino_lock); radix_tree_preload_end(); if (e != tmp) kmem_cache_free(ino_entry_slab, tmp); }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim15081.52%763.64%
chao yuchao yu2111.41%218.18%
gu zhenggu zheng137.07%218.18%
Total184100.00%11100.00%


static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { struct inode_management *im = &sbi->im[type]; struct ino_entry *e; spin_lock(&im->ino_lock); e = radix_tree_lookup(&im->ino_root, ino); if (e) { list_del(&e->list); radix_tree_delete(&im->ino_root, ino); im->ino_num--; spin_unlock(&im->ino_lock); kmem_cache_free(ino_entry_slab, e); return; } spin_unlock(&im->ino_lock); }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim8881.48%571.43%
chao yuchao yu1917.59%114.29%
gu zhenggu zheng10.93%114.29%
Total108100.00%7100.00%


void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { /* add new dirty ino entry into list */ __add_ino_entry(sbi, ino, type); }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim2596.15%150.00%
chao yuchao yu13.85%150.00%
Total26100.00%2100.00%


void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { /* remove dirty ino entry from list */ __remove_ino_entry(sbi, ino, type); }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim2596.15%150.00%
chao yuchao yu13.85%150.00%
Total26100.00%2100.00%

/* mode should be APPEND_INO or UPDATE_INO */
bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode) { struct inode_management *im = &sbi->im[mode]; struct ino_entry *e; spin_lock(&im->ino_lock); e = radix_tree_lookup(&im->ino_root, ino); spin_unlock(&im->ino_lock); return e ? true : false; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim5376.81%150.00%
chao yuchao yu1623.19%150.00%
Total69100.00%2100.00%


void release_ino_entry(struct f2fs_sb_info *sbi, bool all) { struct ino_entry *e, *tmp; int i; for (i = all ? ORPHAN_INO: APPEND_INO; i <= UPDATE_INO; i++) { struct inode_management *im = &sbi->im[i]; spin_lock(&im->ino_lock); list_for_each_entry_safe(e, tmp, &im->ino_list, list) { list_del(&e->list); radix_tree_delete(&im->ino_root, e->ino); kmem_cache_free(ino_entry_slab, e); im->ino_num--; } spin_unlock(&im->ino_lock); } }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim9884.48%360.00%
chao yuchao yu1815.52%240.00%
Total116100.00%5100.00%


int acquire_orphan_inode(struct f2fs_sb_info *sbi) { struct inode_management *im = &sbi->im[ORPHAN_INO]; int err = 0; spin_lock(&im->ino_lock); #ifdef CONFIG_F2FS_FAULT_INJECTION if (time_to_inject(sbi, FAULT_ORPHAN)) { spin_unlock(&im->ino_lock); return -ENOSPC; } #endif if (unlikely(im->ino_num >= sbi->max_orphans)) err = -ENOSPC; else im->ino_num++; spin_unlock(&im->ino_lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim8080.81%466.67%
chao yuchao yu1919.19%233.33%
Total99100.00%6100.00%


void release_orphan_inode(struct f2fs_sb_info *sbi) { struct inode_management *im = &sbi->im[ORPHAN_INO]; spin_lock(&im->ino_lock); f2fs_bug_on(sbi, im->ino_num == 0); im->ino_num--; spin_unlock(&im->ino_lock); }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim2647.27%666.67%
chao yuchao yu2240.00%222.22%
russ w. knizeruss w. knize712.73%111.11%
Total55100.00%9100.00%


void add_orphan_inode(struct inode *inode) { /* add new orphan ino entry into list */ __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO); update_inode_page(inode); }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim2686.67%583.33%
chao yuchao yu413.33%116.67%
Total30100.00%6100.00%


void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) { /* remove orphan entry from orphan list */ __remove_ino_entry(sbi, ino, ORPHAN_INO); }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim23100.00%3100.00%
Total23100.00%3100.00%


static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) { struct inode *inode; struct node_info ni; int err = acquire_orphan_inode(sbi); if (err) { set_sbi_flag(sbi, SBI_NEED_FSCK); f2fs_msg(sbi->sb, KERN_WARNING, "%s: orphan failed (ino=%x), run fsck to fix.", __func__, ino); return err; } __add_ino_entry(sbi, ino, ORPHAN_INO); inode = f2fs_iget_retry(sbi->sb, ino); if (IS_ERR(inode)) { /* * there should be a bug that we can't find the entry * to orphan inode. */ f2fs_bug_on(sbi, PTR_ERR(inode) == -ENOENT); return PTR_ERR(inode); } clear_nlink(inode); /* truncate all the data during iput */ iput(inode); get_node_info(sbi, ino, &ni); /* ENOMEM was fully retried in f2fs_evict_inode. */ if (ni.blk_addr != NULL_ADDR) { set_sbi_flag(sbi, SBI_NEED_FSCK); f2fs_msg(sbi->sb, KERN_WARNING, "%s: orphan failed (ino=%x), run fsck to fix.", __func__, ino); return -EIO; } __remove_ino_entry(sbi, ino, ORPHAN_INO); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim15384.53%583.33%
chao yuchao yu2815.47%116.67%
Total181100.00%6100.00%


int recover_orphan_inodes(struct f2fs_sb_info *sbi) { block_t start_blk, orphan_blocks, i, j; int err; if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) return 0; start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi); orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi); ra_meta_pages(sbi, start_blk, orphan_blocks, META_CP, true); for (i = 0; i < orphan_blocks; i++) { struct page *page = get_meta_page(sbi, start_blk + i); struct f2fs_orphan_block *orphan_blk; orphan_blk = (struct f2fs_orphan_block *)page_address(page); for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) { nid_t ino = le32_to_cpu(orphan_blk->ino[j]); err = recover_orphan_inode(sbi, ino); if (err) { f2fs_put_page(page, 1); return err; } } f2fs_put_page(page, 1); } /* clear Orphan Flag */ clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jaegeuk kimjaegeuk kim14472.73%225.00%
chao yuchao yu4020.20%337.50%
wanpeng liwanpeng li105.05%225.00%
changman leechangman lee42.02%112.50%
Total198100.00%8100.00%


static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) { struct list_head *head; struct f2fs_orphan_block *orphan_blk = NULL; unsigned int nentries = 0; unsigned short index = 1; unsigned short orphan_blocks; struct page *page = NULL; struct ino_entry *orphan = NULL; struct inode_management *im = &sbi->im[ORPHAN_INO]; orphan_blocks = GET_ORPHAN_BLOCKS(im->ino_num); /* * we don't need to do spin_lock(&im->ino_lock) here, since all the * orphan inode operations are covered under f2fs_lock_op(). * And, spin_lock should be avoided due to page operations below. */ head = &im->ino_list; /* loop for each orphan inode entry and write them in Jornal block */ list_for_each_entry(orphan, head, list) { if (!page) { page = grab_meta_page(sbi, start_blk++); orphan_blk = (struct f2fs_orphan_block *)page_address(page); memset(orphan_blk, 0, sizeof(*orphan_blk)); } orphan_blk->ino[nentries++]