1、NOVA inode简介
在NOVA论文中对Inode Table进行了一下描述:
NOVA将每个inode table初始化为2MB的inode块数组。 每个NOVA inode都以128字节边界对齐,因此给定的inode number NOVA可以轻松地定位目标inode。 NOVA按循环顺序将新的inode分配给每个inode table,以便inode在inode table之间均匀分布。 如果inode table已满,则NOVA通过构建2MB sub-tables的链表来扩展它。 为了减小inode table的大小,每个NOVA inode都包含一个有效位,并且NOVA将无效的inode重新用于新文件和目录。 每个CPU一个inode table避免了inode分配争用,并允许在故障恢复中进行并行扫描。
NOVA inode包含指向其log开头和结尾的指针。log是一个4KB页面的链接列表,并且尾部始终指向最新提交的log entry。 当系统首次访问inode时,NOVA从头到尾扫描log以重建DRAM数据结构。
接下来从NOVA源代码中来具体分析inode的初始化与管理~
2、NOVA inode初始化代码
2.1 nova_fill_super()
直接从nova_fill_super()函数入手,在nova_fill_super中也有对inode初始化的相关内容,首先映入眼帘的是inode_map结构体:
struct inode_map *inode_map;
inode_map定义在nova/nova.h文件中:
struct inode_map {
struct mutex inode_table_mutex;
struct rb_root inode_inuse_tree;
unsigned long num_range_node_inode;
struct nova_range_node *first_inode_range;
int allocated;
int freed;
};
通过对其他文件系统的了解,我知道在文件系统(例如ext4)中,有bitmap用来指示一个inode是否已经被分配,其他文件系统似乎就一个bit用来指示分配,0表示该inode没有被分配,1表示该inode已被分配。
看到inode_map第一感觉也与这个相关,里面的结构也有inode_inuse_tree相关的内容,目前还占不清楚它的具体作用,通过继续向下看代码来确定它的作用。
在 nova_fill_super()函数中为inode_maps开辟了空间,同时inode_maps也在nova_sb_info(sbi)中进行了保存:
sbi->inode_maps = kzalloc(sbi->cpus * sizeof(struct inode_map),
GFP_KERNEL);
从上面可以看出,每个CPU都会有一个inode_map结构,因为每个CPU都有自己的inode_table。
继续往下看,将每个inode_map与每个cpu的inode_map对应起来,同时初始化inode_table互斥器(锁)
for (i = 0; i < sbi->cpus; i++) {
inode_map = &sbi->inode_maps[i];
mutex_init(&inode_map->inode_table_mutex);
inode_map->inode_inuse_tree = RB_ROOT;
}
到了这里之后,在nova_fill_super()函数中对于inode的内容就没有了,我们进入到nova_init()函数查看里面是否对inode进行了一些初始化。
2.2 nova_init()
定义在nova/super.c中
在nova_init()函数中,使用了nova_get_inode_by_ino函数来获取inode,看到这里有点奇怪,我们还没看到inode的初始化,为什么这里就开始在获取inode了呢,我们看一看这个函数的执行:
pi = nova_get_inode_by_ino(sb, NOVA_BLOCKNODE_INO);
从上面这行可以看出,获取的inode的inode number是一个宏定义,进入到宏定义中查看具体情况:
/* We have space for 31 reserved inodes */
#define NOVA_ROOT_INO (1)
#define NOVA_IN