Почему не работает remap_file_pages () в этом примере? - PullRequest
4 голосов
/ 08 февраля 2010

Следующий код C иллюстрирует проблему, которую я вижу в Linux 2.6.30.5-43.fc11.x86_64:

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

int main() {
    char buf[1024];
    void *base;
    int fd;
    size_t pagesz = sysconf(_SC_PAGE_SIZE);

    fd = open("<some file, at least 4*pagesz in length>", O_RDONLY);
    if (fd < 0) {
       perror("open");
       return 1;
    }

    base = mmap(0, 4*pagesz, PROT_READ, MAP_SHARED, fd, 0);
    if (base < 0) {
        perror("mmap");
        close(fd);
        return 1;
    }

    memcpy(buf, (char*)base + 2*pagesz, 1024);

    if (remap_file_pages(base, pagesz, 0, 2, 0) < 0) {
        perror("remap_file_pages");
        munmap(base, 4*pagesz);
        close(fd);
        return 1;
    }

    printf("%d\n", memcmp(buf, base, 1024));

    munmap(base, 4*pagesz);
    close(fd);
    return 0;
}

Это всегда терпит неудачу с remap_file_pages (), возвращающим -1 и errno установленным в EINVAL. Глядя на исходный код ядра, я вижу все условия в remap_file_pages (), где он может потерпеть неудачу, но ни одно из них, похоже, не относится к моему примеру. Что происходит?

1 Ответ

5 голосов
/ 08 февраля 2010

Это связано с открытием файла O_RDONLY. Если вы измените режим открытия на O_RDWR, он будет работать (даже если mmap() по-прежнему указывает только PROT_READ).

Этот код в do_mmap_pgoff является основной причиной - он помечает vma как VM_SHARED, если файл был открыт для записи:

vm_flags |= VM_SHARED | VM_MAYSHARE;
if (!(file->f_mode & FMODE_WRITE))
    vm_flags &= ~(VM_MAYWRITE | VM_SHARED);

Итак, в remap_file_pages() вы проваливаете первую проверку:

if (!vma || !(vma->vm_flags & VM_SHARED))
    goto out;
...