F2FS源码分析-6.2 [其他重要数据结构以及函数] f2fs_journal的作用

2024-06-14 10:08

本文主要是介绍F2FS源码分析-6.2 [其他重要数据结构以及函数] f2fs_journal的作用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

F2FS源码分析系列文章
主目录
一、文件系统布局以及元数据结构
二、文件数据的存储以及读写
三、文件与目录的创建以及删除(未完成)
四、垃圾回收机制
五、数据恢复机制
六、重要数据结构或者函数的分析
  1. f2fs_summary的作用
  2. f2fs_journal的作用
  3. f2fs_map_block的作用
  4. get_dnode_of_data的作用
  5. get_node_page的作用(未完成)

F2FS Journal机制

Journal机制的介绍

当F2FS进行文件读写的时候,根据 f2fs_node 的设计以及闪存设备异地更新的特性,每修改一个数据块,都需要改动 f2fs_node 的地址映射,以及NAT,SIT等信息。但是如果仅仅因为一个小改动,例如修改一个块,就需要改动这么多数据,然后再写入磁盘,这样既会导致性能下降,也会导致闪存寿命的下降。

因此F2FS设计了journal机制,用于将这些对SIT和NAT区域的数据的修改暂存在Checkpoint区域的 f2fs_journal 中,这种设计可以减少NAT和SIT的更新产生的大量的I/O

产生大量I/O的原因是,sit和nat的值会随机更新,由于flash的机制,即使更新SIT/NAT其中的一个entry,都要将这个entry所在的整个NAT/SIT的block进行重写。如用户更新了多个node(segment),每一个node/segment的更改都要更新了其中一个entry,即f2fs_nat_entry(f2fs_sit_entry)。假设这些需要更新的entry都不在通过一个f2fs_nat_block(f2fs_sit_block),那么系统就要将所有的block更新,从而产生大量的4KB的I/O,即使只改动其中一个entry。

F2FS则是通过journal机制,将这些随机更新的f2fs_nat_entry(f2fs_sit_entry)都会尝试集中写到checkpoint区域的f2fs_journal当中,即把随机更新的NAT/SIT的block需要更新的entry都集中写到同一个block,从而减少I/O的写入。如果f2fs_journal的空间还没用尽,系统就会将更新的NAT/SIT entry写入journal中,如果这些journal用尽了,才回写到NAT/SIT区域当中。

Journal涉及到的数据结构

struct f2fs_journal {union {__le16 n_nats; /* 这个journal里面包含多少个nat_journal对象 */__le16 n_sits; /* 这个journal里面包含多少个sit_journal对象 */};/* spare area is used by NAT or SIT journals or extra info */union {struct nat_journal nat_j;struct sit_journal sit_j;struct f2fs_extra_info info;};
} __packed;

f2fs_journal 可以保存NAT的journal也可以保存SIT的journal,以下分别分析:

NAT Journal
每一个nat_journal都对应了一个node,记录了这个node是属于哪一个inode,以及这个node的在flash设备的物理地址。

struct nat_journal {struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES];__u8 reserved[NAT_JOURNAL_RESERVED];
} __packed;struct nat_journal_entry {__le32 nid; /* 当前node的nid信息 */struct f2fs_nat_entry ne;
} __packed;struct f2fs_nat_entry {__u8 version;		/* latest version of cached nat entry */__le32 ino;		/* 属于哪一个inode */__le32 block_addr;	/* flash设备的物理地址 */
} __packed;

SIT Journal
每一个sit_journal都对应了一个segment,记录了该segment的有效block的数目 vblocks 以及 它的分配状态bitmap valid_map

struct sit_journal {struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES];__u8 reserved[SIT_JOURNAL_RESERVED];
} __packed;struct sit_journal_entry {__le32 segno; /* 当前的segment number */struct f2fs_sit_entry se;
} __packed;struct f2fs_sit_entry {__le16 vblocks;				/* 有效block的数目 */__u8 valid_map[SIT_VBLOCK_MAP_SIZE]; /* SIT_VBLOCK_MAP_SIZE=64,64*8=512可以表示每一个块的valid状态 */__le64 mtime;				/* 用于GC的victim segment selection */
} __packed;

Journal机制的实现

前面提及Journal机制主要用于将频繁的NAT和SIT的更新集中写到checkpoint区域的f2fs_journal中,从而提高性能,延长闪存颗粒的寿命。去分析Journal机制如何实现时,首先我们需要分析,系统什么时候会读写NAT、SIT区域的数据:

NAT: 更新一个node的物理地址,获取一个node的物理地址
SIT: 分配segment中的block,回收segment中的block

对于node的物理地址的更新,以及segment中的block分配状态的更新,可以参考Checkpoint机制这一节的f2fs_flush_nat_entries函数以及f2fs_flush_sit_entries函数。

因此这里关注如何获取一个node的物理地址,以及一个segment的block分配状态。

通过Journal获取一个node的物理地址

F2FS一般是通过f2fs_get_node_info函数,根据传入的nid值,找到对应的物理地址。首先从内存中找一下nid有没有cache,如果没有则使用journal寻址,如果还是没有采取NAT找,最后找到之后将这个entry的信息,加入到cache中。

void f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,struct node_info *ni)
{struct f2fs_nm_info *nm_i = NM_I(sbi);struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);struct f2fs_journal *journal = curseg->journal;nid_t start_nid = START_NID(nid); // 计算这个nid所在的f2fs_nat_block的第一个nidstruct f2fs_nat_block *nat_blk;struct page *page = NULL;struct f2fs_nat_entry ne;struct nat_entry *e;pgoff_t index;int i;ni->nid = nid;/* 根据nid从cache寻找物理地址信息 */down_read(&nm_i->nat_tree_lock);e = __lookup_nat_cache(nm_i, nid);if (e) { // 如果有就返回ni->ino = nat_get_ino(e);ni->blk_addr = nat_get_blkaddr(e);ni->version = nat_get_version(e);up_read(&nm_i->nat_tree_lock);return;}memset(&ne, 0, sizeof(struct f2fs_nat_entry));/* 再去journal找 */down_read(&curseg->journal_rwsem);/* * 根据nid从journal找nat_entry的信息,如果 i>=0 ,* 则表示journal有这个信息,否则表示journal不存在这个nid的信息 * */i = f2fs_lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0);if (i >= 0) {ne = nat_in_journal(journal, i); // 将journal中的nat_entry返回出来node_info_from_raw_nat(ni, &ne); // 读到node_info中}up_read(&curseg->journal_rwsem);if (i >= 0) {up_read(&nm_i->nat_tree_lock);goto cache; // 在journal找到了,直接就返回}/** 如果journal都没有,就要从NAT读取* * 先根据这个nid计算一下所属的f2fs_nat_block的偏移,即物理地址* */index = current_nat_addr(sbi, nid);up_read(&nm_i->nat_tree_lock);/* 根据f2fs_nat_block偏移,将从磁盘读取出来 */page = f2fs_get_meta_page(sbi, index); /* 将数据转换为f2fs_nat_block的形式 */nat_blk = (struct f2fs_nat_block *)page_address(page);/* start_nid是这个nat_block的第一个nid,* 减去它就可以找出当前nid在nat_block内的偏移,然后都取出来 * */ne = nat_blk->entries[nid - start_nid];/* 根据读取出来的entry转为为ne的值,返回给调用函数 */node_info_from_raw_nat(ni, &ne);f2fs_put_page(page, 1);
cache:/* 如果cache不存在自然要缓存一下到内存中 */cache_nat_entry(sbi, nid, &ne); // 缓存这个node_entry
}

通过Journal获取一个segment的block分配状态

F2FS一般是通过get_seg_entry函数根据segment number(segno)获取对应的entry。由于segment的entry的数目比node entry少很多,所以F2FS将所有的segment的entry都读入了内存,参考Segment结构这一节。因此系统中读取segmeng entry的状态是简单的数组访问:

/* seg_entry是f2fs_sit_entry的内存结构,同样记录了vblock valid_bitmap等信息 */
static inline struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi,unsigned int segno)
{struct sit_info *sit_i = SIT_I(sbi); // 获取segment的内存管理结构return &sit_i->sentries[segno]; // 根据segno返回entry
}

这篇关于F2FS源码分析-6.2 [其他重要数据结构以及函数] f2fs_journal的作用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1060104

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、