编程获取PCI设备NUMA节点及/dev条目到NUMA节点的映射方法
标准实现方案:使用sysfs属性
你完全不需要自定义ioctl,Linux内核已经为所有struct device默认导出了NUMA节点属性,通过sysfs文件系统就可以直接在应用层读取,这是当前最通用的标准实现方式。
具体实现步骤
- 对你打开的
/dev/mydevX设备文件调用fstat,获取字符设备的主次设备号 - 拼接sysfs路径
/sys/dev/char/<主设备号>:<次设备号>/numa_node - 直接读取该文件的整数值,就是设备对应的NUMA节点编号,读取失败则说明系统不支持NUMA或者设备未关联NUMA节点
示例代码
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/sysmacros.h> #include <numa.h> int get_device_numa_node(int dev_fd) { struct stat dev_stat; if (fstat(dev_fd, &dev_stat) < 0) { return -1; } // 校验是否为字符设备 if (!S_ISCHR(dev_stat.st_mode)) { return -1; } unsigned int major_num = major(dev_stat.st_rdev); unsigned int minor_num = minor(dev_stat.st_rdev); char numa_node_path[128]; snprintf(numa_node_path, sizeof(numa_node_path), "/sys/dev/char/%u:%u/numa_node", major_num, minor_num); FILE *node_file = fopen(numa_node_path, "r"); if (!node_file) { return -1; } int numa_node = -1; if (fscanf(node_file, "%d", &numa_node) != 1) { numa_node = -1; } fclose(node_file); return numa_node; } // 使用示例 int main() { int dev_fd = open("/dev/mydev0", O_RDWR); int node = get_device_numa_node(dev_fd); if (node >= 0 && numa_available() >= 0) { // 绑定内存分配到对应NUMA节点 struct bitmask *node_mask = numa_allocate_nodemask(); numa_bitmask_setbit(node_mask, node); numa_bind(node_mask); numa_free_nodemask(node_mask); } // 后续业务逻辑 close(dev_fd); return 0; }
驱动侧注意事项
你不需要在驱动中加任何额外代码,只需要在调用device_create之前,确保给对应的struct device的numa_node字段赋值正确即可:
- 如果是PCI设备,内核已经自动填充了
pci_dev->dev.numa_node,直接复用该值即可 - 如果是自定义非PCI设备,根据硬件实际连接的NUMA节点赋值即可
其他可选方案(不推荐)
你提到的lspci查询方式也可以实现,需要先从sysfs中读取设备对应的PCI总线地址,再查询对应PCI设备的NUMA节点,但该方案只适用于PCI设备,通用性远不如直接读取字符设备的numa_node属性。
你原本的自定义ioctl方案也可以正常工作,但不属于标准接口,需要同时维护驱动和应用层的ioctl定义,兼容性和可维护性更差。
内容的提问来源于stack exchange,提问作者Leonardo
相关产品推荐
相关产品推荐

