2

MAP_SHARED を使用してメモリ マップ ファイルを作成しようとしています。ファイル サイズが 2 GB に達すると、問題が発生します。以下に貼り付けたコードは、私が(テストとして)使用しているものです。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>

#define MY_FILE "/dev/shm/mmap_test"
#define BLOCK_SIZE (1024*1024)
#define NUM_FILES 1

void mk_file(int f_num)
{ 
    uint64_t len = 0;
    int fd, j, k;
    char tmp_file[1024], *x, *rr_addr;

    // Open file in /dev/shm
    sprintf(tmp_file, "%s%d", MY_FILE, f_num);
    fd = open(tmp_file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

    if (fd == -1)
    {
        perror("file open");
        exit(-1);
    }

    // 16Gb file 
    len = 16UL * 1024 * 1024 * 1024;
    printf("len: %ld Gb\n", len/(1024*1024*1024));

    printf("Mapping %ld blocks\n", len/BLOCK_SIZE);

    for (j = 0; j < len/BLOCK_SIZE; j++) {
        // Increase the file size
        ftruncate(fd, ((j + 1) * BLOCK_SIZE));

        // Just mmap memory... don't have file backing
        //rr_addr = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_NORESERVE, -1, 0);

        // MMAP a region to the file at a given offset
        rr_addr = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd, (j * BLOCK_SIZE));

        if (rr_addr == MAP_FAILED) {
            perror("mmap error");
            printf("INDEX: %d\n", j);
            exit(-1);
        }

        // Write to every byte of allocated memory
        x = (char *) rr_addr;

        for (k = 0; k < BLOCK_SIZE; k++)
        {
            *x = '1';
            x++;
        }
    }

    return;
}

int main(int argc, char **argv)
{
    uint64_t i;

    for (i = 0; i < NUM_FILES; i++)
       mk_file(i);

    return 0;
}

上記のコードでは、ファイルのオフセットが 2GB に達するとバス エラーが発生します。これらは私が試したことです:

  1. NUM_FILES を 16 に、len を 1GB に変更しても問題はありません。
  2. メモリに書き込む for ループ (mmap のみ) を削除すると、プログラムはクラッシュしません (len が 2GB をはるかに超える場合でも)。Linux カーネルは、読み書きするまでページを実際にファイルにマップしません。 mmap された領域。
  3. mmap 呼び出しを MAP_SHARED から MAP_ANON に変更し (最初の mmap 呼び出しのコメントを解除し、2 番目の mmap 呼び出しをコメントアウト)、ファイルにリンクしていない場合、問題はありません (書き込みが成功した場合でも)。
  4. /dev/shm (30GB) には十分なスペースがあります。ここでは 16GB しか使用していません。
  5. 割り当てられたすべてのバイトに書き込む必要はありません。最後に mmap された領域 (内側の for ループを外側に移動) に書き込む必要があるだけで、オフセット + BLOCK_SIZE >= 2gb の場合、バス エラーが発生します。
  6. Ubuntu 13.10 と CentOS 6.4 でこれを試しましたが、どちらも同じ問題を抱えています。

これは Linux カーネルの問題でしょうか? 2 GB を超える MAP_SHARED を使用して単一のファイルを mmap し、それを正常に使用 (読み取り/書き込み) した人はいますか?

4

2 に答える 2

0

これがあなたの場合に役立つかどうかはわかりません。大きなファイルで問題が発生したときは、次のことが役に立ちました。マクロを入れました:

#define _FILE_OFFSET_BITS 64

標準ヘッダーを含める前。gcc を呼び出すときに、コマンド ラインでも定義できます。

于 2014-04-01T18:59:11.293 に答える