Nachos文件系统实习报告.docx
- 文档编号:10539681
- 上传时间:2023-02-21
- 格式:DOCX
- 页数:41
- 大小:995.54KB
Nachos文件系统实习报告.docx
《Nachos文件系统实习报告.docx》由会员分享,可在线阅读,更多相关《Nachos文件系统实习报告.docx(41页珍藏版)》请在冰豆网上搜索。
Nachos文件系统实习报告
文件系统实习报告
善良的大姐姐
2015.5.3
一:
总体概述
Nachos系统模拟了一个简单的文件系统,其中包括磁盘,文件目录,空闲磁盘快分配表等,用于维护文件的逻辑结构与物理位置之间的映射关系。
还有对文件的基本操作函数和数据结构,如创建、删除、读取、写入等。
本实习希望通过修改Nachos系统的底层源代码,达到“完善文件系统”的目标。
二:
任务完成情况
任务完成列表(Y/N)
Exercise1
Exercise2
Exercise3
Exercise4
Exercise5
Exercise6
Exercise7
Challenge
Yes
Yes
Yes
Yes
Yes
Yes
Yes
Yes
具体Exercise的完成情况
Exercise1:
源代码阅读
任务:
阅读Nachos源代码中与文件系统相关的代码,理解Nachos文件系统的工作原理。
完成情况:
1.Filesys.h(cc)
概述:
定义了一个filesystem类,包括了对文件系统的初始化函数,以及若干个对文件系统中某个文件的操作的函数。
在介绍函数之前,先介绍两个以文件形式存在的重要内容:
1)空闲磁盘块分配表:
以文件的形式存储,头文件位于文件目录的第0项。
是由bitmap类生成的。
每一个bit对应于磁盘中的一个块的使用情况,0表示空闲,1表示已使用。
2)文件目录:
以文件的形式存储,头文件位于文件目录的第1项。
是由directory类(之后会介绍)生成的。
directory的项是
找到的是文件头部所在磁盘块。
接下来介绍函数:
函数名称
主要功能
filesystem构造函数
创建或者载入一个文件系统
解释:
传入一个bool型参数format,当format为true时会初始化filesystem(相当于格式化了文件系统),使用新的空闲磁盘块分配表以及新的文件目录。
否则仅仅载入原来存在的空闲磁盘块分配表以及文件目录。
filesystemcreate函数
在文件系统中创建文件
解释:
参数为文件名和初始长度。
1)从磁盘载入空闲磁盘块分配表文件和文件目录文件(通过bitmap和directory的fetchfrom(sector)实现)
2)为新文件创建文件头部(filehdr):
找到一个空闲磁盘块(通过bitmap的find函数实现,返回空闲磁盘块的sector号);将头文件信息写入目录文件(通过directory的add(name,sector)函数实现);
3)将文件块的信息写入文件头部:
文件被切分成若干个文件块,并在文件头部记录每个文件块位于磁盘的哪个sector(通过filehdr的allocate(bitmap,initialSize)实现)
4)将更新了的空闲磁盘块分配表文件和文件目录文件写回磁盘(通过bitmap和directory的writeback(sector)实现)
filesystemopen函数
在文件系统中打开文件
解释:
参数为文件名。
1)从磁盘载入文件目录文件
2)在文件目录中,通过文件名,查找文件头部对应的磁盘号(通过directory的find(name)实现)
3)如果存在,打开文件头部,并返回一个openfile类的指针(通过new一个openfile类实现)
filesystemremove函数
在文件系统中移除文件
解释:
参数为文件名。
1)从磁盘载入空闲磁盘块分配表文件和文件目录文件
2)将文件块从磁盘中移除(通过filehdr的deallocate(bitmap)函数实现)
3)将文件头部从磁盘中移除(通过bitmap的clear(头部sector)实现)
4)将文件从文件目录中移除(即清除<文件名,文件头部sector>的对子)(通过directory的remove(name)函数实现)
5)将更新了的空闲磁盘块分配表文件和文件目录文件写回磁盘
filesystemlist,print函数
打印文件系统信息
解释:
打印文件系统的相关信息,包括磁盘块分配状况,文件目录情况,以及存在的文件的详细情况等。
具体细节略。
2.Filehdr.h(cc)
概述:
定义了一个fileheader类,模拟文件头部。
私有变量包括文件长度,文件占用的磁盘块个数,<文件块,磁盘块>对应关系数组。
以及对文件块的分配,回收等函数。
由于目前只支持定长文件,因此文件的信息在初始化的时候就确定了,文件头的信息在文件使用过程中不会发生改变,类似于只读。
函数介绍:
函数名称
主要功能
filehdrallocate函数
为文件块分配磁盘块
解释:
参数为空闲磁盘块分配表指针,和文件长度。
1)更新私有变量:
文件长度和文件占用的磁盘块个数(通过文件长度/一个磁盘块大小)实现
2)为文件块分配对应的磁盘块。
(通过bitmap的find函数实现)——注意:
此时磁盘块仅仅是分配了,但是并没将文件写入。
filehdrdeallocate函数
将分配的磁盘块回收
解释:
参数为空闲磁盘块分配表指针
1)for循环,将<文件块,磁盘块>对应关系数组中,每个文件块对应的磁盘块的占用标记清除(通过bitmap的clear函数实现)
filehdrfetchfrom函数
从磁盘中载入一个文件头部
解释:
参数为要载入的磁盘块的sector号
调用synchdick的readsector函数,将sector对应的磁盘块内容读入,覆盖自己(类似于构造函数)
filehdrwriteback函数
将当前文件头部写回磁盘
解释:
和fetchfrom执行相反操作。
filehdrbytetosector函数
读入文件中偏移为offset的位置的磁盘块
解释:
参数为偏移量
1)计算出偏移量对应的文件块
2)通过私有变量数组,找到文件块对应的磁盘块
3)返回磁盘块的磁盘号
filehdrfilelength函数——返回文件大小
fielderprint函数
打印文件头部信息
3.Directory.h(cc)
概述:
定义了两个类,一个是directoryentry类,一个是directory类。
directoryentry类是做<文件名,磁盘号>,以及一个标识位,标志当前entry是否被使用了(注意!
这里与filehdr里的<文件块,磁盘块>数组不同,filehdr里是某个文件所有内容所映射的磁盘块,directoryentry中时某个文件的文件头部映射的磁盘块)。
directory类模拟文件目录。
私有变量包括entry数量和一个directoryentry的entry数组。
目前只实现了一级目录索引,最多只支持10个文件头部的存放。
函数介绍:
函数名称
主要功能
directory构造函数
初始化私有变量(在概述中介绍了)
解释:
初始化entry数组,以及将数组中的每个entry的标识位设为false(未使用)
directoryfetchfrom函数
从文件目录文件中载入directory
解释:
参数为openfile。
调用openfile的readat函数,将文件目录文件的内容覆盖自己(类似于构造函数)
directorywriteback函数
将当前文件目录写回目录文件
解释:
参数为openfile。
调用openfile的writeat函数,将当前directory写回目录文件
directoryfindindex+find函数
在entry数组中查找名字对应的文件头部磁盘块
解释:
参数为文件名
for循环比对。
并返回磁盘块的磁盘号。
找不到返回-1
directoryadd函数
将一个<文件名,文件头部磁盘块的磁盘号>的条目加入entry数组中
解释:
参数为文件名,文件头部磁盘块的磁盘号。
注意修改entry的标识位。
directoryremove函数
和add执行相反功能。
directorylist,print函数
打印directory的信息
4.Openfile.h(cc)
概述:
定义了一个Openfile类,用于对文件执行基本操作:
读和写。
私有变量为文件头部的指针,以及当前文件的光标位置。
函数介绍:
函数名称
主要功能
Openfile构造函数
初始化私有变量
解释:
参数为文件头部的磁盘块号
文件头部的指针通过filehdr->fetchfrom(sector)函数载入磁盘内容;设置初始光标位置为0
Openfileseek函数
将当前光标位置设置为传入的参数
Openfileread函数
读入若干个字节到一个数组里
解释:
参数为返回的内容数组,和需读入的字节数。
1)调用readAt(buffer,字节数,当前光标位置)读入若干字节到buffer当中;
2)更新光标位置;
返回内容数组
Openfilewrite函数
写入若干字节到磁盘中
解释:
参数为需写入的内容数组,和写入的字节数
步骤同read函数,只是将readAt变成了writeAt.
OpenfilereadAt函数
从当前光标位置读入若干字节到一个数组当中
解释:
参数为返回数组,字节数以及当前光标位置。
1)获取文件长度(通过filehdr->filelength函数实现)
2)确定当前光标位置所在的文件块(通过“光标位置/一个sector的大小”向上取整实现)
3)确定需读入的最后一个字节所在的文件块(通过“光标位置+读入字节/一个sector的大小”向上取整实现)
4)计算一共需要访问的磁盘快个数(通过2)3)步做差实现)
5)将文件块对应的磁盘块内容读入数组当中(通过私有变量文件头部的bytetosector函数,得到文件块-磁盘快的映射)
将真正需要的字节从数组当中取出(由于事实上所需要的字节不一定位于块的头,可能要从某个中间位置截断)
图解释:
OpenfilewriteAt函数
从当前光标位置开始写入若干字节
解释:
操作步骤基本同上。
Openfilelength函数
获取文件长度
解释:
通过私有变量文件头部的filelength函数获得。
5.Bitmap.h(cc)
概述:
在上个lab的实验报告中已经介绍过了。
在这次lab中,bitmap作为空闲磁盘块分配表,以文件的形式存放。
每一个bit标志了磁盘中某个块当前的情况。
此外,还可以使用bitmap的函数,达到模拟对磁盘的管理功能。
如改变某个bit为0或者1,或是寻找为0的bit(即空闲的磁盘快)等。
Exercise2:
扩展文件属性
任务:
增加文件描述信息,如“类型”、“创建时间”、“上次访问时间”、“上次修改时间”、“路径”等等。
尝试突破文件名长度的限制。
完成情况:
考虑:
对于文件描述信息,可以在fileheader中加入,也可以在directory中加入。
但考虑到如果都在fileheader中加入,会使得文件系统中最大文件长度急剧缩水(因为fileheader的文件块-磁盘快的映射对数量减少),所以,文件类型和路径,在directoryentry中实现(事实上,也是出于对于ex4的考虑),三个时间在fileheader类中实现。
增加的描述信息
简单介绍
文件类型
1)在directoryEntry中加入。
仅仅区分文件和文件夹(文件为0,文件夹为1)
2)初始化位置:
directory:
:
add
路径
1)在directoryEntry中加入。
2)修改原来最大长度为9的name变两个,char型数组为char*
3)认为这个路径为文件的绝对路径(从root开始算起,为之后ex4做准备)
4)初始化位置:
directory:
:
add
创建时间
1)在filehdr中加入,char变量,配合着两个函数:
设置时间和获取时间函数。
在函数体内,使用linux系统函数获取当前时间,并存入字符数组当中。
2)在filesystem:
:
create函数中调用设置时间函数。
上次访问时间
1)同上1)
2)在openfile:
:
read/write函数中调用设置时间函数,并且注意及时将文件头部指针写回磁盘(因为更新了文件头部中的私有变量,并且原先没有写回文件头部这个操作)
上次修改时间
1)同上1)
2)在openfile:
:
write函数中调用设置时间函数,并且注意及时将文件头部指针写回磁盘
补充:
1)注意修改filehdr.h中关于NumDirect的宏定义,因此此时多占用了3*25(每个时间为25个byte)个byte。
目前文件实际能用扇区:
(128-75)/4*128=11*128=1,408byte
2)Openfile中新增了一个私有变量,用于记录对应的文件头部的磁盘块号,方便文件头部的写回。
3)Fileheader:
:
findindex函数,注意不适用strncmp,改为strcmp。
(因为此时长度不确定了)
测试截图:
测试函数为:
ftest.cc,修改文件大小为50,使得其测试刚好为5次write,5次read。
并且还测试了关闭nachos系统,但不格式化文件系统,重新载入之后的情况。
Exercise3:
扩展文件长度
任务:
改直接索引为间接索引,以突破文件长度不能超过4KB的限制。
完成情况:
概述:
将原来的11个(之前有计算过)直接索引,拆成6个直接索引,5个二级索引。
于是一个文件最多可以对应的磁盘块数量:
5*(128/4)+6=166。
其中128为一个sector的byte大小,4byte一个二级索引号。
图解释直接索引和二级索引:
修改部分
简单解释
1.Fileheader的宏定义
2.Fileheaderallocate函数
1)计算出文件总共需要多少个磁盘块
2)如果需要的数量不大于直接索引,直接用freemap分配即可
3)否则,先分配了所有的直接索引,然后计算剩余量
4)对于剩余量,先用freemap分配一个磁盘块给二级目录,然后按照32(一个二级目录最多容纳32个索引)为单位,调用freemap分配空闲块之后,将得到的<文件块,磁盘块>映射数组通过synchdick的writesector函数,写回二级目录所在的磁盘块。
Fileheaderdeallocate函数
1)先释放直接索引的磁盘块
2)如果使用了二级索引,先通过synchdick的readsector函数,将二级目录所在的磁盘块读入,然后逐一释放,最后再释放当前的二级索引(和allocate函数刚好是相反操作)
Fileheaderbytetosector函数
操作过程类似上面,相比于原先,如果需要二级索引,需要将偏移量先扣除了直接索引的部分,以及二级索引本身,再从二级目录中找到对应文件块,进而找到磁盘块。
测试结果:
logex3.txt
Exercise4:
实现多级目录
任务:
如题。
完成情况:
概述:
为了实现多级目录,需要有方法找到每个目录。
于是想到依照绝对路径进行层级划分。
第一级目录对应的绝对路径是root,第二级目录对应的绝对路径是root/A,以此类推。
容易想到,每个绝对路径的上一层,也就是其父节点,实际上就是文件的相对路径。
因此,我们需要两个变量共同完成多级目录的索引:
绝对路径和相对路径。
由于绝对路径在ex2中已经存在name变量中了,我们只需做简单的字符串扫描工作,就可以得到文件的相对路径。
关键函数介绍:
对于多级目录的实现,最关键的就是能够在这个目录树中找到对应的结点。
函数名称
主要功能
Directory:
:
Getcorrectdirsector(name)
在多级目录中找到name对应的目录项所在的相对路径,返回值为相对路径所在的磁盘块号(如:
如果对应的目录项为root/A/B,则需要找到root/A所在的磁盘块号)
解释:
1)将传入的名字参数(也就是绝对路径,如root/A/B)解析,得到相对路径(即文件所在的上层目录,即root/A)
代码如下:
2)判断相对路径是否是根目录(root),如果是,返回1(根目录的磁盘块编号为1)
3)否则,将相对路径与当前目录文件存储的目录项的绝对路径进行比对,试图寻找可匹配项(如,root/A/B的相对路径为root/A,根目录文件中存在绝对路径为root/A的一项,于是可以知道,此时返回root/A所在的磁盘块号即可),如果存在,返回所在的磁盘块号
4)否则,for循环当前目录文件的目录项table,如果目录项使用了(inuse=true)并且目录项存储的文件的文件类型为文件夹(ex2中设立的filetype在此处派上用场),则载入这个目录文件,并且调用getcorrectdirsector,递归寻找。
如果最后找不到,返回-1
改动部分:
改动函数
Directory:
:
add函数:
增加一个参数——文件类型。
0为文件,1为文件夹。
(table中已经有这个条目了,在ex2中创建的)
Filesys:
:
create函数:
1)参数没变,但规定,initialsize如果传入-1,代表create的文件的文件类型为文件夹。
2)载入了根目录文件后,调用getcorrectdirsector函数,获得文件相对路径的文件头部所在的磁盘块号
3)如果不是根目录文件的磁盘块号(即2)中返回值≠1),意味着我们要载入另一个目录文件:
通过返回的磁盘块号,先用openfile打开文件,然后用directory的fetchfrom函数,覆盖原来的directory指针。
4)在当前目录文件中寻找,要创建的文件是否已经存在(directory->find(name)函数)。
如果不存在,证明可以create.
5)载入freemap文件,先为文件头部分配空闲磁盘块。
(freemap->find()实现)
6)分配成功后,将<文件名,文件头部所在磁盘块号>条目加入当前目录文件中(directory->add(name,sector,filetype)实现)
7)创建文件头部,用文件头部为文件块映射磁盘块(hdr->allocate(freemap,size)实现。
其中,如果是创建文件,则size=initialsize,如果是创建文件夹,则size=DirectoryFileSize宏),并将映射结果写回磁盘(hdr->writeback(sector)实现)
8)接下来要写回目录文件了:
一定要注意,如果当前是在根目录文件,则写回的是directoryFile,如果不是,则写回的是刚才新创建的Openfile
9)最后,如果创建的是文件夹,则需要预先新生成一个directory给它。
鉴于这部分比较难以描述清楚,代码如下:
Filesys:
:
open函数:
1)载入了根目录文件后,调用getcorrectdirsector函数,获得文件相对路径的文件头部所在的磁盘块号
2)如果不是根目录文件的磁盘块号(即2)中返回值≠1),意味着我们要载入另一个目录文件:
通过返回的磁盘块号,先用openfile打开文件,然后用directory的fetchfrom函数,覆盖原来的directory指针。
3)在当前目录文件中寻找,要打开的文件是否存在(directory->find(name)函数)。
如果存在,用find函数返回的sector号打开文件,返回openfile指针。
Filesys:
:
remove函数:
和create函数类似。
但要注意,如果删除的是文件夹,需要遍历一遍文件夹目录文件下的所有结点,将它们一并删除。
补充:
1)事实上,directory中的函数,不需要考虑递归寻找之类的问题。
因为这一切在filesys的函数里已经做了,通过getcorrectdirsector,配合打开新的目录文件,之后只要调用新的目录文件的directory方法,就可以了。
测试截图:
1.测试函数截图:
2.测试结果截图
3.
Exercise5:
动态调整文件长度
任务:
对文件的创建操作和写入操作进行适当修改,以使其符合实习要求。
完成情况:
概述:
由于我们在ex3中实现了多级索引,因此在动态调整文件长度部分,最关键的问题,就是要对扩展的长度占据的磁盘块数量做考察,分类讨论。
关键函数介绍:
函数名称
主要功能
Filehdr:
:
extendallocate(bitmap,filesize)
为扩展的filesize个byte,使用bitmap,分配磁盘块。
解释:
1)计算出需要几个磁盘块,原来用了几个磁盘块
2)更新fileheader的私有变量:
文件字节总数和共占用几个磁盘块(一定要注意更新!
不然在readAt和writeAt部分会出问题的)
3)分类讨论:
如果扩展的磁盘块仍不大于直接索引:
直接用bitmap分配即可。
4)如果扩展的磁盘块位于直接索引和二级索引之间:
先分配完直接索引部分,然后用for循环:
先为二级索引分配一个磁盘块,然后在二级索引对应的table中,分配磁盘块(最多32个)
5)如果扩展的磁盘块仅位于二级索引:
先判断原来的二级索引对应的table使用完了没,如果没用完,先写完剩余的,再新分配下一个二级索引及table.
6)记得调用synchdisk->writesector,将修改的部分写回磁盘。
代码如下:
补充:
事实上,代码中开头红框部分非常重要……不容易想到。
但是在我调试writeAt的时候,才注意到的。
就是,如果扩展的字节并没有超出原来分配的磁盘块,那么就可以直接返回true了。
而不是再分配一个新的sector。
这会造成存放的不连续。
改动部分:
改动/增加函数
增加:
filesys:
:
extendFile(openfile指针,扩展长度)
解释:
1)由于关键函数extendallocate需要参数freemap,因此考虑在filesys文件中调用extendallocate。
考虑到这个函数之后会被openfile的writeAt函数调用,因此设置其中一个参数为openfile指针。
2)载入freemap。
3)调用openfile->私有变量:
文件头部指针->extendallocate(freemap,扩展长度)
4)如果扩展成功(返回值为true),将freemap的改动写回磁盘文件(freemap->writeback)。
一定要记得写回,不然扩展部分根本没有成功分配!
!
修改:
openfile:
:
writeAt函数
解释:
1)在判断position+numBytes是否大于fileLength的时候,如果大于,不是直接返回失败,而是调用filesystem->extendFile(this,扩展长度)
增加的部分代码如下:
测试截图:
A.测试了动态扩展文件的正确性:
测试函数:
修改数字,使得分类讨论的三种情况都能测试到。
测试结果:
1.只需要一级索引
2.需要一级索引及二级索引
3.只需要二级索引
B.测试了writeAt的正确性
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Nachos 文件系统 实习 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)