mmap - システムコールの説明 - Linux コマンド集 一覧表
名前
mmap, munmap - ファイルやデバイスをメモリにマップ/アンマップする
書式
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
説明
mmap ()関数は、ファイル記述子 (file descriptor) fd で指定されたファイル (もしくはその他のオブジェクト) の、オフセット offset から length バイトの範囲をメモリにマップする (張り付ける) 。 このとき、なるべくメモリ上の start アドレスから始めるようにマップする。実際には、このアドレスは関数に 対してのヒントでしかなく、通常は 0 を指定する。 実際にオブジェクトがマップされたアドレスは mmap ()の返り値となり、決して 0 にはなることはない。
引き数 prot には、メモリ保護をどのように行なうかを指定する (ファイルのオープンモードと矛盾してはいけない)。 prot には、 PROT_NONE 、または その他の PROT_* フラグをひとつ以上、ビット毎に OR 演算したものの いずれかを指定することができる。
- PROT_EXEC
- ページは実行可能である。
- PROT_READ
- ページは読み込み可能である。
- PROT_WRITE
- ページに書き込み可能である。
- PROT_NONE
-
ページにはアクセスできない。
引き数 flags には、マップされたオブジェクトのタイプ、マップ時のオプション、 マップされたページコピーへの変更を そのプロセスだけが行えるのか (それとも他のプロセスからも可能なのか) を指定する。 以下に示すビットデータを指定できる。
- MAP_FIXED
- 指定されたアドレス以外のアドレスにマッピングを行なわない。 start と len で指定されたメモリ領域が既存のマッピングのページと重なる場合、 既存のマッピングの重なった部分は捨てられる。 もし指定されたアドレスが使用できない場合、 mmap ()は失敗する。 MAP_FIXED を指定した場合は start はページサイズの倍数でなくてはいけない。 このオプションは使用しない方が良い。
- MAP_SHARED
- このマッピングを、このオブジェクトをマップした他の全てのプロセスと共有する。 この領域への保存は、ファイルへの書き込みと等価である。 ただしファイルが実際に更新されるのは、 msync (2) または munmap (2)が呼ばれたときである。
- MAP_PRIVATE
-
プライベートな copy-on-write (書き込み時コピー) マップを生成する。
この領域への書き込みは、オリジナルのファイルに影響しない。
mmap
()の呼び出し後にオリジナルのファイルに対して行われた変更が、
マップ領域に反映されるかどうかは規定されていない。
MAP_SHARED と MAP_PRIVATE は、必ずどちらかひとつを指定しなければならない。
上記の 3 つのフラグは POSIX.1-2001 で規定されている。 さらに、Linux では以下の非標準のフラグを使用することができる。
- MAP_DENYWRITE
- このフラグは無視される (ずっと前は、マップ元のファイルへの書き込みを行おうとすると、エラー ETXTBUSY で失敗するようにシグナルが設定されていたが、これは denial-of-service (サービス拒否) 攻撃の原因となった)。
- MAP_EXECUTABLE
- このフラグは無視される。
- MAP_NORESERVE
- このマッピングに対するスワップ空間の予約を行わない。 スワップ空間を予約した場合は、このマッピングの変更が必ず可能なことが 保証される。予約を行わなかった場合、物理メモリに空きがないと 書き込み時に SIGSEGV エラーを受け取ることがある。 proc (5) の /proc/sys/vm/overcommit_memory ファイルについての議論も参照。 バージョン 2.6 より前のカーネルでは、このフラグは書き込み可能な プライベート・マッピングについてのみ効果があった。
- MAP_LOCKED (Linux 2.5.37 以降)
- マップされた領域のページを mlock ()の方法でメモリ内にロックする。 それ以前のカーネルでは、このフラグは無視される。
- MAP_GROWSDOWN
- スタック用に使用される。マッピングをメモリ内で逆向きに行うことを カーネル VM システムに指示する。 (訳注:マッピングは通常はメモリ・アドレスが増加する向きに行うが、 このオプションを指定すると逆向きにマッピングを行う)
- MAP_ANONYMOUS
- マッピングはどのファイルとも関連付けされない。 引き数 fd と offset は無視される。このフラグと MAP_SHARED を組み合わせての利用は カーネル 2.4 以降の Linux でのみサポートされている。
- MAP_ANON
- MAP_ANONYMOUS の別名。非推奨。
- MAP_FILE
- 互換性のためのフラグ。無視される。
- MAP_32BIT
- マッピングをプロセスのアドレス空間の先頭 2GB の範囲に配置する。 MAP_FIXED がセットされている場合は、このフラグは無視される。 現在のところ、このフラグがサポートされているのは、x86-64 アーキテクチャ上 の 64 ビット・プログラムについてのみである。
- MAP_POPULATE (Linux 2.5.46 以降)
- ファイルを前もって読み込む (read-ahead) ことで、 ファイルマッピング用のページテーブルを配置 (populate) する (前もってページフォールトさせる (prefault))。 この後は、マッピングに対するアクセスがページフォールトで ブロックされなくなる。
- MAP_NONBLOCK (Linux 2.5.46 以降)
-
MAP_POPULATE
と組み合わせた場合のみ意味を持つ。
read-ahead (前もって読み込むこと) を実行しない。
単に、すでに RAM 上に存在するページに対して
ページテーブルエントリを作成するだけである。
いくつかのシステムでは、上記以外にフラグとして MAP_AUTOGROW, MAP_AUTORESRV, MAP_COPY, MAP_LOCAL が記載されている。
MAP_ANONYMOUS がセットされなかった場合、 fd は有効なファイル記述子でなければならない。 MAP_ANONYMOUS がセットされた場合、 Linux では fd は無視される。しかし、 MAP_ANONYMOUS (または MAP_ANON )を指定する場合に fd を -1 にする必要がある実装もあり、移植性を考慮した アプリケーションではこのようにすべきである。
offset は getpagesize (2) の返すページサイズの整数倍でなければならない。
mmap ()によってマップされたメモリの属性は fork (2) の際に継承される。
ファイルはページサイズの整数倍の領域にマップされる。サイズがページサイズの 整数倍でないファイルの場合、マップ時に残りの領域は 0 で埋められ、この領域へ 書きこみを行ってもファイルに書き出されることはない。マッピングを行った元 ファイルのサイズを変更した場合、元ファイルの追加されたり削除された領域に対応 するマップされたページに対してどのような影響があるかは規定されていない。 システムコール munmap ()は指定されたアドレス範囲のマップを消去し、 これ以降のその範囲内へのメモリ参照は不正となる。 この領域は、プロセスが終了したときにも自動的にアンマップされる。 一方、ファイル記述子をクローズしても、この領域はアンマップされない。
start アドレスはページサイズの整数倍でなければならない。指定された範囲の一部分を 含む全てのページはアンマップされ、これ以降にこれらのページへの参照があると SIGSEGV が発生する。 指定した範囲内にマップされたページが一つも含まれていない場合でも エラーにならない。 ファイルと関連付けられたマッピングの場合、マッピングされたファイルの st_atime フィールドは、 mmap ()されてからアンマップ (unmap) されるまでの間に更新されることがある。 それまでに更新が行われていなければ、マップされたページへの最初の参照があった 際に更新される。
PROT_WRITE と MAP_SHARED の両方を指定してマップされたファイルの場合、書き込みがあると、 st_ctime と st_mtime の両フィールドは、マップされた領域への書き込みより後で、 MS_SYNC または MS_ASYNC フラグが指定して msync ()が呼ばれる前までに更新される。
返り値
mmap ()は成功するとマップされた領域へのポインタを返す。 失敗すると値 MAP_FAILED (つまり (void *) -1) を返し、 errno がエラーの内容にしたがってセットされる。 munmap ()は成功すると 0 を返す。失敗すると -1 を返し、 errno がセットされる (多くの場合 EINVAL になるだろう)。
注意
PROT_READ に PROT_EXEC が含まれるかどうかは、アーキテクチャ依存である。 移植性を考慮したプログラムでは、 新規にマップした領域でコードを実行したい場合は、常に PROT_EXEC をセットすべきである。
エラー
- 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
- start か length か offset が適切でない (例えば、大きすぎるとか、ページ境界にアラインメントされていない)。
- ENFILE
- オープンされたファイルの総数がシステムの制限に達した。
- ENODEV
- 指定されたファイルが置かれているファイルシステムがメモリマッピングをサポート していない。
- ENOMEM
- メモリに空きがない、または処理中のプロセスのマッピング数が最大数を超過した。
- EPERM
- prot 引き数は PROT_EXEC を行うように指定されているが、 no-exec でマウントされたファイルシステム上のファイルに マップ領域が対応している。
- ETXTBSY
-
MAP_DENYWRITE
がセットされているが
fd
で指定されているオブジェクトは書き込み用に開かれている。
マップ領域を利用する際に、以下のシグナルが発生することがある:
- SIGSEGV
- 読み込み専用で mmap された領域へ書き込みを行おうとした。
- SIGBUS
- バッファのうち、ファイルに関連づけられていない部分 (例えばファイル末尾を越えた部分など。これには 他のプロセスがファイルを切り詰めた場合なども含まれる) にアクセスしようとした。
可用性
mmap (), msync () munmap ()が利用可能な POSIX システムでは、 _POSIX_MAPPED_FILES は <unistd.h> で 0 より大きな値に定義される ( sysconf (3)も参照のこと)。
準拠
SVr4, 4.4BSD, POSIX.1-2001.
バグ
Linux においては、上記の
MAP_NORESERVE
で述べられているような保証はない。
デフォルトでは、システムがメモリを使い切った場合には、
どのプロセスがいつ強制終了されるか分からないからである。
2.6.7 より前のカーネルでは、
prot
に
PROT_NONE
が指定された場合にのみ、
MAP_POPULATE
フラグが効力を持つ。
関連項目
getpagesize
(2),
mincore
(2),
mlock
(2),
mmap2
(2),
mremap
(2),
msync
(2),
remap_file_pages
(2),
setrlimit
(2),
shm_open
(3)
B.O. Gallmeister, POSIX.4, O'Reilly, pp. 128-129 and 389-391.