3、基础功能测试:设备枚举与识别、命名空间扫描、容量与LBA格式校验
好,咱们进入第三个章节。前面两章我们把测试环境和工具链搭好了,现在该真刀真枪地干活了。
基础功能测试,说白了就是回答三个问题:
- 系统认没认出这个NVMe设备?
- 设备里有多少个命名空间?
- 每个命名空间的容量和LBA格式对不对?
这三个问题看似简单,但我在项目中遇到过不少坑。有些设备在枚举阶段就翻车了,有些是命名空间数量对不上,还有些是LBA格式配错了导致性能异常。嗯,咱们一个一个来拆解。
3.1 设备枚举与识别
设备枚举是第一步。你插上NVMe SSD,系统得能发现它,并且正确识别它的厂商、型号、固件版本。
我个人习惯先用 lspci 看一眼。NVMe设备在PCIe总线上,所以这条命令最直接:
# 查看NVMe控制器
lspci -vnn | grep -i nvme
# 输出示例
01:00.0 Non-Volatile memory controller [0108]: Samsung Electronics Co Ltd NVMe SSD Controller PM9A1 [144d:a80a] (rev 01)
这里要注意的是,有些设备可能被识别为「Non-Volatile memory controller」,但厂商ID和设备ID对不上。我曾经遇到过一颗国产主控,lspci显示的是「Generic NVMe Controller」,没有具体厂商信息。这种情况就要警惕了——可能是驱动没加载对,或者设备枚举阶段就有问题。
接下来用 nvme list 命令,这是最常用的工具:
nvme list
Node SN Model Version Namespace Usage Format FW Rev
---------------- -------------------- ---------------------------------------- -------- --------- -------------------------- ---------------- --------
/dev/nvme0n1 S6P9NB0R123456 Samsung SSD 980 PRO 1TB 1.4 1 500.11 GB / 500.11 GB 512 B + 0 B 5B2QGXA7
看到这个输出,基本就放心了。但别急,我建议你多检查几个点:
- Node:设备节点是否存在,比如
/dev/nvme0和/dev/nvme0n1 - Model:型号字符串是否完整,有没有乱码
- FW Rev:固件版本是否和标称一致
- Version:NVMe协议版本,比如1.3、1.4、2.0
nvme list 输出为空,但 lspci 能看到设备,大概率是驱动问题。检查一下内核是否加载了 nvme 和 nvme_core 模块。
3.2 命名空间扫描
命名空间(Namespace)是NVMe协议里一个很重要的概念。一个物理设备可以分成多个逻辑空间,每个空间独立管理。
你想想看,如果设备宣称有4个命名空间,但实际只扫出来2个,那后面的测试全白做。
我一般用 nvme id-ctrl 查看控制器的能力,再用 nvme list-ns 列出所有命名空间:
# 查看控制器支持的命名空间数量
nvme id-ctrl /dev/nvme0 | grep -i nn
nn : 4
nn 字段表示控制器支持的命名空间总数。如果这里显示4,但 nvme list-ns 只列出2个,那就有问题了。
# 列出所有命名空间
nvme list-ns /dev/nvme0
[ 0]:0x1
[ 1]:0x2
[ 2]:0x3
[ 3]:0x4
这里输出的是命名空间ID(NSID),从1开始。如果列表数量和 nn 一致,说明扫描通过。
3.3 容量与LBA格式校验
容量校验,听起来简单,但坑不少。我记得有一次,客户反馈说「1TB的盘,系统只显示953GB」。其实这是正常的,因为厂商用十进制(1TB = 1,000,000,000,000字节),而系统用二进制(1TiB = 1,099,511,627,776字节)。但作为测试,我们要确认的是:设备报告的容量和标称容量是否在合理误差范围内。
用 nvme id-ns 查看命名空间的详细信息:
nvme id-ns /dev/nvme0n1
nsze : 0x3a386000
ncap : 0x3a386000
nuse : 0x3a386000
nsfeat : 0x0
nlbaf : 0
flbas : 0
mc : 0
dpc : 0
dps : 0
nmic : 0
rescap : 0
fpi : 0
dlfeat : 0
lbaf0 : 0:0:0:0:0
关键字段解释:
| 字段 | 含义 | 校验要点 |
|---|---|---|
nsze |
命名空间总容量(LBA数量) | 乘以LBA大小后,应接近标称容量 |
ncap |
命名空间最大容量 | 通常等于 nsze,如果小于则说明有预留空间 |
nuse |
当前已使用的LBA数量 | 新盘应为0或接近0 |
nlbaf |
支持的LBA格式数量 | 至少为0(表示支持1种格式) |
flbas |
当前使用的LBA格式索引 | 应在0到 nlbaf 之间 |
lbaf0 |
LBA格式0的描述 | 格式为 LBA数据大小:元数据大小:相对性能:... |
容量计算很简单:
总容量(字节) = nsze × LBA数据大小
# 示例:nsze = 0x3a386000 = 976,773,120 LBA
# LBA数据大小 = 512字节
# 总容量 = 976,773,120 × 512 = 500,107,862,016 字节 ≈ 500GB
LBA格式校验,我建议重点关注两点:
- 支持的格式是否完整:比如设备宣称支持512B、1KB、2KB、4KB,但实际只实现了512B和4KB,那就要标记为缺陷。
- 当前格式是否合理:有些设备默认用4KB LBA,但上层文件系统可能只支持512B扇区。这种不匹配会导致性能下降甚至IO错误。
nlbaf 字段只显示7。后来发现是固件bug,第8种格式的索引写错了。这种问题用 nvme id-ns 一眼就能看出来。
3.4 自动化测试脚本示例
手动测试一遍还行,但回归测试时总不能每次都敲命令吧?我写了个简单的脚本,把这些检查点串起来:
#!/bin/bash
# NVMe基础功能测试脚本
DEVICE="/dev/nvme0"
NAMESPACE="/dev/nvme0n1"
EXPECTED_CAPACITY_GB=500
echo "=== 1. 设备枚举检查 ==="
if [ -e "$DEVICE" ]; then
echo "[PASS] 设备节点存在: $DEVICE"
else
echo "[FAIL] 设备节点不存在"
exit 1
fi
echo "=== 2. 命名空间扫描 ==="
NS_COUNT=$(nvme list-ns $DEVICE | wc -l)
if [ "$NS_COUNT" -ge 1 ]; then
echo "[PASS] 命名空间数量: $NS_COUNT"
else
echo "[FAIL] 未发现命名空间"
exit 1
fi
echo "=== 3. 容量校验 ==="
NSZE=$(nvme id-ns $NAMESPACE | grep "nsze" | awk '{print $3}')
LBA_SIZE=$(nvme id-ns $NAMESPACE | grep "lbaf0" | awk -F: '{print $1}')
CAPACITY_BYTES=$((NSZE * LBA_SIZE))
CAPACITY_GB=$((CAPACITY_BYTES / 1000000000))
if [ "$CAPACITY_GB" -eq "$EXPECTED_CAPACITY_GB" ]; then
echo "[PASS] 容量正确: ${CAPACITY_GB}GB"
else
echo "[WARN] 容量偏差: 期望 ${EXPECTED_CAPACITY_GB}GB, 实际 ${CAPACITY_GB}GB"
fi
echo "=== 测试完成 ==="
这个脚本虽然简单,但覆盖了核心检查点。你可以根据实际需求扩展,比如加入LBA格式校验、固件版本比对等。
3.5 常见问题与避坑指南
最后,分享几个我踩过的坑:
- 设备节点重复:有时候系统会生成
/dev/nvme0和/dev/nvme1指向同一个物理设备。这是因为驱动加载了两次。解决办法是检查/sys/class/nvme/下的符号链接。 - 命名空间ID不连续:理论上NSID从1开始连续递增,但有些设备会跳过某些ID。比如显示1、2、4,缺少3。这不一定是bug,但需要确认。
- LBA格式切换失败:有些设备支持多种LBA格式,但切换后需要复位才能生效。如果测试时发现格式切换后容量不对,先试试
nvme reset。
nvme list 和 nvme id-ctrl 把设备信息保存到日志文件。这样出了问题可以回溯,看看是测试过程中变了,还是初始状态就不对。
好了,基础功能测试就讲到这里。下一章我们会深入IO路径测试,看看读写性能和数据完整性怎么验证。记住,基础不牢,地动山摇——设备枚举和命名空间扫描这一步,千万别偷懒。