您是第 位访客

disksim-3.0 with flashsim 源码分析(四):初始化

在 disksim_main.c 中会先调用 disksim_initialize_disksim_structure()disksim_setup_disksim() 来初始化 disksim。然后调用 initFlash() 来初始化闪存。

下面主要介绍闪存的初始化过程。

ninitFlash() 函数主要分为两个步骤,首先是调用 nand_init() 初始化闪存基本信息,然后调用 FTL 的 init() 函数,初始化FTL。

nand_init() 函数

初始化闪存信息。

首先开辟一个名为 nand_blk[] 的数组空间,保存的是 SSD 的所有块。数组中每个成员为如下的结构体:

1
2
3
4
5
6
7
8
struct nand_blk_info {
struct blk_state state; // 该块的状态,包含三个属性:free,ec(erase counter), update_ec
struct sect_state sect[SECT_NUM_PER_BLK]; // 该块下所有 sector 状态的集合。包含三个属性:free, valid, lsn
_s16 fpc; // free sector counter
_s16 ipc; // invalid sector counter
_s16 lwn; // last written sector number
int page_status[PAGE_NUM_PER_BLK]; //该块下所有page状态的集合,值为0和1
};

然后,初始化全局变量 nand_blk_nummin_fb_numfree_blk_num

1
2
3
nand_blk_num = blk_num; // SSD总的block的数量
free_blk_num = nand_blk_num; // free block number,初始化的时候所有的block都是空闲
min_fb_num = min_free_blk_num; // min free block number

接下来就是初始化 nand_blk[] 了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for (blk_no = 0; blk_no < blk_num; blk_no++) { // 初始化每个block
nand_blk[blk_no].state.free = 1;
nand_blk[blk_no].state.ec = 0;
nand_blk[blk_no].fpc = SECT_NUM_PER_BLK;
nand_blk[blk_no].ipc = 0;
nand_blk[blk_no].lwn = -1;
for(i = 0; i<SECT_NUM_PER_BLK; i++){
nand_blk[blk_no].sect[i].free = 1;
nand_blk[blk_no].sect[i].valid = 0;
nand_blk[blk_no].sect[i].lsn = -1; //初始化为-1
}
for(i = 0; i < PAGE_NUM_PER_BLK; i++){
nand_blk[blk_no].page_status[i] = -1; // 0: data, 1: map table
}
}

init() 函数

初始化FTL,以 DFTL 为例:

首先初始化全局变量 opagemap_num, mapdir_numextra_blk_num

1
2
3
4
5
6
7
opagemap_num = blk_num * PAGE_NUM_PER_BLK; // 表示一共有多少个映射记录
mapdir_num = (opagemap_num / MAP_ENTRIES_PER_PAGE); // 映射表需要存在多少个闪存页上,即GTD的大小
if((opagemap_num % MAP_ENTRIES_PER_PAGE) != 0){
printf("opagemap_num % MAP_ENTRIES_PER_PAGE is not zero\n");
mapdir_num++;
}
extra_blk_num = extra_num;

然后初始化数组 opagemap[]mapdir[]

opagemap[]存储的是闪存的映射表,存储所有闪存的映射信息。数组的大小为 opagemap_num,数组的每个元素是如下的结构体:

1
2
3
4
5
6
7
8
9
struct opm_entry { //单个的映射记录
_u32 free : 1;
_u32 ppn : 31;
int cache_status;
int cache_age;
int map_status;
int map_age;
int update;
};

1
2
3
4
5
6
7
for(i = 0; i<TOTAL_MAP_ENTRIES; i++){
opagemap[i].cache_status = 0;
opagemap[i].cache_age = 0;
opagemap[i].map_status = 0;
opagemap[i].map_age = 0;
opagemap[i].update = 0;
}

mapdir[] 保存的是GTD,也就是映射页(translation page)的映射。数组的大小为 mapdir_num,数组的每个元素是如下的结构:

1
2
3
struct omap_dir{
unsigned int ppn;
};

然后初始化其他变量:

1
2
3
4
5
6
free_blk_no[0] = nand_get_free_blk(0);
free_page_no[0] = 0;
free_blk_no[1] = nand_get_free_blk(0);
free_page_no[1] = 0;
//略

最后,由于SSD的映射表是持久化到闪存上的,所以初始化的时候需要模拟写入映射表:

1
2
3
for(i = 0; i<mapdir_num; i++){
opm_write(i*SECT_NUM_PER_PAGE, SECT_NUM_PER_PAGE, 2); //在闪存上写入映射表
}