山东大学软件学院操作系统课程设计Nachos-实验四-基本文件系统扩展

说明:blog 中写到的这几个实验,不全面而且也不是上交实验报告的最终版本(是自己实验过程中用typora简单记录的笔记),完整内容(含代码+实验报告)可以通过(山东大学软件学院操作系统课设)下载,或者关注“陌兮blog”免费获取
山东大学软件学院操作系统课程设计Nachos-实验四-基本文件系统扩展_第1张图片

一、文件系统分析

查看 /filesys/filesys.cc 中文件系统的构造函数,可以发现以下信息

#define FreeMapSector 		0
#define DirectorySector 	1
#define FreeMapFileSize 	(NumSectors / BitsInByte)
#define NumDirEntries 		10
#define DirectoryFileSize 	(sizeof(DirectoryEntry) * NumDirEntries)

FileSystem::FileSystem(bool format)
{ 
    if (format) {   // 是否应该初始化磁盘
      BitMap *freeMap = new BitMap(NumSectors); // 创建文件位图
      Directory *directory = new Directory(NumDirEntries); // 创建包含10个文件目录项的文件目录表
      FileHeader *mapHdr = new FileHeader; // 创建文件位图的文件头
      FileHeader *dirHdr = new FileHeader; // 创建文件目录表的文件头
      
      // 第一步:文件位图中标记0、1号扇区被占用
      freeMap->Mark(FreeMapSector);		// 0号扇区为文件位图文件头
      freeMap->Mark(DirectorySector); // 1号扇区为文件目录表文件头

			// 第二步:在文件系统中分配位图文件与文件目录表的空间(传入文件位图与空间大小)
      ASSERT(mapHdr->Allocate(freeMap, FreeMapFileSize));   // 位图文件大小为128字节,1个扇区
      ASSERT(dirHdr->Allocate(freeMap, DirectoryFileSize)); // 十个文件目录项大小

			// 第三步:将更新后的位图文件头、文件目录表文件头写入磁盘
      mapHdr->WriteBack(FreeMapSector);   // 传入对应文件头所在扇区号
      dirHdr->WriteBack(DirectorySector);

      // 第四步:创建位图文件、文件目录表的Openfile, Openfile中存储文件头与文件读写位置
      freeMapFile = new OpenFile(FreeMapSector);			// 传入文件头所在扇区, 用于创建Openfile文件头
      directoryFile = new OpenFile(DirectorySector);	// 文件读写位置初始为0
     
			// 第五步:将位图文件信息、文件目录项信息传入对应Openfile中
      freeMap->WriteBack(freeMapFile);	 // 确定Openfile的起始扇区与结束扇区,开辟文件缓冲区
      directory->WriteBack(directoryFile); // 初始化整个文件
    } else {
      // 非初始化操作,则根据原有位图文件头、文件目录表文件头信息初始化Openfile
      freeMapFile = new OpenFile(FreeMapSector);
      directoryFile = new OpenFile(DirectorySector);
    }
}

其中主要包含了位图文件、文件目录表的文件头、Openfile的创建,并将初始化信息写入磁盘。其中位图文件用每位的0、1来表示磁盘该位置是否空闲,分配时从前开始找,一旦有空位则直接分配。另外,从上面文件系统创建的部分可以发现,当文件创建后其大小则无法改变

我们接下来需要自行实现的两个文件命令,-ap、-hap

nachos [-d f] -ap UNIX_filename nachos_filename:表示将一个 UNIX 文件内容添加到 nachos 文件的末尾。
nachos [-d f] -hap UNIX_filename nachos_filename:表示将一个 UNIX 文件内容从 nachos 文件的中间部分开始向后添加并覆盖 nachos 文件的后半部分。

二、文件系统扩展

1、老版本

nachos -ap 与 -hap 命令的实现

首先观察一下 main.cc 中是如何实现 nachos -ap 命令的

else if (!strcmp(*argv, "-ap")) {  // append from UNIX to Nachos
    ASSERT(argc > 2);
    Append(*(argv + 1), *(argv + 2), 0);
    argCount = 3;
}

可以发现 “-ap” 的命令调用了函数 Append(),而该函数主要调用的是 OpenFile::Write()

OpenFile::Write(char *into, int numBytes)
{
   int result = WriteAt(into, numBytes, seekPosition);
   seekPosition += result;
   return result;
}

OpenFile::Write() 调用的是 OpenFile::WriteAt(),因此我们接下来考虑如何修改 OpenFile::WriteAt() 函数来实现该功能。

对原有 WriteAt 函数的分析可以看到,原有函数并不支持写入的数据超过其文件原有大小,因此我们现在需要修改该函数。

// 检查输入是否合法以及避免输入数据超过文件大小
if ((numBytes <= 0) || (position >= fileLength))  // For original Nachos file system
    //if ((numBytes <= 0) || (position > fileLength))  // For lab4 ...
    return 0;				
// check request
if ((position + numBytes) > fileLength)
    numBytes = fileLength - position;

接下来实现这两个命令

大概的思路就是要修改 WriteAt 方法,如果说写入的数据超出了文件的大小,那么进行扩展,再申请新的内存空间。然后调用 OpenFile 的 WriteBack 函数写回磁盘,这个函数通过调用 filehdr 的 WriteBack 方法实现数据的写回操作,我们需要将修改后的文件头写回硬盘时,需要获取该文件头所在扇区号,因此我们在 OpenFile 类中增加一个 sector 变量用于记录该文件头所在扇区号。

首先来实现 ExtendSpace 函数,修改文件大小的方法,完成对文件的扩展,并能够根据文件大小为其分配足够大的扇区。

首先在文件 fileheader.h 中类定义中添加了方法 bool ExtendSpace(int newSize); 然后在文件 fileheader.cc 中实现 FileHeader::ExtendSpace 方法

实现思路:首先根据数据大小判断是否需要扩展数据扇区,这里有两种情况,若不需要,就简单地修改文件大小,若需要,就分配扇区,然后再修改大小。

bool
FileHeader::Extend(int newSize)
{
    if(newSize<numBytes)return FALSE;   //if not a extend operation
    if(newSize==numBytes)return TRUE;   //if size not change
	//计算所需的空间
    int newNumSectors  = divRoundUp(newSize, SectorSize);   //the number of sectors the new size need to be allocated.
    //如果所需空间等于numSectors(原有的空间)
    if(newNumSectors == numSectors){
        //设置一下大小
        numBytes = newSize; 
        return TRUE; 
    }
	//否则计算一下还需要申请的空间
    int diffSector = newNumSectors - numSectors;    
	
    OpenFile *bitmapfile = new OpenFile(0);
    BitMap *freeMap;//新建一个位图
    freeMap = new BitMap(NumSectors);
    freeMap->FetchFrom(bitmapfile);//从磁盘中取出位图
	printf("debug in fhdr extend where new Sector=%d \n",freeMap->NumClear());
    //if disk is full or file size is too big.
    if(newNumSectors>NumDirect||freeMap->NumClear()< diffSector)return FALSE;   
	//申请新的空间,并且存储到文件头
    int i;
    //i从numSectors到newNumSectors,即循环diffSector次
    for(i = numSectors; i<newNumSectors; i++)
    {
        dataSectors[i] = freeMap->Find();
    }
    numBytes = newSize;
    numSectors = newNumSectors;

    return TRUE;
}

接下来实现 WriteBack() 方法:

在文件 openfile.h 类定义中添加方法声明 void WriteBack(); ,然后添加属性 int sector; ,用于记录该文件头所在扇区号

class OpenFile {
  public:
 
//2021.11.21add+++++++++++++++++++++++++++++++++++
	void WriteBack();
//2021.11.21add+++++++++++++++++++++++++++++++++++
private:
  
//2021.11.21add++++++++++++++++++++++++++++++++
	int sector;
//2021.11.21add++++++++++++++++++++++++++++++++

在文件 openfile.cc 构造方法中添加 this->ector = sector; 。

OpenFile::OpenFile(int sector)
{ 
//2021.11.21add++++++++++++++++++++++++++++++++++++++++
	this->sector = sector;
//2021.11.21add++++++++++++++++++++++++++++++++++++++++

WriteAt 方法中修改对于 (position + numBytes) > fileLength 的处理

//2021.11.21add++++++++++++++++++++++++++++++++++++++++
//    if ((numBytes <= 0) || (position >= fileLength))  // For original Nachos file system
    if ((numBytes <= 0) || (position > fileLength))  // For lab4 ...
		return 0;	

	// check request
    if ((position + numBytes) > fileLength)
		//numBytes = fileLength - position;
		hdr->ExtendSpace(position+numBytes);
//2021.11.21add++++++++++++++++++++++++++++++++++++++++	

实现方法 OpenFile::WriteBack ,通过调用 filehdr 的 WriteBack 方法实现数据的写回操作

void
OpenFile::WriteBack()
{
    hdr->WriteBack(sector);
}

最后一步就是按照实验指导书上所提及的,去除掉fstest.cc 中 Append 方法的 openfile->WriteBack() 前面的注释。

//2021.11.21add++++++++++++++++++++++++++++++++++++++++
//  Write the inode back to the disk, because we have changed it
  openFile->WriteBack();
  printf("inodes have been written back\n");
//2021.11.21add++++++++++++++++++++++++++++++++++++++++

2、验收版本

首先需要实现openFile类的WriteBack方法,添加成员变量hdrSector用于记录该文件头所在扇区号,并按照实验指导书上所提及的,去除掉fstest.cc 中 Append 方法的 openfile->WriteBack() 前面的注释。

在openfile.h文件中的openFile类里面添加WriteBack方法

//lab4 add++++++++++++++++++++++++++++
void WriteBack();

添加私有成员变量hdrSector

private:
	//lab4 add+++++++++++++++++++++++++++++
	int hdrSector;

然后在openfile.cc 中实现WriteBack方法

//lab4 add++++++++++++++++++++++++++++
void
OpenFile::WriteBack()
{
    hdr->WriteBack(hdrSector);
}

在openfile.cc文件中的openFile类构造方法中初始化成员变量hdrSector

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BhJ6VjBD-1642243978465)(实验报告.assets/image-20211211200655906.png)]

去除掉fstest.cc 中 Append 方法的 openfile->WriteBack() 前面的注释。

//lab4 add++++++++++++++++++++++++++++
// Write the inode back to the disk, because we have changed it
openFile->WriteBack();
printf("inodes have been written back\n");

接下来实现文件扩展方法ExtendSpace

在filehdr.h文件中的FileHeader类里面添加ExtendSpace方法

//lab4 add++++++++++++++++++++++++++++  
bool ExtendSpace(OpenFile *bitmapfile,int newSize);

然后在filehdr.cc文件实现ExtendSpace方法

//lab4 add++++++++++++++++++++++++++++
bool
FileHeader::ExtendSpace(OpenFile *bitmapfile,int newSize)
{
	//计算所需扇区
    int newNumSectors  = divRoundUp(newSize, SectorSize);
	//不需扩展,直接更新文件头信息
    if(newNumSectors == numSectors){
        numBytes = newSize; 
        return true;   
    }
	//需要扩充的扇区数量
    int diffSector = newNumSectors - numSectors;    
	
    BitMap *freeMap = new BitMap(NumSectors);
    freeMap->FetchFrom(bitmapfile);
	
	//超出一级索引||空间不足
    if(newNumSectors>NumDirect||freeMap->NumClear()< diffSector){
		return false;   
    }
	//分配新扇区,并更改文件头信息
    for(int i = numSectors; i<newNumSectors; i++)
    {
        dataSectors[i] = freeMap->Find();
    }
    numBytes = newSize;
    numSectors = newNumSectors;
    return true;
}
//lab4 add+++++++++++++++++++++++++++++++++++++++++

最后修改openfile.cc文件中的openFile类的WriteAt函数,判断文件是否需要扩展,如果需要扩展则调用ExtendSpace方法进行文件扩展

山东大学软件学院操作系统课程设计Nachos-实验四-基本文件系统扩展_第2张图片

你可能感兴趣的:(山东大学软件学院课程设计,os,操作系统,ubuntu,山东大学软件学院,nachos)