2. Linux设备模型概述
Linux设备模型并不是一个“看得见”的驱动,而是内核中一套用于统一描述设备、驱动、总线及其相互关系的抽象框架。它要解决的核心问题是:当系统里存在成百上千个设备、驱动和总线时,如何用一致的方式表示它们的层次关系、生命周期和用户空间接口。围绕这个问题,内核提供了 kobject、kset、ktype、sysfs、uevent 等基础构件,它们共同构成了设备模型的骨架。
2.1 核心构件与职责
kobject 是设备模型中最小的对象单元,它本身不描述具体设备,而是为上层对象提供通用能力:引用计数、父子关系、名称以及在 sysfs 中的位置。每个 kobject 通常嵌入在更大的结构体中,例如 struct device、struct driver 内部都包含 kobject。引用计数决定对象何时可以释放,父子关系决定它在 sysfs 中的目录层级。
kset 是 kobject 的集合,用于把一组同类对象组织在一起,例如“所有块设备”或“所有 PCI 设备”。kset 自身也内嵌一个 kobject,因此它同样可以出现在 sysfs 中,并成为集合内对象的父目录。kset 还负责在成员加入或离开时产生 uevent,是设备模型中“批量管理”和“事件通知”的关键节点。
ktype 描述某一类 kobject 的公共行为,最重要的是 release 回调,用于在引用计数归零时释放对象。它相当于 kobject 的“类型操作表”,让同类对象共享释放逻辑和属性操作。ktype 与 kobject 的关系类似“类”与“实例”的关系,但内核中更强调它是可选的、按需提供的操作集合。
sysfs 是设备模型面向用户空间的窗口,通常挂载在 /sys。它把内核中的 kobject 层次导出为目录和文件,用户可以通过读写这些文件查看设备状态、修改参数或触发操作。sysfs 中的文件不是普通磁盘文件,而是内核属性的动态映射,读写会直接调用对应的 show/store 回调。
uevent 是内核向用户空间发送的设备事件,例如设备加入、移除或状态变化。它通常由 udev/mdev 等用户空间程序接收,用于创建 /dev 节点、加载固件或执行热插拔策略。uevent 让设备模型不仅“可看”,还“可通知”,是动态设备管理的基础。
2.2 从内核对象到用户可见目录
设备模型最直观的体现是 sysfs 目录树。内核中每注册一个 kobject,就会在 sysfs 中创建一个对应目录;kobject 的父子关系直接决定目录的嵌套层级。例如一个 PCI 设备下挂 SATA 控制器,控制器下挂主机适配器,适配器下挂目标设备,最终形成类似 /sys/devices/pci0000:00/.../block/sda 的深层次路径。这种层次不是随意设计的,而是真实反映了总线、控制器、设备之间的物理或逻辑从属关系。
kset 在 sysfs 中通常表现为一个集合目录,例如 /sys/class、/sys/bus 下的各类子目录。它们把分散在不同物理路径下的同类设备以“类”或“总线”的视角重新聚合,方便用户和工具按功能查找。例如 /sys/class/net/eth0 是一个符号链接,指向该网卡在 /sys/devices 中的真实位置。
ktype 虽然不直接出现在 sysfs 目录名中,但它决定了当对象引用计数归零时如何释放。如果 release 回调缺失或实现错误,就会出现对象无法释放、内存泄漏或释放后仍被访问的问题。因此在调试设备模型时,ktype 的 release 逻辑是重点检查对象之一。
2.3 uevent 与热插拔流程
当设备加入、移除或属性发生变化时,内核会通过 kobject_uevent 发送事件。事件包含设备路径、子系统、动作类型以及环境变量。用户空间的 udev 接收后,会根据规则创建 /dev 节点、设置权限、加载驱动或执行脚本。典型调试命令如下:
# 查看某设备的 uevent 内容
cat /sys/class/net/eth0/uevent
# 实时监听内核 uevent
udevadm monitor --kernel --property
# 查看 sysfs 中的设备层次
ls -l /sys/class/net/eth0
readlink -f /sys/class/net/eth0
如果设备节点没有自动创建,或者热插拔脚本没有执行,通常需要沿着“内核是否发出 uevent → udev 是否收到 → 规则是否匹配 → 权限是否正确”这条链路排查。设备模型中的 kobject 名称、kset 子系统和 uevent 环境变量必须一致,否则用户空间无法正确识别设备。
2.4 典型应用场景与误区
| 构件 | 核心作用 | 典型调试点 |
|---|---|---|
| kobject | 引用计数、父子层次、sysfs 入口 | 引用计数是否泄漏、名称是否冲突 |
| kset | 同类对象集合、批量 uevent | 成员加入/移除是否触发事件 |
| ktype | release 回调与属性操作 | release 是否为空、是否重复释放 |
| sysfs | 用户空间查看和配置设备 | 属性文件是否存在、读写是否越权 |
| uevent | 内核到用户空间的事件通知 | 事件是否发出、udev 规则是否匹配 |
find /sys -name uevent 和 udevadm info 确认对象是否存在、路径是否正确、事件是否可达。很多“设备不识别”问题并不是驱动没加载,而是设备模型中的层次或事件链路没有建立完整。
理解 kobject、kset、ktype、sysfs 和 uevent 的分工与协作,是后续分析设备注册失败、驱动绑定异常、sysfs 属性读写错误以及热插拔事件丢失的基础。设备模型把“设备是谁、挂在哪里、由谁管理、如何通知用户”这几个问题统一到一套结构中,调试时只要沿着对象层次和事件链路逐层检查,就能快速缩小故障范围。