Systémové volania mmap a munmap umožňujú UNIX programom získať väčšiu kontrolu nad ich adresným priestorom. Môžu byť použité na zdeľanie pamäte medzi procesmi, mapovanie súborov do adresného priestoru procesu a rôzne schémy na obsluhu výpadkov stránok z užívateľského prostredia. Na tomto cvičení implementujete tieto systémové volania na mapovanie súborov do pamäte.
Stiahnite si kód pre cvičenie do repozitára a prepnite sa na vetvu mmap:
1 2 3 |
$ git fetch $ git switch mmap # alebo git checkout mmap $ make clean |
Manuálová stránka Linuxu pre mmap (man 2 mmap) uvádza túto deklaráciu funkcie mmap
:
1 2 |
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); |
Ako môžete vidieť z manuálovej stránky, mmap
môže byť volaná mnohými spôsobmi. Na tomto cvičení nám ale bude stačiť funkcionalita pre mapovanie súboru do pamäte. Môžete predpokladať, že argument addr
bude vždy nulový, čiže jadro rozhodne na ktorej virtuálnej adrese namapuje súbor. Funkcia mmap
vráti túto adresu, alebo číslo 0xffffffffffffffff, ak sa súbor nepodarilo namapovať. Argument length
určuje počet bajtov, ktoré sa majú namapovať; nemusí byť rovnaký ako veľkosť súboru. Argument prot
určuje, či má byť pamäť mapovaná na čítanie, zápis a/alebo vykonanie. Môžete predpokladať, že bude nadobúdať hodnoty PROT_READ
, PROT_WRITE
, alebo kombináciu oboch. Argument flags
bude buď MAP_SHARED, čo znamená, že úpravy v namapovanej pamäti majú byť zapísané späť do súboru, alebo MAP_PRIVATE
, kedy úpravy nebudú do súboru spätne zapísané. Podporu iných bitov vo flags
nie je potrebné implementovať. Argument fd je otvorený súborový deskriptor so súborom, ktorý sa má namapovať. Môžete predpokladať, že offset
je nulový (určuje začiatočný bod v súbore, od ktorého sa bude súbor mapovať)
Je v poriadku, ak procesy, ktoré zdieľajú rovnaký MAP_SHARED
súbor nezdieľajú rovnaké fyzické stránky.
Systémové volanie munmap(addr, length)
by malo odstrániť mapovania vytvorené volaním mmap
v požadovanom adresnom rozsahu. Ak proces modifikoval pamäť a táto bola namapovaná ako MAP_SHARED
, modifikácie by mali byť najprv zapísané do súboru. Volanie munmap
môže tiež iba čiastočne pokryť pôvodne mapovaný región. Môžete ale predpokladať, že sa odmapuje buď čiastočne región od začiatku alebo konca súboru, prípadne celý súbor (nikdy sa ale neodmapuje región v strede súboru).
Mali by ste implementovať toľko funkcionality systémových volaní mmap
a munmap
, aby ste prešli testom mmaptest. Ak mmaptest nepoužíva nejakú funkcionalitu systémového volania mmap
, nemusíte túto funkcionalitu implementovať.
Keď budete hotoví, mali by ste vidieť takýto výstup:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ mmaptest mmap_test starting test mmap f test mmap f: OK test mmap private test mmap private: OK test mmap read-only test mmap read-only: OK test mmap read/write test mmap read/write: OK test mmap dirty test mmap dirty: OK test not-mapped unmap test not-mapped unmap: OK test mmap two files test mmap two files: OK mmap_test: ALL OK fork_test starting fork_test OK mmaptest: all tests succeeded $ usertests usertests starting ... ALL TESTS PASSED $ |
Pomôcky:
_mmaptest
do UPROGS
a implementujte systémové volania mmap
a munmap
, aby ste mohli skompilovať user/mmaptest.c. Na začiatok stačí, aby ste z implementovaných systémových volaní vrátili chybové kódy. V súbore kernel/fcntl.h nájdete implementované makro PROT_READ
a ďalšie. Spustite mmaptest, ktorý by mal zlyhať pri prvom volaní mmap
.mmap
nebudete alokovať fyzickú pamäť alebo čítať mapovaný súbor. Namiesto toho to urobíte pomocou obsluhy výpadkov stránok z funkcie usertrap
(alebo pomocou pomocnej funkcie zavolanej odtiaľ), podobne ako ste to robili na piatom cvičení s lenivou alokáciou. Robíte to preto, aby bolo systémové volanie mmap
rýchle aj pre veľké súbory a aby ste mohli mapovať aj súbory, ktoré sú väčšie ako fyzická pamäť.mmap
pre ktorý proces. Definujte štruktúru podobnú VMA (virtual memory area), o ktorej sme hovorili na piatej prednáške a piatom seminári. Zapísať by ste mali adresu, dĺžku, povolenia, súbor, atď. pre rozsah virtuálnej pamäte vytvorený volaním mmap
. Keďže xv6 nemá pamäťový alokátor v jadre, môžete deklarovať pole pevnej dĺžky, do ktorého budete ukladať položky VMA podľa potreby. Dĺžka 16 by mala byť postačujúca.mmap
: nájdite nevyužitý región vo virtuálnej pamäti procesu, do ktorého namapujete súbor a pridajte záznam VMA do tabuľky mapovaných regiónov daného procesu. Záznam VMA by mal obsahovať smerník na štruktúru struct file
súboru, ktorý je mapovaný. Nezabudnite navýšiť počítadlo referencií v tejto štruktúre, aby nezanikla po uzavretí súboru (viď filedup
). Spustite mmaptest: teraz by malo byť prvé volanie mmap
úspešné, ale prvý prístup k mapovanej pamäti spôsobí výpadok stránky, čo vyústi ukončením procesu mmaptest.readi
. Táto funkcia má na vstupe offset, od ktorého načíta súbor (nezabudnite zamknúť/odomknúť príslušný inode, ktorý čítate). Taktiež nezabudnite nastaviť správne povolenia počas mapovania stránky. Po spustení testu mmaptest by ste sa mali dostať až k prvému volaniu munmap
, ktoré zlyhá.munmap
: nájdite VMA pre príslušný adresný rozsah a odmapujte požadované stránky (použite uvmunmap
). Ak munmap
odmapoval všetky stránky súboru, mal by znížiť počítadlo referencií príslušnej štruktúry file
. Ak stránka, ktorú odmapoval bola upravená a súbor bol mapovaný s príznakom MAP_SHARED, zapíšte stránku späť do súboru. Inšpiráciu k tomuto hľadajte vo funkcii filewrite
.MAP_SHARED
stránky, ktoré boli naozaj upravené. Bit dirty (D
) v PTE na RISC-V architektúre signalizuje, že do stránky prebehol zápis. Toto ale mmaptest
netestuje, tak sa zaobídete aj bez tejto úpravy.exit
, aby odmapoval regióny procesu s namapovanými súbormi (tak isto, ako to robí munmap
). Po spustení nmaptest by mal prejsť test nmap_test, ale fork_test ešte asi nie.fork
, aby detský proces mal namapované presne tie isté regióny ako jeho rodič. Nezabudnite tiež zvýšiť počítadlo referencií štruktúry file
pre každý záznam VMA. Pri obsluhe výpadku stránky v detskom procese je v poriadku, ak alokujete novú fyzickú stránku namiesto toho, aby ste ju zdieľali s rodičom. Bolo by to zaujímavé, ale vyžadovalo by to viac práce. Spustite mmaptest. Teraz by mali prejsť mmap_test aj fork_test.Na záver spustite usertests, aby ste overili, či funguje aj zvyšok systému.
Spustite príkaz make grade, aby ste overili správnosť svojho riešenia. Aby ste prešli posledným testom time, musíte vytvoriť nový súbor time.txt, v ktorom uvediete počet hodín, ktorý ste strávili nad zadaním ako celé číslo.
Týmto je cvičenie ukončené. Svoje zmeny môžete commitnúť do repozitára.
BSIZE
na 4096). Namapované bloky musíte pripnúť do kešky, aby z nej nemohli byť vyhodené. Musíte teda upraviť počítadlo referencií.exec
, aby používal VMA pre rôzne sekcie spustiteľných súborov, aby načítanie inštrukcií pri behu programu prebiehalo na požiadanie. Takto budú programy štartovať rýchlejšie, pretože exec
nebude musieť načítať dáta zo súborového systému.