Как обеспечить функциональность расширения при записи для файлов с отображенной памятью в Linux? - PullRequest
5 голосов
/ 04 августа 2011

Я работаю над переносом кода из AIX в Linux.Части кода используют системный вызов shmat() для создания новых файлов.При использовании с SHM_MAP в режиме записи можно расширить файл за пределы его первоначальной длины (в моем случае нуля):

Когда файл отображается на сегмент, файлссылка на доступ к сегменту.Система подкачки памяти автоматически заботится о физическом вводе / выводе.Ссылки после конца файла приводят к расширению файла с шагом в размер страницы.Файл не может быть расширен за границы следующего сегмента.

(«Сегмент» в AIX - это блок памяти размером 256 МБ, а «страница» - обычно 4 КБ.)

Что бы я хотел бы сделать в Linux, так это:

  • Зарезервировать кусок адресного пространства большого размера (он не должен быть таким большим, как256 МБ, это не такие большие файлы)
  • Установите биты защиты страницы таким образом, чтобы при первом обращении к странице, которая не была затронута до
  • Вкл, генерируется ошибка.сбой страницы, очистите бит «причина сбоя страницы» и выделите выделенную память для страницы, разрешив запись (или чтение), которая вызвала сбой страницы,
  • После закрытия области общей памяти запишитеизмененные страницы в файл

Я знаю, что могу сделать это в Windows с помощью функции VirtualProtect , бита защиты памяти PAGE_GUARD и структурированного обработчика исключений .Каков соответствующий метод в Linux, чтобы сделать то же самое?Возможно, есть лучший способ реализовать эту функцию расширения при записи в Linux?

Я уже рассмотрел:

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

Естественно, я хотел бы сделать это с минимальными изменениями вкод приложения.

Ответы [ 3 ]

5 голосов
/ 04 августа 2011

Это очень похоже на домашнюю работу, которую я когда-то делал. В основном у меня был список «страниц» и список «фреймов» со связанной информацией. Используя SIGSEGV, я бы улавливал ошибки и при необходимости изменял защитные биты памяти. Я включу части, которые вы можете найти полезными.

Создать отображение. Изначально у него нет разрешений.

int w_create_mapping(size_t size, void **addr)
{

    *addr = mmap(NULL,
            size * w_get_page_size(),
            PROT_NONE,
            MAP_ANONYMOUS | MAP_PRIVATE,
            -1,
            0
    );

    if (*addr == MAP_FAILED) {
        perror("mmap");
        return FALSE;
    }

    return TRUE;
}

Установить обработчик сигнала

int w_set_exception_handler(w_exception_handler_t handler)
{
    static struct sigaction sa;
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    sigaddset(&sa.sa_mask, SIGSEGV);
    sa.sa_flags = SA_SIGINFO;

    if (sigaction(SIGSEGV, &sa, &previous_action) < 0)
        return FALSE;

    return TRUE;
}

Обработчик исключений

static void fault_handler(int signum, siginfo_t *info, void *context)
{
    void *address;      /* the address that faulted */

    /* Memory location which caused fault */
    address = info->si_addr;

    if (FALSE == page_fault(address)) {
        _exit(1);
    }
}

Повышение защиты

int w_protect_mapping(void *addr, size_t num_pages, w_prot_t protection)
{
    int prot;

    switch (protection) {
    case PROTECTION_NONE:
        prot = PROT_NONE;
        break;
    case PROTECTION_READ:
        prot = PROT_READ;
        break;
    case PROTECTION_WRITE:
        prot = PROT_READ | PROT_WRITE;
        break;
    }

    if (mprotect(addr, num_pages * w_get_page_size(), prot) < 0)
        return FALSE;

    return TRUE;
}

Я не могу публично сделать все это доступным, поскольку команда, скорее всего, снова использует ту же домашнюю работу.

3 голосов
/ 04 августа 2011

Выделите большой буфер, как вам нравится, и затем используйте системный вызов mprotect () *, чтобы сделать хвост буфера доступным только для чтения, и зарегистрируйте обработчик сигнала для SIGSEGV, чтобы заметить, где были сделаны записи до, и используйте mprotect ().еще раз, чтобы включить запись.

0 голосов
/ 04 августа 2011

Я сам размышлял о подобных вещах и не нашел способа для mmap() расширить файл поддержки.

В настоящее время я планирую попробовать две альтернативы:

  • вручную управляйте размером файла, расширяя его самостоятельно и mremap() 'впоследствии
  • создайте разреженный файл и надеитесь, что виртуальная машина выделит необходимые сектора при удалении грязных страниц.

честно говоря, я не думаю, что разреженные файлы будут работать, но стоит попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...