linux - 让 linux 将内存更改持久保存到磁盘

标签 linux mmap

我正在尝试查看是否可以为我将操作系统、Linux、持久内存更改保存到磁盘。我会将文件的某些部分映射到内存中。假设文件是​​一个循环队列。我在想如果让操作系统处理将更改的页面写入磁盘会更有效率。

我开始研究 mmap()、msync() 和 munmap()。我找到了以下文章:

c linux msync(MS_ASYNC) flush order

其中一篇文章指出 msync() 的 MS_ASYNC 是空操作,因为操作系统已经跟踪脏页并在必要时将它们刷新到存储中。很高兴确切地知道这意味着什么。我还发现了这个:

msync() behaviour broken for MS_ASYNC, revert patch?

我不太理解那次谈话。我想我正在寻找一种有效的方法来将我对内存表示所做的更改持久保存到磁盘,即使在发生崩溃时也是如此。

我在下面编写了小型示例应用程序。似乎即使我引入崩溃,我写入映射内存的最新数据也会存储到磁盘。

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

void main(int argc, char* argv[])
{
    int result;
    int fd = -1;

    if (argc != 2)
        {
        printf("Error, missing file name argument\n");
        goto done;
        }

    fd = open(argv[1], O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
    if (fd == -1)
        {
        printf("Failed opening file %s: %d\n", argv[1], errno);
        goto done;
        }

    unsigned int size = 8 * 1024L * 1024L;
    result = ftruncate(fd, size);
    if (result != 0)
        {
        printf("Failed setting file size: %d\n", errno);
        goto done;
        }

    void* addr;
    addr = mmap(NULL, size, PROT_WRITE, MAP_FILE | MAP_SHARED,
            fd, 0);
    if (addr == MAP_FAILED)
        {
        printf("Failed to map memory: %d\n", errno);
        goto done;
        }
    memset(addr, 'r', size);
    result = msync(addr, size, MS_ASYNC);
    getchar();
    if (result != 0)
        {
        printf("Failed syncing mapped memory: %d\n", errno);
        goto done;
        }
    memset(addr, 'p', size);
    getchar();

    memset(addr, 'm', size);

    // crash.

    *((int*) 0) = 0;

done:
    printf("done\n");
    if (fd != -1)
        close(fd);
    printf("closed file\n");
    return;
}

那么使用 mmap()、msync(MS_ASYNC) 是否是让操作系统将内存中的更改保存到磁盘的合理方法?

谢谢, 尼克

最佳答案

So is using mmap(), msync(MS_ASYNC) a reasonable way to have the OS persist my in-memory changes to disk?

不,不是。

您的测试用例并不能证明在所有情况下您的数据都会持久保存到稳定的存储中 - 只是它恰好在您的狭窄场景中可见。此外,当人们谈论写入磁盘的数据在遇到“崩溃”时仍然存在时,他们通常指的是操作系统崩溃或硬件断电(例如内核崩溃、突然断电等)——用户态程序只是段错误' 阻止正在运行的内核访问(甚至同步)在内存中滚动的脏数据。不幸的是,这意味着您的测试展示了与您需要的不同的东西。

如前所述here , 要知道数据是否真正进入稳定存储,您必须使用(并检查结果)以下之一:

  • msync(MS_SYNC)
  • 同步
  • sync_file_range + fsync(用于元数据)

你永远无法使用 msync(MS_ASYNC) 因为它不会告诉你数据何时成功持久化(在 Linux 上它甚至不会强制写回开始您链接到的帖子警告的地方)。要么:

  • 您关心持久性,您需要知道数据何时完成写入持久稳定存储(例如,您想要推迟一些其他操作,直到它完成)。
  • 或者您不在乎,并且您认为该数据仅在系统继续正常运行时才可读,因此您可以接受该数据在其他情况下是不确定的。

关于linux - 让 linux 将内存更改持久保存到磁盘,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38089727/

相关文章:

performance - 访问映射到同一物理地址的虚拟地址是否会受到惩罚?

java - 指定Java内存分配池地址

linux - 腻子 : Execute a shell script onto the host machine

linux - 键盘扫描码?

C++ mmap到 "fast"读取与gzip文件的耦合

python - 如何从映射文件中读取行?

c - 将文件映射到内存后出现段错误

java - 带有嵌入式 tomcat 的 Spring Boot 在一个端口上运行,但它不起作用

linux - 在 bash 中替换太多的 if 语句

linux - 在 Debian Wheezy 上升级 GLIBC