Linux下判断路径是否位于NVMe物理盘上,需先用stat获取主次设备号,再通过/sys/dev/block/MAJ:MIN/device/subsystem软链接目标是否含“nvme”确认;Windows则须以管理员权限打开物理磁盘句柄并用IOCTL_STORAGE_QUERY_PROPERTY查询BusType是否等于BusTypeNvme。

Linux下用stat和ioctl查设备类型最可靠
仅靠路径字符串或挂载点名称无法判断是否落在NVMe物理盘上——/dev/nvme0n1p1可能被软链接到/mnt/data,也可能被LVM或mdraid抽象掉。真正有效的方式是获取该路径对应inode的底层块设备节点,再读取其设备属性。
核心步骤:先用stat -c "%t %T" /path拿到主次设备号(major/minor),再用major查/sys/dev/block/<em>MAJ</em>:<em>MIN</em>/device/model或/sys/dev/block/<em>MAJ</em>:<em>MIN</em>/device/subsystem确认是否指向nvme子系统。
-
stat返回的%t %T是十六进制主次设备号,需转十进制后拼成MAJ:MIN格式 - 若
/sys/dev/block/MAJ:MIN/device/subsystem软链接目标含nvme(如../../../../../class/nvme),基本可确认 - 注意LVM逻辑卷会指向
dm子系统,需进一步查/sys/dev/block/MAJ:MIN/dm/uuid反推原始设备
C++里用stat()和readlink()做自动化判断
不能只依赖statfs()或getmntent()——它们只告诉你挂载在哪,不告诉你底层是什么。必须穿透到block device层。
关键代码片段:
立即学习“C++免费学习笔记(深入)”;
struct stat st;
if (stat("/your/path", &st) == 0 && S_ISBLK(st.st_mode)) {
int maj = major(st.st_rdev);
int min = minor(st.st_rdev);
char path[256];
snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device/subsystem", maj, min);
char target[512];
ssize_t len = readlink(path, target, sizeof(target)-1);
if (len > 0) {
target[len] = ' ';
if (strstr(target, "nvme") != nullptr) {
// 真实NVMe介质
}
}
}
-
st.st_rdev才是设备号,st.st_dev是文件系统设备号,别混淆 -
readlink()返回的是相对路径,需检查是否含"nvme"而非硬匹配全路径 - 某些NVMe驱动(如老内核的
nvme-fabrics)可能暴露为rdma子系统,需额外查/sys/dev/block/.../device/transport
Windows下必须用IOCTL_STORAGE_QUERY_PROPERTY
Windows没有统一/sys接口,靠GetDriveType()或GetVolumeInformation()完全没用——它们连SSD/HDD都分不清,更别说NVMe了。
正确做法:打开卷句柄 → 获取物理磁盘号 → 打开物理磁盘句柄 → 发送IOCTL_STORAGE_QUERY_PROPERTY查询StorageAdapterProperty结构体里的BusType字段。
- 若
BusType等于BusTypeNvme(值为19),才是NVMe;BusTypeSata(8)是SATA SSD,不是NVMe - 注意:需以管理员权限打开物理磁盘(
\.PhysicalDriveX),普通用户权限会失败 - 从路径转物理盘号要用
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,别直接猜盘符映射
别信hdparm -I或smartctl输出里的“NVMe”字样
这些工具输出容易误导:如果路径挂在ZFS池、Btrfs多设备阵列或Ceph RBD上,smartctl -i /dev/sda显示NVMe,不代表你访问的文件就走NVMe路径——中间可能经过网络、内存或虚拟块层。
- 真实场景中,
/mnt/ceph/data底层可能是NVMe,但I/O路径经过TCP+RDMA+内核模块,延迟和带宽已脱离NVMe特性 - 数据库或存储引擎(如RocksDB)若开启direct I/O,才真正绕过page cache接触物理设备;否则哪怕在NVMe上,也受VFS缓存影响
- 容器环境更要小心:
docker run -v /host/nvme:/container/path只是bind mount,宿主机路径是否NVMe,容器里stat结果一样,但cgroup blkio限速可能作用在不同层级
物理介质类型只是起点,I/O栈深度、队列深度、是否启用I/O scheduler、甚至PCIe拓扑(比如NVMe盘插在PLX switch下游),都会让“是不是NVMe”这个判断失去单一意义。


















