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. 安装依赖
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。