can';t使用mmap/malloc/open等在64位linux系统上创建大于2GB的文件

can';t使用mmap/malloc/open等在64位linux系统上创建大于2GB的文件,c,linux,memory,64-bit,limits,C,Linux,Memory,64 Bit,Limits,好的,我知道以前有人以各种形式问过类似的问题,我已经阅读了所有这些问题,并尝试了所有建议,但我仍然无法在64位系统上使用malloc、open、lseek、诸如此类的技巧创建一个超过2GB的文件 很明显我在写c。我正在运行Fedora 20,实际上我正在尝试mmap文件,但这并不是它失败的地方,我最初的方法是使用open(),然后lseek到文件应该结束的位置,在本例中为3GB,edit:然后在文件结束位置写入一个字节以实际创建该大小的文件,然后mmap文件。我无法查看超过2GB的数据。我也不能

好的,我知道以前有人以各种形式问过类似的问题,我已经阅读了所有这些问题,并尝试了所有建议,但我仍然无法在64位系统上使用malloc、open、lseek、诸如此类的技巧创建一个超过2GB的文件

很明显我在写c。我正在运行Fedora 20,实际上我正在尝试mmap文件,但这并不是它失败的地方,我最初的方法是使用open(),然后lseek到文件应该结束的位置,在本例中为3GB,edit:然后在文件结束位置写入一个字节以实际创建该大小的文件,然后mmap文件。我无法查看超过2GB的数据。我也不能超过2GB。ulimit-a etc all show unlimited,/etc/security/limits.conf不显示任何内容

当我尝试lseek超过2GB时,我得到了errno的EINVAL,lseek的ret val是-1。edit:lseek的size参数是off类型,它定义为长整型(64位有符号),而不是我前面所说的size

编辑: 我已经尝试过定义_LARGEFILE64 _SOURCE&_FILE _OFFSET(偏移量)位64,但没有任何区别。 我还专门为64位即m64进行编译

我迷路了。我不知道为什么我不能这样做

任何帮助都将不胜感激

谢谢

编辑:我已经删除了很多完全不正确的胡言乱语,以及其他一些不重要的胡言乱语,这些都将在以后处理


我的2GB问题在于多种不同类型的交换非常草率。问题是有符号和无符号的混合。基本上,我传递给lseek的3GB位置被解释/转换为-1GB的位置,显然lseek不喜欢这样。所以我的错。完全愚蠢

我将按照p_l的建议改为使用posix_fallocate()。虽然它确实删除了一个函数调用,即只需要posix_fallocate,而不需要lseek,然后进行写入,但对我来说,这并不重要,事实是posix_fallocate正直接执行我想要的操作,而lseek方法没有。因此,特别感谢p_l的建议,特别感谢NominalAnimal,他更了解NominalAnimal的坚持,间接地让我意识到我无法计数,这反过来又让我接受posix_fallocate会起作用,因此改用它

不管我用的是什么结束法。2GB的问题完全是我自己的垃圾编码,再次感谢EOF、chux、p_l和Jonathon Leffler,他们都提供了信息和建议,引导我解决了我为自己制造的问题

我在回答中加入了一个简短的版本。

首先,请尝试:

//Before any includes:
#define  _LARGEFILE64_SOURCE
#define  _FILE_OFFSET_BITS 64
如果这不起作用,请像这样将
lseek
更改为
lseek64

lseek64(fd, 3221225472, SEEK_SET);
lseek
更好的选择可能是
posix\u fallocate()

在调用mmap()之前


不过,我建议保留定义:)

这是我创建的一个测试程序(
a2b.c
):

创建了
big.file

dd if=/dev/zero of=big.file bs=1048576 count=5000
我得到了令人安心的结果:

File: big.file; size 5242880000
All OK
我不得不使用
\u Static\u assert
而不是
Static\u assert
,因为Mac
头没有定义
Static\u assert
。当我使用
-m32
编译时,静态断言被触发

当我在Ubuntu13.10 64位虚拟机上运行它时,它有1Gib的虚拟物理内存(或者是重复的?),我毫不奇怪地得到了以下输出:

File: big.file; size 5242880000
failed to malloc 3221225472 bytes: (12) Cannot allocate memory
我使用完全相同的命令行编译代码;它在Linux上用
静态断言
代替
\u静态断言
编译OK。
ulimit-a
的输出表明最大内存大小是无限的,但这意味着“不小于机器上虚拟内存量施加的限制”,而不是任何更大的限制

请注意,我的编译没有明确包括
-m64
,但它们是自动的64位编译


你得到了什么?
dd
可以创建大文件吗?代码是否编译?(如果编译器中不支持C11,则需要将静态断言替换为正常的“动态”断言,删除错误消息。)代码是否运行?你得到了什么结果。

我的2GB问题是在多个不同类型的交换中非常草率。问题是有符号和无符号的混合。基本上,我传递给lseek的3GB位置被解释/转换为-1GB的位置,显然lseek不喜欢这样。所以我的错。完全愚蠢的垃圾编码

再次感谢EOF、chux、p_l和Jonathon Leffler,他们都提供了信息和建议,引导我找到了我创造的问题及其解决方案

再次感谢p_l建议posix_fallocate(),并特别感谢NominalAnimal,他更了解NominalAnimal的坚持,这间接地让我意识到我无法计数,这反过来又让我接受posix_fallocate将起作用,因此改为使用它


@虽然我实际问题的解决方案不在你的答案中,但我仍然支持你建议使用posix\u fallocate的答案,但我没有足够的理由这么做。

下面是一个示例程序,
example.c

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

static void err_exit(const char *fmt, ...);

int main(void)
{
    char const filename[] = "big.file";
    int fd = open(filename, O_RDONLY);
    if (fd < 0)
        err_exit("Failed to open file %s for reading", filename);
    struct stat sb;
    fstat(fd, &sb);
    uint64_t size = sb.st_size;
    printf("File: %s; size %" PRIu64 "\n", filename, size);
    assert(size > UINT64_C(3) * 1024 * 1024 * 1024);
    off_t offset = UINT64_C(3) * 1024 * 1024 * 1024;
    if (lseek(fd, offset, SEEK_SET) < 0)
        err_exit("lseek failed");
    close(fd);
    _Static_assert(sizeof(size_t) > 4, "sizeof(size_t) is too small");
    size = UINT64_C(3) * 1024 * 1024 * 1024;
    void *space = malloc(size);
    if (space == 0)
        err_exit("failed to malloc %zu bytes", size);
    *((char *)space + size - 1) = '\xFF';
    printf("All OK\n");
    return 0;
}

static void err_exit(const char *fmt, ...)
{
    int errnum = errno;
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, ": (%d) %s", errnum, strerror(errnum));
    putc('\n', stderr);
    exit(1);
}
/* Not required on 64-bit architectures; recommended anyway. */
#define  _FILE_OFFSET_BITS 64

/* Tell the compiler we do need POSIX.1-2001 features. */
#define  _POSIX_C_SOURCE 200112L

/* Needed to get MAP_NORESERVE. */
#define  _GNU_SOURCE

#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#ifndef   FILE_NAME
#define   FILE_NAME   "data.map"
#endif

#ifndef   FILE_SIZE
#define   FILE_SIZE   3221225472UL
#endif

int main(void)
{
    const size_t      size = FILE_SIZE;
    const char *const file = FILE_NAME;

    size_t            page;
    unsigned char    *data;

    int               descriptor;
    int               result;

    /* First, obtain the normal page size. */
    page = (size_t)sysconf(_SC_PAGESIZE);
    if (page < 1) {
        fprintf(stderr, "BUG: sysconf(_SC_PAGESIZE) returned an invalid value!\n");
        return EXIT_FAILURE;
    }

    /* Verify the map size is a multiple of page size. */
    if (size % page) {
        fprintf(stderr, "Map size (%lu) is not a multiple of page size (%lu)!\n",
                (unsigned long)size, (unsigned long)page);
        return EXIT_FAILURE;
    }

    /* Create backing file. */
    do {
        descriptor = open(file, O_RDWR | O_CREAT | O_EXCL, 0600);
    } while (descriptor == -1 && errno == EINTR);
    if (descriptor == -1) {
        fprintf(stderr, "Cannot create backing file '%s': %s.\n", file, strerror(errno));
        return EXIT_FAILURE;
    }

#ifdef FILE_ALLOCATE

    /* Allocate disk space for backing file. */
    do {
        result = posix_fallocate(descriptor, (off_t)0, (off_t)size);
    } while (result == -1 && errno == EINTR);
    if (result == -1) {
        fprintf(stderr, "Cannot resize and allocate %lu bytes for backing file '%s': %s.\n",
                (unsigned long)size, file, strerror(errno));
        unlink(file);
        return EXIT_FAILURE;
    }

#else

    /* Backing file is sparse; disk space is not allocated. */
    do {
        result = ftruncate(descriptor, (off_t)size);
    } while (result == -1 && errno == EINTR);
    if (result == -1) {
        fprintf(stderr, "Cannot resize backing file '%s' to %lu bytes: %s.\n",
                file, (unsigned long)size, strerror(errno));
        unlink(file);
        return EXIT_FAILURE;
    }

#endif

    /* Map the file.
     * If MAP_NORESERVE is not used, then the mapping size is limited
     * to the amount of available RAM and swap combined in Linux.
     * MAP_NORESERVE means that no swap is allocated for the mapping;
     * the file itself acts as the backing store. That's why MAP_SHARED
     * is also used. */
    do {
        data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE,
                    descriptor, (off_t)0);
    } while ((void *)data == MAP_FAILED && errno == EINTR);
    if ((void *)data == MAP_FAILED) {
        fprintf(stderr, "Cannot map file '%s': %s.\n", file, strerror(errno));
        unlink(file);
        return EXIT_FAILURE;
    }

    /* Notify of success. */
    fprintf(stdout, "Mapped %lu bytes of file '%s'.\n", (unsigned long)size, file);
    fflush(stdout);

#if defined(FILE_FILL)
    memset(data, ~0UL, size);
#elif defined(FILE_ZERO)
    memset(data, 0, size);
#elif defined(FILE_MIDDLE)
    data[size/2] = 1; /* One byte in the middle set to one. */
#else

    /*
     * Do something with the mapping, data[0] .. data[size-1]
    */

#endif

    /* Unmap. */
    do {
        result = munmap(data, size);
    } while (result == -1 && errno == EINTR);
    if (result == -1)
        fprintf(stderr, "munmap(): %s.\n", strerror(errno));

    /* Close the backing file. */
    result = close(descriptor);
    if (result)
        fprintf(stderr, "close(): %s.\n", strerror(errno));

#ifndef FILE_KEEP

    /* Remove the backing file. */
    result = unlink(file);
    if (result)
        fprintf(stderr, "unlink(): %s.\n", strerror(errno));

#endif

    /* We keep the file. */
    fprintf(stdout, "Done.\n");
    fflush(stdout);

    return EXIT_SUCCESS;
}
上述操作将创建一个3 GB(10243)的稀疏文件
data.map
,并将其中的中间字节设置为
1
\x01
)。文件中的所有其他字节保持为零。然后你就可以跑了

du -h data.map
查看这样一个稀疏文件在磁盘上实际占用的空间,以及

hexdump -C data.map
如果您希望验证文件内容是否与我声称的相同

有几个编译时标志(宏)可用于更改示例程序的行为方式:

  • '-DFILE_NAME=“filename”

    使用文件名
    filename
    而不是
    data.map
    。请注意,en
    gcc -W -Wall -O3 -DFILE_KEEP -DFILE_MIDDLE example.c -o example
    ./example
    
    du -h data.map
    
    hexdump -C data.map