2. SPDK环境搭建与Hello World

任务说明

本案例在 Linux 上从源码编译 SPDK,配置大页内存与 VFIO 用户态驱动,绑定一块 NVMe 设备,然后运行 hello_world 示例。成功标志是程序枚举出已绑定的 NVMe 控制器并打印其 PCI 地址与型号,说明用户态驱动、大页内存、设备绑定三者均正常。

环境与依赖

  • Ubuntu 22.04 / 内核 5.x 以上,root 或 sudo 权限。
  • 依赖:git build-essential libnuma-dev libssl-dev python3 uuid-dev pkg-config meson ninja-build。
  • 一块未被内核 nvme 驱动占用的 NVMe 盘(可用虚拟机挂载的 NVMe 设备)。

执行流程

1. 编译 SPDK 2. 配置大页内存 3. 绑定 VFIO 驱动 4. 运行示例 hello_world 内部: spdk_env_init → 扫描 PCI → 枚举 NVMe 控制器 输出:NVMe Controller at 0000:xx:00.0

完整操作步骤

# 1. 安装依赖
sudo apt update
sudo apt install -y git build-essential libnuma-dev libssl-dev python3 \
    uuid-dev pkg-config meson ninja-build

# 2. 获取并编译 SPDK
git clone --depth 1 --branch v23.09 https://github.com/spdk/spdk.git
cd spdk
git submodule update --init
./configure
make -j$(nproc)

# 3. 配置大页内存(2GB,每页 2MB)
sudo HUGEMEM=2048 scripts/setup.sh

# 4. 查看可绑定的 NVMe 设备
scripts/setup.sh status

# 5. 绑定 NVMe 到 VFIO 用户态驱动(替换为实际 BDF)
sudo scripts/setup.sh config 0000:01:00.0
sudo scripts/setup.sh bind 0000:01:00.0

# 6. 运行 hello_world
sudo ./build/examples/hello_world

关键代码:hello_world 核心逻辑

SPDK 自带示例已包含完整实现,下面给出其核心调用链,便于理解验证点。若需自建最小示例,可参考此结构:

#include "spdk/stdinc.h"
#include "spdk/env.h"
#include "spdk/nvme.h"

static bool probe_cb(void *ctx, const struct spdk_nvme_transport_id *trid,
                     struct spdk_nvme_ctrlr_opts *opts)
{
    printf("Attaching to NVMe at %s\n", trid->traddr);
    return true;
}

static void attach_cb(void *ctx, const struct spdk_nvme_transport_id *trid,
                      struct spdk_nvme_ctrlr *ctrlr,
                      const struct spdk_nvme_ctrlr_opts *opts)
{
    printf("Attached NVMe Controller at %s\n", trid->traddr);
}

int main(int argc, char **argv)
{
    struct spdk_env_opts env_opts;
    spdk_env_opts_init(&env_opts);
    env_opts.name = "hello_world";
    if (spdk_env_init(&env_opts) < 0) {
        fprintf(stderr, "spdk_env_init failed\n");
        return 1;
    }

    if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
        fprintf(stderr, "spdk_nvme_probe failed\n");
        return 1;
    }

    spdk_env_fini();
    return 0;
}

验证方法与通过条件

  • scripts/setup.sh status 中目标 NVMe 的驱动列显示为 vfio-pci,且大页内存显示已分配(如 HugePages_Total: 1024)。
  • 运行 hello_world 后输出包含 Attaching to NVMe at 0000:xx:00.0 与 Attached NVMe Controller at ...,且进程正常退出(返回码 0)。
  • 若输出为空或报 spdk_env_init failed,说明大页内存未配置;若报 spdk_nvme_probe failed,说明设备未绑定到 VFIO 或权限不足。

常见问题

  • 大页内存不足:HUGEMEM 值需为 2MB 的整数倍,且不超过可用内存。
  • 设备被内核占用:绑定前需确认 nvme 驱动未加载该设备,可用 echo 0000:01:00.0 > /sys/bus/pci/drivers/nvme/unbind 解绑。
  • 恢复内核驱动:sudo scripts/setup.sh unbind 0000:01:00.0 后重新加载 nvme。