Почему mmap () не работает с ENOMEM для разреженного файла размером 1 ТБ?

Я работал с большими разреженными файлами на openSUSE 11.2 x86_64. Когда я пытаюсь использовать mmap () для разреженного файла размером 1 ТБ, ENOMEM терпит неудачу. Я бы подумал, что 64-битное адресное пространство будет достаточно для отображения в терабайте, но, похоже, нет. Поэкспериментируя дальше, файл размером 1 ГБ работает нормально, а файл размером 2 ГБ (и все, что больше) не работает. Я предполагаю, что здесь есть какие-то настройки, но тщательный поиск ничего не дает.

Вот пример кода, который показывает проблему - какие-нибудь подсказки?

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    char * filename = argv[1];
    int fd;
    off_t size = 1UL << 40; // 30 == 1GB, 40 == 1TB

    fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
    ftruncate(fd, size);
    printf("Created %ld byte sparse file\n", size);

    char * buffer = (char *)mmap(NULL, (size_t)size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if ( buffer == MAP_FAILED ) {
        perror("mmap");
        exit(1);
    }
    printf("Done mmap - returned 0x0%lx\n", (unsigned long)buffer);

    strcpy( buffer, "cafebabe" );
    printf("Wrote to start\n");

    strcpy( buffer + (size - 9), "deadbeef" );
    printf("Wrote to end\n");

    if ( munmap(buffer, (size_t)size) < 0 ) {
        perror("munmap");
        exit(1);
    }
    close(fd);

    return 0;
}

person metadaddy    schedule 26.05.2010    source источник
comment
Интересно, что ваша программа работает для меня размером до 256 ГБ (1 << 38), а все, что выше, возвращает EINVAL. Это на RHEL4 (ядро 2.6.9-42.0.3.ELsmp).   -  person caf    schedule 26.05.2010
comment
Что говорит ulimit -a?   -  person bmargulies    schedule 26.05.2010
comment
Спасибо, bmargulies, вот и все. ulimit -a сообщил о размере виртуальной памяти 1804800 кбайт (немногим более 1,7 ГБ). ulimit -v 1610612736 (1,5 ТБ) позволяет мне отображать мой разреженный файл размером 1 ТБ. Я отвечу на свой вопрос, чтобы «закрыть» его ...   -  person metadaddy    schedule 27.05.2010


Ответы (3)


Проблема заключалась в том, что предел виртуальной памяти для каждого процесса был установлен всего на 1,7 ГБ. ulimit -v 1610612736 установил его на 1,5 ТБ, и мой вызов mmap () завершился успешно. Спасибо, bmargulies, за подсказку попробовать ulimit -a!

person metadaddy    schedule 27.05.2010
comment
И, по-видимому, я могу установить желаемое значение (которое может быть «неограниченным») в / etc / profile, чтобы сделать его постоянным. - person metadaddy; 27.05.2010

Есть ли какая-то квота на пользователя, ограничивающая объем памяти, доступной для пользовательского процесса?

person Martin Beckett    schedule 26.05.2010
comment
Да - я попробовал предложение bmargulies попробовать ulimit -a, и это указывало на ограничение процесса виртуальной памяти как на виновника - см. Мой ответ ниже ... - person metadaddy; 27.05.2010

Я предполагаю, что ядро ​​испытывает трудности с выделением памяти, которая ему нужна, чтобы не отставать от этого отображения памяти. Я не знаю, как выгруженные страницы поддерживаются в ядре Linux (и я предполагаю, что большая часть файла будет в отключенном состоянии большую часть времени), но может потребоваться запись для каждой страницы памяти, которую файл занимает в таблице. Поскольку этот файл может быть отображен более чем одним процессом, ядро ​​должно поддерживать отображение с точки зрения процесса, которое будет отображаться на другую точку зрения, которая будет отображаться на вторичное хранилище (и включать поля для устройства и местоположения ).

Это поместится в ваше адресное пространство, но может не уместиться (по крайней мере, непрерывно) в физической памяти.

Если кто-то знает больше о том, как Linux это делает, мне было бы интересно узнать об этом.

person nategoose    schedule 26.05.2010
comment
Linux не будет создавать PTE (записи таблицы страниц) до тех пор, пока эти страницы не будут затронуты. Все, что он делает, когда вы создаете сопоставление, - это создание единой структуры VMA (области виртуальной памяти), которая в основном содержит информацию из mmap(). - person caf; 26.05.2010