我面临着CMA的问题。我试图通过cma(连续内存分配)为运行linux 3.8内核的基于arm的目标板分配设备内存。
通过私有cma节点请求内存分配时,会导致“无memin-cma区域”。尽管我们保留了所需的内存。在调试“_alloc_contig_migrate_range”功能时,发现部分页面迁移失败,导致CMA区域没有内存。
在迁移“migrate_page_move_mapping(migrate.c)”函数中满足以下条件的页面时。
if (!mapping) {
/* Anonymous page without mapping */
if (page_count(page) != 1) {
return -EAGAIN;
}
return MIGRATEPAGE_SUCCESS;
}
其他页面在migrate_page_move_mapping()中失败并返回
if (page_count(page) != expected_count ||
radix_tree_deref_slot_protected(pslot, &mapping->tree_lock) != page) {
spin_unlock_irq(&mapping->tree_lock);
return -EAGAIN;
}
而页计数(页)-->3和预期的计数-->2不匹配,因此重复返回-eagain。
当我查看页面标记时,发现标记中存在以下差异。
迁移成功->0xC3A40059
迁移失败->0xc3a000d
标志中的差异为
观察标志-->
pg_脏
PG U激活
包装棉
PG U参考
迁移成功--->
套
套
套
未设置
迁移失败--->
未设置
未设置
未设置
套
任何建议都会有帮助的。
最佳答案
记录了CMA迁移在3.18之前的内核上可能失败的两个原因
here(伙伴分配器记帐错误)和here(不支持ksm迁移)。
与普遍的看法相反,linux内核中的连续内存分配框架
不保证在系统的整个生命周期内连续内存的可用性。
CMA的核心概念如下…
在启动时,允许将一定数量的内存定义为连续缓冲池。
在运行时,允许从这个连续缓冲池为常规内存分配请求分配内存(作为最后手段)。
每当请求一个大的连续缓冲区时,
a.立即将上面步骤2中分配的页面迁移到常规内存池中。
为请求者提供一个大的连续缓冲区。
问题在于,在某些情况下,
在步骤3a中迁移页面可能会失败。这可能是由于:
缺少可用内存或交换作为迁移已在CMA池中分配的非连续小页的目标。
进程分配给它们的pin memory/buffers能力。
由于没有一个单一的方法来更新/替换CMA,它以其当前的形式继续存在,大部分时间,但不保证在所有可能的情况下的连续存储器。随着smmus的出现和对其他控制器的分散收集dma支持,对大型连续缓冲区的需求减少了。
也就是说,有两个主要的方法来改进CMA,已经在一些圈子里尝试并被接受:
GCMA
ZONE CMA
基于他们认为可以接受的折衷,这两种方法都有自己的局限性。