操作系统:ucore的部分Bug&挑战练习
ucore是清华大学提供的一个学习操作系统的平台。ucore有完整的mooc视频与说明文档。
本文将主要记录在完成ucore平台的实验时,个人认为ucore内核及Result中的存在的问题,以及部分挑战练习内容。由于个人水平有限,可能理解有误,欢迎前来讨论。
本文主要内容:
- Lab2 物理内存管理 练习一 Result代码错误
- Lab3 虚拟内存管理 挑战练习 Clock算法实现
- Lab8 文件系统 内核错误 用户程序
ls
错误
Lab2 练习一 Result代码错误
在实现first fit 内存分配算法的回收函数时,要考虑地址连续的空闲块之间的合并操作。提示:在建立空闲页块链表时,需要按照空闲页块起始地址来排序,形成一个有序的链表。
ans中思路是把所有的空闲页都加入空闲列表,这样效率非常低,且其中有很多标志位置位错误。我选择使用类似于实验指导书上的思路,将一个空闲块中的一个空闲页加入到空闲列表中。所有的操作只是对空闲段里面的第一个空闲页的操作。
代码中详细的注释,这里不做过多的说明。
/*
* Details of FFMA
* Prepare: In order to implement the First-Fit Mem Alloc (FFMA), we should manage the free mem block use some list.
* 为了能够接入FFMA我们要先建立空闲列表
* The struct free_area_t is used for the management of free mem blocks.
* free_area_t是空闲列表的中的结构体
* At first you should be familiar to the struct list in list.h.
* struct list is a simple doubly linked list implementation.
* 首先要在list.h找到list结构体
* list是一个双向链表
* You should know howto USE: list_init, list_add(list_add_after), list_add_before, list_del, list_next, list_prev
* 嗨呀就是简单的链表操作
* Another tricky method is to transform a general list struct to a special struct (such as struct page):
* you can find some MACRO: le2page (in memlayout.h), (in future labs: le2vma (in vmm.h), le2proc (in proc.h),etc.)
* 可以吧list的结构体转为page|proc的结构体
**/
free_area_t free_area;
#define free_list (free_area.free_list)
#define nr_free (free_area.nr_free)
/**
* default_init:
* you can reuse the demo default_init fun to
* init the free_list and set nr_free to 0.
* 代码已经实现了 init freelist 然后设置nr_free 为0
* free_list : is used to record the free mem blocks.
* nr_free : is the total number for free mem blocks.
*/
static void default_init(void) {
list_init(&free_list);
nr_free = 0;
}
/**
* default_init_memmap:
* 调用顺序: kern_init --> pmm_init-->page_init-->init_memmap--> pmm_manager->init_memmap
* This fun is used to init a free block (with parameter: addr_base, page_number).
* 这个函数是用来初始化一个free block 参数有base和page_number
* 若本页是空的 且不是第一页,flag中的property位设置为0
* 若本页是空的 且是第一页,flag中的property位设置为1 说明其有效
* 若本页空 且是第一页 property就是总共的空block数
* reference 引用的count清0 也就是有没有对应咯
**/
static void default_init_memmap(struct Page *base, size_t n) {
//assert用来检查一个判断是否为真
assert(n > 0);
struct Page *p = base;
for (; p != base + n; p++) {
p->flags = 0;
//若本页空&&不是第一页,property就是总共的空block数
p->property = 0;
//reference引用的count清0
p->ref = 0;
ClearPageReserved(p);
// from memlayout
// if this bit=1:
// the Page is reserved for kernel,
// cannot be used in alloc/free_pages;
// otherwise, this bit=0
}
//跟新一共有多少个free page
nr_free += n;
//first block
SetPageProperty(base);
//若本页空&&第一页,property就是总共的空block数
base->property = n;
list_add(&free_list, &(base->page_link));
}
/**
* default_alloc_pages:
* search find a first free block (block size >=n)
* in free list and reszie the free block,
* return the addr of malloced block.
**/
static struct Page *
default_alloc_pages(size_t n) {
list_entry_t *list_iterator, *nxtptr;
struct Page *first_fit_page;
assert(n > 0);
//要分配的页数大于剩余的free数
if (n > nr_free) {
return NULL;
}
list_iterator = &free_list;
//循环访问一次free list
while ((list_iterator = list_next(list_iterator)) != &free_list) {
//从link回去找到page的base addr
first_fit_page = le2page(list_iterator, page_link);
//若当前的page可用大于需要的size
//注意这个地方,只有一个空闲区域里面的first page才会有property的data
if (first_fit_page->property >= n) {
//将这片空闲区域中的n个block分配出去
//检查这n个block能否分配
struct Page *alloc = first_fit_page;
for (; alloc != first_fit_page + n; alloc++) {
//若Reserved位为1 不能alloc和free
assert(!PageReserved(alloc));
}
//若这个空闲区域里面空闲的数量比我需要的数量还要多
if (first_fit_page->property > n) {
//原来空闲的空间这样子 H是空闲区域里面first page
//||H1....................x..................||
//现在这个空闲的区域变成了这样子
//.......n.......||H2........x-n.............||
//设置其property为剩下的x-n个block
//向后找n个page后的page
struct Page *new_head = first_fit_page + n;
new_head->property = first_fit_page->property - n;
SetPageProperty(new_head);
//因为按照addr的order 则直接添加到first fit page的后面就好了
list_add(&(first_fit_page->page_link), &(new_head->page_link));
}
//从free list 中删除分配走的page的link
list_del(&(first_fit_page->page_link));
ClearPageProperty(first_fit_page);
nr_free -= n;
return first_fit_page;
}
}
return NULL;
}
/**
* default_free_pages
* free掉分配了的页
* base:为free的页的first page的基地址
* n :为free掉多少页
*/
static void default_free_pages(struct Page *base, size_t n) {
assert(n > 0);
struct Page *p = base;
//将n这么多空间释放
for (; p != base + n; p++) {
//检查要free的n个size时候合法
//不能被标记Reserved和Property
assert(!PageReserved(p) && !PageProperty(p));
//初始化flags位
p->flags = 0;
//清空页面访问counter
set_page_ref(p, 0);
}
//更新新的base
base->property = n;
SetPageProperty(base);
//下面开始找能否合并到其他的已有的区域
list_entry_t *le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
le = list_next(le);
//若base后面接着了p
if (base + base->property == p) {
base->property += p->property;
p->property = 0;
ClearPageProperty(p);
list_del(&(p->page_link));
}
//若p后面接着了base
else if (p + p->property == base) {
p->property += base->property;
ClearPageProperty(base);
base->property = 0;
base = p;
list_del(&(p->page_link));
}
}
// 按照地址顺序插入这个新的base节点
nr_free += n;
le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
if (p > base)
break;
le = list_next(le);
}
//插入到list中去
list_add_before(le, &(base->page_link));
}
static size_t default_nr_free_pages(void) {
return nr_free;
}
Lab3 挑战练习 Clock算法实现
设定swap策略为Clock算法
/*
* 设定swap策略
*/
struct swap_manager swap_manager_clock = {
.name = "clock clock manager",
.init = &_clock_init,
.init_mm = &_clock_init_mm,
.tick_event = &_clock_tick_event,
.map_swappable = &_clock_map_swappable,
.set_unswappable = &_clock_set_unswappable,
.swap_out_victim = &_clock_swap_out_victim,
.check_clock_swap = &_clock_check_swap,
};
选择调用clock算法
#ifdef CLOCK
sm = &swap_manager_clock;
#else
sm = &swap_manager_fifo;
#endif
由于每次我们访问一个地址时,要对物理页做标记,所以要用到mm中的pd的基地址,从而获取pte,获取page对象,再对dirty位做标记,这里在抽象类中添加一个方法(mm是拥有相同PDT)
int (*check_clock_swap)(struct mm_struct *mm);
在接入该接口时添加调用的mm参数
static inline int check_content_access(struct mm_struct *mm){
#ifdef CLOCK
int ret = sm->check_clock_swap(mm);
return ret;
#else
int ret = sm->check_swap();
return ret;
#endif
}
在page的结构体中flag标志位加入dirtybit
#define PG_dirtybit 2 // Used for clock pra
#define SetDirtyBit(page) set_bit(PG_dirtybit, &((page)->flags))
#define ClearDirtyBit(page) clear_bit(PG_dirtybit, &((page)->flags))
#define PageDirty(page) test_bit(PG_dirtybit,&((page)->flags))
CLOCK实现
#include <defs.h>
#include <x86.h>
#include <stdio.h>
#include <string.h>
#include <swap.h>
#include <swap_clock.h>
#include <list.h>
list_entry_t pra_list_head;
static int _clock_init_mm(struct mm_struct *mm) {
list_init(&pra_list_head);
mm->sm_priv = &pra_list_head;
return 0;
}
static int _clock_map_swappable(struct mm_struct *mm, uintptr_t addr,
struct Page *page, int swap_in) {
list_entry_t *head = (list_entry_t*) mm->sm_priv;
list_entry_t *entry = &(page->pra_page_link);
assert(entry != NULL && head != NULL);
//将entry加入到list的头
list_add(head->prev, entry);
//page->has_used = 1;
SetDirtyBit(page);
//init present_ptr
if(mm->present_ptr == NULL){
//cprintf("INIT\n\n\n\n");
mm->present_ptr = entry;
}
return 0;
}
static int _clock_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page,
int in_tick) {
list_entry_t *head = (list_entry_t*) mm->sm_priv;
list_entry_t *tmp;
struct Page *iter;
assert(head != NULL);
assert(in_tick == 0);
//cprintf("Present PTR %x\n", mm->present_ptr);
cprintf("\nLet's find victim!!!\n");
//list empty
assert(head -> next != head);
while(1){
//若转了一圈回到了head 跳过head
if(mm->present_ptr == head) {
cprintf("Hit head!\n");
mm->present_ptr = mm->present_ptr->next;
}
iter = le2page(mm->present_ptr,pra_page_link);
//若标记dirtybit为0就替换走
if(!PageDirty(iter)) {
cprintf("Find it!!!\n\n");
tmp = mm->present_ptr;
mm->present_ptr = mm->present_ptr->next;
*ptr_page = iter;
list_del(tmp);
return 0;
}
cprintf("Not good\n");
ClearDirtyBit(iter);
mm->present_ptr = mm->present_ptr->next;
}
return 1;
}
static void visit(struct mm_struct *mm,uintptr_t addr,int value){
*(unsigned char*) addr = value;
//从虚拟地址获取pte
uintptr_t *tmp = get_pte(mm->pgdir,addr,0);
//从pte获取page
struct Page *page = pte2page(*tmp);
//设置dirty_bit
SetDirtyBit(page);
}
/*
* _clock_init
*/
static int _clock_init(void) {
return 0;
}
/*
* _clock_set_unswappable
* 设置addr为不可被换出的
*/
static int _clock_set_unswappable(struct mm_struct *mm, uintptr_t addr) {
list_entry_t *head = (list_entry_t*) mm->sm_priv;
list_entry_t *iter = head->next;
//从虚拟地址获取pte
uintptr_t *tmp = get_pte(mm->pgdir,addr,0);
//从pte获取page
struct Page *page = pte2page(*tmp);
while(iter != head){
if(iter == &(page->pra_page_link)){
list_del(iter);
return 0;
}
iter = iter->next;
}
cprintf("Cannot find addr in list");
assert(0);
return 1;
}
static int _clock_tick_event(struct mm_struct *mm) {
return 0;
}
测试函数
static int _clock_check_swap(struct mm_struct *mm) {
cprintf("write Virt Page c in clock_check_swap\n");
visit(mm,0x3000,0x0c);
cprintf("PGFAULT_NUM:%d\n",pgfault_num);
cprintf("write Virt Page a in clock_check_swap\n");
visit(mm,0x1000,0x0a);
//assert(pgfault_num == 4);
cprintf("PGFAULT_NUM:%d\n",pgfault_num);
cprintf("write Virt Page d in clock_check_swap\n");
visit(mm,0x4000, 0x0d);
//assert(pgfault_num == 4);
cprintf("PGFAULT_NUM:%d\n",pgfault_num);
cprintf("write Virt Page b in clock_check_swap\n");
visit(mm,0x2000 ,0x0b);
//assert(pgfault_num == 4);
cprintf("PGFAULT_NUM:%d\n",pgfault_num);
cprintf("write Virt Page e in clock_check_swap\n");
visit(mm,0x5000 , 0x0e);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
//assert(pgfault_num == 5);
cprintf("write Virt Page b in clock_check_swap\n");
visit(mm,0x2000, 0x0b);
//assert(pgfault_num == 5);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
cprintf("write Virt Page a in clock_check_swap\n");
visit(mm, 0x1000 , 0x0a);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
//assert(pgfault_num == 6);
cprintf("write Virt Page b in clock_check_swap\n");
visit(mm, 0x2000 , 0x0b);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
//assert(pgfault_num == 7);
cprintf("write Virt Page c in clock_check_swap\n");
visit(mm, 0x3000 , 0x0c);
//assert(pgfault_num == 8);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
cprintf("write Virt Page d in clock_check_swap\n");
visit(mm, 0x4000 , 0x0d);
cprintf("PGFAULT_NUM:%d\n\n",pgfault_num);
//assert(pgfault_num == 9);
return 0;
}
其中由于每次访问时需要吧dirty bit置为1,而直接等号赋值不能实现该功能,故将访问打包到visit函数内
输出分析
前四次是冷启动,必然会出现四次miss
set up init env for check_swap begin!
page fault at 0x00001000: K/W [no page found].
page fault at 0x00002000: K/W [no page found].
page fault at 0x00003000: K/W [no page found].
page fault at 0x00004000: K/W [no page found].
set up init env for check_swap over!后面的输出分析见下表格
set up init env for check_swap over!
write Virt Page c in clock_check_swap
PGFAULT_NUM:4
write Virt Page a in clock_check_swap
PGFAULT_NUM:4
write Virt Page d in clock_check_swap
PGFAULT_NUM:4
write Virt Page b in clock_check_swap
PGFAULT_NUM:4
write Virt Page e in clock_check_swap
page fault at 0x00005000: K/W [no page found]. Let's find victim!!!
Not good
Not good
Not good
Not good
Hit head!
Find it!!! swap_out: i 0, store page in vaddr 0x1000 to disk swap entry 2
PGFAULT_NUM:5 write Virt Page b in clock_check_swap
PGFAULT_NUM:5 write Virt Page a in clock_check_swap
page fault at 0x00001000: K/W [no page found]. Let's find victim!!!
Not good
Find it!!! swap_out: i 0, store page in vaddr 0x3000 to disk swap entry 4
swap_in: load disk swap entry 2 with swap_page in vadr 0x1000
PGFAULT_NUM:6 write Virt Page b in clock_check_swap
PGFAULT_NUM:6 write Virt Page c in clock_check_swap
page fault at 0x00003000: K/W [no page found]. Let's find victim!!!
Find it!!! swap_out: i 0, store page in vaddr 0x4000 to disk swap entry 5
swap_in: load disk swap entry 4 with swap_page in vadr 0x3000
PGFAULT_NUM:7 write Virt Page d in clock_check_swap
page fault at 0x00004000: K/W [no page found]. Let's find victim!!!
Not good
Not good
Not good
Hit head!
Not good
Find it!!! swap_out: i 0, store page in vaddr 0x5000 to disk swap entry 6
swap_in: load disk swap entry 5 with swap_page in vadr 0x4000
PGFAULT_NUM:8 count is 0, total is 7
check_swap() succeeded!实际情况分析如图:
Lab8 内核错误 用户程序ls
错误
利用Lab8练习2写好的程序,测试ls
(ls也写错了,下面为修改过的ls)
查看内核代码,发现sfs_lookup()
写错了,下面是修改过的sfs_lookup()
这里只是随手改的,没有管协定文件目录长度,最大设置为40
暴力遍历分解子目录
/*
* sfs_lookup - Parse path relative to the passed directory
* DIR, and hand back the inode for the file it
* refers to.
*/
static int
sfs_lookup(struct inode *node, char *path, struct inode **node_store) {
struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs);
assert(*path != '\0' && *path != '/');
vop_ref_inc(node);
struct sfs_inode *sin = vop_info(node, sfs_inode);
if (sin->din->type != SFS_TYPE_DIR) {
vop_ref_dec(node);
return -E_NOTDIR;
}
struct inode *subnode;
struct sfs_inode *cur_node = sin;
// cprintf("Show Path:%s\n",path);
//开始拆分
char tmp[40];
int i = 0,j = 0,ret = 0;
for(j = 0;;j++){
//末尾
if(path[j]=='\0'){
tmp[i] = '\0';
i = 0;
// cprintf("Find: %s\n",tmp);
ret = sfs_lookup_once(sfs, cur_node, tmp, &subnode, NULL);
break;
}
//遇到/
if(path[j]=='/'){
tmp[i] = '\0';
i = 0;
// cprintf("Find: %s\n",tmp);
if((ret = sfs_lookup_once(sfs, cur_node, tmp, &subnode, NULL))!=0) break;
//cur_node为当前目录inode
cur_node = vop_info(subnode, sfs_inode);
}
//正常
else{
tmp[i]=path[j];
i++;
}
}
vop_ref_dec(node);
if (ret != 0) {
return ret;
}
*node_store = subnode;
return 0;
}
修改ls里面的bug:
int lsdir(const char *path) {
struct stat __stat, *stat = &__stat;
int ret;
DIR *dirp = opendir(path);
if (dirp == NULL) {
return -1;
}
struct dirent *direntp;
char tmppath[40];
while ((direntp = readdir(dirp)) != NULL) {
strcpy(tmppath,path);
strcat(tmppath,"/");
strcat(tmppath,direntp->name);
// printf("File has %s\n",tmppath);
if ((ret = getstat(tmppath, stat)) != 0) {
goto failed;
}
lsstat(stat, direntp->name);
}
printf("lsdir: step 4\n");
closedir(dirp);
return 0;
failed:
closedir(dirp);
return ret;
}
修改disk0的文件系统如图,测试ls正常:
操作系统:ucore的部分Bug&挑战练习的更多相关文章
- 关于ucore实验一的资料查找
任务:阅读实验一makefile 搞清楚ucore.img是如何构建的 $@ $< $^ 这三个变量分别是什么意思 https://blog.csdn.net/YEYUANGEN/arti ...
- 【测试基础第六篇】bug定义及生命周期
bug定义 狭义:软件程序的漏洞或缺陷 广义:测试工程师或用户所发现和提出的软件可改进的细节(增强型.建议性)或需求文档存在差异的功能实现 职责:发现bug,提给开发,让其修改 bug类型--了解 代 ...
- 如何为编程爱好者设计一款好玩的智能硬件(三)——该选什么样的MCU呢?
一.我的构想:如何为编程爱好者设计一款好玩的智能硬件(一)——即插即用.积木化.功能重组的智能硬件模块构想 二.别人家的孩子:如何为编程爱好者设计一款好玩的智能硬件(二)——别人是如何设计硬件积木的! ...
- Linux(9.14-9.20)学习笔记
实验一 Linux系统简介 一.Linux 为何物 Linux 就是一个操作系统,Linux 也就是系统调用和内核那两层. 二.Linux 历史简介 操作系统始于二十世纪 50 年代,当时的操作系统能 ...
- Linux 读书笔记 一
一.Linux 简介 实验介绍 本节主要介绍 Linux 的历史,Linux 与 Windows 的区别等入门知识.如果你已经有过充分的了解,可以跳过本节,直接进入下一个实验. 一.Linux 为何物 ...
- 1.1Linux 系统简介(学习过程)
=====课程笔记===== 一.Linux 为何物 Linux 是一个操作系统,就像你多少已经了解的 Windows(xp,7,8)和 Max OS . Linux 也就是系统调用和内核两层,我们使 ...
- iOS 黑屏
1. 首先看操作系统是否有很多Bug 9.0.2 的系统不稳定. http://tech.163.com/15/1020/05/B6BL6PML000915BD.html
- SQLite在多线程环境下的应用
文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...
- iOS sqlite3数据库解析
看来从版本3.3.1基本上已经支持线程句柄的传递功能.具体限制我标记了一下.(6) Is SQLite threadsafe?SQLite is threadsafe. We make this co ...
随机推荐
- 整理自己的.net工具库
前言 今天我会把自己平日整理的工具库给开放出来,提供给有需要的朋友,如果有朋友平常也在积累欢迎提意见,我会乐意采纳并补充完整.按照惯例在文章结尾给出地址^_^. 之前我开放其他源码的时候(Framew ...
- swift3.0 顶部状态栏隐藏
横屏进入手机状态栏是隐藏的,但是调用了相册选去图片后顶部状态栏又显示了出来,网上查阅按照以下方式: override var prefersStatusBarHidden: Bool{ return ...
- jQuery基础知识总结二
* DOM操作 *1 基本操作 * html() - 等价于innerHTML属性 * text() - 等价于textContent属性 * val() - 等价于value属性 * attr() ...
- theOS环境搭建
http://joeyio.com/ios/2014/01/01/make-a-mobile-substrate-tweak-using-theos/~/Doucment>: cd mytwea ...
- vue模板的几种写法及变化
第一种: 2+版本支持,1+版本支持 <script> <template id="aaa"> <h1>我是组件2</h1> < ...
- Node.js 入门简介
Node.js简介 1.1 简介 V8引擎本身就是用于Chrome浏览器的JS解释部分,但是Ryan Dahl鬼才般的把这个V8搬到了服务器上,用于做服务器的软件. Node.js是一个专注于实现高性 ...
- CentOS 6.5安装JDK、Tomcat、Mysql
安装JDK 1.下载JDK7 下载jdk-7u79-linux-x64.tar.gz 百度网盘下载地址:https://pan.baidu.com/s/1c1JZo2k 在Linux上新建/usr/j ...
- Maven干货
好处: 1. 依赖管理:对jar包统一管理 2. 项目构建: 项目编码完成后,对项目进行编译.测试.打包.部署.之前项目构建通过eclipse工具实现.今天学习新的工具也可以实现这些过程.比如:通过m ...
- CSSc常用样式
一.CSS常用文本属性 1.css中的颜色表示方式 1.1直接使用颜色的单词表示:red.green.blue 1.2使用颜色的十六进制表示:#ff0000,#00ff00: ...
- HTML-CSS相关(2)
[CSS常用文本属性] 1,字体.字号类: ① font-weight:字体粗细. bold-加粗 noemal-正常 lighter-细体 也可以使用100-900数值,400表示normal,70 ...