如何在Linux中为内存映射文件提供写时扩展功能? [英] How to provide extend-on-write functionality for memory mapped files in Linux?

查看:123
本文介绍了如何在Linux中为内存映射文件提供写时扩展功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将一些代码从AIX移植到Linux.部分代码使用

I'm working on porting some code from AIX to Linux. Parts of the code use the shmat() system call to create new files. When used with SHM_MAP in a writable mode, one can extend the file beyond its original length (of zero, in my case):

将文件映射到段时,通过访问该段来引用该文件.内存分页系统会自动处理物理I/O.超出文件末尾的引用会导致文件以页面大小的增量进行扩展.该文件不能扩展到下一个段边界之外.

When a file is mapped onto a segment, the file is referenced by accessing the segment. The memory paging system automatically takes care of the physical I/O. References beyond the end of the file cause the file to be extended in page-sized increments. The file cannot be extended beyond the next segment boundary.

(AIX中的段"是256 MB的地址空间块,而页面"通常是4 KB.)

(A "segment" in AIX is a 256 MB chunk of address space, and a "page" is usually 4 KB.)

我在Linux上希望要做的事情如下:

What I would like to do on Linux is the following:

  • 保留很大一部分地址空间(不必大到256 MB,这些不是很大的文件)
  • 设置页面保护位,以便在第一次访问之前未触及的页面时生成段错误
  • 在发生页面错误时,清除引起页面错误"位并为该页面分配已提交的内存,以允许导致该页面错误的写入(或读取)继续进行
  • 关闭共享存储区后,将修改后的页面写入文件

我知道我可以在Windows上使用

I know I can do this on Windows with the VirtualProtect function, the PAGE_GUARD memory protection bit, and a structured exception handler. What is the corresponding method on Linux to do the same? Is there perhaps a better way to implement this extend-on-write functionality on Linux?

我已经考虑过:

  • 使用具有一定固定大小的mmap(),但是我无法确定应用程序代码写入了多少文件
  • 分配一个很大的匿名共享内存区域,但是我仍然无法确定已经写入了多少区域
  • mmap()本身似乎没有提供任何工具来扩展备份文件的长度
  • using mmap() with some fixed large-ish size, but I can't tell how much of the file was written to by the application code
  • allocating an anonymous shared memory area of large-ish size, but again I can't tell how much of the area has been written
  • mmap() by itself does not seem to provide any facility to extend the length of the backing file

自然,我希望对应用程序代码进行最少的更改.

Naturally I would like to do this with only minimal changes to the application code.

推荐答案

非常类似于我曾经做过的作业.基本上,我有一个页面"列表和一个框架"列表以及相关信息.使用SIGSEGV,我将捕获故障并根据需要更改内存保护位.我将提供您可能会觉得有用的部分.

This is very similar to a homework I once did. Basically I had a list of "pages" and a list of "frames", with associated information. Using SIGSEGV I would catch faults and alter the memory protection bits as necessary. I'll include parts that you may find useful.

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;
}

我无法公开提供所有内容,因为团队很可能会再次使用相同的作业.

I can't publicly make it all available since the team is likely to use that same homework again.

这篇关于如何在Linux中为内存映射文件提供写时扩展功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆