Stronicowanie plikow (zwane tez mapowaniem plikow) jest mechanizmem pozwalajacym an odzwierciedlenie binarnej postaci pliku dyskowego (a dokladniej pliku pochodzacego z dowolnego systemu plikow wspierajacego mechanizm stronicowania plikow) w obszar wirtualnej przestrzeni adresowej procesu. Strony objete takim obszarem sa stonicowane bezposrednio z/do danego pliku, a nie z/do standardowych urzadzen wymiany stron.
Najszerszym chyba zastosowaniem tego mechanizmu jest ladoanie przez jadro plikow wykonywalnych (funkcja exec), ktore zamiast wczytywac, po prostu mapujemy do pamieci wirtualnej - potrzebne strony beda wczytywane w wyniku bledow braku strony. Programista Linuxowy moze uzywac mapowania plikow dla wlasnych zastosowan za pomoca funkcji bibliotecznych:
caddr_t mmap(caddr_t addr, size_t len, int prot, int fd, off_t off);
int munmap(caddr_t addr, size_t len);
Stronicowanie plikow w Linuxie zostalo zrealizowanie na bazie ogolnego mechanizmu pamieci wirtualnej procesu i jest z nim bardzo silnie powiazane. Pamiec wirtualna procesu reprezentowana jest przez zbor (dokladnie: liste i drzewo AVL - polea mm->mmap i mm->mmap_avl w task_struct) struktur vm_area_struct opisujacych przyznane procesowi spojne obszary wirtualnej przestrzeni adresowej. Z karzdym takim obszaem sa zwiazane jego wlasciwosci i potencjalnie rozne funkcje obslugi stronicowania. Tak ogolnie rozumiana wirtualnosc obszarow pozwala na stosunkowo proste implementowanie roznorakich rozszerzen, w tym mapowania plikow!!!
Oto dokladna definicja struktury vm_area_struct z pliku include/linux/mm.h:
struct vm_area_struct { struct mm_struct * vm_mm; /* parametry obszaru: */ unsigned long vm_start; /* adres poczatku, */ unsigned long vm_end; /* konca */ pgprot_t vm_page_prot; /* znaczniki ochrony */ unsigned short vm_flags; /* dodatkowe znaczniki (obszar dzielony, etc.) */ /* pola organizujace drzewo AVL (sortowane po vm_start) struktur vm_area_struct danego procesu */ short vm_avl_height; struct vm_area_struct * vm_avl_left; struct vm_area_struct * vm_avl_right; /* pole organizujace liste (sortowana po vm_start) struktur vm_area_struct danego procesu*/ struct vm_area_struct * vm_next; /* pola organizujace cykliczna liste struktur vm_area_struct (nie koniecznie jednego procesu) */ /* uzywane tylko dla pamieci dzielonej lub obszarow z i-wezlem (n.p. stronicowania plikow) */ struct vm_area_struct * vm_next_share; struct vm_area_struct * vm_prev_share; struct vm_operations_struct * vm_ops; /* funkcje obslugi stronicowania */ unsigned long vm_offset; /* offset w pliku */ struct inode * vm_inode; /* i-wezel pliku */ unsigned long vm_pte; /* katalog stron */ };
Oto dokladna definicja struktury vm_operations_struct z pliku include/linux/mm.h:
struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); /* unmap - wywolywana przed odlaczeniem obszaru - typowo wywoluje sync*/ void (*unmap)(struct vm_area_struct *area, unsigned long, size_t); void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot); /* sync - wywolywana na rzadanie procesu - ma za zadanie zsynchronizowac pamiec z plikiem */ int (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags); void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise); /* nopage - wywolywana przy bledzie braku strony */ unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access); /* wppage - wywolywana przy zapisie do strony chronionej przed zapisem */ unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address, unsigned long page); /* swapout, swapin - wywolywane przy wymianie stron */ int (*swapout)(struct vm_area_struct *, unsigned long, pte_t *); pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long); };
unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long off);
argumenty:
file - okreslenie pliku, ktory mapujemy; mozliwe jest podanie NULL wtedy przylaczany segment nie bedzie zwiazany z plikiem (czyli bedzie zupelnie normalnym segmentem - warto zauwazyc, ze funkcja sys_brk sprowadza sie do wywolania do_mmap(NULL,...) lub do_munmap(...) po uprzednim sprawdzeniu argumentow)
addr - adres pod jaki chcemy zmapowac (do flags trzeba wtedy dodac MAP_FIXED) lub NULL aby system sam przydzielil adres
prot, flags - opcje ochrony i dzielenia (patrz include/asm/mman.h)
off - offset w pliku (uwaga: przy trybie dzielenia offset musi byc wielokrotnoscia rozmiaru strony)
zwraca:
przydzielony adres lub ujemny kod bledu
dzialanie:
- sprawdza poprawnasc argumentow (wlacznie z trybem otwarcia pliku)
- alokuje pamiec jadra na nowa strukture vm_area_struct i inicjuje ja (pola vm_ops, vm_inode, vm_pte sa zerowane)
- wywoluje do_munmap(addr,len) aby zwolnic poprzednie obszary o zachodzacych adresach
- wywoluje funkcje (*mmap) charakterystyczna dla systemu plikow pliku file (dla zwyklych systemow plikow n.p. ext2 jest to funkcja generic_file_mmap, a dla NFS jakas inna), ktora to funkcja konczy inicjalizacje struktury vm_area_struct (pola vm_ops, vm_inode, ...)
- wstawia nowa strukture do zbioru (funkcje insert_vm_struct,
merge_segments)
int do_munmap(unsigned long addr, size_t len)
argumenty:
addr, len - specyfikacja obszaru do odlaczenia
zwraca:
0 gdy OK lub ujemny kod bledu
dzialanie:
- sprawdza poprawnosc argumentow
- wyjmuje odpowiednia strukture vm_area_struct ze zbioru (funkcja remove_shared_vm_struct)
- wywoluje funkcje (*unmap) specuficzna dla danej struktury
- zwalnia strony
- zwalnia pamiec jadra uzywana przez vm_area_struct
int generic_file_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
argumenty:
inode - i-wezel mapowanego pliku
file - "okreslenie" pliku
vma - obszar wirtualnej przestrzeni adresowej
zwraca:
0 gdy OK lub ujemny kod bledu
dzialanie:
- sprawdza prawa dostepu, etc.
- wpisuje inode do vma->vm_inode i zwieksza licznik dowiazan i-wezla
- inicjuje strukture funkcji obslugi stronicowania (vma->vm_ops) na file_shared_mmap dla obszarow dzielonych lub na file_private_mmap dla prywatnych
brak...