如何从内核空间中收缩Linux页面缓存?
我正在开发一个系统,其中包括一些定制硬件和我为该硬件编写的定制Linux设备驱动程序。系统有时需要非常快速地移动大量数据,因此我的驱动程序会动态(即在需要时)分配大量(1 GB)DMA缓冲区,这些缓冲区会被使用,然后在不再需要时释放。为了分配这样大的缓冲区,我实际上使用如何从内核空间中收缩Linux页面缓存?,linux,memory-management,linux-kernel,linux-device-driver,Linux,Memory Management,Linux Kernel,Linux Device Driver,我正在开发一个系统,其中包括一些定制硬件和我为该硬件编写的定制Linux设备驱动程序。系统有时需要非常快速地移动大量数据,因此我的驱动程序会动态(即在需要时)分配大量(1 GB)DMA缓冲区,这些缓冲区会被使用,然后在不再需要时释放。为了分配这样大的缓冲区,我实际上使用dma\u alloc\u coherent分配了一堆较小的缓冲区(256 X 4MB),然后使用remap\u pfn\u range将它们连续映射到用户空间。这在大多数情况下都很有效 在测试过程中,在系统运行测试用例很长时间后
dma\u alloc\u coherent
分配了一堆较小的缓冲区(256 X 4MB),然后使用remap\u pfn\u range
将它们连续映射到用户空间。这在大多数情况下都很有效
在测试过程中,在系统运行测试用例很长时间后,我有时会看到DMA分配失败,其中驱动程序中的一个DMA\u alloc\u相干
调用失败,导致我的应用层软件崩溃。我终于找到了这个问题,我发现当我看到DMA分配失败时,Linux内核页面缓存非常满
例如,在上一次捕获失败时,页面缓存填充了系统上32GB内存中的27GB。我怀疑页面缓存“满”导致dma\u alloc\u相干
调用失败。为了测试这一理论,我使用以下方法手动清空页面缓存:
# echo 1 > /proc/sys/vm/drop_caches
这将缓存的大小从27 GB降至94 MB,并且我能够分配20+1 GB DMA缓冲区而没有任何问题
显然,页面缓存是一件有益的事情,因此我不希望在分配DMA缓冲区时每次空间用完时都将其完全清空。我的问题是:如何在内核空间中动态收缩页面缓存,以便在调用dma\u alloc\u coherent
失败时,我可以恢复足够的空间,以便重试调用并使其成功
我的系统基于x86_64,运行3.16.x Linux内核
我发现一些模糊的参考资料表明我的尝试可能是可能的,例如“这些对象是自动生成的”
当系统上其他地方需要内存时,由内核回收。“(发件人:)。但我还没有找到任何具体的说明如何回收内存
任何与此相关的帮助都将不胜感激 从技术上讲,当某些分配失败时,内核将尝试释放内存。具体取决于内存故障(软故障/硬故障)。硬故障导致内核进入直接回收路径。直接回收是一项成本高昂的操作,可能需要未定义的时间才能完成,甚至在分配之后也可能失败 这里有两个选项: 1) 使用虚拟机设置,如脏内存比率、脏内存背景比率等,以保持可用内存。见:
2) 编写一个内核守护进程,它调用处理drop\u缓存的内核函数(因为drop\u缓存可能会休眠) TL;DR:扫描活动超级块并删除对非脏超级块的引用,直到回收了所需的系统内存。(或者最终耗尽了对活动超级块的引用。)
如何编写内核代码来动态收缩fs页面缓存,
要恢复足够的空间,以便后续调用
dma\u alloc\u coherent()
成功
为了回答这个问题,让我们看看“drop\u caches
操作”是如何将系统上的fs页面缓存从27GB减少到94MB的
echo 1>/proc/sys/vm/drop\u缓存
调用
将指针传递给函数
iterate\u supers()
扫描活动的超级块,每次找到一个超级块时,它都调用drop\u pagecache\u sb()
,将对活动超级块的引用传递给它
此迭代过程将继续,直到从fs页缓存中释放对所有活动超级块的引用。这是一种非破坏性操作,只会释放完全未使用的块。脏对象将继续使用,直到写入磁盘,并且无法释放。如果您先运行sync
将它们刷新到磁盘,则“drop\u caches
操作”倾向于释放更多内存
由于您有兴趣运行此过程以回收有限/已知的内存量,即使用dma\u alloc\u coherent()
将要请求的内存量,您只需在每次迭代结束时通过附加检查实现上述功能,并在可用系统内存量超过所需级别时立即中止超级块扫描
要进一步优化此程序,请记住两点:
- 某些块设备是否优于其他设备?
您可能希望迭代不关心的块设备的活动超级块。如果没有回收足够的内存,则扫描希望保留在fs页缓存中的块设备,除非绝对需要回收所需内存。可能会有帮助 - 似乎很有趣
它允许在特定的超块上进行迭代
我在触发内存回收的
dma\u alloc\u相干的代码路径中找不到任何地方。正如我之前所说的,我更愿意使用尽可能多的页面缓存,如果不是必须的话,也不要清空它(调用drop_cache)。谢谢你的回复,你所描述的正是我所做的。它确实感觉像一个巨大的黑客