c - mremap(2) 与 HugeTLB 改变虚拟地址?

标签 c linux

Linux mremap(2) 函数是否可以将从 mmap() 获得的 HugeTLB 的虚拟地址更改为新的固定虚拟地址?

(背景:我想根据我得到的内存的物理地址重新映射虚拟地址。这是通过直接检查指针地址来有效地执行虚拟地址到物理地址的转换。我将使用内存从 DMA 到硬件用户空间。)

这似乎不适用于我的简单测试程序:

#define _GNU_SOURCE
#include <stdio.h>
#include <sys/mman.h>
#include <stdint.h>

#define LARGE_PAGE_SIZE (1024*1024*1024)

int main() {
  void *p1;
  void *p2;
  p1 = mmap(NULL, LARGE_PAGE_SIZE, PROT_READ|PROT_WRITE,
    MAP_SHARED|MAP_ANONYMOUS|MAP_HUGETLB|MAP_LOCKED,
    0, 0);
  if (p1 == MAP_FAILED) {
perror("mmap");
return 1;
  }
  printf("p1 = %p\n", p1);
  p2 = mremap(p1, LARGE_PAGE_SIZE, LARGE_PAGE_SIZE,
      MREMAP_MAYMOVE|MREMAP_FIXED,
      (void*)(((uint64_t)p1) | 0x500000000000ULL));
  if (p2 == MAP_FAILED) {
perror("mremap");
return 1;
  }
  printf("p2 = %p\n", p2);
}

mmap() 成功,mremap() 失败:

$ gcc -o mremap_hugetlb mremap_hugetlb.c && sudo ./mremap_hugetlb
p1 = 0x2aaac0000000
mremap: Invalid argument

请注意,新地址是根据原始 mmap() 获得的地址计算得出的。这很重要。无法提前知道所需的地址,因此我不能简单地将 MAP_FIXED 传递给 mmap()。

我目前使用的解决方法是使 mmap() 文件支持,这样我就可以在固定地址再次对它进行 mmap(),并 munmap() 旧映射。这是次优的,因为它需要我找到一个挂载的 hugetlbfs 文件系统,我不喜欢这种依赖的复杂性。

基于解决方法的当前代码: https://github.com/lukego/snabbswitch/blob/straightline/src/core/memory.c#L56

最佳答案

现在看来您必须使用 hugetlbfs。

除非我弄错了,否则问题出现在 Linux 内核中,因为 mm/mremap.c:mremap_to()电话 mm/mremap.c:vma_to_resize() ,这fails with EINVAL for huge pages .

也许测试不正确,或者函数缺少正确处理大页面的代码。我想知道是否应该联系 linux-kernellinux-mm邮件列表,看看这是否是一个应该/可以轻松修复的错误。但是,这对依赖当前(和旧版)内核的用户没有帮助。

请记住,在文件描述符上使用 mmap() 时,您通常会使用不同的代码路径,因为每个文件系统都可以指定自己的 mmap 处理程序。对于 hugetlbfs,代码在 fs/hugetlbfs/inode.c:hugetlbfs_file_mmap() 中. 而且,正如您所说,该代码路径似乎适合您。

请注意,最好让用户配置 hugetlbfs 挂载点,而不是从 /proc/mounts 中扫描一个挂载点,因为这样系统管理员可以配置多个 hugetlbfs 挂载点,每个挂载点都有不同的配置,针对服务器上运行的每个服务。 (我希望您的服务不需要以 root 身份运行。)

关于c - mremap(2) 与 HugeTLB 改变虚拟地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27997934/

相关文章:

c - 我将如何从命令行扫描短语?

c - 使用 Lapack&co 求解病态线性方程组

c++ - Pthreads问题和几个问题

linux - 如何在 Linux 中转义 scp 复制路径中的空格?

c - 请推荐一个好的D-Bus教程(Linux C GTK+)

c - 在 C 中使用消息队列时获取 "bad system call (core dumped)"

c++ - 如何仅在 C 中将 SIGINT 发送到后台进程

c++ - 使用 sbrk 自定义内存管理

ruby - 连接到本地 linux 安装上的 postgres 数据库

python - 在 Scientific Linux 6.5 上安装 PyQt4.11.2