如何在Linux下将SPDK管理的NVMe SSD暴露为常规块设备?
解决方案:把SPDK管理的NVMe转成Linux块设备,同时用自研I/O栈处理请求
核心逻辑
用SPDK的用户态块设备(ublk)或者vhost-blk功能就能搞定——这俩都是官方支持的方案,能把SPDK接管的NVMe SSD封装成Linux内核可识别的块设备节点,同时所有I/O请求都会路由到SPDK用户态栈(包括你的自研逻辑),完全绕开内核的块层。
步骤1:编译带ublk/vhost支持的SPDK
首先得确保SPDK编译时开了对应的功能,不然用不了:
# 进入SPDK源码目录,配置编译选项,开启ublk和vhost支持 ./configure --enable-ublk --enable-vhost # 多线程编译安装,加速构建 make -j$(nproc) make install
步骤2:用SPDK ublk暴露块设备(宿主机直接使用的首选方案)
ublk是Linux内核提供的用户态块设备框架,SPDK官方已经做好对接,是最直接的实现方式:
- 将NVMe设备绑定到SPDK用户态驱动
先卸载内核NVMe驱动,把设备交给SPDK管理:
# 查看NVMe设备的PCI地址,示例输出类似0000:01:00.0 lspci | grep NVMe # 重置设备并绑定到SPDK的uio驱动 sudo scripts/setup.sh reset sudo scripts/setup.sh bind -b uio_pci_generic 0000:01:00.0
- 启动SPDK ublk服务,生成块设备
用spdk_ublk工具直接将SPDK管理的NVMe转换为Linux块设备:
# 先查看SPDK可识别的块设备名称,示例为Nvme0n1 build/bin/spdk_bdev_get_bdevs # 将Nvme0n1暴露为/dev/ublkb0 sudo build/bin/spdk_ublk start -b Nvme0n1 -u 0
参数说明:
-b:指定SPDK侧的目标块设备名称-u:指定ublk设备编号,对应生成/dev/ublkb[编号]节点
如果你的自研I/O栈是基于SPDK的bdev框架开发的,直接替换自定义bdev名称即可:
sudo build/bin/spdk_ublk start -b YourCustomBdev -u 0
- 验证块设备可用性
确认设备生成且I/O正常走SPDK栈:
# 查看块设备信息 lsblk /dev/ublkb0 # 简单读写测试验证 dd if=/dev/zero of=/dev/ublkb0 bs=4k count=1000
步骤3:集成自研I/O栈
如果你的自研I/O栈基于SPDK的bdev框架实现,只需以下操作:
- 将自定义bdev驱动编译为SPDK模块,或直接链接到
spdk_ublk二进制文件中 - 创建配置文件
config.json加载自定义bdev:{ "subsystems": [ { "subsystem": "bdev", "config": [ { "method": "your_custom_bdev_create", "params": { "name": "YourCustomBdev", "nvme_device": "Nvme0n1" } } ] } ] } - 启动时指定配置文件:
sudo build/bin/spdk_ublk start -c config.json -b YourCustomBdev -u 0
替代方案:用SPDK vhost-blk(适合虚拟机场景)
如果需要在虚拟机内运行MySQL/YCSB等测试,可使用vhost-blk:
- 编写vhost配置文件
vhost_config.json,指定要暴露的SPDK块设备 - 启动SPDK vhost服务:
sudo build/bin/spdk_tgt --config=vhost_config.json - 通过QEMU将vhost-blk设备挂载到虚拟机,虚拟机内即可识别为常规块设备。不过宿主机直接使用的话,ublk方案更简便。
注意事项
- 要求Linux内核版本≥5.19,否则ublk功能无法正常使用
- 操作前务必备份SSD数据,避免误操作导致数据丢失
- 测试完成后清理环境:
# 停止ublk服务 sudo build/bin/spdk_ublk stop -u 0 # 将设备绑定回内核NVMe驱动 sudo scripts/setup.sh unbind 0000:01:00.0
内容的提问来源于stack exchange,提问作者Jzzzsen Li
相关产品推荐
相关产品推荐

