1. 营销策划师首页

数据存储:clean状态的ne和数据结构关系图大的原则

数据存储:clean状态的ne和数据结构关系图大的原则entry(简称ne)在代码中涉及多个数据结构,先上图。ne涉及的数据结构关系图layout中的(持久化存储);蓝色部分是内存数据结构。比如在文件尾部写新数据;lseek到hole区域,等等。eg1:在文件尾部写新数据,分配了新的block比如更新文件数据,,被更新的数据块已经存在与disk上。除非被路径10或11回收,否则ne一直作为缓存存在系统中。

nat entry(简称ne)在代码中涉及多个数据结构,先上图。

图1 ne涉及的数据结构关系图

大的原则

1)红色部分是disk layout中的(持久化存储);蓝色部分是内存数据结构。

2)系统中所有的ne,缓存在nat cache中(radix tree管理),用于快速检索ne。

3)所有clean状态的ne,通过clean list管理。

4)一个NAT block中的所有ne,归属于同一个set;所有的set通过radix tree管理。引入set的目的是为了在将dirty ne刷入disk时,属于同一个block的呢会被一起写入block,提高性能和存储设备寿命。

5)系统内存压力大时,f2fs_balance_fs会回收clean状态的ne。

6)dirty ne的block add是NEW_ADDR时,说明是刚分配的,checkpoint时不需要写回存储设备,也是出于性能、寿命考虑。

7)journal是能用尽量用的,即使checkpoint后,journal中也会存在一些ne,这些ne还没有写回nat block。这也是出于性能考虑,如果不用journal缓存ne,那么ne就需要写回nat block,这会导致频繁的写disk;而用journal则可以将所有的ne一次性写入checkpoint的cp pack区域。

图1执行路径描述

1)挂载f2fs场景。从disk layout的cp pack区域读入journal,存于struct curseg_info->journal中。

f2fs_fill_super –>f2fs_build_segment_manager –>build_curseg –>restore_curseg_summaries –>read_compacted_summaries 或 read_normal_summaries

cp pack、compatced/normal summaries概念参考待整理文章。

2)第一次访问ne,并且disk NAT区域没有该ne场景。在内存中,这些ne是新创建的,需记录在nat cache和clean list中。

比如在文件尾部写新数据;lseek到hole区域,等等。

eg1:在文件尾部写新数据,分配了新的block

vfs_write –> new_sync_write –> call_write_iter –> f2fs_file_write_iter -> f2fs_buffered_write_iter –> generic_perform_write –> f2fs_write_begin –> prepare_write_begin –> f2fs_get_block –> f2fs_reserve_block –> f2fs_get_dnode_of_data –> f2fs_new_node_page –> set_node_addr–> __init_nat_entry

eg2:seek到文件的空洞区域

vfs_llseek –> f2fs_llseek –> f2fs_seek_block –> f2fs_get_dnode_of_data –> f2fs_new_node_page –> set_node_addr

3)第一次访问ne,这个ne存在于disk NAT区域。在内存中,这些ne是新创建的,需记录在nat cache和clean list中。

比如更新文件数据,,被更新的数据块已经存在与disk上。

vfs_write –> new_sync_write –> call_write_iter –> f2fs_file_write_iter –> f2fs_preallocate_blocks –> f2fs_map_blocks –> f2fs_get_dnode_of_data –> f2fs_new_node_page –> set_node_addr–> __init_nat_entry

4)checkpoint时,journal(内存)中的ne在mount读取后一直没访问过,并且journal(内存)中没有空间容纳脏ne了,journal(内存)中的ne将被nat cache和clean list记录起来

f2fs_write_checkpoint –>f2fs_flush_nat_entries –>

 if (cpc->reason & CP_UMOUNT ||       !__has_cursum_space(journal,     nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL))     remove_nats_in_journal(sbi);

系统中所有的ne都会记录在nat cache中。除非被路径10或11回收,否则ne一直作为缓存存在系统中。

5)修改ne的场景,常见于做了set_node_addr操作数据存储,修改后的ne被移入dirty list

eg1:序号2中写文件场景。f2fs lfs模式更新文件数据,需新分配了一个block,所以会修改ne的block address,执行set_node_addr。

eg2:在目录中创建了一个文件。

f2fs_create –> f2fs_add_link –> f2fs_do_add_link –> f2fs_add_dentry –> f2fs_add_regular_entry –> f2fs_init_inode_metadata –> f2fs_new_inode_page –> f2fs_new_node_page –> set_node_addr –> __set_nat_cache_dirty

6)checkpoint时,journal(内存)中没有空间容纳dirty list中的ne了,不能放入journal中的ne将被写入page中

f2fs_write_checkpoint –>f2fs_flush_nat_entries –>__flush_nat_entry_set –>

  if ((cpc->reason & CP_UMOUNT) ||        !__has_cursum_space(journal, set->entry_cnt, NAT_JOURNAL))        to_journal = false;    if (to_journal) {        down_write(&curseg->journal_rwsem);    } else {        /* 获取ne所在的nat block,读入page */        page = get_next_nat_page(sbi, start_nid);        if (IS_ERR(page))            return PTR_ERR(page);        nat_blk = page_address(page);        f2fs_bug_on(sbi, !nat_blk);    }    ……    /* 更新ne信息到page */    raw_ne = &nat_blk->entries[nid - start_nid];    raw_nat_from_node_info(raw_ne, &ne->ni);    ……

7)checkpoint时,journal(内存)中还有空间容纳dirty list中的ne,dirty list中的ne移至dirty list

f2fs_write_checkpoint –>f2fs_flush_nat_entries –>__flush_nat_entry_set –>

/* flush dirty nats in nat entry set */	list_for_each_entry_safe(ne, cur, &set->entry_list, list) {		struct f2fs_nat_entry *raw_ne;		nid_t nid = nat_get_nid(ne);		int offset;		f2fs_bug_on(sbi, nat_get_blkaddr(ne) == NEW_ADDR);		if (to_journal) {            /*              * 如果journal中有ne,则返回ne所在的位置偏移              * 如果journal中没有ne,则返回journal下一个空闲位置             */			offset = f2fs_lookup_journal_in_cursum(journal,							NAT_JOURNAL, nid, 1);			f2fs_bug_on(sbi, offset entries[nid - start_nid];		}        /* 更新journal中ne信息 */		raw_nat_from_node_info(raw_ne, &ne->ni);		nat_reset_flag(ne);		__clear_nat_cache_dirty(NM_I(sbi), set, ne);

8)checkpoint时,journal中的ne写入cp pack区域(即持久化存储)

f2fs_write_checkpoint –> do_checkpoint –> f2fs_write_data_summaries –> write_compacted_summaries 或write_normal_summaries

mount f2fs时,路径1读取compatcted/normalsummaries到内存中。

9)脏元数据页写入nat block(即持久化存储)

worker_thread –> process_one_work –> wb_workfn –> wb_do_writeback –> wb_check_start_all或wb_check_background_flush –> wb_writeback –> __writeback_inodes_wb –> writeback_sb_inodes –> __writeback_single_inode –> do_writepages –> f2fs_write_meta_pages

kworker线程将脏页数据写入storage device。在大多数情况下,kworker线程周期性回写脏页数据,但也可能因系统脏页过多而主动回写。

10)系统内存压力大时,回收clean状态的ne

f2fs_balance_fs –>f2fs_balance_fs_bg –>f2fs_try_to_free_nats –>__del_from_nat_cache –>__free_nat_entry

只要内存中生成ne数据存储,都会缓存在nat cache中(最大数量10万个,见宏定义DEF_NAT_CACHE_THRESHOLD),系统内存压力大的时候,需要回收clean状态的ne,避免f2fs对系统内存的影响。checkpoint或者f2fs_write_node_pages都会触发f2fs_balance_fs_bg,然后根据系统内存使用情况决定是否回收ne。

void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg){	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))		return;	/* try to shrink extent cache when there is no enough memory */	if (!f2fs_available_free_memory(sbi, EXTENT_CACHE))		f2fs_shrink_extent_tree(sbi, EXTENT_CACHE_SHRINK_NUMBER);	/* check the # of cached NAT entries */	if (!f2fs_available_free_memory(sbi, NAT_ENTRIES))		f2fs_try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK);

11)umount时回收ne

f2fs_put_super –>f2fs_destroy_node_manager –>__del_from_nat_cache –>__free_nat_entry

发表评论

邮箱地址不会被公开。 必填项已用*标注

联系我们

400-800-8888

在线咨询:点击这里给我发消息

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息