Provided by: manpages-ja-dev_0.5.0.0.20131015+dfsg-2_all
名前
mmap, munmap - ファイルやデバイスをメモリにマップ/アンマップする
書式
#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length); 機能検査マクロの要件に関する情報は「注意」の節を参照。
説明
mmap() は、新しいマッピングを呼び出し元プロセスの仮想アドレス空間に作成する。 新しいマッ ピングの開始アドレスは addr で指定される。マッピングの長さは length 引き数で指定される。 addr が NULL の場合、カーネルがマッピングを作成するアドレスを選択する。 この方法は最も移植 性のある新しいマッピングの作成方法である。 addr が NULL でない場合、カーネルはマッピングを どこに配置するかのヒントとして addr を使用する。Linux では、マッピングはすぐ近くのページ境 界に作成される。 新しいマッピングのアドレスは、呼び出しの返り値として返される。 ファイルマッピングの内容は、 ファイルディスクリプタ fd で参照されるファイル (もしくは他の オブジェクト) のオフセット offset から開始される length バイトのデータで初期化される (ファ イルマッピングは無名マッピングの反対語である。 MAP_ANONYMOUS を参照)。 offset は sysconf(_SC_PAGE_SIZE) が返すページサイズの倍数でなければならない。 引き数 prot には、マッピングのメモリ保護をどのように行なうかを指定する (ファイルのオープン モードと矛盾してはいけない)。 prot には、 PROT_NONE か、以下のフラグをひとつ以上ビット毎の 論理和 (OR) をとったものを 指定できる。 PROT_EXEC ページは実行可能である。 PROT_READ ページは読み込み可能である。 PROT_WRITE ページに書き込み可能である。 PROT_NONE ページにはアクセスできない。 flags 引き数により、マッピングに対する更新が同じ領域をマッピングしている 他のプロセスに見 えるか、更新がマッピング元のファイルを通じて 伝えられるか、が決定される。この動作は、以下 の値のいずれか一つだけ (複数は指定できない) を flags に含めることで指定する。 MAP_SHARED このマッピングを共有する。 マッピングに対する更新はこのファイルをマッピングして いる他のプロセス から見える。更新はマッピング元のファイルを通じて伝えられる。 ただし、ファイルの実際の更新は msync(2) または munmap() が呼ばれるまで行われな いこともある。 MAP_PRIVATE プライベートな copy-on-write (書き込み時コピー) マップを生成する。 マッピングに 対する更新は同じファイルをマッピングしている他のプロセス には見えず、更新がマッ ピング元のファイルを通じて伝えられることもない。 mmap() の呼び出し後にマッピン グ元のファイルに対して行われた変更が、 マップ領域に反映されるかどうかは規定され ていない。 上記の二つのフラグは POSIX.1-2001 で規定されている。 さらに、以下の値のうち 0 個以上をビット毎の論理和 (OR) で flags に指定することができる。 MAP_32BIT (Linux 2.4.20, 2.6 以降) マッピングをプロセスのアドレス空間の先頭 2 ギガバイト以内に配置する。 このフラグが サポートされているのは x86-64 アーキテクチャ上の 64 ビットプログラムのみである。 こ のフラグが追加されたのは、スレッドのスタックをメモリの先頭 2GB 以内の どこかに割り 当てることで、初期のいくつかの 64 ビットプロセッサにおける コンテキストスイッチの性 能問題を改善するためである。 最近の x86-64 プロセッサではこの性能問題はもはや存在せ ず、 そのようなシステムではこのフラグを使用する必要はない。 MAP_FIXED がセットされ ている場合は、 MAP_32BIT フラグは無視される。 MAP_ANON MAP_ANONYMOUS の同義語。非推奨。 MAP_ANONYMOUS マッピングはどのファイルとも関連付けされない。 マッピングの内容は 0 で初期化され る。 引き数 fd と offset は無視される。 ただし、実装によっては MAP_ANONYMOUS (もし くは MAP_ANON) が指定された場合、 fd を -1 にする必要があり、 移植性が必要なアプリ ケーションでは必ず fd を -1 にすべきである。 MAP_ANONYMOUS と MAP_SHARED を組み合わ せての利用は カーネル 2.4 以降の Linux でのみサポートされている。 MAP_DENYWRITE このフラグは無視される (ずっと前は、マップ元のファイルへの書き込みを行おうとする と、エラー ETXTBUSY で失敗するようにシグナルが設定されていたが、これは denial-of-service (サービス拒否) 攻撃の原因となった)。 MAP_EXECUTABLE このフラグは無視される。 MAP_FILE 互換性のためのフラグ。無視される。 MAP_FIXED addr をアドレスのヒントとして使用するのではなく、 addr で指定されたアドレスをそのま ま使用してマッピングを配置する。 addr はページサイズの倍数でなければならない。 addr と len で指定されたメモリ領域が既存のマッピングのページと重なる場合、 既存のマッピ ングの重なった部分は捨てられる。 もし指定されたアドレスが使用できない場合、 mmap() は失敗する。 マッピングに対して固定アドレスを要求するのは移植性の面で劣るので、 こ のオプションは使用しないことを推奨する。 MAP_GROWSDOWN スタック用に使用される。マッピングをメモリ内で逆向きに行うことを カーネル仮想メモリ システムに指示する。 (訳注:マッピングは通常はメモリ・アドレスが増加する向きに行う が、 このオプションを指定すると逆向きにマッピングを行う) MAP_HUGETLB (Linux 2.6.32 以降) "huge page" を使ってマッピングを割り当てる。詳しい情報は、Linux カーネルソースの Documentation/vm/hugetlbpage.txt を参照。 MAP_LOCKED (Linux 2.5.37 以降) マップされた領域のページを mlock(2) の方法でメモリ内にロックする。 それ以前のカー ネルでは、このフラグは無視される。 MAP_NONBLOCK (Linux 2.5.46 以降) MAP_POPULATE と組み合わせた場合のみ意味を持つ。 read-ahead (前もって読み込むこと) を実行しない。 単に、すでに RAM 上に存在するページに対してのみページテーブルエント リを作成する。 Linux 2.6.23 以降では、このフラグは MAP_POPULATE に何の影響も与えな い。 いつか MAP_POPULATE と MAP_NONBLOCK を組み合わせた場合の動作は実装し直されるか もしれない。 MAP_NORESERVE このマッピングに対するスワップ空間の予約を行わない。 スワップ空間を予約した場合 は、このマッピングの変更が必ず可能なことが 保証される。予約を行わなかった場合、物理 メモリに空きがないと 書き込み時に SIGSEGV エラーを受け取ることがある。 proc(5) の /proc/sys/vm/overcommit_memory ファイルについての議論も参照。 バージョン 2.6 より前 のカーネルでは、このフラグは書き込み可能な プライベート・マッピングについてのみ効果 があった。 MAP_POPULATE (Linux 2.5.46 以降) マッピング用のページテーブルを配置 (populate) する ファイルマッピングの場合には、こ れによりファイルが先読み (read-ahead) が行われる。この以後は、マッピングに対するア クセスがページフォールトで ブロックされることがなくなる。 Linux 2.6.23 以降でのみプ ライベート・マッピングについて MAP_POPULATE がサポートされている。 MAP_STACK (Linux 2.6.27 以降) プロセスやスレッドのスタックに適したアドレスにマッピングを割り当てる。 現在のとこ ろ、このフラグは何もしないが、 glibc のスレッド実装では使用されている。 これは、い くつかのアーキテクチャではスタックの割り当てに関して特別な扱い が必要な場合 に、glibc にそのサポートを後で透過的に実装できるようにする ためである。 MAP_UNINITIALIZED (Linux 2.6.33 以降) 無名ページ (anonymous page) のクリアを行わない。このフラグは組み込みデバイス での性 能向上を目的に作られてものである。カーネルの設定で CONFIG_MMAP_ALLOW_UNINITIALIZED オプションが有効になっている場合のみ、 このフラグは効果を持つ。 セキュリティ面の考 慮から、このオプションは通常組み込みデバイス (すなわち、 ユーザメモリの内容を完全に 制御化におけるデバイス) においてのみ有効にされる。 上記のフラグの中では、 MAP_FIXED だけが POSIX.1-2001 で規定されている。 しかしながら、ほと んどのシステムで MAP_ANONYMOUS (またはその同義語である MAP_ANON) もサポートされている。 いくつかのシステムでは、上記以外にフラグとして MAP_AUTOGROW, MAP_AUTORESRV, MAP_COPY, MAP_LOCAL が規定されている。 mmap() によってマップされたメモリの属性は fork(2) の際に継承される。 ファイルはページサイズの整数倍の領域にマップされる。サイズがページサイズの 整数倍でない ファイルの場合、マップ時に残りの領域は 0 で埋められ、この領域へ 書きこみを行ってもファイル に書き出されることはない。マッピングを行った元 ファイルのサイズを変更した場合、元ファイル の追加されたり削除された領域に対応 するマップされたページに対してどのような影響があるかは 規定されていない。 munmap() システムコール munmap() は指定されたアドレス範囲のマップを消去し、 これ以降のその範囲内へ のメモリ参照は不正となる。 この領域は、プロセスが終了したときにも自動的にアンマップされ る。 一方、ファイル記述子をクローズしても、この領域はアンマップされない。 addr アドレスはページサイズの整数倍でなければならない。指定された範囲の一部分を 含む全ての ページはアンマップされ、これ以降にこれらのページへの参照があると SIGSEGV が発生する。 指定 した範囲内にマップされたページが一つも含まれていない場合でも エラーにならない。 ファイルと関連付けられたマッピングに対するタイムスタンプの更新 ファイルと関連付けられたマッピングの場合、マッピングされたファイルの st_atime フィールド は、 mmap() されてからアンマップ (unmap) されるまでの間に更新されることがある。 それまで に更新が行われていなければ、マップされたページへの最初の参照があった 際に更新される。 PROT_WRITE と MAP_SHARED の両方を指定してマップされたファイルの場合、書き込みがあると、 st_ctime と st_mtime の両フィールドは、マップされた領域への書き込みより後で、 MS_SYNC また は MS_ASYNC フラグを指定して msync(2) が呼ばれる前までに更新される。
返り値
mmap() は成功するとマップされた領域へのポインタを返す。 失敗すると値 MAP_FAILED (つまり (void *) -1) を返し、 errno がエラーの内容にしたがってセットされる。 munmap() は成功する と 0 を返す。失敗すると -1 を返し、 errno がセットされる (多くの場合 EINVAL になるだろ う)。
エラー
EACCES 以下のいずれかの場合。 ファイル記述子の参照先が通常のファイルではない (non-regular file) 。 MAP_PRIVATE を要求したが fd は読み込み用にオープンされていない。 MAP_SHARED を要求して PROT_WRITE をセットしたが fd は読み書きモード (O_RDWR) で オープンされていない、 PROT_WRITE をセットしたが、ファイルは追加 (append) 専用であ る。 EAGAIN ファイルがロックされている。またはロックされているメモリが多すぎる (setrlimit(2) を参照)。 EBADF fd が有効なファイル記述子 (file descriptor) ではない (かつ MAP_ANONYMOUS がセットさ れていない)。 EINVAL addr か length か offset が適切でない (例えば、大きすぎるとか、ページ境界にアライン メントされていない)。 EINVAL (Linux 2.6.12 以降) length が 0 であった。 EINVAL flags に MAP_PRIVATE と MAP_SHARED のどちらも含まれていなかった、もしくは その両方 が含まれていた。 ENFILE システム全体でオープンされているファイルの総数が上限に達した。 ENODEV 指定されたファイルが置かれているファイルシステムがメモリマッピングをサポート してい ない。 ENOMEM メモリに空きがない、または処理中のプロセスのマッピング数が最大数を超過した。 EPERM prot 引き数は PROT_EXEC を行うように指定されているが、 no-exec でマウントされたファ イルシステム上のファイルに マップ領域が対応している。 ETXTBSY MAP_DENYWRITE がセットされているが fd で指定されているオブジェクトは書き込み用に開 かれている。 EOVERFLOW 32 ビットアーキテクチャで large file 拡張を使っている場合 (つまり 64 ビットの off_t を使う場合)、 length で使うページ数と offset で使うページ数を足した値は unsigned long (32 ビット) を超えてしまう (オーバーフローしてしまう) 場合がある。 マップ領域を利用する際に、以下のシグナルが発生することがある: SIGSEGV 読み込み専用で mmap された領域へ書き込みを行おうとした。 SIGBUS バッファのうち、ファイルに関連づけられていない部分 (例えばファイル末尾を越えた部分 など。これには 他のプロセスがファイルを切り詰めた場合なども含まれる) にアクセスし ようとした。
準拠
SVr4, 4.4BSD, POSIX.1-2001.
可用性
mmap(), msync(2) munmap() が利用可能な POSIX システムでは、 _POSIX_MAPPED_FILES は <unistd.h> で 0 より大きな値に定義される (sysconf(3) も参照のこと)。
注意
このページでは glibc の mmap() のラッパー関数が提供するインターフェースに ついて説明してい る。元々は、この関数は同じ名前のシステムコールを起動していた。 カーネル 2.4 以降、このシス テムコールは mmap2(2) に取って代わられ、現在 では、 glibc の mmap() のラッパー関数は offset を適切に調整してから mmap2(2) を起動する。 (i386 などの) いくつかのアーキテクチャでは、 PROT_WRITE をセットすると、暗黙のうちに PROT_READ がセットされる。 PROT_READ をセットした際に暗黙のうちに PROT_EXEC がセットされる かどうかは、アーキテクチャ依存である。 移植性を考慮したプログラムでは、 新規にマップした領 域でコードを実行したい場合は、常に PROT_EXEC をセットすべきである。 マッピングを作成する移植性のある方法は、 addr に 0 (NULL) を指定し、 flags から MAP_FIXED を外すことである。 この場合、システムがマッピング用のアドレスの選択を行う。 アドレスは既存 のマッピングと衝突しないように、 かつ 0 にならないように選択される。 MAP_FIXED フラグが指 定され、かつ addr が 0 (NULL) の場合には、マップされるアドレスが 0 (NULL) になる。 特定の flags 定数は _BSD_SOURCE か _SVID_SOURCE のいずれかが定義された場合にのみ定義され る。 (_GNU_SOURCE も定義されている必要がある。これらのフラグはすべて Linux 固有のものなの で、 特に _GNU_SOURCE を必要とする点はもっと論理的に決められるべきであった。) 関係するフラ グは MAP_32BIT, MAP_ANONYMOUS (とその同義語の MAP_ANON), MAP_DENYWRITE, MAP_EXECUTABLE, MAP_FILE, MAP_GROWSDOWN, MAP_HUGETLB, MAP_LOCKED, MAP_NONBLOCK, MAP_NORESERVE, MAP_POPULATE, MAP_STACK である。
バグ
Linux においては、上記の MAP_NORESERVE で述べられているような保証はない。 デフォルトで は、システムがメモリを使い切った場合には、 どのプロセスがいつ強制終了されるか分からないか らである。 2.6.7 より前のカーネルでは、 prot に PROT_NONE が指定された場合にのみ、 MAP_POPULATE フラ グが効力を持つ。 SUSv3 では、 length が 0 の場合、 mmap() は失敗すると規定されている。しかしながら、2.6.12 より前のカーネルでは、 この場合に mmap() は成功していた (マッピングは作成されず、 addr が 返されていた)。 カーネル 2.6.12 以降では、 mmap() はエラー EINVAL で失敗する。 POSIX では、 システムはオブジェクト末尾の部分ページを常に 0 で埋め、 末尾より後ろのオブ ジェクトを決して変更してはならない、と規定している。 Linux では、 オブジェクト末尾より後ろ の部分ページにデータを書き込んだ場合、 そのファイルをクローズしてアンマップした後であって もページキャッシュにデータが残り続け、 データがファイル自体に書き込まれていなくても、 それ 以降のマッピングで変更された内容が見える可能性がある。 いくつかの場合では、 アンマップを行 う前に msync(2) を呼び出すことで、 この状況を修正することができる。 しかし、 これは tmpfs では機能しない (例えば、 shm_overview(7) で説明されている POSIX 共有メモリインターフェース を使った場合)。
例
以下のプログラムは、一番目のコマンドライン引き数で指定された ファイルの一部を標準出力に表 示する。 表示する範囲は、二番目、三番目のコマンドライン引き数で渡される オフセットと長さで 指定される。 このプログラムは、指定されたファイルの必要なページのメモリ・ マッピングを作成 し、 write(2) を使って所望のバイトを出力する。 #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[]) { char *addr; int fd; struct stat sb; off_t offset, pa_offset; size_t length; ssize_t s; if (argc < 3 || argc > 4) { fprintf(stderr, "%s file offset [length]\n", argv[0]); exit(EXIT_FAILURE); } fd = open(argv[1], O_RDONLY); if (fd == -1) handle_error("open"); if (fstat(fd, &sb) == -1) /* To obtain file size */ handle_error("fstat"); offset = atoi(argv[2]); pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1); /* offset for mmap() must be page aligned */ if (offset >= sb.st_size) { fprintf(stderr, "offset is past end of file\n"); exit(EXIT_FAILURE); } if (argc == 4) { length = atoi(argv[3]); if (offset + length > sb.st_size) length = sb.st_size - offset; /* Can't display bytes past end of file */ } else { /* No length arg ==> display to end of file */ 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, "partial write"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
関連項目
getpagesize(2), mincore(2), mlock(2), mmap2(2), mprotect(2), mremap(2), msync(2), remap_file_pages(2), setrlimit(2), shmat(2), shm_open(3), shm_overview(7) proc(5) の /proc/[pid]/maps, /proc/[pid]/map_files, /proc/[pid]/smaps の説明。 B.O. Gallmeister, POSIX.4, O'Reilly, pp. 128-129 and 389-391.
この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.54 の一部 である。プロジェクト の説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。