2. 设备节点基础:Linux 设备文件系统与节点创建机制

在 Linux 系统中,设备节点是用户空间与内核驱动交互的“门把手”。理解设备文件系统(devfs/sysfs)、主次设备号以及节点创建机制,是掌握 HAL 层驱动开发的第一步。本章将系统梳理这些基础概念,并通过结构图与表格帮助建立清晰的认知模型。

2.1 设备文件系统:devfs 与 sysfs

Linux 通过虚拟文件系统将内核中的设备信息暴露给用户空间。历史上先后出现了 devfs 和 sysfs 两种主要机制,它们的设计理念与用途有显著差异。

特性 devfs(设备文件系统) sysfs(系统文件系统)
挂载点 /dev /sys
主要用途 提供设备节点文件,用于 open/read/write 导出内核对象、驱动、设备拓扑与属性
设备节点管理 内核自动创建/删除设备节点 不直接创建设备节点,提供设备信息
用户空间交互 通过文件 I/O 操作设备 通过读写属性文件查询/配置设备
生命周期 Linux 2.6 早期,已被 udev 取代 从 Linux 2.6 至今,持续使用
命名策略 内核硬编码,不灵活 基于 kobject 层次结构,动态生成
实践要点: 在 HAL 层开发中,/sys 用于发现设备拓扑和读取属性(如设备号、供应商 ID),而 /dev 下的节点才是实际进行数据读写的入口。两者协同工作,缺一不可。
设备文件系统对比:devfs vs sysfs devfs (传统) 内核驱动 自动创建设备节点 节点命名由内核硬编码 (如 /dev/ttyS0, /dev/hda) 缺点:不灵活,命名冲突,/dev 臃肿 sysfs (现代) 内核对象 (kobject) 导出设备拓扑与属性 属性文件:可读可写 (如 /sys/class/gpio/gpio48/value) 优点:灵活,标准化,与 udev 配合

2.2 主设备号与次设备号

每个设备节点在 Linux 内核中由一对整数唯一标识:主设备号(Major Number) 和 次设备号(Minor Number)。它们是驱动与设备节点绑定的核心纽带。

  • 主设备号: 标识设备对应的驱动程序。内核通过主设备号在全局设备表(chrdevs / blkdevs)中找到对应的 file_operations 结构体。
  • 次设备号: 由驱动内部解释,通常用于区分同一驱动控制下的多个物理或逻辑设备(如多个串口、多个分区)。
关键理解: 主设备号是“驱动索引”,次设备号是“设备实例索引”。一个驱动可以管理多个次设备,但一个次设备只能属于一个主设备号。
概念 范围(典型) 分配方式 查看命令
主设备号 1 ~ 511(字符设备) 静态分配(Documentation/devices.txt)或动态分配(alloc_chrdev_region) cat /proc/devices
次设备号 0 ~ 1048575(20 位) 驱动开发者自定义,通常从 0 开始顺序编号 ls -l /dev(显示主,次)
主设备号与次设备号映射关系 用户空间:/dev/ttyS0 用户空间:/dev/ttyS1 内核空间 主设备号: 4 (串口驱动) 次设备号: 0 (ttyS0) 次设备号: 1 (ttyS1)

2.3 设备节点创建机制:mknod 与 udev

设备节点本质上是存储在磁盘上的一个特殊文件,包含设备类型(字符/块)、主设备号和次设备号。创建节点有两种典型方式:手动创建(mknod)和自动创建(udev)。

2.3.1 手动创建:mknod 命令

mknod 是最原始的设备节点创建工具,在嵌入式系统早期或 initramfs 环境中仍会使用。其语法为:

mknod /dev/mydevice [c|b] major minor
  • c:字符设备
  • b:块设备
  • major:主设备号
  • minor:次设备号
注意: 手动 mknod 要求开发者预先知道主次设备号,且节点不会随设备热插拔自动消失。在动态设备越来越多的今天,这种方式已不推荐用于产品环境。

2.3.2 自动创建:udev 机制

udev 是 Linux 用户空间设备管理器,它监听内核通过 uevent 发送的设备事件,并根据规则自动在 /dev 下创建或删除设备节点。udev 的工作流程如下:

  1. 内核事件触发: 驱动注册设备时,内核通过 kobject_uevent() 发送 ADD 事件。
  2. udev 守护进程接收: udevd 通过 netlink socket 接收 uevent。
  3. 规则匹配: udev 根据 /etc/udev/rules.d/ 下的规则文件匹配设备属性(如 vendor、product、kernel 名称)。
  4. 节点创建: 匹配成功后,udev 调用 mknod 创建节点,并可执行自定义脚本(如设置权限、创建符号链接)。
udev 设备节点自动创建流程 ① 驱动注册设备 ② 内核发送 uevent ③ udevd 接收事件 ④ 匹配 udev 规则 ⑤ 创建 /dev 节点 规则文件示例 /etc/udev/rules.d/ 99-mydevice.rules ACTION=="add", KERNEL=="ttyUSB*", MODE="0666", SYMLINK+="myuart"

2.4 设备节点访问控制基础

在 HAL 层开发中,设备节点的访问权限直接决定了用户空间程序能否成功打开设备。权限控制分为三个层面:

控制层面 机制 典型配置
文件权限 标准的 UNIX 文件权限(rwx) crw-rw---- 1 root dialout 4, 64 ...
udev 规则 通过 MODE、OWNER、GROUP 字段控制 MODE="0660", GROUP="dialout"
Security Modules SELinux / AppArmor 强制访问控制 针对 HAL 守护进程的 domain 策略
HAL 层实践建议: 在嵌入式系统中,通常通过 udev 规则将设备节点权限设置为 0660,并将 HAL 守护进程加入对应的用户组(如 dialout、gpio),避免使用 0777 权限带来的安全风险。

2.5 本章小结

  • devfs 是早期的设备节点管理方式,已被 sysfs + udev 取代。
  • 主设备号 标识驱动,次设备号 标识设备实例,两者共同构成设备节点的“身份证”。
  • mknod 用于手动创建节点,适合调试和最小系统;udev 是生产环境的标准方案,支持热插拔和灵活规则配置。
  • 设备节点的访问权限控制是 HAL 层安全的基础,应遵循最小权限原则。