geekos-project5 项目5:GOSFS文件系统

项目5:GOSFS文件系统

2.6 Project5

2.6.1项目设计目的

        了解文件系统的设计原理,掌握操作系统文件系统的具体实现技术。

2.6.2项目设计要求

        为实现GOSFS文件系统,用户在“/src/geeekos /gosfs.c”中添加代码,实现以下函数。

  1. GOSFS_Fstat()函数:为给定的文件得到元数据;
  2. GOSFS_Read()函数:从给定文件的当前位置读数据;
  3. GOSFS_Write()函数:从给定文件的当前位置写数;
  4. GOSFS_Close()函数:关闭给定文件;
  5. GOSFS_Read GOSFS_Fstat_Directory()函数:为一个打开的目录得到元数据;
  6. GOSFS_Close_Directory()函数:关闭给定目录。_Entry()函数:从打开的目录表读一个目录项;
  7. GOSFS_Open()函数:为给定的路径名打开一个文件;
  8. GOSFS_Create_Directory()函数:为给定的路径创建一个目录;
  9. GOSFS_Open_Directory()函数:为给定的路径打开一个目录。
  10. GOSFS_Delete()函数:为给定的路径名删除一个文件;
  11. GOSFS_stat()函数:为给定的路径得到元数据(大小,权限等信息);
  12. GOSFS_Sync()函数:对磁盘上的文件系统数据实现同步操作;
  13. GOSFS_Format()函数:格式化GOSFS文件系统操作;
  14. GOSFS_Mount()函数:挂载文件系统操作。

2.6.3原理分析

        从Geekos系统层面分析,其原本搭载的文件系统为PFAT,需仿照PFAT文件的实现原理来实现GOSFS文件系统。

1.磁盘的逻辑结构

 

图表 1磁盘的逻辑结构

2.文件基本框架

 

图表 2文件的基本框架

3.文件系统的结构

 

图表 3文件系统的结构

4.多层索引的图示

 

图表 4多层索引的演示

2.6.4主要操作分析

(1)FORMAT格式化操作:GOSFS_Format()函数,目的是将原始磁盘格式化为GOSFS格式,将挂载区域blockDev进行GOSFS格式化。

        利用Get_Num_Blocks函数获取磁盘容量,并FindNumBlocks函数计算所需块数量。创建根目录,使得指针指向目录,并创建超级块,即GOSFS_Superblock结构体(定义于gosfs.h头文件下),Malloc(byteCountSuperblock)赋予超级块的空间,GOSFS_Superblock->magic变量表示在GOSFS_Mount挂载中检查是否为GOSFS文件系统,其块数量以及大小也需赋值。最后将超级块写入硬盘即可,此处,写入时需用到缓存来进行辅助操作。

        根据所掌握的信息可知,Format操作完成文件系统的格式化操作时,在系统编译时GeekOS会自动生成10兆大小的磁盘镜像,并初始化内容为全零。GOSFS_Format将这种原始磁盘格式化为GOSFS格式的磁盘,操作包括写入引导块,文件系统初始超级块以及根目录信息节点。需要注意的是,该操作只是针对GOSFS,不能格式化PFAT。

(2)挂载GOSFS操作:GOSFS_Mount()函数,目的是挂载mountPoint指向的文件系统。

        该操作首先初始化内存中的GOSFS_Superblock,之后初始化Mount_Point,最后创建一个空目录,通常规定为/d。具体操作为,首先建立一个新的高速缓冲区(缓冲区的存取的互斥的),标记超级块,以及超级块里的数据,利用超级块结构体下的magic变量,进行魔数检查,验证是否为GOSFS文件系统,若检查是,则释放缓冲区,并创建文件系统实例(创建GOSFS文件系统的空目录)。

        据所掌握的信息可知,GOSFS_Mount操作负责将一块GOSFS格式的磁盘挂载到GeekOS。这个操作必须在磁盘访问操作进行之前完成。挂载操作首先初始化内存中的实体超级块,之后初始化虚拟超级块,最后初始化GOSFS根目录“d”。挂载操作成功完成后,文件系统就可以访问超级块与文件系统根目录,并完成相应操作。

(3)高速缓冲区操作:其实际上是开内存上开辟一个空间,使数据读写时通过该缓冲区,即使得一部分保留在内存当中。当然,在高速缓冲区(内存)中读写数据明显要比在磁盘中读写数据要快得多。并且,缓冲区的存取的互斥的,保证了数据的正确性和安全性。

        高速缓冲区的使用需要经过申请-修改-释放三个步骤,其在bufcache.c文件中有所定义,Create_FS_Buffer_Cache()函数为创建一个新的缓冲区,Get_FS_Buffer()函数为调用该创建的缓冲区,并带有代码Mutex_Lock(&cache->lock)(表示在缓冲区上加锁),也就是确保缓冲区的存取互斥,等待Get_Buffer函数调用成功后,既可释放锁。其Modify_FS_Buffer()函数为修改缓冲区操作,Sync_FS_Buffer()函数为同步缓冲区操作,而Release_FS_Buffer()函数为释放缓冲区操作。

(4)挂载点、索引以及重要关联文件(目录)结构体介绍

        a.挂载点:gosfs.c文件下有一个很重要的内容,就是挂载点Mount_Point,其Mount_Point结构体在vfs.h中有定义,作为挂载点,是进行文件操作的关键对象。

        其Mount_Point结构体中,包含了Mount_Point_Ops数据结构(与各种基本文件操作相关),而辅助基本文件操作的指针则存储在该定义下的fsData变量之中。

        Mount_Point挂载点也是辅助格式化并挂载完成GOSFS文件系统,即创建文件及目录。

        b.Inode索引:GOSFS文件系统使用inode形式,在每一个目录下分配一个inode,inode表示目录条目的数量,而非物理大小。而读文件即可通过inode文件索引来找到所需的目录,inode可保存目录和文件到相关信息,其中,有blockLisas成员数组记录了文件数据块指针。

        c.关联文件结构体:利用该结构体可有效关联文件的基本操作

static struct File_Ops s_gosfsFileOps = {//文件

    &GOSFS_FStat,

    &GOSFS_Read,

    &GOSFS_Write,

    &GOSFS_Seek,

    &GOSFS_Close,

    0, /* Read_Entry */

    &GOSFS_Clone,

};

        d.关联目录结构体:利用该结构体可有效关联目录的基本操作

static struct File_Ops s_gosfsDirOps = {//目录

    &GOSFS_FStat_Directory,

    0, /* Read */

    0, /* Write */

//  0, /* Seek */

    &GOSFS_Seek,

    &GOSFS_Close_Directory,

    &GOSFS_Read_Entry,

};

(5)读写操作:通过读写操作来分析具体过程。

        了解写操作,GOSFS_Write()函数,针对写操作,首先对其上锁,防止读写同步操作,污染数据或者读到脏数据,检查写操作是否被允许,若被允许写入时,计算需要写入的数据块(即赋值初始数据块、起始数据块地址、末尾数据块),后将文件中的数据按块的方式写入新块。

        在写入时使用循环的方式利用CreateFileBlock函数分配空间,并利用GetPhysicalBlockByLogical函数,即通过块的线性地址得到块的物理地址,计算开始写入的物理地址,利用Get_FS_Buffer缓冲区写入数据,当然,写完记得释放缓冲区,同时,使inode信息和文件描述符保持最新,并释放锁。最后,返回写好完毕的指令。

        而读操作,与写操作类同。

       其是从给定文件的当前位置读数据。首先了解下GOSFS_FileEntry结构体(在gosfs.h头文件中),其中定义着文件索引以及文件对象(对象中包括锁和缓冲区),即inode文件索引、instance文件对象(GOSFS_Instance结构体)。

        首先对其上锁(即instance文件对象中的锁),防止读写同步操作,污染数据或者读到脏数据,检查读操作是否被允许,若被允许读出时,检查文件指针是否在文件尾,通过循环的方式,从块头到块尾查找,并标记实际地址。同样,利用Get_FS_Buffer缓冲区读出数据,读取完释放缓冲区,并将指针更新读到的地方,至此,具体读操作完成。

(6)其它文件操作:举例目录方面的具体操作。

        a.创建一个指定路径的目录,GOSFS_Create_Directory()函数中实现。有定义目录结构GOSFS_Directory、高速缓冲区FS_Buffer、文件对象GOSFS_Instance。

        首先,将挂载点的信息mountPoint->fsData复赋值于该文件对象GOSFS_Instance,上锁,获取存储空间,并获取所指定路径,从路径中删除文件名,并清空已有索引。检查是否已经存在该路径下的目录,若无,则标记好索引,并对文件对象进行适当的填充,最后,释放锁。

        b.删除有给定路径命名的文件或目录,与其创建的操作类同(当然,首先必须先找到给定路径,检查是否存在)。

        c. 从打开的目录中读取目录项,GOSFS_Read_Entry()函数中实现。

        必须知道的是,在每个创建的目录下,都会有一个独特的索引inode、类型type以及里头所定义的文件名(可查看GOSFS_Directory结构体,在gosfs.h文件中)。

        在该函数中,主要使用了两个标准C库函数strcpy()和memcpy(),此两函数区别在于strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。

        利用strcpy()复制目录下所有的文件名,而memcpy()则复制目录下的索引信息。

2.6.5运行输出分析结果

原有文件格式为PFAT系统

测试文件格式化:format ide1 gosfs

挂载GOSFS文件:mount ide1 /d gosfs

显示所有文件:ls /d

创建文件夹:mkdir /d/xxx

创建文件:touch /d/xxx

删除文件夹或者文件:rm /d/xxx

1.格式化与挂载GOSFS文件系统

(2)显示所有文件

 (3)创建文件夹以及文件

(4)删除文件夹以及文件

 

 

2.6.6解决作业问题

(1)GeekOS系统原始的文件系统是什么格式?

        原始的文件系统是PFAT文件系统。

(2)在GeekOS系统中,如何注册挂载一个新的文件系统?

        GOSFS_Format()和GOSFS_Mount()两个函数,前者先格式化硬盘,后者主要用于挂载到GeekOS上。

(3)在新文件系统中,文件目录项如何设置?

        每个目录分配一个inode,表示目录条目的数量,而不是物理大小,具体的内容仅由inode的直接块指针引用,创建目录项实体,主要涉及GOSFS_Dir_Entry结构体,其中保存了目录和文件的相关信息,其中的blockLisas数组记录了文件数据块指针。

(4)在新文件系统中,如何创建一个文件?

        通过调用自定义Find_InodeByName()子函数检查文件是否存在,如果文件不存在,再进行写操作的检查,允许写操作则调用CreateFileINode()函数来创建inode节点,其中进行搜索根节点和间接节点的操作;如果文件存在,则调用vfs.c中内置的Allocate_File()分配文件对象,其中文件对象参数s_gosfsFileOps关联了文件相关操作&GOSFS_Write(),&GOSFS_Read(),&GOSFS_Seek(),&GOSFS_Clone()等,最后返回该文件指针。

        也可以认为是,先通过Find_InodeByName()判断文件是否存在,存在了就不能拿这个名创建,不存在就可以创建文件,先用CreateFileINode()函数来创建inode节点,接着创建文件实体,接着把文件实体的信息赋值好,接着通过Allocate_File()分配文件对象,最后返回该文件指针。

(5)在新文件系统中,如何读写一个文件?

        写文件操作:检查写操作是否允许被执行,接着计算需要写入的数据块startblock以及写入起始地址startblockOffset,for循环计算需要写入的数据块数量,每一次循环调用CreateFileBlock()分配空间,通过GetPhysicalByLogical()函数来计算开始写入的物理地址,最后通过Get_FS_Buffer()函数写数据,结束循环后更新inode节点的状态信息读文件操作:检查读操作是否允许被执行,再检查文件指针是否在文件尾,遍历开始块到结束块,计算开始读的物理地址,将数据读入缓存,最后不用时记得释放缓存。

(6)在新文件系统中,文件的目录结构如何设置?

        文件的目录结构分为直接块、间接块还有二级间接的方式。

(7)在新文件系统中,如何给一个文件分配磁盘空间?

        以块的形式给一个文件分配磁盘空间。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值