DMA 一致性分配
先走 CMA 等连续内存路径
拿到连续内存
主路径,本次不改
CMA 等路径失败
回退到 buddy 分配器
buddy 只按 2 的幂 order 出页
没有「3 页」这种块
回退路径:get_order(size) 向上取整
页数不是 2 的幂时,先取整到最近的 order,再把整块占住
取整多出来的尾页,也跟着这次分配被占住
请求 3 页
get_order(size)
取整成 order 2
3 页不是 2 的幂
整块 4 页
buddy 按 order 2 取出整块
4 页一起交给这次分配
记账也按整块
尾页跟着请求页走
闲置到释放
尾页别人用不上,直到整块释放才归还
请求离 2 的幂越远,浪费越大,最多接近整块的一半
alloc_pages_exact_nid()
分配侧
free_pages_exact()
释放侧
DMA 回退路径的分配与释放,换成这对精确分配接口
alloc_pages_exact_nid() 仍按取整后的 order 拿整块
从 buddy 取的这一步没变,buddy 只能整块出
make_alloc_exact() 把块切开
请求页逐页独立引用计数
留给调用者
只有实际请求的那几页
多出的尾页逐页还给 buddy
请求页
尾页
还给 buddy 的空闲链表
立即可被其他分配复用
释放侧 free_pages_exact() 按请求页数逐页归还
与分配侧对称:拿到几页就还几页
调用者只占请求的页数
从拿到块的那一刻起
不再整块压在手里
尾页早已回到空闲链表
三条分配路径
dma-iommu
分配
direct
分配
ops_helpers
分配
dma_free_contiguous() 的 buddy 回退释放
分配换到哪,释放也换到哪,收发对称
__meminit 标注随之去掉
alloc_pages_exact_nid() 原本只供内存初始化路径使用
现在 DMA 运行时会调它,标注不再成立
替换覆盖回退路径的全部环节
改动前
整块 4 页都被占住
改动后
只占请求的 3 页
尾页已还给 buddy
同一请求:改动前占 4 页,改动后占 3 页
尾页从「闲置到释放」变成「立即可复用」
尾页不再被占住
其他分配立刻能用
不用等整块释放
请求越偏离 2 的幂
取整出来的尾页越多
省下来的也越多
最多省下接近整块的一半
例:请求 3 页、整块 4 页,尾页就占掉四分之一
上限永远是取整时多出来的那些尾页
CMA 主分配路径不变
只有 buddy 回退路径改变行为
调用者的接口与语义也没变
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x