Linux内核空间中的“魔术环缓冲区”实现?
问题描述:
我知道了"magic ring buffer"把戏,涉及镜像基础缓冲区的进程的地址空间,让数据块与单个memcpy()
入队,而不必担心回绕的。Linux内核空间中的“魔术环缓冲区”实现?
我想完成同样的事情,但在Linux内核模块。假设我有dma_alloc_coherent()
创建的缓冲器,其虚拟地址为V
其长度为N
。如何创建映射,使其虚拟地址[V+N,V+2N)
映射到与[V,V+N)
相同的底层页面?
注:这是在32位ARM Linux操作系统。
答
drivers/firewire/ohci.c映射异步的某些页面接收环形缓冲区两次以允许该环绕接收的数据包更容易获得:
for (i = 0; i < AR_BUFFERS; i++) {
ctx->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32);
...
dma_addr = dma_map_page(ohci->card.device, ctx->pages[i],
0, PAGE_SIZE, DMA_FROM_DEVICE);
...
}
for (i = 0; i < AR_BUFFERS; i++)
pages[i] = ctx->pages[i];
for (i = 0; i < AR_WRAPAROUND_PAGES; i++)
pages[AR_BUFFERS + i] = ctx->pages[i];
ctx->buffer = vmap(pages, ARRAY_SIZE(pages), VM_MAP, PAGE_KERNEL);
...
据我所看到的,是一致的DMA没有类似的API记忆。如果您知道您的架构如何处理此问题,您可以重新映射由dma_alloc_coherent()
返回的页面。
请注意,某些架构可以有自己的缓存,如果你正在使用多个虚拟地址修改同一个物理地址的问题;即使您设法映射它,您也必须检查连贯的DMA内存是否可以在特定的arch中进行缓存。
[kfifo.c](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/libkfifo.c)和[kfifo.h](https: //git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/kfifo.h)是支持固定大小的元素没有任何MMU帮助版本。它们在内核中更常见。 –
谢谢!我认为这将适用于我的应用程序,我不认为镜像缓冲区是必要的。 –