【FEMU源码深度解析】黑盒模式下的ftl.c核心代码详解
·
本文为 FEMU开源SSD仿真平台 源码深度解析系列,专注讲解 ftl.c 核心实现。
适合方向:SSD存储仿真、FTL算法、NAND Flash仿真、毕业设计/科研实验。
一、前言:什么是FEMU与FTL
1.1 FEMU简介
FEMU 是一个基于QEMU的开源SSD仿真器,专门用于白盒/黑盒SSD仿真、性能测试、FTL算法研究,广泛用于学术界与工业界存储系统实验。
1.2 FTL是什么
FTL(Flash Translation Layer) 是SSD的核心灵魂,负责:
- 逻辑地址(LBA/LPN) ↔ 物理地址(PPA) 映射
- 垃圾回收(GC)
- 磨损均衡
- 坏块管理
- 写放大控制
本文解析的 ftl.c,就是FEMU中完整实现FTL核心功能的源码文件。
二、ftl.c 整体功能定位
ftl.c = FEMU的FTL层核心实现
它的核心作用:
- 接收上层IO读写请求
- 完成逻辑页号(LPN) → 物理页地址(PPA)转换
- 管理NAND Flash的块、线、通道、Plane
- 执行GC(垃圾回收)
- 支持FDP(NVMe Flexible Data Placement)数据放置扩展
三、源码结构与核心模块划分
ftl.c 代码分为 6大核心模块:
模块1:全局声明与工具函数
static void *ftl_thread(void *arg);
static inline bool should_gc(struct ssd *ssd);
static inline struct ppa get_maptbl_ent(struct ssd *ssd, uint64_t lpn);
static void ssd_init_lines(struct ssd *ssd);
- 定义GC判断、映射表读写、地址转换等基础工具
- 提供LPN ↔ PPA快速转换
模块2:SSD初始化逻辑
void ssd_init(FemuCtrl *n)
{
ssd_init_params(spp, n);
ssd_init_maptbl(ssd);
ssd_init_rmap(ssd);
ssd_init_lines(ssd);
...
}
功能:
- 初始化SSD硬件参数
- 初始化映射表(maptbl)与反向映射表(rmap)
- 初始化Line(超级块)管理
- 区分FDP模式/普通模式
模块3:地址映射(核心)
static inline struct ppa get_maptbl_ent(...)
static inline void set_maptbl_ent(...)
static inline void set_rmap_ent(...)
- maptbl:LPN → PPA(正向映射)
- rmap:PPA → LPN(反向映射,GC必须用到)
模块4:写指针与空间分配
static struct ppa get_new_page(struct ssd *ssd)
static void ssd_advance_write_pointer(struct ssd *ssd)
- 模拟SSD实际写入顺序
- 按Channel/Lun/Block/Page依次分配新物理页
模块5:垃圾回收GC(最核心)
static int do_gc(struct ssd *ssd, bool force)
static struct line *select_victim_line(...)
static void clean_one_block(...)
GC流程:
- 选择无效页最多的Line作为受害者
- 迁移有效页到新位置
- 擦除整块
- 重新加入空闲队列
模块6:IO读写入口
static uint64_t ssd_read(struct ssd *ssd, NvmeRequest *req)
static uint64_t ssd_write(struct ssd *ssd, NvmeRequest *req)
static uint64_t ssd_trim(struct ssd *ssd, NvmeRequest *req)
- 处理上层NVMe读写指令
- 写操作会自动触发GC
- Trim指令用于标记无效页
模块7:FDP扩展支持
uint64_t nvme_do_write_fdp(...)
static int do_gc_fdp_style(...)
FDP = NVMe灵活数据放置,支持流隔离、按RU回收、降低写放大。
四、核心函数逐行解析
4.1 ssd_init():SSD全局初始化
void ssd_init(FemuCtrl *n)
{
ssd_init_params(spp, n); // 配置SSD参数
ssd_init_maptbl(ssd); // 初始化映射表
ssd_init_rmap(ssd); // 反向映射
ssd_init_lines(ssd); // 初始化超级块
qemu_thread_create(&ssd->ftl_thread, ...); // 启动FTL线程
}
作用: 启动时一次性构建好整个SSD的存储结构与映射表。
4.2 ssd_write():写流程
static uint64_t ssd_write(struct ssd *ssd, NvmeRequest *req)
{
// 1. 检查是否需要GC
while (should_gc_high(ssd)) {
do_gc(ssd, true);
}
// 2. 旧地址失效
mark_page_invalid(ssd, &ppa);
// 3. 分配新物理页
ppa = get_new_page(ssd);
// 4. 更新映射表
set_maptbl_ent(ssd, lpn, &ppa);
set_rmap_ent(ssd, lpn, &ppa);
// 5. 推进写指针
ssd_advance_write_pointer(ssd);
}
写流程总结:
GC检查 → 旧页失效 → 分配新页 → 更新映射 → 推进指针
4.3 do_gc():垃圾回收
static int do_gc(struct ssd *ssd, bool force)
{
victim_line = select_victim_line(ssd, force);
// 迁移有效数据
for (ch, lun) {
clean_one_block(ssd, &ppa);
mark_block_free(ssd, &ppa);
}
// 标记Line为空闲
mark_line_free(ssd, &ppa);
}
GC本质: 腾挪有效数据 → 擦除块 → 回收空间
4.4 ftl_thread():FTL后台线程
static void *ftl_thread(void *arg)
{
while (1) {
// 处理读写IO
process_io();
// 后台GC
if (should_gc(ssd)) {
do_gc(ssd, false);
}
}
}
- 独立线程异步处理IO与GC
- 不阻塞上层系统
五、重要的数据结构
5.1 PPA:物理页地址
struct ppa {
uint32_t ch; // 通道
uint32_t lun; // 逻辑单元
uint32_t pl; // plane
uint32_t blk; // 块
uint32_t pg; // 页
};
代表NAND Flash中唯一物理位置。
5.2 Line:超级块(FEMU特色)
- Line = 跨所有Channel/Lun的一组Block
- 目的:提升并行读写性能
5.3 maptbl & rmap
maptbl[LPN] = PPArmap[PPA] = LPN
GC必须依靠反向映射才能找到有效数据归属。
六、FDP特性:高级FTL模式
你提供的代码中包含大量 FDP相关函数:
nvme_do_write_fdpdo_gc_fdp_stylefdp_get_new_pagemark_page_invalid_fdp
FDP作用:
- 数据按流隔离(冷热数据分离)
- RU(回收单元)独立管理
- 降低写放大WAF
- 提升GC效率
适合用于企业级SSD、QoS保障、数据库SSD优化。
七、总结:ftl.c 到底在做什么?
- 执行
./run-blackbox.sh - QEMU启动
- FEMU加载
ftl.c - 模拟出一块完整行为的NVMe SSD
建议学习路径:
ssd_init → ssd_write → do_gc → FDP扩展
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)