BBS水木清华站∶精华区
发信人: raner (lilo), 信区: Linux
标 题: NACHOS论坛(3)
发信站: BBS 水木调试站 (Thu Jun 4 16:47:19 1998)
作 家: solmon (所罗门王) on board 'Unix'
题 目: NACHOS论坛(3)
来 源: 鼓浪听涛站
日 期: Thu Mar 6 23:04:30 1997
出 处: [email protected]
第三章 文件系统
Nachos文件系统的界面类似于UNIX,有与UNIX的creat,open,close,read,write,
lseek和unlink相似(不是完全一样)的系统调用.一个重要的不同点在于Nachos文件系
统是用C++实现的.Creat(相当于UNIX中的creat),Open(open),和Remove(unlink)都是
定义在FileSystem类中的,因为它们都是与正在操作的文件名和目录相联系的.
FileSystem::Open返回一个指针,它指向一个OpenFile对象,OpenFile对象与UNIX中的
打开文件描述符类似,可以用这个对象直接对文件进行操作,如Seek(lseek), Read
(read), Write(write)只要把这个OpenFile对象删除(delete)就可以关闭(close)这个
已打开文件了.
Nachos文件系统的结构如图:
┏━━━━━━━━━━━━━━━━━━━┓
┃ 文 件 用 户 ┃
┣━━━━━━━━━━━━━━━━━━━┫
┃ FileSystem OpenFile Directory ┃
┣━━━━━━━━━━━━━━━━━━━┫
┃ FileHeader ┃
┣━━━━━━━━━━━━━━━━━━━┫
┃ SynchDisk ┃
┣━━━━━━━━━━━━━━━━━━━┫
┃ Disk ┃
┗━━━━━━━━━━━━━━━━━━━┛
在Nachos文件系统中,许多数据结构既可存放在内存里,又可存放在磁盘里.为了一
致起见,文件系统中Synchdisk以上的类都有一个FetchFrom成员函数,它把数据结构从
磁盘读到内存;还有一个WriteBack成员函数,它与FetchFrom相反,把数据结构从内存写
回磁盘.在内存中的数据结构与磁盘上的完全一致,没有增减数据项,给管理带来了不少
方便.在以后的介绍中这两个函数不再重复了.
让我们从下往上分析文件系统.Disk模拟了一个物理磁盘,它的具体实现在机器模
拟部分已经介绍了.
SynchDisk类在物理磁盘的基础上定义了一个同步磁盘的抽象界面.象别的I/O设备
一样,物理磁盘是异步设备.用户提出读写请求后立即返回,这以后会有一个中断发生,
报告磁盘操作完成.同步磁盘有些不同,进程提出读写请求后将睡眠等待,以后在磁盘�
断的处理函数中唤醒它,所以进程将等待磁盘操作完成后才能返回.
SynchDisk类的界面为:
┏━━━━━━━━━━━�
┃ SynchDisk ┃
┣━━━━━━━━━━━┫
┃ ReadSector ┃
┃ WriteSector ┃
┗━━━━━━━━━━━┛
SynchDisk类的生成函数生成了一个锁,一个信号量,一个物理磁盘对象,由于物理
磁盘一次只能接受一个读写请求,锁就是用来实现读写互斥的.信号量用来实现中断程
序和发出磁盘请求的程序之间同步。
ReadSector成员函数的执行过程如下:
1.关闭锁.(如果别的进程正在操作磁盘,则睡眠等待别的进程的磁盘操作�
成)
2.向物理磁盘发读数据请求.
3.对信号量作P操作(睡眠等待磁盘操作的完成,将由读磁盘的中断处理程序
唤醒本进程).
4.解锁.
WriteSector成员函数的执行过程与ReadSector类似.
FileHeader类是用来管理一个文件块在磁盘上分布情况的数据结构.这个数据结构
称为文件控制块.文件控制块中还可以包括一些有关文件的信息,如长度,拥有者等等,
文件控制块与UNIX中的i-node类似.文件控制块可以放在内存中或磁盘里.当它在磁盘
里时,只占用一个扇区,Nachos没有实现文件控制块的间接定位,所以文件控制块的大小
是固定的,也导致Nachos文件最大长度为4Kbytes.
FileHeader的界面为:
┏━━━━━━━━┓
┃ FileHeader ┃
┣━━━━━━━━┫
┃ Allocate ┃
┃ Deallocate ┃
┃ ByteToSector ┃
┃ FileLength ┃
┣━━━━━━━━┫
┃ numBytes ┃
┃ numSectors ┃
┃ dataSectors[] ┃
┗━━━━━━━━┛
其中numBytes 为文件长度,numSectors为文件占用的扇区数,dataSectors[]数组
指明文件的每个数据块存放在第几个扇区里.例如,有一个文件长度为200 byte,Nachos
定义一个扇区的长度为128 byte,则numBytes=200, numSectors= ceil(200/128)=2,文
件占用了两个扇区,如果文件的第一块放在第5扇区,第二块放在第20扇区,则
dataSectors[0]=5,dataSectors[1]=20,dataSectors数组其他元素值不定,也没有用.
Allocate成员函数用来初始化文件控制块,为本文件分配磁盘空间.它的执行过程如
下:
1.根据文件长度对numBytes,numSectors赋初值.
2.如果文件需要的扇区数大于磁盘上的空闲扇区数,则返回失败.
3.给文件分配空闲扇区,把扇区号放入dataSectors数组,并把这些扇区的使
用标志从空闲改为已占用.
Deallocate成员函数释放文件占用的扇区.
ByteToSector返回存放着文件第x字节数据的扇区号.
FileLength返回文件长度.
OpenFile类用来实现文件的读写操作.Nachos将文件的操作转化为对扇区的操作.
在现有实现中并没有考虑文件系统的并发问题,这些留给学生作为课程作业.OpenFile
的界面为:
┏━━━━━━━━┓
┃ OpenFile ┃
┣━━━━━━━━┫
┃ Seek ┃
┃ ReadAt ┃
┃ WriteAt ┃
┃ Read ┃
┃ Write ┃
┃ Length ┃
┣━━━━━━━━┫
┃ seekPosition ┃
┃ FileHeader* hdr┃
┗━━━━━━━━┛
seekPosition是文件当前读写指针,hdr是文件控制块的地址.OpenFile的生成函数
带有一个int型的参数,指明存放文件控制块的扇区号.生成函数先给hdr分配空间,然后
从磁盘中读出这个文件的文件控制块,放入hdr指向的内存.seekPositon 赋为0,使得文
件当前读写指针指向文件开头.
Seek成员函数将文件当前读写指针移到新的位置.
ReadAt/WriteAt用于读写数据.读写的开始位置和读写数据长度由参数指定.由于
Nachos文件长度不可改变,所以超过文件长度的读写都被忽略.又因为磁盘读写单位是
整个扇区,所以ReadAt读出包括要读数据的所有扇区,然后只把要求读出的数据拷贝给
调用者.WriteAt先读出写入数据所在的全部扇区,然后把新数据写入要修改的位置,最
后将这些扇区写回磁盘,这样就保证了不会覆盖不应被修改的部分.这两个函数返回实
际读/写的长度.
Read/Write成员函数分别调用ReadAt/WriteAt成员函数,从文件当前读写指针处开
始读/写数据.它的执行过程如下:
1.分别调用ReadAt/WriteAt函数从文件当前读写指针处开始读/写数据.
2.文件当前读写指针向后移动实际读/写的长度.
3.返回实际读/写的长度.
Length返回文件长度.
Nachos的目录是由一组目录项组成,每个目录项代表一个文件.目录项的内容有:已
使用标志inUse,文件控制块所在扇区号sector,文件名字name,文件名有最大长度,这样
每个目录项都有固定长度.当我们知道文件所在目录和文件名后,就可以从它所在目录
中找到名字与之相同的目录项,于是就可以知道此文件的文件控制块所在扇区,而文件
控制块中记录了文件内容所在的扇区号,这样就可以读写这个文件了.与文件系统的其
他数据结构一样,目录结构既可以放在内存中,又可以放在磁盘上.当它存放在磁盘上时,
是作为一个常规的Nachos文件存储的,由于Nachos文件长度固定,所以目录的目录项个
数在生成目录时就固定了,以后不能改变.现有实现中,对目录操作的互斥是由调用者保
证的.
目录的界面为:
┏━━━━━━━━┓
┃ Directory ┃
┣━━━━━━━━┫
┃ Find ┃
┃ Add ┃
┃ Remove ┃
┃ List ┃
┃ FindIndex ┃
┣━━━━━━━━┫
┃ tableSize ┃
┃ table ┃
┗━━━━━━━━┛
tableSize放的是目录项的个数,table是目录项数组的地址.
Directory类的生成函数的执行过程如下:
1.此目录的目录项个数由参数传入,用这个参数给
tableSize赋值.
2.给目录项数组table分配空间,它的元素个数为tableSize.
3.将所有目录项的使用标志清零.
一个目录类对象才生成时,目录项内容总是空的,如果这个目录已经存在,就需要用
FetchFrom成员函数把目录项内容从磁盘上读出来.
FindIndex(char* name)成员函数在目录中寻找文件名为name的文件,如果找到就
返回此文件在目录项数组中的索引,否则返回-1.
Fine(char* name)成员函数在目录中寻找文件名为name的文件,如果找到就返回此
文件的文件控制块所在扇区号,否则返回-1.
bool Add( char* name,int newSector) 函数增加一个文件到目录中,这个文件的
名字为name,文件控制块所在扇区号为newSector.如果添加成功,返回TRUE.在下列情况
返回FALSE:
1.目录中已经存在这个文件名.
2.目录已满.
bool Remove( char* name ) 把名字为name的文件从目录中删除.如果成功返回
TRUE.若在目录中没有这个文件,则失败,返回FALSE.
List() 显示目录中所有的文件.
FileSystem是Nachos的文件系统的顶层界面.它提供了一些用文件名来操作文件的
功能.
FileSystem的界面为:
┏━━━━━━━━┓
┃ FileSystem ┃
┣━━━━━━━━┫
┃ Creat ┃
┃ Open ┃
┃ Remove ┃
┃ List ┃
┣━━━━━━━━┫
┃ freeMapfile ┃
┃ directoryFile ┃
┗━━━━━━━━┛
其中freeMapfile和directoryFile是两个OpenFile类的指针.
freeMapfile指向用来管理磁盘空间的BitMap文件.磁盘的每个扇区对应BitMap中
的一位,如果在BitMap中这位为0,则说明此扇区为空,否则说明此扇区已被某个文件占
用.directoryFile指向根目录文件.Nachos没有实现多级目录结构,它只有一个根目录,
文件系统的所有文件都放在根目录下.
FileSystem的生成函数有一个format参数,如果它为非零,将格式化(Format)整个
文件系统,否则从模拟磁盘上读出文件系统的信息.
Format文件系统的过程为:
1.生成一个空的BitMap和根目录.
2.把磁盘0扇区分配给freeMapfile文件的文件控制块;
1扇区分配给根目录的文件控制块.
3.为这两个文件分配磁盘空间.
4.打开这两个文件,即在内存中生成两个OpenFile对象.
5.把freeMapfile,directoryFile两个文件写回磁盘.
6.释放函数中分配的辅助内存空间,但freeMapfile和directoryFile这两个
OpenFile对象仍然保留在内存中.
如果生成文件系统时不需要格式化,就只要从磁盘上读出freeMapfile,
directoryFile两个文件即可.
文件系统生成后,freeMapfile,directoryFile这两个OpenFile对象总是保留在内
存中的.
Creat(char* name, int initialSize)成员函数用来创建一个新文件,新文件的名
字是name,长度为initialSize,它的执行过程如下:
┏━━━━━━━━┓
┃ 从磁盘读入根 ┃
┃ 目录文件 ┃
┗━━━┳━━━━┛
┃
↓
━━━━━━━━━
目录中已经 Y
存在同名文件 ━━━━━━┓
━━━━━━━━━ ┃
┃ ┃
┃ N ┃
↓ ┃
┏━━━━━━━━┓ ┃
┃从磁盘读入BitMap┃ ┃
┃文件,给文件控制 ┃ ┃
┃块分配一个扇区 ┃ ┃
┗━━━┳━━━━┛ ┃
┃ ┃
┃ ┃
↓ ┃
━━━━━━━ N ┃
分配成功 ━━━━━━━→┃
━━━━━━━ ┃
┃ ┃
┃ Y ┃
↓ ┃
┏━━━━━━━━┓ ┃
┃ 将文件加入根 ┃ ┃
┃ 目录 ┃ ┃
┗━━━┳━━━━┛ ┃
┃ ┃
↓ ┃
━━━━━━ N ┃
成功加入 ━━━━━━━→┃
━━━━━━ ┃
┃ ┃
┃ Y ┃
↓ ┃
┏━━━━━━━━┓ ┃
┃ 为文件分配 ┃ ┃
┃ 磁盘空间 ┃ ┃
┗━━━┳━━━━┛ ┃
┃ ┃
↓ ┃
━━━━━━ N ┃
分配成功 ━━━━━━━→┃
━━━━━━ ┃
┃ ┃
┃ Y ┃
↓ ┃
┏━━━━━━━━┓ ┃
┃ 将BitMap文件和 ┃ ┃
┃ 根目录文件写入 ┃ ┃
┃ 磁盘 ┃ ┃
┗━━━┳━━━━┛ ┃
┃ ┃
┃ ┃
↓ ↓
┏━━━━━━━━┓ ┏━━━━━━━━┓
┃ 返回TRUE ┃ ┃ 返回FALSE ┃
┗━━━━━━━━┛ ┗━━━━━━━━┛
在Creat函数的处理过程中只修改内存中的BitMap和根目录,磁盘上的数据不会被
修改,这样如果文件生成失败,只要返回FALSE即可.如果执行成功,才把这两个文件写
回磁盘.
Remove(char* name)删除文件名为name的文件.它的执行过程如下:
1.从磁盘读入根目录文件.
2.如果根目录中没有这个文件,则返回FALSE.
3.读入此文件的文件控制块.
4.释放此文件占用的磁盘扇区,并删除其目录项.
5.释放此文件的文件控制块占用的磁盘扇区.
6.把修改后的BitMap和目录文件写回磁盘.
7.返回TRUE.
OpenFile* Open(char* name)成员函数打开名为name的文件,可以用返回的
OpenFile指针读写此文件.Open的执行过程如下:
1.将目录文件读入内存.
2.用Directory::Find(char* name)函数求出name文件的文件控制块所在扇
区.
3.读入文件控制块,并生成此文件的OpenFile对象.
4.返回OpenFile对象的指针.
List成员函数显示根目录的内容.
关闭文件只须删除(delete)OpenFile对象即可.
--
m※ 来源:.鼓浪听涛站 bbs.xmu.edu.cn.[FROM: [email protected]] m
--
※ 来源:·BBS 水木调试站 Leeward.lib.tsinghua.edu.cn·[FROM: 166.111.68.98]
BBS水木清华站∶精华区