NOVA为了让NVMM空间分配与回收更快,它将NVMM分为持久性内存池(pools),每个CPU一个内存池(pool),并将空闲的NVMM页面lists放置在DRAM中。
如果当前的CPU pool中没有足够的页面可用,那么NOVA就从最大的那个池(pool)中进行分配,同时使用per-pool locks进行保护。
为了减少分配器的大小,NOVA使用一棵红黑树来维护空闲列表按地址排序,从而实现有效的合并并提供O(logn)回收。
为了提高性能,NOVA在运行期间不将分配器状态存储在NVMM中。 正常关闭时,它将在电源中断的情况下将分配器状态记录到recovery inode’s log ,并通过扫描所有索引节点的日志来恢复分配器状态。
NOVA积极分配日志空间,以避免需要频繁调整日志大小。 最初,inode的日志包含一页。 当日志耗尽可用空间时,NOVA分配足够的新页面使日志空间增加一倍,并将其附加到日志中。 如果日志长度超过给定阈值,则NOVA每次都会分配固定数量的页面。
NOVA源码:
https://github.com/NVSL/NOVA (论文中的)
https://github.com/NVSL/linux-nova(后续更新)
使用DRAM模拟持久性内存:
https://blog.csdn.net/SweeNeil/article/details/90265226
NOVA的安装与挂载:
https://blog.csdn.net/qq_34018840/article/details/79739307
在源码中 balloc.c文件中主要是与空间管理相关的代码~
1、free-list初始化
在NOVA中使用 struct free_list结构来描述空闲列表,在这里我把free_list称为空闲列表描述符,每个CPU都有一个free_list,该结构定义在头文件nova.h中:
struct free_list {
spinlock_t s_lock;
//rb_tree的根,前面介绍过红黑树来进行按地址排序的空闲列表维护
struct rb_root block_free_tree;
struct nova_range_node *first_node;
struct nova_range_node *last_node;
int index;
unsigned long csum_start;
unsigned long replica_csum_start;
unsigned long parity_start;
unsigned long block_start;
unsigned long block_end;
unsigned long num_free_blocks;
unsigned long num_blocknode;
unsigned long num_csum_blocks;
unsigned long num_parity_blocks;
u32 csum; /* Protect integrity */
/* Statistics */
unsigned long alloc_log_count;
unsigned long alloc_data_count;
unsigned long free_log_count;
unsigned long free_data_count;
unsigned long alloc_log_pages;
unsigned long alloc_data_pages;
unsigned long freed_log_pages;
unsigned long freed_data_pages;
u64 padding[8]; /* Cache line break */
};
要分析NOVA空间管理,先从NOVA开始的地方出发,在super.c中,有init_nova_fs(),这是NOVA文件系统模块的加载函数,里面对nova_range_node_cachep、nova_inode_cachep、nova_snapshot_info_cachep开辟空间,然后注册文件系统~
在NOVA被mount的时候,整个流程如下:
vfs_kern_mount(vfs代码,super.c)->mount_fs(vfs代码,super.c)-> nova_mount(nova代码,这里传进来了sb,说明sb在这之前就进行了初始化,在mount_fs中)-> nova_fill_super();
static struct dentry *nova_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_bdev(fs_type, flags, dev_name, data, nova_fill_super);
}