You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

能否将kmalloc分配的内存映射到用户态以用于TCP的sendmsg MSG_ZEROCOPY?

问题:kmalloc分配的内存映射到用户态后无法用于sendmsg的MSG_ZEROCOPY模式

我正在开发一个项目,内核模块使用kmalloc()分配物理连续内存,并通过remap_pfn_range()将其映射到用户态。但remap_pfn_range()会将vm_area_structvm_flags字段设置为VM_IO | VM_PFNMAP(还有其他无关标志)。当我使用mmap()返回的地址调用带MSG_ZEROCOPY选项的sendmsg()时,调用失败并返回errno=EFAULT

内核错误追踪

我定位到内核中首次返回-EFAULT的位置在mm/gup.ccheck_vma_flags()函数,问题根源就是vm_flags的上述标志:

static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
{
    vm_flags_t vm_flags = vma->vm_flags;
    int write = (gup_flags & FOLL_WRITE);
    int foreign = (gup_flags & FOLL_REMOTE);

    if (vm_flags & (VM_IO | VM_PFNMAP))
        return -EFAULT; // <= 该错误会传播到用户态。
}

背景信息

  • 分配的内存用于Cyclone V SOC-FPGA的CPU与FPGA之间共享,FPGA会向缓冲区写入大量数据,要求内存物理连续
  • 当前使用Linux内核版本为v5.3-rc8
  • 这种内存映射在不使用零拷贝的常规send()调用中工作正常;而用malloc()分配的常规用户态内存测试时,sendmsg()的零拷贝模式能让传输速率提升高达50%,因此需要启用该模式优化性能

尝试过的无效方法

我曾在remap_pfn_range()调用后手动清除vm_area_struct.vm_flags中的VM_IOVM_PFNMAP位,此时sendmsg()看似“成功”——系统调用返回期望发送的缓冲区大小,但客户端实际未收到数据,且重启内核时串口控制台会打印大量错误。显然这种操作不符合内核规范,vm_flags的设置有其必要性,remap_pfn_range()也没有提供阻止设置这些标志的参数。

核心疑问

有没有办法将kmalloc()获取的内存映射到用户态,使其能被传入带MSG_ZEROCOPY选项的sendmsg()


更新
我找到了一些相关讨论,会尝试其中的建议并后续反馈:

  • 零拷贝用户态TCP发送dma_mmap_coherent映射的内存
  • 将物理内存映射为用户态常规的、由struct page支持的映射

内容的提问来源于stack exchange,提问作者K Aronsen

火山引擎 最新活动