页面分配器

内核页面分配器服务于所有通用页面分配请求,例如 kmalloc。 CXL 配置步骤会根据所选的内存区域和容量所在的 NUMA 节点 影响页面分配器的行为。

本节主要关注这些配置如何影响页面分配器(截至 Linux v6.15),而不是整体页面分配器行为。

NUMA 节点和内存策略

除非任务显式注册内存策略,否则 Linux 内核的默认内存策略是首先从本地 NUMA 节点分配内存,并且仅在本地节点受到压力时才回退到其他节点。

通常,我们期望在单独的 NUMA 节点上看到本地 DRAM 和 CXL 内存,其中 CXL 内存是非本地的。 然而,从技术上讲,计算节点有可能没有本地 DRAM,并且 CXL 内存是该计算节点的本地容量。

内存区域

CXL 容量可以在 ZONE_NORMALZONE_MOVABLE 中上线。

截至 v6.15,页面分配器首先尝试从本地节点为分配分配最高可用和兼容的 ZONE。

区域不兼容的一个例子是尝试从 ZONE_MOVABLE 提供标记为 GFP_KERNEL 的分配。 内核分配通常是不可迁移的,因此只能从 ZONE_NORMAL 或更低的区域提供服务。

为了简化这一点,页面分配器默认会优先选择 ZONE_MOVABLE 而不是 ZONE_NORMAL,但如果 ZONE_MOVABLE 耗尽,它将回退到从 ZONE_NORMAL 分配。

区域和节点怪癖

让我们考虑这样一种配置,其中本地 DRAM 容量主要上线到 ZONE_NORMAL,而没有 ZONE_MOVABLE 容量。 CXL 容量具有相反的配置 - 全部在 ZONE_MOVABLE 中上线。

在默认分配策略下,页面分配器将完全跳过 ZONE_MOVABLE 作为有效的分配目标。 这是因为,截至 Linux v6.15,页面分配器会(大致)执行以下操作

for (each zone in local_node):

  for (each node in fallback_order):

    attempt_allocation(gfp_flags);

由于本地节点没有 ZONE_MOVABLE,因此 CXL 节点在功能上无法直接分配。 因此,使用 CXL 容量的唯一方法是通过回收路径中的降级

这种配置还意味着,如果 DRAM 节点具有 ZONE_MOVABLE 容量 - 当该容量耗尽时,页面分配器实际上会优先选择 CXL ZONE_MOVABLE 页面而不是 DRAM ZONE_NORMAL 页面。

我们可能希望在未来的 Linux 版本中反转此优先级。

如果禁用降级交换,Linux 将在 DRAM 节点耗尽时开始导致 OOM 崩溃。 有关更多详细信息,请参见回收部分。

CGroups 和 CPUSets

最后,假设 CXL 内存可以通过页面分配访问(即,在线在 ZONE_NORMAL 中),cpusets.mems_allowed 可以被容器使用,以限制该容器中任务对某些 NUMA 节点的访问。 用户可能希望在多租户系统中使用它,其中一些任务不希望使用速度较慢的内存。

在回收部分,我们将讨论此接口的一些限制,以防止共享数据降级到 CXL 内存(如果启用了降级)。