4. CXL 内存设备在线与离线

任务说明

本案例通过 CXL 内存设备的 sysfs 接口,执行内存块的在线(online)与离线(offline)操作,观察内核内存热插拔行为。核心操作对象是 /sys/devices/system/memory/memoryN/ 下的 state 文件。

CXL 内存设备被内核识别后,会以 memory block 的形式注册到 /sys/devices/system/memory/。每个 block 对应一个 memoryN 目录,其 state 文件可读写:写入 online 或 offline 触发内存热插拔。

环境与依赖

  • Linux 内核 5.19+,已启用 CONFIG_MEMORY_HOTPLUG 与 CXL 相关配置
  • 系统已识别到 CXL 内存设备(daxctl 或 cxl list 可见)
  • root 权限(写 sysfs 需要 CAP_SYS_ADMIN)
  • Python 3.6+(仅用标准库)

操作流程

枚举 memoryN /sys/devices/system/memory 读取 state online / offline 写入 offline echo offline > state 验证 state 回读确认 写入 online echo online > state 验证 state 回读确认 offline 释放内存块 → online 重新纳入内存管理

核心代码

以下脚本枚举所有 memory block,对指定 block 执行 offline 与 online,并在每步后回读 state 验证结果。

#!/usr/bin/env python3
"""CXL 内存设备在线/离线操作与验证"""
import os
import sys

MEM_BASE = "/sys/devices/system/memory"

def list_blocks():
    """返回所有 memoryN 目录名(按编号排序)"""
    blocks = []
    for name in os.listdir(MEM_BASE):
        if name.startswith("memory") and name[6:].isdigit():
            blocks.append(name)
    return sorted(blocks, key=lambda n: int(n[6:]))

def read_state(block):
    path = os.path.join(MEM_BASE, block, "state")
    with open(path) as f:
        return f.read().strip()

def write_state(block, value):
    path = os.path.join(MEM_BASE, block, "state")
    with open(path, "w") as f:
        f.write(value)

def set_state(block, target):
    """切换状态并回读验证,返回 (成功, 实际状态)"""
    before = read_state(block)
    if before == target:
        return True, before
    try:
        write_state(block, target)
    except OSError as e:
        return False, f"写入失败: {e}"
    after = read_state(block)
    return after == target, after

def main():
    blocks = list_blocks()
    if not blocks:
        print("未发现 memory block,请确认内核已启用内存热插拔")
        sys.exit(1)

    print(f"发现 {len(blocks)} 个 memory block: {blocks[0]} .. {blocks[-1]}")
    print(f"{'block':<12} {'初始':<10} {'offline后':<10} {'online后':<10}")
    print("-" * 46)

    for block in blocks:
        init = read_state(block)
        ok_off, after_off = set_state(block, "offline")
        ok_on, after_on = set_state(block, "online")
        flag = "OK" if (ok_off and ok_on) else "FAIL"
        print(f"{block:<12} {init:<10} {after_off:<10} {after_on:<10} [{flag}]")

if __name__ == "__main__":
    main()

运行方式

sudo python3 cxl_mem_online_offline.py

若只想操作单个 block,可手动执行:

# 查看当前状态
cat /sys/devices/system/memory/memory0/state
# 离线
echo offline | sudo tee /sys/devices/system/memory/memory0/state
# 在线
echo online | sudo tee /sys/devices/system/memory/memory0/state

验证方法与通过条件

  • 脚本输出每个 block 的初始状态、offline 后状态、online 后状态。
  • 通过条件:offline 后 state 回读为 offline,online 后回读为 online,标记为 [OK]。
  • 若某 block 无法离线(如正在被使用),写入会返回 EBUSY,脚本标记 [FAIL] 并显示错误信息,属正常现象。
  • 可同时用 dmesg | tail 观察内核热插拔日志,确认 Offlined memory block / Online memory block 记录。

常见问题

  • 写入返回 EBUSY:该内存块正在被使用(如内核数据结构、不可迁移页),无法离线。可尝试其他 block。
  • state 文件不存在:内核未启用 CONFIG_MEMORY_HOTPLUG,或 CXL 设备未以内存设备模式注册。
  • 权限不足:需 root 或 CAP_SYS_ADMIN 权限写入 sysfs。