[Nachos-3.4] Lab4-filesystem

Objectives

The purpose of this laboratory session is to study the functionality of the file system in Nachos. The file system in Nachos is designed to be small and simple so that you can read all its source code in a short period of time. Before starting to read the code, it is very useful to get an idea of what functionality the Nachos file system offers. In this laboratory session, you will run the commands of the Nachos file system and watch the effects on the simulated hard disk in Nachos. On the completion of this laboratory session, you should know

    • what is the functionality of the Nachos file system, and

    • how to examine the contents of the simulated hard disk in Nachos.

Preliminary preparation

  • Learn about bitmap

       参考:https://blog.csdn.net/pipisorry/article/details/62443757?utm_source=itdadao&utm_medium=referral

       所谓的bitmap就是用一个bit位来标记某个元素对应的value,而key即是该元素。由于采用了bit为单位来存储数据,因此在存储空间方面,可以大大节省空间。文件系统中用bitmap来映射块空间,bitmap中1表示块被占用,0表示空闲块。

[Nachos-3.4] Lab4-filesystem

       像上述的bitmap可以被称作空间磁盘块分配表,其以文件的形式存储,头文件位于文件目录的第0项。每一个bit对应磁盘中的一个块的使用情况,0表示空闲,1表示已分配。

Note: Block number的计算

[Nachos-3.4] Lab4-filesystem

       此外,在nachos中,文件目录是以文件的形式存储,头文件位于文件目录的第1项。是由nachos中directory类生成的。directory的项是<name,sector>的pair,用于文件名->磁盘块的索引,找到的是文件头部所在的磁盘块。

  • Learn about Ext2

       参考:https://www.cnblogs.com/bellkosmos/p/detail_of_linux_file_system.html
 

  • Reading the source code

  1. Filesys.h(cc)

         概述:定义了一个filesystem类,包括了对nachos filesystem的初始化函数,以及若干个对nachos filesystem中某个文件的操作函数。

- FileSystem(bool format)

filesystem构造函数。用于创建或者载入一个文件系统。

当format为true时会初始化filesystem(相当于格式化了文件系统),使用新的空闲磁盘块分配表以及新的文件目录。否则仅仅载入原来存在的空闲磁盘块表以及文件目录。

- bool Create(char *name, int initialSize)

用于在文件系统中创建文件,name为文件名,initialSize为文件初始长度

1)从磁盘载入空闲磁盘块分配表文件和文件目录文件(通过bitmap和directory->FetchFrom(sector)实现;               bitmap->find(name)用来检测文件是否已存在,如果存在则返回-1)

2)为新文件创建文件头部(filehdr):找到一个空闲磁盘块(通过bitmap->Find()实现,如果没有空闲的块空间,则返回-1,否则返回空闲磁盘块的sector号);将头文件信息写入目录文件(directory->add(name,sector));

3)将文件块的信息写入文件头部:文件被切分成若干个文件块,并在文件头部记录每个文件块位于磁盘的哪个sector(通过filehdr->Allocate(bitmap,initialSize)实现)

4)将更新了的空闲磁盘块分配表文件和文件目录文件写回磁盘(通过bitmap和directory->WriteBack(sector)实现)

- OpenFile * Open(char *name)

用于在文件系统中打开文件,name为文件名

1)从磁盘载入文件目录

2)在文件目录中,通过文件名,查找文件头部对应的磁盘号(directory->Find(name))

3)如果存在,打开文件头部,并返回一个openfile类的指针(通过new一个openfile类实现)

- bool Remove(char *name)

用于在nachos文件系统中移除文件,name为文件名

1)从磁盘载入空闲磁盘块分配表文件和文件目录文件

2)将文件块从磁盘中移除(fileHdr->Deallocate(bitmap))

3)将文件头部从磁盘中移除(bitmap->clear(sector))

4)将文件从文件目录中移除(即清除pair<name,sector>)(directory->Remove(name))

5)将更新了的空闲磁盘块分配表文件和文件目录文件写回磁盘

- void List()  and void Print()

打印nachos文件系统的相关信息,包括磁盘块分配状况,文件目录情况,以及存在的文件的详细情况等。

 

    2. Filehdr.h(cc)

       概述:定义了一个FileHeader类,模拟文件头部。私有变量包括文件长度,文件占用的磁盘块个数以及数组dataSectors[NumDirect],其模拟了 <文件块,磁盘块>的对应关系。类内还定义了对文件块的分配、回收等函数。由于nachos的文件系统只支持定长文件,因此文件的信息在初始化的时候就确定了,文件头的信息在文件使用过程中不会发生改变,类似于只读。

- bool Allocate(BitMap *bitMap, int fileSize)

为文件块分配磁盘块,bitMap为空闲磁盘块分配表指针,fileSize为文件长度

1)更新私有变量:文件长度和文件占用的磁盘块个数(divRoundUp(fileSize, SectorSize),文件长度/一个磁盘块大小)

2)为文件块分配对应的磁盘块。(bitmap->Find())——注意:此时磁盘块仅仅是分配了,但是并没将文件写入。

- void Deallocate(BitMap *bitMap)

将分配的磁盘块回收,bitMap为空闲磁盘块分配表指针

利用for循环遍历数组dataSectors,因其表示<文件块,磁盘块>的关系,所以可以通过遍历将每个文件块对应的磁盘块的占用标记清除(通过bitmap->Clear()函数实现)

- void FetchFrom(int sectorNumber)

从磁盘中载入一个文件头部,sectorNumber为要载入的磁盘块sector号

调用synchDick->ReadSector(sector,(char *)this)函数,将sector对应的磁盘块内容读入,覆盖自己(类似于构造函数)

- void WriteBack(int sectorNumber)

将当前文件头部写回磁盘,和FeychFrom执行相反操作

- int ByteToSector(int offset)

读入文件中偏移为offset的位置的磁盘块

1)计算出偏移量对应的文件块

2)通过私有变量数组,找到文件块对应的磁盘块

3)返回磁盘块的磁盘号

-  int FileLength()

返回文件大小

- void Print()

打印文件头部信息

 

     3.Directory.h(cc)

     概述:定义了两个类,一个是DirectoryEntry,一个是Directory。DirectoryEntry类有三个成员变量,分别是bool inUse, int sector, char name[FileNameMaxLen + 1],用来模拟<文件名,磁盘号>的对应关系,以及标记当前entry是否被使用了。(Note:DirectoryEntry类所表示的对应关系与filehdr文件里的dataSectors数组所表示的对应关系不同,dataSectors数组表示的是某个文件所有内容所映射的磁盘块,而此处的DirectoryEntry类表示的是某个文件的文件头部映射的磁盘块)。Directory类模拟文件目录,私有变量包括tableSize(entry的数量)和一个DirectoryEntry的数组。目前只实现了一级目录索引,最多只支持10个文件头部的存放。

- Directory(int size)

Directory类构造函数,用来初始化私有变量,并且初始化DirectoryEntry数组全为false(即未使用)

- void FetchFrom(OpenFile *file)

从文件目录文件中载入directory

通过调用参数OpenFile的ReadAt函数,将文件目录文件的内容覆盖自己(类似于构造函数)

- void WriteBack(OpenFile *file)

将当前文件目录写回目录文件

通过调用OpenFile的WriteAt函数,将当前directory写回目录文件

- int Find(char *name) and int FindIndex(char *name)

在DirectoryEntry数组中查找名字对应的文件头部磁盘块,name为文件名

利用for循环比对文件名字,如果找到对应的文件名字则返回磁盘块的磁盘号,找不到则返回-1

- bool Add(char *name, int newSector)

将一个<文件名,文件头部磁盘块的磁盘号>的条目加入DirectoryEntry数组中。name为文件名,newSector为文件头部磁盘块的磁盘号。

修改对应的DirectoryEntry数组的标识位。

- bool Remove(char *name)

和add执行相反的功能

- void List() and void Print()

打印Directory的信息

 

     4.openfile.h(cc)

       概述:定义了一个OpenFile类,用于对文件执行基本操作:读和写。私有变量为FileHeader *hdr文件头部指针,int seekPosition记录当前文件的光标位置

- OpenFile(int sector)

OpenFile构造函数,初始化私有变量。sector为文件头部的磁盘块号。

文件头部的指针通过hdr->FetchFrom(sector)载入磁盘内容,设置初始光标位置seekPosition为0

- void Seek(int position)

将当前光标位置设置为传入的参数

- int Read(char *into, int numBytes)

读入若干个字节到一个数组里,into为返回的内容的数组,numBytes为需读入的字节数

1)调用ReadAt(buffer,字节数,当前光标位置)读入若干字节到buffer当中

2)更新光标位置

3)返回内容数组

- int Write(char *from, int numBytes)

写入若干字节到磁盘中,from为需写入的内容数组,numBytes为写入的字节数

步骤同Read函数,只是将ReadAt变成了WriteAt

- int ReadAt(char *into, int numBytes, int position)

从当前光标位置读入若干字节到一个数组当中,into为返回数组,numBytes为字节数,position为当前光标位置

1)获取文件长度(hdr->FileLength())

2)确定当前光标位置所在的文件块(divRoundDown(),通过“光标位置/一个sector的大小”向上取整实现)

3)确定需读入的最后一个字节所在的文件块(divRoundDown(),通过“光标位置+读入字节/一个sector的大小”向上取整实现)

4)计算一共需要访问的磁盘快个数(通过2、3)步做差实现)

5)将文件块对应的磁盘块内容读入数组当中(通过私有变量hdr->ByteToSector函数,得到文件块-磁盘块的映射)

6)将真正需要的字节从数组当中取出(由于事实上所需要的字节不一定位于块的头,可能要从某个中间位置截断)

[Nachos-3.4] Lab4-filesystem

- int WriteAt(char *from, int numBytes, int position)

从当前光标位置开始写入若干字节,操作步骤基本上同

- int Length()

获取文件长度,通过私有变量hdr->FileLength()获得

  • Things to Do 

  1. Compiling Nachos File System
    Move to the directory  ../filesys  and execute command make . A new version of Nachos with its file system included will be made in the directory.
  2. Testing Nachos File System
    Execute the following commands and check the results as described:

    (a) Execute ./nachos -f. Nachos should have created the simulated hard disk called DISK in your current directory.
    (b) Execute ./nachos -D to dump the whole file system on the simulated hard disk DISK and you should have the following dump:

    ....
    FileHeader contents. File size: 128. File blocks: 2 File contents: \1f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
    \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 Directory file header: FileHeader contents. File size: 200. File blocks: 3 4 File contents: \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
    Bitmap set: 0, 1, 2, 3, 4,
    Directory contents:

    Directory contents:

    No threads ready or runnable, and no pending interrupts.
    Assuming the program completed.
    Machine halting!
    Ticks: total 5500, idle 5030, system 470, user 0
    Disk I/O: reads 10, writes 0
    Console I/O: reads 0, writes 0
    Paging: faults 0
    Network I/O: packets received 0, sent 0

    Cleaning up...

    We have deleted the output from function ThreadTest() in the above dump. You can get rid of them by making a copy of ../threads/main.cc in your current ../filesys directory and comment out the line of invoking function ThreadTest(). This dump shows that the Nachos file system has been created on DISK. There are no files at the moment in the only directory of the Nachos file system. 
    [Nachos-3.4] Lab4-filesystem
    [Nachos-3.4] Lab4-filesystem
    (c) Execute od -c DISK and you should have the following dump on the screen:

    0000000 211 g E 200 \0 \0 \0 001 \0 \0 \0 002 \0 \0 \0
    0000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 *
    0000200 \0 \0 \0 \0 \0 \0 \0 002 \0 \0 \0 003 \0 \0 \0
    0000220 004 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
    0000240 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 *
    0000400 \0 \0 \0 \0 037 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
    0000420 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0

    You can also execute od -A d -c DISK and you can see that the address is decimal
    [Nachos-3.4] Lab4-filesystem

    (d) Execute ./nachos -cp test/small small to copy file small into the Nachos file system.
    Use ./nachos -l, ./nachos -p <filename> and ./nachos -D to make sure you do create a new file named small in the Nachos file system.
    Watch the dump of od -c DISK or od -A d -c DISK again to see what has been changed.

    (e) Continue the experiment with other nachos commands such as nachos -r on more files.
  • Questions

  1. According to the result of the last command ./nachos -D and the result of od -c DISK, how many files are there on the hard disk DISK?
    在删除文件后,通过指令 ./nachos -D 可以看到文件系统内只剩下位图文件头文件(sector 0)、位图文件(sector 2),文件目录头文件(sector 1)和文件目录(sector 3,4),而通过指令 od -c DICK 可以看到之前文件的内容依旧保存在DISK中。这是因为Nachos模拟的文件系统是通过bitmap中bit位是否被占用来判断是否有空间或文件存在,在创建文件的时候,找到合适的空闲位置后,便将content写入实际的disk中,并在对应的bit位标记已被使用;在删除文件的时候并没有实际删除disk中的content,而是将该文件占用的bit位修改成未使用。可以通过先创建一个big文件再删除big文件,然后再创建一个small文件或者medium文件,通过od -c DICK指令可以看到新创建的文件覆盖了被删除的文件的位置。
  2. What are the sector numbers of data blocks for file big?
    5块
  3.  What is the sector number of the disk to store the file header for file big?
    头文件的sector是第一个data block的前一个,头文件单独占1个sector
  4.  The sector size of the Nachos hard disk is 128 bytes. Could you check the result of od -c DISK to make sure that the data blocks and the file header of big are in the right places in the disk?
    yes