FSDAX 模式是 CXL REGION 的一种配置模式,通过将 CXL 内存格式化为支持 DAX(Direct Access) 的文件系统(如 EXT4、XFS),允许应用程序通过标准文件接口直接访问内存,同时绕过传统的块设备层和页缓存. 此模式结合了文件系统的易用性与直接内存访问的高性能,特别适合需要持久化存储和文件接口的场景.有了 CXL REGION FSDAX 模式,那么可以将文件系统的一些应用运用到该模式下,例如交换分区技术(SWAP).

SWAP 功能是操作系统中的一种内存管理技术,用于在物理内存(RAM) 不足时,临时将不常用的数据从内存移到硬盘的交换空间(SWAP Space)中,当需要再次访问这些数据时,系统再通过缺页异常(PageFault)机制将数据从交换空间拷贝到物理内存,以此缓解系统内存压力. 交换空间(SWAP SPACE)本质是文件存储,因此可以是磁盘也可以是文件.

FSDAX 模式可以将 CXL Type3 设备作为文件存储使用,从操作系统角度来看,FSDAX 模式创建的 “/dev/pmem” 块设备就是一个磁盘,因此可以将其设置为 SWAP Space,另外由于 CXL Type3 本身的延时介于 DDR 和 SDD 之间,因此会比传统的 SWAP 延时更低. 接下来通过一个实践案例介绍如何将 CXL Type3 设备作为 SWAP Space,实践案例在 BiscuitOS 上的部署逻辑如下:

# 切换到 BiscuitOS 项目目录
cd /BiscuitOS
# 选择开发环境,如果已经选择过可以跳过,这里与 linux 6.10 X86 为例
make linux-6.10-x86_64_defconfig
# 通过 Kbuild 选择需要部署的应用程序
make menuconfig

  [*] DIY BiscuitOS/Broiler Hardware  --->
      [*] CXL: Compute Express Link
            CXL Hardware Topology (CXL2.0: x1 VCS + x1 Type3 PMEM)  --->
      (512) CXL Type3 PMEM Size(MiB)
  [*] Package  --->
      [*] HETEROGENEOUS MEMORY MANAGEMENT
          [*] CXL SWAP: MADV PAGEOUT  --->

# 配置完毕保存,然后进行部署
make

# 切换到实践案例所在目录
cd output/linux-6.10-x86_64/package/BiscuitOS-CXL-SWAP-default
# 准备依赖工具
make prepare
# 编译实践案例
make download
make build

图片无法显示,请右键点击新窗口打开图片

当 BiscuitOS 启动之后,直接运行 RunBiscuitOS.sh 脚本,脚本里包含了运行实践案例的所有命令,可以看到脚本里创建了一个 CXL REGION,然后将其模式修改为 FSDAX,接着是基于 “/dev/pmem” 块设备直接构建 SWAP SPACE,并使用 free 命令查看构建的 SWAP Space 大小,接着运行实践案例的应用程序,此时通过 free 命令可以看到 SWAP Space 空间有物理页内容被交换出去. 接下来分析源码:

图片无法显示,请右键点击新窗口打开图片

实践案例由一个应用程序构成,其在 24 行调用 mmap 函数分配一段内存,然后在 33-34 行对内存进行读写操作,接着在 37 行调用 madvise 函数向虚拟内存发起 MADV_PAGEOUT 请求,该请求会让 mem 对应的虚拟内存直接交换到 SWAP Space 里. 待睡眠 2s 之后,在 43 行再次对内存进行访问,此时会触发缺页产生 SWAP IN 将内容从 SWAP Space 加载到内存里,也就是从 CXL 加载到 DDR 里. 实践完毕之后,调用 munmap 函数将内存进行回收. 通过上面的实践案例看到了内存交换到 CXL 构成的 SWAP SPACE 上,接下来看一下 CXL REGION 构造 SWAP Space 的具体命令:

# 基于 CXL Type3 设备构建一个 CXL REGION
cxl destroy-region -f all
cxl create-region -d decoder0.0 -m mem0 -s 512M -t pmem -w 1 -g 4096 -u
cxl enable-region region0

# 基于 CXL REGION 创建 /dev/pmem 块设备
ndctl destroy-namespace --force all
ndctl enable-region region0
ndctl create-namespace --mode=fsdax -f

# 将 /dev/pmem0 块设备设置为 SWAP,并使能 SWAP SPACE 
mkswap /dev/pmem0
swapon /dev/pmem0

以上的关键是 “/dev/pmem0” 是一个块设备,因此可以直接使用 mkswap 和 swapon 命令创建 SWAP Space. SWAP Space 创建成功之后,内核回收线程会定期将冷页交换到 SWAP Space. 在上面的案例里,使用的 madvise 方式将匿名内存交换到 SWAP Space,这种方式是代码级别的 SWAP 操作. 如果开发者不想修改代码的情况下想让内存进入到 SWAP Space, 那么可以借助 MEMORY CGROUP 机制, 那么接下来通过一个实践案例介绍 CGROUP、SWAP 和 CXL 三者结合的案例,实践案例在 BiscuitOS 上的部署逻辑如下(请提前使能 CONFIG_MEMCG):

# 切换到 BiscuitOS 项目目录
cd /BiscuitOS
# 选择开发环境,如果已经选择过可以跳过,这里与 linux 6.10 X86 为例
make linux-6.10-x86_64_defconfig
# 通过 Kbuild 选择需要部署的应用程序
make menuconfig

  [*] DIY BiscuitOS/Broiler Hardware  --->
      [*] CXL: Compute Express Link
            CXL Hardware Topology (CXL2.0: x1 VCS + x1 Type3 PMEM)  --->
  [*] Package  --->
      [*] HETEROGENEOUS MEMORY MANAGEMENT
          [*] CXL SWAP: MEMORY CGROUP  --->

# 配置完毕保存,然后进行部署
make

# 切换到实践案例所在目录
cd output/linux-6.10-x86_64/package/BiscuitOS-CXL-SWAP-CGROUP-default
# 第一次部署,打开内核宏
cd ../../linux/linux/
scripts/config --enable CONFIG_MEMCG
cd -
make kernel
# 准备依赖工具
make prepare
# 编译实践案例
make download
make build

图片无法显示,请右键点击新窗口打开图片

当 BiscuitOS 启动之后,直接运行 RunBiscuitOS.sh 脚本,脚本里包含了运行实践案例的所有命令,可以看到脚本里创建了一个 CXL REGION,然后将其模式修改为 FSDAX,接着是基于 “/dev/pmem” 块设备直接构建 SWAP SPACE,并使用 free 命令查看构建的 SWAP Space 大小,接着运行实践案例的应用程序,并使用 CGROUP 对该应用程序进行严格限制,不断使用 free 命令可以看到 SWAP Space 空间有物理页内容被交换出去. 接下来分析源码:

图片无法显示,请右键点击新窗口打开图片

实践案例由一个应用程序构成,其在 23-32 行使用一个 while 循环,每次循环过程中,在 25 行调用 mmap 函数分配内存,由于使用了 MAP_POPULATE 的缘故,分配虚拟内存的时候也分配了物理内存. 该案例会让应用程序的物理内存消耗急剧上升,接下来看一下 CGROUP 的限制逻辑:

# 创建 MEMORY CGROUP 
mkdir -p /mnt/BiscuitOS/
mount -t cgroup -o memory BiscuitOS-CGROUP /mnt/BiscuitOS/
mkdir -p /mnt/BiscuitOS/MEMORY
# 将 MEMORY CGROUP 的内存使用量限制在 100M
echo 100M > /mnt/BiscuitOS/MEMORY/memory.limit_in_bytes

# 运行应用程序,并获得应用程序的 PID
BiscuitOS-CXL-SWAP-CGROUP-default &
sleep 0.1
PID=$(pidof BiscuitOS-CXL-SWAP-CGROUP-default)

# 将应用程序的 PID 加入到 MEMORY CGROUP 进行限制
echo ${PID} > /mnt/BiscuitOS/MEMORY/cgroup.procs

通过上面的命令之后,MEMORY CGROUP 在管理的应用程序的物理内存使用量超过 100M 时,会在每次缺页分配物理内存时,主动触发内存回收流程,将 CGROUP 管理进程的物理内存交换到 SWAP Space 上, 待物理消耗量小于 100M 时,CGROUP 管理的进程才能分配新的物理内存. 通过上面两个实践案例基本也对 CXL Type3 PMEM 设备作为 SWAP Space 有了认识,那么开发者可以根据需求去利用 CXL 这一特性.

图片无法显示,请右键点击新窗口打开图片