操作系统课设实验五---Nachos文件系统扩展
這次的實驗讓我想起了上學(xué)期被操作系統(tǒng)的九個實驗支配的恐懼,因為這次可能也是前五次試驗中最難的一次了,讀源碼加實現(xiàn)花了可能一兩天的時間,所以也有必要記錄一下,有些地方做的不是很好,比如Makefile自己寫的話可能不需要把所有文件都從filesys復(fù)制到lab5,可是我太菜做不到,所以先這樣湊合著吧emmm,畢竟還有一堆其他實驗。
一、實驗要求重述
目標(biāo)
在lab5目錄下,通過對nachos源代碼的修改,實現(xiàn)可擴展的文件系統(tǒng),即滿足以下需求
- 當(dāng)一個文件創(chuàng)建的時候,它的初始大小為0
- 文件的大小可以在文件內(nèi)容增加時改變
如:100 bytes大小的文件在50 bytes的位置往后再寫100個byte,文件大小變?yōu)?50 bytes.
設(shè)計與實現(xiàn)的提示
取消最后兩行的注釋即可。此外,在取消注釋之后還需要在OpenFile的類中實現(xiàn)Writeback方法。
二、分析
首先我們需要分析nachos文件部分的源代碼,一方面是要了解那七個文件的用法,另一方面要閱讀測試使用的main. cc和fstest. cc,通過閱讀源碼,我們才能達(dá)到盡可能少的修改源碼來實現(xiàn)功能的目的。
通過對這些源碼的閱讀以及實驗指導(dǎo)書的提示,首先我們需要修改OpenFile這個類,要實現(xiàn)它的WriteBack方法,這個方法的作用是將大小改變的文件頭信息寫回磁盤。其次在寫的方法上我們也要進行修改,那就是該類的WriteAt方法,而因為這里的邏輯是假設(shè)文件大小固定,因此我們需要為它添加一個申請新的磁盤空間的方法,這里我在OpenFile類新建了一個AllocateSpace方法。但在實際申請磁盤空間的時候,應(yīng)該需要在FileHeader類中進行,因此我們?yōu)槠湓黾右粋€ExtendSpace方法。最后,在文件大小變化的時候,應(yīng)該修改FileHeader類中的numBytes的值,因此我們需要添加一個set方法SetLength。這一切就緒之后,就可以依次實現(xiàn)這些方法了。
ps:原來我在AllocateSpace方法中是直接先釋放所有磁盤空間再申請新空間來實現(xiàn)擴容的,經(jīng)過小伙伴指正我也發(fā)現(xiàn)這樣確實不行,如果內(nèi)容存儲扇區(qū)之前的扇區(qū)空間都被別的內(nèi)容占用的話的沒有問題,可是如果有空扇區(qū)的話,申請之后文件頭信息中指向的內(nèi)容扇區(qū)就會和實際存儲的扇區(qū)有偏差。
至少之前的設(shè)計是有問題的,可以用以下命令實驗下試試
之前的結(jié)果:
現(xiàn)在的結(jié)果
三、實現(xiàn)
首先來說FileHeader類中的SetLength方法,我們只需要簡單的設(shè)置即可,因此它的代碼也非常簡單,如下:
void FileHeader::SetLength(int length) {this->numBytes=length; }下一步來實現(xiàn)相對簡單一點的OpenFile類中的WriteBack方法,這里我們要把其內(nèi)部的FileHeader類型的成員hdr寫回到磁盤中,FileHeader內(nèi)部實現(xiàn)了寫回磁盤的方法,但是它需要扇區(qū)參數(shù),而在這個OpenFile類中這個值并不好取得,因此我們再給OpenFile類增加一個私有成員sector,并在其構(gòu)造函數(shù)中利用傳入的頭信息扇區(qū)號來初始化。如下:
OpenFile::OpenFile(int sector) { hdr = new FileHeader;hdr->FetchFrom(sector);seekPosition = 0;this->sector=sector; }這樣,我們就能在WriteBack方法中拿到扇區(qū)號了。如下:
void OpenFile::WriteBack() {hdr->WriteBack(sector); }然后,我們就只剩下OpenFile類中的AllocateSpace與WriteAt函數(shù)和FileHeader類中的ExtendSpace函數(shù)需要完成了。
由于OpenFile類里面的兩個函數(shù)的實現(xiàn)都需要使用到ExtendSpace函數(shù)的功能,因此這里首先來實現(xiàn)這個函數(shù),這個函數(shù)模仿Allocate函數(shù)實現(xiàn),需要做的就是根據(jù)要申請的空間大小和比特圖來申請新的磁盤扇區(qū)空間。如下:
bool FileHeader::ExtendSpace(BitMap *freeMap,int appendSize) {int oriSectors=numSectors; //記錄原空間大小numSectors = divRoundUp(appendSize, SectorSize)+oriSectors; //計算新扇區(qū)大小 // printf("newSectorsNum is %d\n", numSectors);if (freeMap->NumClear() < numSectors-oriSectors){numSectors=oriSectors;//將空間大小復(fù)原return FALSE; // not enough space}for (int i = oriSectors; i < numSectors; i++) //申請新的扇區(qū)dataSectors[i] = freeMap->Find();return TRUE; }在WriteAt函數(shù)中需要調(diào)用AllocateSpace函數(shù),所以首先應(yīng)該來實現(xiàn)AllocateSpace函數(shù):
這個函數(shù)的功能應(yīng)該是給它一個需要擴展的文件長度,它就能申請到這個長度對應(yīng)的扇區(qū)來進行以后的存儲,而具體的申請操作在OpenFile類的FileHeader類型的hdr成員已經(jīng)實現(xiàn)了,這里可以直接調(diào)用它來做:
完成這些之后,可以來實現(xiàn)WriteAt方法了,這個方法在實現(xiàn)的時候已經(jīng)考慮到了不從頭開始寫的情況,因此我們也不需要太擔(dān)心ap和hap命令的實現(xiàn),在實現(xiàn)這個函數(shù)之前,我們應(yīng)該先進行一些思考:
如果是cp模式,即直接復(fù)制UNIX文件的內(nèi)容到nachos文件系統(tǒng)中去,則當(dāng)前的代碼已經(jīng)不需要修改了。如果我們要實現(xiàn)ap或者h(yuǎn)ap模式,則需要申請新的空間,而剩余的部分也不需要進行修改,因此,我們首先需要判斷一下是不是追加模式,如果是,則去申請新的空間。而判斷是否為追加模式,我們可以用當(dāng)前文件指針的位置是否大于文件大小來確定。如果是追加模式,我們則分兩種情況討論:
1.加上新的字符后的文件大小還沒有占滿整個扇區(qū),這時只需要設(shè)置文件大小即可。
2.加上新的字符后文件大小已經(jīng)超過了整個扇區(qū),這時候就需要申請新的磁盤空間來對文件進行存儲了。
此外再排除一些WriteAt本來的關(guān)于文件長度的一些限制之后,修改的WriteAt方法如下:
int OpenFile::WriteAt(char *from, int numBytes, int position) {int fileLength = hdr->FileLength();int i, firstSector, lastSector, numSectors;bool firstAligned, lastAligned;char *buf; // printf("seekPosition is %d,fileLength is %d\n",seekPosition,fileLength);if (numBytes < 0) return 0; // check requestif(seekPosition>=fileLength) //如果文件指針已經(jīng)超過了文件大小{numSectors=divRoundUp(fileLength,SectorSize); //計算當(dāng)前需要的扇區(qū)int numPos=seekPosition+numBytes; //計算添加新字節(jié)之后的指針位置if(numPos>numSectors*SectorSize) //如果文件為空或者超過了已有扇區(qū)空間{AllocateSpace(numPos-numSectors*SectorSize);//申請新空間fileLength+=numBytes; //增大文件空間}hdr->SetLength(numPos); //根據(jù)新指針位置設(shè)置新的文件大小}//寫入的部分已經(jīng)考慮了從中間寫入的情況if(fileLength==0) return 0;DEBUG('f', "Writing %d bytes at %d, from file of length %d.\n", numBytes, position, fileLength);firstSector = divRoundDown(position, SectorSize);lastSector = divRoundDown(position + numBytes - 1, SectorSize);numSectors = 1 + lastSector - firstSector; // printf("firstSector is %d,lastSector is %d\n",firstSector,lastSector);buf = new char[numSectors * SectorSize];firstAligned = (bool)(position == (firstSector * SectorSize));lastAligned = (bool)((position + numBytes) == ((lastSector + 1) * SectorSize));// read in first and last sector, if they are to be partially modifiedif (!firstAligned)ReadAt(buf, SectorSize, firstSector * SectorSize); if (!lastAligned && ((firstSector != lastSector) || firstAligned))ReadAt(&buf[(lastSector - firstSector) * SectorSize], SectorSize, lastSector * SectorSize); // copy in the bytes we want to change bcopy(from, &buf[position - (firstSector * SectorSize)], numBytes);// write modified sectors backfor (i = firstSector; i <= lastSector; i++) synchDisk->WriteSector(hdr->ByteToSector(i * SectorSize), &buf[(i - firstSector) * SectorSize]);delete [] buf;return numBytes; }最后,我們則是按照實驗指導(dǎo)書上的提示,在fstest.cc文件中取消掉調(diào)用WriteBack的部分的注釋。
// Write the inode back to the disk, because we have changed itopenFile->WriteBack();printf("inodes have been written back\n");源碼部分處理完成以后就要進行編譯與測試了,這里實驗要求自己編寫Makefile文件,由于nachos的編譯模塊過于復(fù)雜,這里我先把filesys中的所有除fstest.cc之外的文件復(fù)制到lab5目錄下,然后修改Makefile文件來實現(xiàn)的編譯,兩個相關(guān)的Makefile代碼如下:
Makefile.local:
ifndef MAKEFILE_LAB5_LOCAL define MAKEFILE_LAB5_LOCAL yes endef# Add new sourcefiles here.CCFILES +=bitmap.cc\directory.cc\filehdr.cc\filesys.cc\fstest.cc\openfile.cc\synchdisk.cc\disk.cc\main.ccifdef MAKEFILE_USERPROG_LOCAL DEFINES := $(DEFINES:FILESYS_STUB=FILESYS) else INCPATH += -I../userprog -I../lab5 DEFINES += -DFILESYS_NEEDED -DFILESYS endifendif # MAKEFILE_FILESYS_LOCALMakefile:
ifndef MAKEFILE_LAB5 define MAKEFILE_LAB5 yes endef# You can re-order the assignments. If filesys comes before userprog, # just re-order and comment the includes below as appropriate.include ../threads/Makefile.local include ../lab5/Makefile.local #include ../userprog/Makefile.local #include ../vm/Makefile.local #include ../filesys/Makefile.localinclude ../Makefile.dep include ../Makefile.commonendif # MAKEFILE_FILESYS這里有一個源碼中的坑,就是在測試要用的main.cc中,如果不改的話編譯會報如下錯誤:
只需要進入lab5下的main. cc,把NAppend函數(shù)的聲明修改一下即可:
四、測試
測試可能需要若干命令,這里我們可以寫一個Shell腳本來保存連續(xù)的命令,需要的時候調(diào)用然后觀察最后結(jié)果即可,這里我準(zhǔn)備了兩個測試腳本,修改完源碼并且編譯之后執(zhí)行即可:
測試ap參數(shù):
rm DISK ./nachos -f ./nachos -cp test/small small ./nachos -ap test/small small ./nachos -cp test/empty empty ./nachos -ap test/medium empty ./nachos -D測試hap參數(shù):
rm DISK ./nachos -f ./nachos -cp test/small small ./nachos -cp test/big big ./nachos -hap test/big small ./nachos -hap test/small big ./nachos -D將上述兩個腳本分別另存為ap. sh和hap. sh,然后在命令行中執(zhí)行如下命令給予其執(zhí)行權(quán)限:
$chmod a+x ap.sh $chmod a+x hap.sh然后首先我們測試ap參數(shù)的運行情況,運行結(jié)果如下:
可見,與實驗指導(dǎo)書預(yù)計的結(jié)果一致,即ap功能得以實現(xiàn)。
接下來再來測試一下hap命令。
這里測試了兩種情況,即從大文件的中間寫小文件和從小文件的中間寫大文件。結(jié)果如下:運行結(jié)果如下:
從結(jié)果來看,hap的功能也得到了實現(xiàn)。
五、結(jié)論分析與體會
從輸出結(jié)果來看,拓展之后的文件系統(tǒng)在保證了基本的cp命令執(zhí)行不出錯的情況下,增加了ap和hap兩個命令,讓原來固定大小的文件系統(tǒng)變成了大小可變的文件系統(tǒng)。
本次實驗在掌握了nachos基本文件命令用法的情況下,對其功能進行了拓展,增加了文件可變的功能,而實現(xiàn)這個功能的前提也是足夠了解nachos磁盤系統(tǒng)相關(guān)的源代碼,因此通過擴展這個功能,我對nachos文件系統(tǒng)相關(guān)的部分有了更深的認(rèn)識,也對操作系統(tǒng)中所講的文件系統(tǒng)相關(guān)的內(nèi)容進行了很好的回顧。
總結(jié)
以上是生活随笔為你收集整理的操作系统课设实验五---Nachos文件系统扩展的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3、Finished with erro
- 下一篇: SNS大负载系统解决方案研究