struct ttm_mem_zone 与 struct ttm_page_pool 的联系

struct ttm_mem_zonestruct ttm_page_pool 的联系

内核版本5.4

它们 没有直接的指针引用 ,而是通过 struct ttm_mem_global 这个中间层间接关联。二者属于 TTM 内存管理体系的两个不同层次,各司其职,通过初始化时的参数传递和运行时的 API 调用协作。

关键联系点

1. 初始化时的联系 --- max_mem 参数传递

ttm_page_alloc_init()ttm_mem_global_init() 中被调用,zone 的内存上限决定了 pool 的最大缓存页数:

ttm_memory.h

复制代码
struct ttm_mem_zone *zone_kernel;
// zone_kernel->max_mem = 系统 RAM 的一半 (减去一些余量)

ttm_memory.c

复制代码
ttm_page_alloc_init(glob, glob->zone_kernel->max_mem/(2*PAGE_SIZE));
//                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                       zone 的 max_mem / (2 * PAGE_SIZE) → pool 的 max_pages

pool 的最大缓存容量 = zone 内核区可用显存的一半(按页计算)。这是一个松耦合------zone 只提供一个数字,pool 用这个数字限制自己的缓存大小。

2. sysfs 层级的父子关系

pool manager 的 kobject 挂在 glob->kobj 下面,而每个 zone 的 kobj 也挂在 glob->kobj 下面:

ttm_page_alloc.c

复制代码
ret = kobject_init_and_add(&_manager->kobj, &ttm_pool_kobj_type,
                           &glob->kobj, "pool");

所以在 sysfs 中它们是兄弟节点:

复制代码
/sys/.../memory_accounting/
├── zone_kernel/          ← ttm_mem_zone (zone_kernel)
├── zone_dma32/           ← ttm_mem_zone (zone_dma32 或 highmem)
└── pool/                 ← ttm_pool_manager
    └── (各个 page_pool 的统计信息)
3. 运行时的联系 --- 记账 API

Page Pool 不直接操作 ttm_mem_zone 。Page Pool 负责物理页面的缓存和分配 ,而 ttm_mem_zone 负责内存用量记账 。它们通过 ttm_mem_global_alloc_page() / ttm_mem_global_free_page() 这个 API 桥接。

ttm_pool_populate() 分配页面时:

ttm_page_alloc.c

复制代码
struct ttm_mem_global *mem_glob = ttm->bdev->glob->mem_glob;

ret = ttm_get_pages(ttm->pages, ttm->num_pages, ttm->page_flags,
                    ttm->caching_state);           // 从 pool 获取页面
// ...
for (i = 0; i < ttm->num_pages; ++i) {
    ret = ttm_mem_global_alloc_page(mem_glob, ttm->pages[i],
                                    PAGE_SIZE, ctx);  // 向 zone 记账
}

ttm->caching_state 所以通过这个变量,mem zone和ttm_pool关联了起来

复制代码
enum ttm_caching_state {
	tt_uncached,
	tt_wc,
	tt_cached
};

释放时同理:

ttm_page_alloc.c

复制代码
ttm_mem_global_free_page(mem_glob, ttm->pages[i], PAGE_SIZE);  // 向 zone 减记账

ttm_mem_global_alloc_page() 内部会根据页面属性(是否 HIGHMEM)找到对应的 zone,更新其 used_mem

ttm_memory.c

复制代码
int ttm_mem_global_alloc_page(struct ttm_mem_global *glob,
                              struct page *page, uint64_t size,
                              struct ttm_operation_ctx *ctx)
{
    struct ttm_mem_zone *zone = NULL;
    // ...
#ifdef CONFIG_HIGHMEM
    if (PageHighMem(page) && glob->zone_highmem != NULL)
        zone = glob->zone_highmem;
    else
#endif
    zone = glob->zone_kernel;
    // ... 在 zone 上记账,检查是否超过 max_mem/emer_mem ...
}

总结对比

维度 ttm_mem_zone ttm_page_pool
职责 内存用量记账、限额管理、swap 控制 物理页面的缓存池(减少 alloc/free 开销)
文件 ttm_memory.c ttm_page_alloc.c
数量 最多 2 个(kernel + highmem/dma32) 6 个(wc/uc × normal/dma32/huge)
数据结构 zone_mem, max_mem, used_mem, swap_limit list_head 页面链表, npages 计数
关联方式 通过 ttm_mem_global_alloc/free_page() 被调用 在 populate/unpopulate 时调用 zone 的记账 API
初始化耦合 zone_kernel->max_mem 传入 pool 的 max_pages max_pages 来自 zone 的 max_mem

简而言之:ttm_mem_zone 是"会计",ttm_page_pool 是"仓库" 。它们不直接引用对方,而是都通过 ttm_mem_global 这个全局协调者进行间接协作------仓库每次进出货物都会通知会计记账。

相关推荐
hhcs11 小时前
Linux TTM 子系统:ttm_mem_reg → ttm_resource
linux·drm mm·drm ttm