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 zdieľ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í budete implementovať 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 |
Riešenia úloh z tohto cvičenia ukladajte do vetvy mmap.
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); |
Z manuálovej stránky môžete vidieť, že 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 adresu, na ktorú bude namapovaný súbor určí jadro. 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).
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 -q 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 implementácie spomenutých makier, napríklad PROT_READ
. 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ľ). 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 VMA (virtual memory area), ktorá bude obsahovať pomocné údaje k mapovaniu. 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. Ak veľkosť súboru nie je zaokrúhlená na hranicu stránky, koniec poslednej namapovanej stránky za obsahom súboru vyplňte nulami. 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 (inšpirujte sa funkciou 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. Teraz by mal prejsť mmap_test.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.exit
, aby odmapoval regióny procesu s namapovanými súbormi (tak isto, ako to robí munmap
). Po spustení mmaptest by mali prejsť testy mmap_test a fork_test.Na záver spustite usertests -q, aby ste overili, či funguje aj zvyšok systému.
Spustite príkaz make grade, aby ste overili správnosť svojho riešenia. Po úspešnom dokončení úlohy nezabudnite vytvoriť commit! 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. Na záver aj túto zmenu commitnite do repozitára. Týmto je cvičenie ukončené.
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.