我的博客 整理了JOS的部分实现原理,以及它与xv6和linux的某些对比
- 梳理了我在实验过程中的心得
- 比较了xv6和JOS两个操作系统, 尤其是文件系统那一块,由于JOS不是宏内核,所以具体实现与xv6、linux的实现有很大差别。我自行阅读xv6源码将其整理出来,其中日志层的实现是JOS没有的。
- 其中也补充了linux相关的内容,尤其是进程调度那一方面。
cd mit6.828
make clean
make qemu
按ctrl + a 再按x
JOS使用缺页中断的方式将磁盘缓冲块读如内存,然而JOS缺少一种剔除策略,这些缓冲块将永远存放与物理内存中。
我对其进行了一些优化:限制物理内存对磁盘块的缓冲(我是限定了30),当缓冲块满时,使用LRU剔除策略选择一个牺牲块移出内存。
具体实现方式参考了xv6的实现。
- 定义了一个容量为30的blockcaches数组,其中blockcache结构有两个指针,这是构成双向链表的基础,还有一个vaddr的成员,记录该缓冲块对应的虚拟地址。
- cache_head, 是blockcache结构形成链表的头部
- cache_size, 表示文件服务进程当前缓冲块的数量,初始值为0, 当cache_size == BLOCK_CACHE_CAP时,会使用LRU剔除策略选择要牺牲的块
init_blockcaches函数则把这些缓冲块初始化,并形成双向链表。
#define BLOCK_CACHE_CAP 30
struct blockcache{
struct blockcache* prev;
struct blockcache* next;
void* vaddr;
};
struct blockcache blockcaches[BLOCK_CACHE_CAP];
struct blockcache cache_head;
static int cache_size;
static void init_blockcaches(){
// 初始化 buffercache 链表
cache_head.next = &cache_head;
cache_head.prev = &cache_head;
cache_head.vaddr = 0 ;
cache_size = 0;
struct blockcache* bc;
for (bc = blockcaches; bc < blockcaches + BLOCK_CACHE_CAP; bc++) {
bc->next = cache_head.next;
bc->prev = &cache_head;
bc->vaddr = 0;
cache_head.next->prev = bc;
cache_head.next = bc;
}
}
// 在bc_init()中添加init_blockcaches函数的调用
void
bc_init(void)
{
//...
init_blockcaches();
// ..
}
另一个主要改动在bc_pgfault函数中,从磁盘读如一个block后,对cache_size递增,判断是否需要剔除一个block:
static void
bc_pgfault(struct UTrapframe *utf)
{
// ...
// 从磁盘读如一个block后
/* 以下代码是cache block的LRU剔除策略*/
if (++cache_size == BLOCK_CACHE_CAP + 1) {
// cache容量满,剔除最后一个cache
void* evict_addr = cache_head.prev->vaddr;
if (uvpt[PGNUM(evict_addr)] & PTE_D) { // 如果此块已脏,flush到磁盘
flush_block(evict_addr);
}
if ((sys_page_unmap(thisenv->env_id, evict_addr)) < 0) { // 解除映射
panic("bc.c bc_pgfault, sys_page_unmap failed\n ");
}
cache_size--;
// 记录新的地址
cache_head.prev->vaddr = addr;
struct blockcache* new_cache = cache_head.prev;
// 把这个cacheblock移动到链表头部
remove_cachelist(new_cache);
add_head_cachelist(new_cache);
}else {
// cache容量未满,从头到尾扫描一个可以用的cache
// cprintf("\t debug Log : get a available cache\n");
struct blockcache* bc = cache_head.next;
for (; bc != &cache_head; bc = bc->next) {
if (bc->vaddr == 0) {
bc->vaddr = addr;
break;
}
}
}
}
两个操作链表的辅助函数remove_cachelist、add_head_cachelist见源码,就不单独列出了。
git remote
git branch
git checkout 分支名
git push 自己的仓库