mmap(2) System Calls Manual mmap(2) NAZWA mmap, munmap - mapuje lub usuwa mapowanie plikow lub urzadzen w pamieci BIBLIOTEKA Standardowa biblioteka C (libc, -lc) SKLADNIA #include void *mmap(void addr[.length], size_t length, int prot, int flags, int fd, off_t offset); int munmap(void addr[.length], size_t length); Informacje o wymaganych makrach sprawdzania cech znajduja sie w rozdziale UWAGI. OPIS mmap() tworzy nowe mapowanie w wirtualnej przestrzeni adresowej procesu wywolujacego. Poczatkowy adres nowego mapowania podaje sie w addr. Argument length okresla dlugosc mapowania (musi byc ono wieksze niz 0). Jesli addr wynosi NULL, to jadro wybiera (wyrownany do strony) adres, na ktorym utworzy mapowanie; jest to najbardziej przenosna metoda tworzenia nowych mapowan. Jesli addr nie wynosi NULL, to jadro traktuje go jako wskazowke na temat miejsca umieszczenia mapowania; w Linuksie, jadro wybierze najblizsza granice strony (jednak bedzie ona zawsze rowna lub wieksza wartosci okreslonej w /proc/sys/vm/mmap_min_addr) i sprobuje utworzyc tu nowe mapowanie. Jesli inne mapowanie juz tu istnieje, jadro wybierze nowy adres, ktory moze, lecz nie musi, zalezec od wskazowki. Adres nowego mapowania jest zwracany jako wynik wywolania. Zawartosc mapowania pliku (w przeciwienstwie do mapowania anonimowego; zob. MAP_ANONYMOUS ponizej) jest inicjowana za pomoca length bajtow zaczynajacych sie w przesunieciu offset w pliku (lub innym obiekcie), do ktorego odnosi sie deskryptor pliku fd. offset musi byc wielokrotnoscia rozmiaru strony, jaki zwraca sysconf(_SC_PAGE_SIZE). Po powrocie wywolania mmap(), deskryptor pliku fd moze byc niezwlocznie zamkniety, nie uniewazniajac mapowania. Argument prot opisuje oczekiwany sposob ochrony pamieci mapowania (i nie moze byc sprzeczny z trybem otwarcia pliku). Moze on byc rowny PROT_NONE lub moze byc suma bitowa (OR) jednego lub wiecej sposrod innych znacznikow PROT_*. PROT_EXEC Strony moga byc wykonywane. PROT_READ Strony moga byc odczytywane. PROT_WRITE Strony moga byc zapisywane. PROT_NONE Strony moga nie byc dostepne. Argument flags Argument flags okresla, czy aktualizacje mapowania sa widoczne dla innych procesow mapowanych do tego samego miejsca i czy aktualizacje sa przenoszone na sam plik. To zachowanie zalezy od podanej, dokladnie jednej z ponizszych wartosci flags: MAP_SHARED Dzieli zadane mapowanie. Aktualizacje mapowania sa widoczne dla innych procesow mapowanych do tego samego miejsca i (w przypadku mapowan opartych na pliku) sa przenoszone do samego pliku (aby kontrolowac dokladnie, kiedy aktualizacje sa przenoszone na sam plik, konieczne jest uzycie msync(2)). MAP_SHARED_VALIDATE (od Linuksa 4.15) Znacznik zapewnia takie same zachowanie jak MAP_SHARED z ta roznica, ze mapowania MAP_SHARED ignoruja nieznane znaczniki we flags. Przy tworzeniu mapowan z uzyciem MAP_SHARED_VALIDATE, jadro sprawdza natomiast, czy wszystkie przekazane znaczniki sa znane i odmawia mapowania z bledem EOPNOTSUPP, jesli wystapia nieznane znaczniki. Ten typ mapowania jest rowniez wymagany, aby moc korzystac z niektorych znacznikow mapowan (np. MAP_SYNC). MAP_PRIVATE Tworzy prywatne mapowanie, typu ,,kopiowanie podczas zapisu". Aktualizacje mapowania nie sa widoczne dla innych procesow mapujacych ten sam plik i nie sa przenoszone na sam plik. Nie jest okreslone, czy zmiany zawartosci pliku wykonane po wywolaniu mmap() beda uwidocznione w mapowanym obszarze. MAP_SHARED i MAP_PRIVATE sa opisane w POSIX.1-2001 i POSIX.1-2008. MAP_SHARED_VALIDATE jest rozszerzeniem Linuksa. Ponadto, zero lub wiecej ponizszych wartosci mozna zsumowac bitowo (OR) we flags: MAP_32BIT (od Linuksa 2.4.20, 2.6) Umieszcza mapowanie w pierwszych 2 gigabajtach przestrzeni adresowej procesu. Znacznik jest obslugiwany tylko na architekturze x86-64, w przypadku programow 64-bitowych. Znacznik dodano, aby pozwolic stosom watkow na zaalokowanie w pierwszych 2 GB pamieci, co usprawnialo wydajnosc przelaczania kontekstow na pewnych wczesnych procesorach 64-bitowych. Wspolczesne procesory x86-64 nie maja takiego problemu z wydajnoscia, zatem znacznik ten nie jest wymagany na tych systemach. Znacznik MAP_32BIT jest ignorowany, gdy ustawiony jest MAP_FIXED. MAP_ANON Rownowazne MAP_ANONYMOUS; istnieje dla kompatybilnosci z innymi implementacjami. MAP_ANONYMOUS Mapowanie nie jest oparte na pliku; jego zawartosc jest inicjowana jako zero. Argument fd jest ignorowany, jednak niektore implementacje wymagaja, aby fd wynosilo -1 jesli podano MAP_ANONYMOUS (lub MAP_ANON), dlatego przenosne aplikacje powinny uzywac tej wartosci. Argument offset powinien wynosic zero. Obsluge MAP_ANONYMOUS w polaczeniu z MAP_SHARED dodano w Linuksie 2.4. MAP_DENYWRITE Ten znacznik jest ignorowany (dawno temu -- Linux 2.0 i wczesniejsze -- sygnalizowal on, ze proba zapisu to mapowanego pliku powinna zawiesc z ETXTBSY; bylo to jednak zrodlem atakow blokujacych usluge (DoS)). MAP_EXECUTABLE Ten znacznik jest ignorowany. MAP_FILE Znacznik sluzacy zgodnosci. Ignorowany. MAP_FIXED Nie interpretuje addr jako wskazowki: umieszcza mapowanie dokladnie na podanym adresie. addr musi byc wlasciwie wyrownany: w przypadku wiekszosci architektur, wystarczajaca jest wielokrotnosc rozmiaru strony; jednak niektore architektury moga narzucac dodatkowe ograniczenia. Jesli obszar pamieci podany w addr i length nachodzi na strony jakiegos istniejacego mapowania, to te nachodzace czesci istniejacego mapowania zostana odrzucone. Jesli podany adres nie moze byc uzyty, wywolanie mmap() zawiedzie. Oprogramowanie, ktore ma zamiar byc przenosne, powinno bardzo ostroznie korzystac ze znacznika MAP_FIXED, majac na wzgledzie, ze dokladny schemat mapowan pamieci procesu moze sie znacznie zmieniac pomiedzy wersjami Linuksa, wersjami biblioteki C i wydaniami systemu operacyjnego. Prosze dokladnie przeczytac omowienie tego znacznika w UWAGACH! MAP_FIXED_NOREPLACE (od Linuksa 4.17) Znacznik zapewnia zachowanie podobne do MAP_FIXED, jesli chodzi o wymuszenie adresu addr, lecz z ta roznica, ze MAP_FIXED_NOREPLACE nigdy nie narusza wczesniejszego zakresu mapowania. Jesli zadany zakres kolidowalby z istniejacym mapowaniem, to wywolanie zawiedzie z bledem EEXIST. Znacznik ten moze zatem posluzyc do niepodzielnej (z uwzglednieniem innym watkow) proby mapowania zakresu adresowego: u jednego watku powiedzie sie to, wszystkie inne zawioda. Prosze zauwazyc, ze starsze jadra, ktore nie rozpoznaja znacznika MAP_FIXED_NOREPLACE, zwykle (po wykryciu kolizji z wczesniejszym mapowaniem) awaryjnie zachowaja sie jak ,,nie-MAP_FIXED": zwroca adres, ktory jest odmienny od adresu zadanego. Oprogramowanie, ktore ma byc kompatybilne wstecznie, powinno zatem sprawdzac zwracany adres z adresem zadanym. MAP_GROWSDOWN Znacznik jest uzywany do stosow. Wskazuje systemowi pamieci wirtualnej jadra, ze mapowanie ma kontynuowac sie w dol pamieci. Zwracany adres jest o jedna strone nizej, niz obszar pamieci, ktory jest w rzeczywistosci tworzony w wirtualnej przestrzeni adresowej procesu. Dotkniecie adresu w ,,strzezonej" stronie (guard page) ponizej mapowania spowoduje zwiekszenie mapowania o jedna strone. Ten wzrost mozna powtarzac do momentu, gdy mapowanie osiagnie wysoki koniec strony nastepnego nizszego mapowania; wowczas dotkniecie ,,strzezonej" strony spowoduje sygnal SIGSEGV. MAP_HUGETLB (od Linuksa 2.6.32) Przydziela mapowanie za pomoca duzych (,,huge") stron. Wiecej informacji w pliku Documentation/admin-guide/mm/hugetlbpage.rst w zrodlach jadra Linux oraz w UWAGACH ponizej. MAP_HUGE_2MB MAP_HUGE_1GB (od Linuksa 3.8) Uzywane w polaczeniu z MAP_HUGETLB, do wybrania alternatywnych rozmiarow strony hugetlb (odpowiednio, 2 MB i 1 GB) w systemach, ktore obsluguja wiele rozmiarow stron hugetlb. Ogolniej, zadany rozmiar duzych stron mozna skonfigurowac, podajac logarytm o podstawie 2, zadanego rozmiaru strony, w szesciu bitach na przesunieciu MAP_HUGE_SHIFT (wartosc zero w tym polu bitowym oznacza domyslny rozmiar duzej strony; mozna go sprawdzic za pomoca pola Hugepagesize ujawnianego w /proc/meminfo). Zatem, powyzsze dwie stale sa zdefiniowane jako: #define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT) #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) Zakres obslugiwanych rozmiarow duzych stron w systemie mozna sprawdzic, wypisujac podkatalogi w katalogu /sys/kernel/mm/hugepages. MAP_LOCKED (od Linuksa 2.5.37) Oznacza mapowany obszar jako zablokowany w ten sam sposob, jak robi to mlock(2). Ta implementacja postara sie wypelnic (prefault) caly zakres, lecz wywolanie mmap() nie zawodzi z bledem ENOMEM gdy sie to nie powiedzie. Z tego wzgledu pozniej moga wystapic glowne chybienia stron (ang. major page fault). Semantyka ta nie jest zatem tak mocna jak mlock(2). Jesli po zainicjowaniu mapowania nie sa pozniej dopuszczalne glowne chybienia stron, nalezy korzystac w zamian z mmap() wraz z mlock(2). Znacznik MAP_LOCKED jest ignorowany przez starsze jadra. MAP_NONBLOCK (od Linuksa 2.5.46) Znacznik ten ma znaczenie tylko w polaczeniu z MAP_POPULATE. Nie przeprowadza odczytu naprzod: wpisy tablicy stron sa tworzone tylko w przypadku stron, ktore sa juz obecne w RAM. Od Linuksa 2.6.23, znacznik ten nie ma wplywu na MAP_POPULATE. W przyszlosci, polaczenie MAP_POPULATE z MAP_NONBLOCK moze zostac na nowo zaimplementowane. MAP_NORESERVE Poleca nie rezerwowac przestrzeni wymiany dla tego mapowania. Gdy przestrzen wymiany jest zarezerwowana, ma sie gwarancje, ze istnieje mozliwosc modyfikacji mapowania. Gdy przestrzen wymiany nie jest zarezerwowana, mozna otrzymac SIGSEGV podczas zapisu, jesli braknie pamieci fizycznej. Prosze zapoznac sie rowniez z opisem pliku /proc/sys/vm/overcommit_memory w proc(5). Przed Linuksem 2.6, znacznik ten dzialal tylko dla prywatnych, zapisywalnych mapowan. MAP_POPULATE (od Linuksa 2.5.46) Wypelnia (prefault) tablice strony dla mapowania. W przypadku mapowania pliku, powoduje to odczyt z wyprzedzeniem pliku. W ten sposob redukuje sie blokowanie, przy pozniejszych chybieniach stron (ang. page fault). Wywolanie mmap() nie zawodzi, jesli nie da sie wypelnic mapowania (np. ze wzgledu na ograniczenie liczby mapowanych duzych (huge) stron, za pomoca MAP_HUGETLB). Obsluge MAP_POPULATE w polaczeniu z mapowaniami prywatnymi dodano w Linuksie 2.6.23. MAP_STACK (od Linuksa 2.6.27) Przydziela mapowanie na adresie odpowiednim dla stosu: procesu lub watku. Znacznik ten jest w Linuksie instrukcja pusta. Jednak podajac go, przenosne aplikacje moga zapewnic zyskanie obslugi znacznika, gdy zostanie on w przyszlosci zaimplementowany. Z tego wzgledu jest uzywany w implementacji watkowania glibc, aby uwzglednic fakt, ze niektore architektury moga (w przyszlosci) wymagac specjalnego traktowania przy alokowaniu stosu. Kolejnym powodem korzystania z tego znacznika jest przenosnosc: MAP_STACK istnieje (i dziala) na niektorych innych systemach (np. niektorych BSD). MAP_SYNC (od Linuksa 4.15) Znacznik ten jest dostepny jedynie z typem mapowania MAP_SHARED_VALIDATE; mapowania typu MAP_SHARED po cichu go zignoruja. Znacznik ten jest obslugiwany jedynie dla plikow obslugujacych DAX (bezposrednie mapowanie do pamieci trwalej). W przypadku innych plikow, utworzenie mapowania z tym znacznikiem spowoduje wystapienie bledu EOPNOTSUPP. Dzielone mapowania pliku z tym znacznikiem zapewniaja gwarancje, ze choc pewna czesc pamieci bedzie zmapowana jako zapisywalna w przestrzeni adresowej procesu, bedzie ona widoczna w tym samym pliku, na tym samym przesunieciu, nawet po zalamaniu lub przeladowaniu systemu. W polaczeniu z odpowiednimi instrukcjami procesora, uzytkownicy takich mapowan maja zapewniona lepszy tryb czynienia modyfikacji danych trwalymi. MAP_UNINITIALIZED (od Linuksa 2.6.33) Nie czysci stron anonimowych. Znacznik ten ma polepszyc wydajnosc na urzadzeniach wbudowanych. Znacznik jest przestrzegany tylko, gdy jadro skonfigurowano z opcja CONFIG_MMAP_ALLOW_UNINITIALIZED. Ze wzgledu na skutki w zakresie bezpieczenstwa, opcja ta jest zwykle wlaczana wylacznie na urzadzeniach wbudowanych (tj. majacych calkowita kontrole nad zawartoscia pamieci uzytkownika). Z powyzszych znacznikow, jedynie MAP_FIXED jest okreslony przez POSIX.1-2001 i POSIX.1-2008. Wiekszosc systemow obsluguje jednak takze MAP_ANONYMOUS (lub jego synonim MAP_ANON). munmap() Wywolanie systemowe munmap() usuwa mapowanie z podanego zakresu adresow i powoduje, ze dalsze odwolania do adresow z tego zakresu beda generowac nieprawidlowe odwolania do pamieci. Mapowanie obszaru jest rowniez automatycznie usuwane, gdy proces sie zakonczy. Z drugiej strony, zamkniecie deskryptora pliku nie usuwa mapowania obszaru. Adres addr musi byc wielokrotnoscia rozmiaru strony (ale length juz nie musi). Usuwane jest mapowanie wszystkich stron zawierajacych fragmenty ze wskazanego zakresu, wszystkie pozniejsze odwolania do tych stron wygeneruja SIGSEGV. Nie jest bledem, gdy brak w podanym zakresie zamapowanych stron. WARTOSC ZWRACANA Po pomyslnym zakonczeniu mmap() zwraca wskaznik do mapowanego obszaru. Po bledzie zwracane jest MAP_FAILED (tj. (void *) -1) i ustawiane errno, wskazujac blad. Po pomyslnym zakonczeniu munmap() zwraca 0. Po bledzie zwracane jest -1 i ustawiane errno, wskazujac blad (prawdopodobnie 1EINVAL). BLEDY EACCES Deskryptor pliku odnosi sie do pliku innego niz zwykly plik. Lub zazadano mapowania pliku, lecz fd nie jest otwarty do odczytu. Lub zazadano MAP_SHARED i ustawiono PROT_WRITE, lecz fd nie jest otwarte w trybie do odczytu i do zapisu (O_RDWR). Lub ustawiono PROT_WRITE, lecz plik jest otwarty tylko do dopisywania. EAGAIN Plik zostal zablokowany lub zablokowano zbyt wiele pamieci (zob. setrlimit(2)). EBADF fd nie jest prawidlowym deskryptorem pliku (a nie ustawiono MAP_ANONYMOUS). EEXIST We flags podano MAP_FIXED_NOREPLACE, a zakres ktory opisuje addr i length koliduje z istniejacym mapowaniem. EINVAL Niewlasciwe addr, length lub offset (np. moga byc zbyt duze lub niewyrownane do granicy strony). EINVAL (od Linuksa 2.6.12) length wynosila 0. EINVAL We flags nie wystapilo zadne z: MAP_PRIVATE, MAP_SHARED lub MAP_SHARED_VALIDATE. ENFILE Zostalo osiagniete systemowe ograniczenie na calkowita liczbe otwartych plikow. ENODEV System plikow, na ktorym znajduje sie podany plik, nie obsluguje mapowania w pamieci. ENOMEM Brak dostepnej pamieci. ENOMEM Doszloby do przekroczenia maksymalnej liczby mapowan procesu. Blad ten moze wystapic rowniez dla munmap(), przy usuwaniu mapowania z obszaru w srodku istniejacego mapowania, poniewaz spowodowaloby to powstanie dwoch mniejszych mapowan po obu stronach niezmapowanego obszaru. ENOMEM (od Linuksa 4.7) Doszloby do przekroczenia limitu RLIMIT_DATA procesu, opisanego w podreczniku getrlimit(2). ENOMEM addr przekroczyloby wirtualna przestrzen adresowa procesora. EOVERFLOW Na architekturze 32-bitowej z rozszerzeniem duzych plikow (tj. korzystajac z 64-bitowego off_t): liczba stron uzytych dla length wraz z liczba stron uzytych dla offset przepelnilaby liczbe typu unsigned long (32-bitowa). EPERM Argument prot pyta o PROT_EXEC lecz mapowany obszar nalezy do pliku zamontowanego na systemie plikow z opcja no-exec (bez zezwolenia na wykonywanie). EPERM Operacja zablokowana, z powodu zapieczetowania pliku (ang. file seal); zob. fcntl(2). EPERM Podano znacznik MAP_HUGETLB, lecz wywolujacy nie byl uprzywilejowany (nie mial przywileju CAP_IPC_LOCK (ang. capability)) i nie jest czlonkiem grupy sysctl_hugetlb_shm_group; zob. opis /proc/sys/vm/sysctl_hugetlb_shm_group w proc_sys(5). ETXTBSY Ustawiono MAP_DENYWRITE, lecz obiekt wskazywany przez fd jest otwarty do zapisu. Uzycie zamapowanego obszaru moze spowodowac wystapienie nastepujacych sygnalow: SIGSEGV Proba zapisu do obszaru zmapowanego tylko do odczytu. SIGBUS Proba dostepu do strony bufora, ktora lezy poza koncem mapowanego pliku. Wyjasnienie traktowania bajtow w stronie, ktora odnosi sie do konca mapowanego pliku i nie jest wielokrotnoscia rozmiaru strony zamieszczono w UWAGACH. ATRYBUTY Informacje o pojeciach uzywanych w tym rozdziale mozna znalezc w podreczniku attributes(7). +---------------------------+--------------------------+---------------+ |Interfejs | Atrybut | Wartosc | +---------------------------+--------------------------+---------------+ |mmap(), munmap() | Bezpieczenstwo watkowe | MT-bezpieczne | +---------------------------+--------------------------+---------------+ WERSJE Na niektorych architekturach sprzetowych (np. i386), PROT_WRITE wymusza PROT_READ. Od architektury zalezy, czy PROT_READ wymusza PROT_EXEC, czy nie. Programy przenosne powinny zawsze ustawiac PROT_EXEC, jesli maja zamiar wykonywac kod w nowym mapowaniu. Przenosnym sposobem tworzenia mapowan jest podanie addr jako 0 (NULL) i pominiecie MAP_FIXED z flags. W takim przypadku to system wybierze adres mapowania; wybrany adres uniknie konfliktu z istniejacymi mapowaniami i nie bedzie wynosil 0. Jesli podano znacznik MAP_FIXED , a addr wynosi 0 (NULL), to mapowany adres bedzie wynosil 0 (NULL). Pewne stale flags sa zdefiniowane tylko wtedy, gdy zdefiniowano okreslone makro sprawdzania cech (byc moze stalo sie to domyslnie): _DEFAULT_SOURCE z glibc 2.19 lub pozniejszymi; _BSD_SOURCE lub _SVID_SOURCE w glibc 2.19 i wczesniejszych (podanie _GNU_SOURCE jest rowniez wystarczajace i wymaganie wlasnie tego makra byloby logiczniejsze, skoro wszystkie te znaczniki sa typowo linuksowe). Chodzi tu o znaczniki: MAP_32BIT, MAP_ANONYMOUS (i synonim MAP_ANON), MAP_DENYWRITE, MAP_EXECUTABLE, MAP_FILE, MAP_GROWSDOWN, MAP_HUGETLB, MAP_LOCKED, MAP_NONBLOCK, MAP_NORESERVE, MAP_POPULATE oraz MAP_STACK. Roznice biblioteki C/jadra Niniejszy podrecznik opisuje interfejs zapewniany przez funkcje opakowujaca mmap() z glibc. Pierwotnie, funkcja ta przywolywala wywolanie systemowe o tej samej nazwie. Od Linuksa 2.4, to wywolanie zostalo zastapione wywolaniem mmap2(2), dlatego obecnie funkcja opakowujaca mmap() z glibc przywoluje mmap2(2) z odpowiednio dostosowanymi wartosciami offset. STANDARDY POSIX.1-2008. HISTORIA POSIX.1-2001, SVr4, 4.4BSD. W systemach POSIX, na ktorych dostepne sa mmap(), msync(2) i munmap(), _POSIX_MAPPED_FILES jest zdefiniowane w na wartosc wieksza niz 0 (zob. tez sysconf(3)). UWAGI Pamiec mapowana za pomoca mmap() jest zachowywana poprzez fork(2) z tymi samymi atrybutami. Plik jest mapowany w wielokrotnosciach rozmiaru strony. Dla plikow, ktore nie sa wielokrotnosciami rozmiaru strony, pozostale bajty w czesciowej stronie na koncu mapowania sa zerowane podczas mapowania, a modyfikacje tego obszaru nie sa zapisywane w pliku. Efekt zmiany rozmiaru zamapowanego pliku na zamapowane strony, ktore odpowiadaja dodanym lub usunietym obszarom pliku, jest nieokreslony. Aplikacje moga sprawdzic, ktore strony mapowania sa aktualnie rezydentne w buforze/buforze strony za pomoca mincore(2). Bezpieczne korzystanie z MAP_FIXED Jedyne bezpieczne zastosowanie MAP_FIXED jest wtedy, gdy podany za pomoca addr i length zakres adresow byl uprzednio zarezerwowany przy uzyciu innego mapowania; w przeciwnym przypadku MAP_FIXED jest niebezpieczne, poniewaz przymusowo usuwa wczesniejsze mapowania, przez co w przypadku procesow wielowatkowych, latwe staje sie uszkodzenie swojej przestrzeni adresowej. Przykladowo zalozmy, ze watek A przeglada /proc/pid/maps, aby odszukac nieuzywany zakres adresow, ktore mozna zmapowac przy uzyciu MAP_FIXED, a watek B w tym samym czasie uzyska czesc lub calosc tego samego zakresu adresow. Gdy watek A nastepnie uzyje mmap(MAP_FIXED), efektywnie naruszy mapowanie, ktore utworzyl watek B. W opisywanym scenariuszu, watek B nie musi bezposrednio tworzyc mapowania; wystarczy utworzenie wywolania bibliotecznego, ktore wewnetrznie korzysta z dlopen(3) do zaladowania jakiejs innej biblioteki wspoldzielonej. Wywolanie dlopen(3) zmapuje biblioteke do przestrzeni adresowej procesu. Co wiecej, niemal kazde wywolanie biblioteczne moze byc zaimplementowane w sposob, ktory dodaje mapowania pamieci do przestrzeni adresowej, albo za pomoca tej techniki, albo jedynie alokujac pamiec. Przykladem moga byc brk(2), malloc(3), pthread_create(3) i biblioteki PAM . Od Linuksa 4.17, program wielowatkowy moze skorzystac ze znacznika MAP_FIXED_NOREPLACE, aby uniknac niebezpieczenstwa opisanego wyzej, przy tworzeniu mapowania pod konkretnym adresem, ktory nie zostal zarezerwowany wczesniejszym mapowaniem. Zmiany znacznikow czasu w przypadku mapowan opartych na plikach Dla mapowan opartych na plikach pole st_atime zamapowanego pliku moze zostac zaktualizowane w dowolnym momencie pomiedzy mmap() i usunieciem odpowiedniego mapowania; pierwsze odwolanie do zamapowanej strony spowoduje zaktualizowanie tego pola, jesli nie stalo sie to wczesniej. Pola st_ctime i st_mtime pliku zamapowanego z PROT_WRITE i MAP_SHARED zostanie zaktualizowane po zapisie do mapowanego obszaru, a przed pozniejszym wywolaniem msync(2) ze znacznikiem MS_SYNC lub MS_ASYNC, jesli taki wywolanie wystapi. Mapowania duzych stron (Huge TLB) W przypadku mapowan korzystajacych z duzych (huge) stron, wymagania dotyczace argumentow mmap() i munmap() roznia sie nieco, od wymagan mapowan, korzystajacych z natywnego systemowego rozmiaru strony. W przypadku mmap(), offset musi byc wielokrotnoscia uzywanego rozmiaru duzej strony. System automatycznie wyrowna length do wielokrotnosci uzywanego rozmiaru duzej strony. W przypadku munmap(), addr i length musza byc wielokrotnosciami uzywanego systemowego rozmiaru duzej strony. USTERKI W Linuksie, gwarancje zasugerowane powyzej w opisie MAP_NORESERVE nie istnieja. Domyslnie, kazdy proces moze byc zabity w dowolnym momencie, gdy systemowi wyczerpie sie pamiec. Przed Linuksem 2.6.7, znacznik MAP_POPULATE dzialal tylko, gdy prot okreslono jako PROT_NONE. SUSv3 okresla, ze mmap() powinno zawiesc, gdy length wynosi 0. Jednak przed Linuksem 2.6.12, mmap() bylo w takim przypadku pomyslne: nie tworzono mapowania, a wywolanie zwracalo addr. Od Linuksa 2.6.12, mmap() zawodzi w takim przypadku z bledem EINVAL. POSIX okresla, ze system powinien zawsze wypelniac zerami wszelkie strony czesciowe na koncu obiektu, a system nigdy nie zapisze zadnych modyfikacji obiektu poza jego koncem. W Linuksie, jesli zapisze sie dane do takiej czesciowej strony, poza koncem obiektu, dane pozostaja w buforze strony nawet po zamknieciu i odmapowaniu pliku, a choc dane nigdy nie sa zapisywane do samego pliku, kolejne mapowania moga zobaczyc zmodyfikowana zawartosc. W niektorych przypadkach, to zachowanie mozna poprawic wywolujac msync(2) przed dokonaniem odmapowania; jednak nie dziala to na tmpfs(5) (np. przy uzyciu interfejsu pamieci dzielonej POSIX opisanego w podreczniku shm_overview(7)). PRZYKLADY Ponizszy program wypisuje czesc pliku, okreslonego w jego pierwszym argumencie wiersza polecen, na standardowe wyjscie. Zakres wypisywanych bajtow podaje sie za pomoca wartosci przesuniecia i dlugosci, w drugim i trzecim argumencie wiersza polecen. Program tworzy mapowania pamieci wymaganych stron pliku, a nastepnie uzywa write(2) do wypisania zadanych bajtow. Kod zrodlowy programu #include #include #include #include #include #include #include #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[]) { int fd; char *addr; off_t offset, pa_offset; size_t length; ssize_t s; struct stat sb; if (argc < 3 || argc > 4) { fprintf(stderr, "przesuniecie pliku %s [dlugosc]\n", argv[0]); exit(EXIT_FAILURE); } fd = open(argv[1], O_RDONLY); if (fd == -1) handle_error("open"); if (fstat(fd, &sb) == -1) /* Do pobrania rozmiaru pliku */ handle_error("fstat"); offset = atoi(argv[2]); pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1); /* przesuniecie dla mmap() musi byc wyrownane do strony */ if (offset >= sb.st_size) { fprintf(stderr, "przesuniecie za koncem pliku\n"); exit(EXIT_FAILURE); } if (argc == 4) { length = atoi(argv[3]); if (offset + length > sb.st_size) length = sb.st_size - offset; /* Nie mozna wypisac bajtow poza koncem pliku */ } else { /* Brak arg. dlugosci ==> wyswietl do konca pliku */ length = sb.st_size - offset; } addr = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_PRIVATE, fd, pa_offset); if (addr == MAP_FAILED) handle_error("mmap"); s = write(STDOUT_FILENO, addr + offset - pa_offset, length); if (s != length) { if (s == -1) handle_error("write"); fprintf(stderr, "czesciowy zapis"); exit(EXIT_FAILURE); } munmap(addr, length + offset - pa_offset); close(fd); exit(EXIT_SUCCESS); } ZOBACZ TAKZE ftruncate(2), getpagesize(2), memfd_create(2), mincore(2), mlock(2), mmap2(2), mprotect(2), mremap(2), msync(2), remap_file_pages(2), setrlimit(2), shmat(2), userfaultfd(2), shm_open(3), shm_overview(7) Opis ponizszych plikow w proc(5): /proc/pid/maps, /proc/pid/map_files i /proc/pid/smaps. B.O. Gallmeister, POSIX.4, O'Reilly, str. 128-129 i 389-391. TLUMACZENIE Autorami polskiego tlumaczenia niniejszej strony podrecznika sa: Przemek Borys , Andrzej Krzysztofowicz i Michal Kulach Niniejsze tlumaczenie jest wolna dokumentacja. Blizsze informacje o warunkach licencji mozna uzyskac zapoznajac sie z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje sie ZADNEJ ODPOWIEDZIALNOSCI. Bledy w tlumaczeniu strony podrecznika prosimy zglaszac na adres listy dyskusyjnej . Linux man-pages 6.8 2 maja 2024 r. mmap(2)