从映射缓冲区写入`O_DIRECT`输出文件

问题描述 投票:0回答:1

我有一个可以写入视频缓冲区的设备。该缓冲区是使用 CMA 在系统内存中分配的,我想实现从该缓冲区到块设备的流式写入。我的应用程序使用 mmap 打开视频缓冲区,我想使用

O_DIRECT
写入来避免与页面缓存相关的开销。基本上,应用程序的伪代码如下所示:

f_in = open("/dev/videobuf", O_RDONLY);
f_mmap = mmap(0, BUFFER_SIZE, PROT_READ, MAP_SHARED, f_in, 0);
f_out = open("/dev/sda", O_WRONLY | O_DIRECT);
write(f_out, f_mmap, BLOCK_SIZE);

其中 BLOCK_SIZE 是扇区对齐值。 f_out 打开没有任何错误,但将结果写入

EFAULT
。我试图找出这个问题,结果发现视频缓冲区驱动程序中的 mmap 实现使用
remap_pfn_range()
,它为 VMA 设置
VM_IO
VM_PFNMAP
标志。块设备驱动程序中的
O_DIRECT
路径检查这些标志并返回
EFAULT
。据我了解,
O_DIRECT
写入需要固定内存页面,但VMA标志表明底层内存缺少
struct page
,这会导致错误。我在这儿吗?

主要问题是如何正确实现

O_DIRECT
从映射缓冲区写入?我有视频缓冲区驱动程序,可以适当修改它。

我发现了类似的问题,但这些没有明确的答案。

io linux-kernel mmap
1个回答
0
投票

函数

remap_pfn_range
通过使用
special
将您的虚拟内存区域指定为
pte_mkspecial
,并将
VM_IO/VM_PFNMAP
包含在vma中。因此,它无法通过
Direct I/O
的特定验证。

由于您的记忆来自

CMA
,它已经支持
struct page
,您可以通过以下步骤使用
vm_insert_pages

  1. 使用内核参数或设备树源添加
    CMA
    区域 (
    DTS
    )。
  2. 从 CMA 获取结构页:
dma_page = dma_alloc_contiguous(&pdev->dev, size, GFP_KERNEL);
if (!dma_page) {
    pr_err("%s %d, dma_alloc_contiguous fail\n", __func__, __LINE__);
    return -ENOMEM;
}
nr_pages = DIV_ROUND_UP(size, PAGE_SIZE);
pages = kvmalloc_array(nr_pages, sizeof(*pages), GFP_KERNEL);
for (i = 0; i < nr_pages; i++)
    pages[i] = &dma_page[i];
  1. 调用时将页面插入vma
    mmap
    :
int your_mmap(struct file *file, struct vm_area_struct *vma) {
    int ret = 0;
    unsigned long temp_nr_pages;

    if (vma->vm_end - vma->vm_start > size)
        return -EINVAL;

    /* Duplicate nr_pages as vm_insert_pages can change nr_pages */
    temp_nr_pages = nr_pages;

    ret = vm_insert_pages(vma, vma->vm_start, pages, &temp_nr_pages);
    if (ret < 0)
        pr_err("%s vm_insert_pages fail, error is %d\n", __func__, ret);

    return ret;
}
  1. 导出
    dma_alloc_contiguous
    (唯一的内存管理代码更改,但可以接受)。
modified   kernel/dma/contiguous.c
@@ -332,6 +332,7 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)

        return cma_alloc_aligned(dma_contiguous_default_area, size, gfp);  }
+EXPORT_SYMBOL(dma_alloc_contiguous);

 /**
  * dma_free_contiguous() - release allocated pages
© www.soinside.com 2019 - 2024. All rights reserved.