Provided by: manpages-pl-dev_4.26.0-1_all 

NAZWA
mmap, munmap - mapuje lub usuwa mapowanie plików lub urządzeń w pamięci
BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)
SKŁADNIA
#include <sys/mman.h>
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 znajdują się w rozdziale UWAGI.
OPIS
mmap() tworzy nowe mapowanie w wirtualnej przestrzeni adresowej procesu wywołującego. Początkowy adres
nowego mapowania podaje się w addr. Argument length określa długość mapowania (musi być ono większe niż
0).
Jeśli addr wynosi NULL, to jądro wybiera (wyrównany do strony) adres, na którym utworzy mapowanie; jest
to najbardziej przenośna metoda tworzenia nowych mapowań. Jeśli addr nie wynosi NULL, to jądro traktuje
go jako wskazówkę na temat miejsca umieszczenia mapowania; w Linuksie, jądro wybierze najbliższą granicę
strony (jednak będzie ona zawsze równa lub większa wartości określonej w /proc/sys/vm/mmap_min_addr) i
spróbuje utworzyć tu nowe mapowanie. Jeśli inne mapowanie już tu istnieje, jądro wybierze nowy adres,
który może, lecz nie musi, zależeć od wskazówki. Adres nowego mapowania jest zwracany jako wynik
wywołania.
Zawartość mapowania pliku (w przeciwieństwie do mapowania anonimowego; zob. MAP_ANONYMOUS poniżej) jest
inicjowana za pomocą length bajtów zaczynających się w przesunięciu offset w pliku (lub innym obiekcie),
do którego odnosi się deskryptor pliku fd. offset musi być wielokrotnością rozmiaru strony, jaki zwraca
sysconf(_SC_PAGE_SIZE).
Po powrocie wywołania mmap(), deskryptor pliku fd może być niezwłocznie zamknięty, nie unieważniając
mapowania.
Argument prot opisuje oczekiwany sposób ochrony pamięci mapowania (i nie może być sprzeczny z trybem
otwarcia pliku). Może on być równy PROT_NONE lub może być sumą bitową (OR) jednego lub więcej spośród
innych znaczników PROT_*.
PROT_EXEC Strony mogą być wykonywane.
PROT_READ Strony mogą być odczytywane.
PROT_WRITE Strony mogą być zapisywane.
PROT_NONE Strony mogą nie być dostępne.
Argument flags
Argument flags określa, czy aktualizacje mapowania są widoczne dla innych procesów mapowanych do tego
samego miejsca i czy aktualizacje są przenoszone na sam plik. To zachowanie zależy od podanej, dokładnie
jednej z poniższych wartości flags:
MAP_SHARED
Dzieli zadane mapowanie. Aktualizacje mapowania są widoczne dla innych procesów mapowanych do tego
samego miejsca i (w przypadku mapowań opartych na pliku) są przenoszone do samego pliku (aby
kontrolować dokładnie, kiedy aktualizacje są przenoszone na sam plik, konieczne jest użycie
msync(2)).
MAP_SHARED_VALIDATE (od Linuksa 4.15)
Znacznik zapewnia takie same zachowanie jak MAP_SHARED z tą różnicą, że mapowania MAP_SHARED
ignorują nieznane znaczniki we flags. Przy tworzeniu mapowań z użyciem MAP_SHARED_VALIDATE, jądro
sprawdza natomiast, czy wszystkie przekazane znaczniki są znane i odmawia mapowania z błędem
EOPNOTSUPP, jeśli wystąpią nieznane znaczniki. Ten typ mapowania jest również wymagany, aby móc
korzystać z niektórych znaczników mapowań (np. MAP_SYNC).
MAP_PRIVATE
Tworzy prywatne mapowanie, typu „kopiowanie podczas zapisu”. Aktualizacje mapowania nie są
widoczne dla innych procesów mapujących ten sam plik i nie są przenoszone na sam plik. Nie jest
określone, czy zmiany zawartości pliku wykonane po wywołaniu mmap() będą uwidocznione w mapowanym
obszarze.
MAP_SHARED i MAP_PRIVATE są opisane w POSIX.1-2001 i POSIX.1-2008. MAP_SHARED_VALIDATE jest
rozszerzeniem Linuksa.
Ponadto, zero lub więcej poniższych wartości można zsumować bitowo (OR) we flags:
MAP_32BIT (od Linuksa 2.4.20, 2.6)
Umieszcza mapowanie w pierwszych 2 gigabajtach przestrzeni adresowej procesu. Znacznik jest
obsługiwany tylko na architekturze x86-64, w przypadku programów 64-bitowych. Znacznik dodano, aby
pozwolić stosom wątków na zaalokowanie w pierwszych 2 GB pamięci, co usprawniało wydajność
przełączania kontekstów na pewnych wczesnych procesorach 64-bitowych. Współczesne procesory x86-64
nie mają takiego problemu z wydajnością, zatem znacznik ten nie jest wymagany na tych systemach.
Znacznik MAP_32BIT jest ignorowany, gdy ustawiony jest MAP_FIXED.
MAP_ANON
Równoważne MAP_ANONYMOUS; istnieje dla kompatybilności z innymi implementacjami.
MAP_ANONYMOUS
Mapowanie nie jest oparte na pliku; jego zawartość jest inicjowana jako zero. Argument fd jest
ignorowany, jednak niektóre implementacje wymagają, aby fd wynosiło -1 jeśli podano MAP_ANONYMOUS
(lub MAP_ANON), dlatego przenośne aplikacje powinny używać tej wartości. Argument offset powinien
wynosić zero. Obsługę MAP_ANONYMOUS w połączeniu z MAP_SHARED dodano w Linuksie 2.4.
MAP_DENYWRITE
Ten znacznik jest ignorowany (dawno temu — Linux 2.0 i wcześniejsze — sygnalizował on, że próba
zapisu to mapowanego pliku powinna zawieść z ETXTBSY; było to jednak źródłem ataków blokujących
usługę (DoS)).
MAP_EXECUTABLE
Ten znacznik jest ignorowany.
MAP_FILE
Znacznik służący zgodności. Ignorowany.
MAP_FIXED
Nie interpretuje addr jako wskazówki: umieszcza mapowanie dokładnie na podanym adresie. addr musi
być właściwie wyrównany: w przypadku większości architektur, wystarczająca jest wielokrotność
rozmiaru strony; jednak niektóre architektury mogą narzucać dodatkowe ograniczenia. Jeśli obszar
pamięci podany w addr i length nachodzi na strony jakiegoś istniejącego mapowania, to te
nachodzące części istniejącego mapowania zostaną odrzucone. Jeśli podany adres nie może być użyty,
wywołanie mmap() zawiedzie.
Oprogramowanie, które ma zamiar być przenośne, powinno bardzo ostrożnie korzystać ze znacznika
MAP_FIXED, mając na względzie, że dokładny schemat mapowań pamięci procesu może się znacznie
zmieniać pomiędzy wersjami Linuksa, wersjami biblioteki C i wydaniami systemu operacyjnego. Proszę
dokładnie przeczytać omówienie tego znacznika w UWAGACH!
MAP_FIXED_NOREPLACE (od Linuksa 4.17)
Znacznik zapewnia zachowanie podobne do MAP_FIXED, jeśli chodzi o wymuszenie adresu addr, lecz z
tą różnicą, że MAP_FIXED_NOREPLACE nigdy nie narusza wcześniejszego zakresu mapowania. Jeśli
żądany zakres kolidowałby z istniejącym mapowaniem, to wywołanie zawiedzie z błędem EEXIST.
Znacznik ten może zatem posłużyć do niepodzielnej (z uwzględnieniem innym wątków) próby mapowania
zakresu adresowego: u jednego wątku powiedzie się to, wszystkie inne zawiodą.
Proszę zauważyć, że starsze jądra, które nie rozpoznają znacznika MAP_FIXED_NOREPLACE, zwykle (po
wykryciu kolizji z wcześniejszym mapowaniem) awaryjnie zachowają się jak „nie-MAP_FIXED”: zwrócą
adres, który jest odmienny od adresu żądanego. Oprogramowanie, które ma być kompatybilne
wstecznie, powinno zatem sprawdzać zwracany adres z adresem żądanym.
MAP_GROWSDOWN
Znacznik jest używany do stosów. Wskazuje systemowi pamięci wirtualnej jądra, że mapowanie ma
kontynuować się w dół pamięci. Zwracany adres jest o jedną stronę niżej, niż obszar pamięci, który
jest w rzeczywistości tworzony w wirtualnej przestrzeni adresowej procesu. Dotknięcie adresu w
„strzeżonej” stronie (guard page) poniżej mapowania spowoduje zwiększenie mapowania o jedną
stronę. Ten wzrost można powtarzać do momentu, gdy mapowanie osiągnie wysoki koniec strony
następnego niższego mapowania; wówczas dotknięcie „strzeżonej” strony spowoduje sygnał SIGSEGV.
MAP_HUGETLB (od Linuksa 2.6.32)
Przydziela mapowanie za pomocą dużych („huge”) stron. Więcej informacji w pliku
Documentation/admin-guide/mm/hugetlbpage.rst w źródłach jądra Linux oraz w UWAGACH poniżej.
MAP_HUGE_2MB
MAP_HUGE_1GB (od Linuksa 3.8)
Używane w połączeniu z MAP_HUGETLB, do wybrania alternatywnych rozmiarów strony hugetlb
(odpowiednio, 2 MB i 1 GB) w systemach, które obsługują wiele rozmiarów stron hugetlb.
Ogólniej, żądany rozmiar dużych stron można skonfigurować, podając logarytm o podstawie 2,
żądanego rozmiaru strony, w sześciu bitach na przesunięciu MAP_HUGE_SHIFT (wartość zero w tym polu
bitowym oznacza domyślny rozmiar dużej strony; można go sprawdzić za pomocą pola Hugepagesize
ujawnianego w /proc/meminfo). Zatem, powyższe dwie stałe są zdefiniowane jako:
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
Zakres obsługiwanych rozmiarów dużych stron w systemie można sprawdzić, wypisując podkatalogi w
katalogu /sys/kernel/mm/hugepages.
MAP_LOCKED (od Linuksa 2.5.37)
Oznacza mapowany obszar jako zablokowany w ten sam sposób, jak robi to mlock(2). Ta implementacja
postara się wypełnić (prefault) cały zakres, lecz wywołanie mmap() nie zawodzi z błędem ENOMEM gdy
się to nie powiedzie. Z tego względu później mogą wystąpić główne chybienia stron (ang. major page
fault). Semantyka ta nie jest zatem tak mocna jak mlock(2). Jeśli po zainicjowaniu mapowania nie
są później dopuszczalne główne chybienia stron, należy korzystać w zamian z mmap() wraz z
mlock(2). Znacznik MAP_LOCKED jest ignorowany przez starsze jądra.
MAP_NONBLOCK (od Linuksa 2.5.46)
Znacznik ten ma znaczenie tylko w połączeniu z MAP_POPULATE. Nie przeprowadza odczytu naprzód:
wpisy tablicy stron są tworzone tylko w przypadku stron, które są już obecne w RAM. Od Linuksa
2.6.23, znacznik ten nie ma wpływu na MAP_POPULATE. W przyszłości, połączenie MAP_POPULATE z
MAP_NONBLOCK może zostać na nowo zaimplementowane.
MAP_NORESERVE
Poleca nie rezerwować przestrzeni wymiany dla tego mapowania. Gdy przestrzeń wymiany jest
zarezerwowana, ma się gwarancję, że istnieje możliwość modyfikacji mapowania. Gdy przestrzeń
wymiany nie jest zarezerwowana, można otrzymać SIGSEGV podczas zapisu, jeśli braknie pamięci
fizycznej. Proszę zapoznać się również z opisem pliku /proc/sys/vm/overcommit_memory w proc(5).
Przed Linuksem 2.6, znacznik ten działał tylko dla prywatnych, zapisywalnych mapowań.
MAP_POPULATE (od Linuksa 2.5.46)
Wypełnia (prefault) tablice strony dla mapowania. W przypadku mapowania pliku, powoduje to odczyt
z wyprzedzeniem pliku. W ten sposób redukuje się blokowanie, przy późniejszych chybieniach stron
(ang. page fault). Wywołanie mmap() nie zawodzi, jeśli nie da się wypełnić mapowania (np. ze
względu na ograniczenie liczby mapowanych dużych (huge) stron, za pomocą MAP_HUGETLB). Obsługę
MAP_POPULATE w połączeniu 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 wątku.
Znacznik ten jest w Linuksie instrukcją pustą. Jednak podając go, przenośne aplikacje mogą
zapewnić zyskanie obsługi znacznika, gdy zostanie on w przyszłości zaimplementowany. Z tego
względu jest używany w implementacji wątkowania glibc, aby uwzględnić fakt, że niektóre
architektury mogą (w przyszłości) wymagać specjalnego traktowania przy alokowaniu stosu. Kolejnym
powodem korzystania z tego znacznika jest przenośność: MAP_STACK istnieje (i działa) na niektórych
innych systemach (np. niektórych BSD).
MAP_SYNC (od Linuksa 4.15)
Znacznik ten jest dostępny jedynie z typem mapowania MAP_SHARED_VALIDATE; mapowania typu
MAP_SHARED po cichu go zignorują. Znacznik ten jest obsługiwany jedynie dla plików obsługujących
DAX (bezpośrednie mapowanie do pamięci trwałej). W przypadku innych plików, utworzenie mapowania z
tym znacznikiem spowoduje wystąpienie błędu EOPNOTSUPP.
Dzielone mapowania pliku z tym znacznikiem zapewniają gwarancję, że choć pewna część pamięci
będzie zmapowana jako zapisywalna w przestrzeni adresowej procesu, będzie ona widoczna w tym samym
pliku, na tym samym przesunięciu, nawet po załamaniu lub przeładowaniu systemu. W połączeniu z
odpowiednimi instrukcjami procesora, użytkownicy takich mapowań mają zapewnioną lepszy tryb
czynienia modyfikacji danych trwałymi.
MAP_UNINITIALIZED (od Linuksa 2.6.33)
Nie czyści stron anonimowych. Znacznik ten ma polepszyć wydajność na urządzeniach wbudowanych.
Znacznik jest przestrzegany tylko, gdy jądro skonfigurowano z opcją
CONFIG_MMAP_ALLOW_UNINITIALIZED. Ze względu na skutki w zakresie bezpieczeństwa, opcja ta jest
zwykle włączana wyłącznie na urządzeniach wbudowanych (tj. mających całkowitą kontrolę nad
zawartością pamięci użytkownika).
Z powyższych znaczników, jedynie MAP_FIXED jest określony przez POSIX.1-2001 i POSIX.1-2008. Większość
systemów obsługuje jednak także MAP_ANONYMOUS (lub jego synonim MAP_ANON).
munmap()
Wywołanie systemowe munmap() usuwa mapowanie z podanego zakresu adresów i powoduje, że dalsze odwołania
do adresów z tego zakresu będą generować nieprawidłowe odwołania do pamięci. Mapowanie obszaru jest
również automatycznie usuwane, gdy proces się zakończy. Z drugiej strony, zamknięcie deskryptora pliku
nie usuwa mapowania obszaru.
Adres addr musi być wielokrotnością rozmiaru strony (ale length już nie musi). Usuwane jest mapowanie
wszystkich stron zawierających fragmenty ze wskazanego zakresu, wszystkie późniejsze odwołania do tych
stron wygenerują SIGSEGV. Nie jest błędem, gdy brak w podanym zakresie zamapowanych stron.
WARTOŚĆ ZWRACANA
Po pomyślnym zakończeniu mmap() zwraca wskaźnik do mapowanego obszaru. Po błędzie zwracane jest
MAP_FAILED (tj. (void *) -1) i ustawiane errno, wskazując błąd.
Po pomyślnym zakończeniu munmap() zwraca 0. Po błędzie zwracane jest -1 i ustawiane errno, wskazując błąd
(prawdopodobnie 1EINVAL).
BŁĘDY
EACCES Deskryptor pliku odnosi się do pliku innego niż zwykły plik. Lub zażądano mapowania pliku, lecz fd
nie jest otwarty do odczytu. Lub zażądano 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 został zablokowany lub zablokowano zbyt wiele pamięci (zob. setrlimit(2)).
EBADF fd nie jest prawidłowym deskryptorem pliku (a nie ustawiono MAP_ANONYMOUS).
EEXIST We flags podano MAP_FIXED_NOREPLACE, a zakres który opisuje addr i length koliduje z istniejącym
mapowaniem.
EINVAL Niewłaściwe addr, length lub offset (np. mogą być zbyt duże lub niewyrównane do granicy strony).
EINVAL (od Linuksa 2.6.12) length wynosiła 0.
EINVAL We flags nie wystąpiło żadne z: MAP_PRIVATE, MAP_SHARED lub MAP_SHARED_VALIDATE.
ENFILE Zostało osiągnięte systemowe ograniczenie na całkowitą liczbę otwartych plików.
ENODEV System plików, na którym znajduje się podany plik, nie obsługuje mapowania w pamięci.
ENOMEM Brak dostępnej pamięci.
ENOMEM Doszłoby do przekroczenia maksymalnej liczby mapowań procesu. Błąd ten może wystąpić również dla
munmap(), przy usuwaniu mapowania z obszaru w środku istniejącego mapowania, ponieważ
spowodowałoby to powstanie dwóch mniejszych mapowań po obu stronach niezmapowanego obszaru.
ENOMEM (od Linuksa 4.7) Doszłoby do przekroczenia limitu RLIMIT_DATA procesu, opisanego w podręczniku
getrlimit(2).
ENOMEM addr przekroczyłoby wirtualną przestrzeń adresową procesora.
EOVERFLOW
Na architekturze 32-bitowej z rozszerzeniem dużych plików (tj. korzystając z 64-bitowego off_t):
liczba stron użytych dla length wraz z liczbą stron użytych dla offset przepełniłaby liczbę typu
unsigned long (32-bitową).
EPERM Argument prot pyta o PROT_EXEC lecz mapowany obszar należy do pliku zamontowanego na systemie
plików z opcją no-exec (bez zezwolenia na wykonywanie).
EPERM Operacja zablokowana, z powodu zapieczętowania pliku (ang. file seal); zob. fcntl(2).
EPERM Podano znacznik MAP_HUGETLB, lecz wywołujący nie był uprzywilejowany (nie miał przywileju
CAP_IPC_LOCK (ang. capability)) i nie jest członkiem 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.
Użycie zamapowanego obszaru może spowodować wystąpienie następujących sygnałów:
SIGSEGV
Próba zapisu do obszaru zmapowanego tylko do odczytu.
SIGBUS Próba dostępu do strony bufora, która leży poza końcem mapowanego pliku. Wyjaśnienie traktowania
bajtów w stronie, która odnosi się do końca mapowanego pliku i nie jest wielokrotnością rozmiaru
strony zamieszczono w UWAGACH.
ATRYBUTY
Informacje o pojęciach używanych w tym rozdziale można znaleźć w podręczniku attributes(7).
┌──────────────────────────────────────────────────────────────┬────────────────────────┬───────────────┐
│ Interfejs │ Atrybut │ Wartość │
├──────────────────────────────────────────────────────────────┼────────────────────────┼───────────────┤
│ mmap(), munmap() │ Bezpieczeństwo wątkowe │ MT-bezpieczne │
└──────────────────────────────────────────────────────────────┴────────────────────────┴───────────────┘
WERSJE
Na niektórych architekturach sprzętowych (np. i386), PROT_WRITE wymusza PROT_READ. Od architektury
zależy, czy PROT_READ wymusza PROT_EXEC, czy nie. Programy przenośne powinny zawsze ustawiać PROT_EXEC,
jeśli mają zamiar wykonywać kod w nowym mapowaniu.
Przenośnym sposobem tworzenia mapowań jest podanie addr jako 0 (NULL) i pominięcie MAP_FIXED z flags. W
takim przypadku to system wybierze adres mapowania; wybrany adres uniknie konfliktu z istniejącymi
mapowaniami i nie będzie wynosił 0. Jeśli podano znacznik MAP_FIXED , a addr wynosi 0 (NULL), to mapowany
adres będzie wynosił 0 (NULL).
Pewne stałe flags są zdefiniowane tylko wtedy, gdy zdefiniowano określone makro sprawdzania cech (być
może stało się to domyślnie): _DEFAULT_SOURCE z glibc 2.19 lub późniejszymi; _BSD_SOURCE lub _SVID_SOURCE
w glibc 2.19 i wcześniejszych (podanie _GNU_SOURCE jest również wystarczające i wymaganie właśnie tego
makra byłoby logiczniejsze, skoro wszystkie te znaczniki są 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.
Różnice biblioteki C/jądra
Niniejszy podręcznik opisuje interfejs zapewniany przez funkcję opakowującą mmap() z glibc. Pierwotnie,
funkcja ta przywoływała wywołanie systemowe o tej samej nazwie. Od Linuksa 2.4, to wywołanie zostało
zastąpione wywołaniem mmap2(2), dlatego obecnie funkcja opakowująca mmap() z glibc przywołuje mmap2(2) z
odpowiednio dostosowanymi wartościami offset.
STANDARDY
POSIX.1-2008.
HISTORIA
POSIX.1-2001, SVr4, 4.4BSD.
W systemach POSIX, na których dostępne są mmap(), msync(2) i munmap(), _POSIX_MAPPED_FILES jest
zdefiniowane w <unistd.h> na wartość większą niż 0 (zob. też sysconf(3)).
UWAGI
Pamięć mapowana za pomocą mmap() jest zachowywana poprzez fork(2) z tymi samymi atrybutami.
Plik jest mapowany w wielokrotnościach rozmiaru strony. Dla plików, które nie są wielokrotnościami
rozmiaru strony, pozostałe bajty w częściowej stronie na końcu mapowania są zerowane podczas mapowania, a
modyfikacje tego obszaru nie są zapisywane w pliku. Efekt zmiany rozmiaru zamapowanego pliku na
zamapowane strony, które odpowiadają dodanym lub usuniętym obszarom pliku, jest nieokreślony.
Aplikacje mogą sprawdzić, które strony mapowania są aktualnie rezydentne w buforze/buforze strony za
pomocą mincore(2).
Bezpieczne korzystanie z MAP_FIXED
Jedyne bezpieczne zastosowanie MAP_FIXED jest wtedy, gdy podany za pomocą addr i length zakres adresów
był uprzednio zarezerwowany przy użyciu innego mapowania; w przeciwnym przypadku MAP_FIXED jest
niebezpieczne, ponieważ przymusowo usuwa wcześniejsze mapowania, przez co w przypadku procesów
wielowątkowych, łatwe staje się uszkodzenie swojej przestrzeni adresowej.
Przykładowo załóżmy, że wątek A przegląda /proc/pid/maps, aby odszukać nieużywany zakres adresów, które
można zmapować przy użyciu MAP_FIXED, a wątek B w tym samym czasie uzyska część lub całość tego samego
zakresu adresów. Gdy wątek A następnie użyje mmap(MAP_FIXED), efektywnie naruszy mapowanie, które
utworzył wątek B. W opisywanym scenariuszu, wątek B nie musi bezpośrednio tworzyć mapowania; wystarczy
utworzenie wywołania bibliotecznego, które wewnętrznie korzysta z dlopen(3) do załadowania jakiejś innej
biblioteki współdzielonej. Wywołanie dlopen(3) zmapuje bibliotekę do przestrzeni adresowej procesu. Co
więcej, niemal każde wywołanie biblioteczne może być zaimplementowane w sposób, który dodaje mapowania
pamięci do przestrzeni adresowej, albo za pomocą tej techniki, albo jedynie alokując pamięć. Przykładem
mogą być brk(2), malloc(3), pthread_create(3) i biblioteki PAM http://www.linux-pam.org.
Od Linuksa 4.17, program wielowątkowy może skorzystać ze znacznika MAP_FIXED_NOREPLACE, aby uniknąć
niebezpieczeństwa opisanego wyżej, przy tworzeniu mapowania pod konkretnym adresem, który nie został
zarezerwowany wcześniejszym mapowaniem.
Zmiany znaczników czasu w przypadku mapowań opartych na plikach
Dla mapowań opartych na plikach pole st_atime zamapowanego pliku może zostać zaktualizowane w dowolnym
momencie pomiędzy mmap() i usunięciem odpowiedniego mapowania; pierwsze odwołanie do zamapowanej strony
spowoduje zaktualizowanie tego pola, jeśli nie stało się to wcześniej.
Pola st_ctime i st_mtime pliku zamapowanego z PROT_WRITE i MAP_SHARED zostanie zaktualizowane po zapisie
do mapowanego obszaru, a przed późniejszym wywołaniem msync(2) ze znacznikiem MS_SYNC lub MS_ASYNC, jeśli
taki wywołanie wystąpi.
Mapowania dużych stron (Huge TLB)
W przypadku mapowań korzystających z dużych (huge) stron, wymagania dotyczące argumentów mmap() i
munmap() różnią się nieco, od wymagań mapowań, korzystających z natywnego systemowego rozmiaru strony.
W przypadku mmap(), offset musi być wielokrotnością używanego rozmiaru dużej strony. System automatycznie
wyrówna length do wielokrotności używanego rozmiaru dużej strony.
W przypadku munmap(), addr i length muszą być wielokrotnościami używanego systemowego rozmiaru dużej
strony.
USTERKI
W Linuksie, gwarancje zasugerowane powyżej w opisie MAP_NORESERVE nie istnieją. Domyślnie, każdy proces
może być zabity w dowolnym momencie, gdy systemowi wyczerpie się pamięć.
Przed Linuksem 2.6.7, znacznik MAP_POPULATE działał tylko, gdy prot określono jako PROT_NONE.
SUSv3 określa, że mmap() powinno zawieść, gdy length wynosi 0. Jednak przed Linuksem 2.6.12, mmap() było
w takim przypadku pomyślne: nie tworzono mapowania, a wywołanie zwracało addr. Od Linuksa 2.6.12, mmap()
zawodzi w takim przypadku z błędem EINVAL.
POSIX określa, ze system powinien zawsze wypełniać zerami wszelkie strony częściowe na końcu obiektu, a
system nigdy nie zapisze żadnych modyfikacji obiektu poza jego końcem. W Linuksie, jeśli zapisze się dane
do takiej częściowej strony, poza końcem obiektu, dane pozostają w buforze strony nawet po zamknięciu i
odmapowaniu pliku, a choć dane nigdy nie są zapisywane do samego pliku, kolejne mapowania mogą zobaczyć
zmodyfikowaną zawartość. W niektórych przypadkach, to zachowanie można poprawić wywołując msync(2) przed
dokonaniem odmapowania; jednak nie działa to na tmpfs(5) (np. przy użyciu interfejsu pamięci dzielonej
POSIX opisanego w podręczniku shm_overview(7)).
PRZYKŁADY
Poniższy program wypisuje część pliku, określonego w jego pierwszym argumencie wiersza poleceń, na
standardowe wyjście. Zakres wypisywanych bajtów podaje się za pomocą wartości przesunięcia i długości, w
drugim i trzecim argumencie wiersza poleceń. Program tworzy mapowania pamięci wymaganych stron pliku, a
następnie używa write(2) do wypisania żądanych bajtów.
Kod źródłowy programu
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#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, "przesunięcie pliku %s [długość]\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);
/* przesunięcie dla mmap() musi być wyrównane do strony */
if (offset >= sb.st_size) {
fprintf(stderr, "przesunięcie za końcem pliku\n");
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Nie można wypisać bajtów poza końcem pliku */
} else { /* Brak arg. długości ==> wyświetl do końca 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, "częściowy zapis");
exit(EXIT_FAILURE);
}
munmap(addr, length + offset - pa_offset);
close(fd);
exit(EXIT_SUCCESS);
}
ZOBACZ TAKŻE
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 poniższych plików 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.
TŁUMACZENIE
Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Przemek Borys <pborys@dione.ids.pl>,
Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl> i Michał Kułach <michal.kulach@gmail.com>
Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać
zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ
ODPOWIEDZIALNOŚCI.
Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-
list@lists.sourceforge.net.
Linux man-pages 6.9.1 15 czerwca 2024 r. mmap(2)