mmap总线错误通过2Gb写入MAP_SHARED文件

时间:2014-04-01 18:52:22

标签: c linux mmap sigbus

我正在尝试使用MAP_SHARED创建内存映射文件。当文件大小达到2GB时,我遇到了问题。下面粘贴的代码就是我正在使用的代码(作为测试)。

#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)b / c linux内核实际上不会将页面映射到文件,直到你读取/写入mmap的区域。
  3. 如果我将mmap调用从MAP_SHARED更改为MAP_ANON(取消注释第一个mmap调用并注释掉第二个调用)并且没有链接到文件,则没有问题(即使写入成功)。
  4. / dev / shm(30gb)上有足够的空间,我这里只使用16GB。
  5. 我不必写入每个分配的字节。我只需要写入最后一个mmap的区域(将内部for循环移到外面),如果偏移+ BLOCK_SIZE&gt; = 2gb,那么我得到一个总线错误。
  6. 我在Ubuntu 13.10和CentOS 6.4上尝试了这个,但两者都有同样的问题。
  7. 我想知道这是否是Linux内核中的一个问题?有没有人尝试使用大于2gb的MAP_SHARED mmap'单个文件并成功使用(读/写)?

2 个答案:

答案 0 :(得分:2)

我认为问题是jint。当j达到较大值时,(j + 1) * BLOCK_SIZE会溢出并且您的ftruncate调用无法执行您想要的操作。检查ftruncate的返回值应该确认这一点。

mmap man page专门调用SIGBUS,意味着文件不支持尝试访问。

答案 1 :(得分:0)

我不确定这对您的情况是否有帮助。当我们遇到大文件问题时,以下内容有所帮助。我们把宏:

#define _FILE_OFFSET_BITS 64

包括标准标题之前。您也可以在调用gcc时在命令行上定义它。