Разрешено ли объединение страниц в mmap? - PullRequest
2 голосов
/ 02 марта 2020

Короче говоря, я хочу изменить размер памяти, но иметь старую память в середине новой.

Поэтому я использовал mmap для начального размера (p1), mmap по адресу до p1 чтобы сделать вид, что я увеличил объем памяти, а затем обработать новый указатель, как если бы я создал его с одним mmap (p3, mremap). Код, кажется, работает, но я не уверен, что это то, что я должен делать. Если это не так, как я должен создать больше памяти и иметь старую / текущую память в середине этого?

#include <sys/mman.h>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <cerrno>
int main()
{
    auto p1 = (char*) mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    if (!p1 || p1==(char*)-1)
        return -1;

    auto p1_32 = (int *)p1;
    memset(p1, 0, 4096);
    p1_32[5] = 1035;

    auto p2 = mmap(p1-4096, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
    if (!p2 || p2==(void*)-1)
        return -2;

    auto p2_32 = (int *)p2;
    memset(p2, 0, 4096);
    p2_32[5] = 5301;

    assert(p2_32[1024+5] == 1035);

    auto p3 = mremap(p2, 4096*2, 4096*4, MREMAP_MAYMOVE);
    if (p3==(char*)-1)
    {
        printf("Errno %d\n", errno);
        return -2;
    }
    auto p3_32 = (int*)p3;

    assert(p3_32[5] == 5301);
    assert(p3_32[1024+5] == 1035);

    printf("Is this correct?\n");
    return 0;
}

1 Ответ

3 голосов
/ 02 марта 2020

Как описано здесь

Функция munmap() должна удалять любые отображения для целых страниц, содержащих любую часть адресного пространства процесса, начиная с addr, и продолжается для len байтов.

, поэтому разрешено удалять несколько сопоставлений одним вызовом munmap (как если бы это было одно сопоставление).

Существует Но проблема с вашим кодом: откуда вы знаете, что страница (p2) перед вашей страницей (p1) не используется? Он может быть уже выделен другими компонентами программы (включая malloc), используя MAP_FIXED, например, вы перепишите (переназначите) его содержимое:

Когда установлено MAP_FIXED аргумент flags, реализация информируется, что значение pa должно быть addr, точно. Если установлено MAP_FIXED, mmap() может вернуть MAP_FAILED и установить errno на [EINVAL]. Если запрос MAP_FIXED выполнен успешно, сопоставление, установленное mmap(), заменяет все предыдущие сопоставления для страниц процесса в диапазоне [pa,pa+len).

Так что я не думаю, что этот трюк может в общем случае полезно использовать mremap.

Что касается того, как это реализовано: Linux объединяет последовательные частные анонимные сопоставления, поэтому оба будут объединены в один vma_struct в ядро. Эта «особенность» имеет нежелательные побочные эффекты, такие как munmap, когда не удается освободить память с помощью ENOMEM. Но это больше детали реализации, а не то, что вы можете контролировать.

...