Provided by: manpages-pl-dev_4.23.1-1_all bug

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).
       ┌──────────────────────────────────────────────────────────────┬────────────────────────┬───────────────┐
       │ InterfejsAtrybutWartość       │
       ├──────────────────────────────────────────────────────────────┼────────────────────────┼───────────────┤
       │ 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.8                              2 maja 2024 r.                                          mmap(2)