MMAP(2) | Linux Programmer's Manual | MMAP(2) |
名前
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 引き数で指定される。引き数 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
- On 32-bit architecture together with the large file extension (i.e., using 64-bit off_t): the number of pages used for length plus number of pages used for offset would overflow unsigned long (32 bits).
マップ領域を利用する際に、以下のシグナルが発生することがある:
- 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) を起動する。バグ
Linux においては、上記の MAP_NORESERVE で述べられているような保証はない。デフォルトでは、システムがメモリを使い切った場合には、どのプロセスがいつ強制終了されるか分からないからである。例
以下のプログラムは、一番目のコマンドライン引き数で指定されたファイルの一部を標準出力に表示する。表示する範囲は、二番目、三番目のコマンドライン引き数で渡されるオフセットと長さで指定される。このプログラムは、指定されたファイルの必要なページのメモリ・マッピングを作成し、 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)この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.51 の一部である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。2013-04-17 | Linux |