访问sysfs信息的规则¶
内核导出的 sysfs 导出内部内核实现细节,并且依赖于内部内核结构和布局。内核开发人员一致认为 Linux 内核不提供稳定的内部 API。因此,sysfs 接口的某些方面可能在内核发行版之间不稳定。
为了最大限度地减少由于新内核发行版而破坏 sysfs 用户(在大多数情况下是低级用户空间应用程序)的风险,sysfs 用户必须遵循一些规则,以尽可能抽象的方式访问此文件系统。当前的 udev 和 HAL 程序已经实现了这一点,并且鼓励用户尽可能插入这些程序提供的抽象,而不是直接访问 sysfs。
但是,如果您确实想要或需要直接访问 sysfs,请遵循以下规则,然后您的程序应该可以与未来的 sysfs 接口版本一起使用。
- 不要使用 libsysfs
它对 sysfs 做出了一些不正确的假设。它的 API 不提供任何抽象,它在其自己的 API 中公开了所有内核驱动程序核心的实现细节。因此,它并不比自己读取目录和打开文件更好。而且,它没有积极维护,在反映当前内核开发方面。提供稳定接口给sysfs的目标已经失败;它造成的问题比它解决的更多。它违反了本文档中的许多规则。
- sysfs 始终位于
/sys
解析
/proc/mounts
是在浪费时间。其他的挂载点是您不应该尝试解决的系统配置错误。对于测试用例,可能支持一个SYSFS_PATH
环境变量来覆盖应用程序的行为,但永远不要尝试搜索 sysfs。如果您不是早期启动脚本,则永远不要尝试挂载它。
- sysfs 始终位于
- 设备只是“设备”
在用户空间中,没有什么像类设备、总线设备、物理设备、接口等你可以依赖的东西。一切都只是一个简单的“设备”。类设备、总线设备、物理设备......类型只是内核实现细节,应用程序在 sysfs 中查找设备时不应该期望它们。
设备的属性是
devpath (
/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0
)与设备创建和删除时内核发送的事件中的 DEVPATH 值相同
该设备在那个时间点的唯一键
不带前导
/sys
的设备目录的内核路径,并且始终以斜杠开头devpath 的所有元素都必须是真实目录。指向 /sys/devices 的符号链接必须始终解析为其真实目标,并且必须使用目标路径来访问该设备。这样,设备的 devpath 与事件时使用的内核的 devpath 相匹配。
将符号链接值用作 devpath 字符串中的元素是应用程序中的一个 bug
内核名称 (
sda
,tty
,0000:00:1f.2
, ...)目录名,与 devpath 的最后一个元素相同
应用程序需要处理名称中的空格和字符,如
!
子系统 (
block
,tty
,pci
, ...)简单字符串,永远不是路径或链接
通过读取“subsystem”链接并仅使用目标路径的最后一个元素来检索
驱动程序 (
tg3
,ata_piix
,uhci_hcd
)一个简单的字符串,可能包含空格,永远不是路径或链接
它通过读取“driver”链接并仅使用目标路径的最后一个元素来检索
没有“driver”链接的设备只是没有驱动程序;在子设备上下文中复制驱动程序值是应用程序中的一个 bug
属性
设备目录中的文件或同一设备目录的子目录下的文件
访问通过指向另一个设备的符号链接(如“device”链接)访问的属性是应用程序中的一个 bug
其他一切都只是内核驱动程序核心实现细节,不应假定在内核发行版之间保持稳定。
- 父设备的属性永远不属于子设备。
始终查看父设备本身以确定设备上下文属性。如果设备
eth0
或sda
没有“driver”链接,则此设备没有驱动程序。它的值为空。永远不要将父设备的任何属性复制到子设备中。父设备属性可能会动态更改,而不会通知子设备。
- 单个设备树中的层次结构
sysfs 中只有一个有效的位置可以检查层次结构,那就是:
/sys/devices.
计划将所有设备目录都放在此目录下的树中。
- 按子系统分类
目前有三个用于设备分类的地方:
/sys/block,
/sys/class
和/sys/bus.
计划这些目录本身不包含任何设备目录,而只包含指向统一/sys/devices
树的符号链接的扁平列表。所有三个地方都有完全不同的规则来访问设备信息。计划将所有三个分类目录合并到一个位置,即/sys/subsystem
,遵循总线目录的布局。所有总线和类,包括转换后的块子系统,都将显示在那里。属于子系统的设备将在/sys/subsystem/<name>/devices
的“devices”目录中创建一个符号链接。如果
/sys/subsystem
存在,则可以忽略/sys/bus
、/sys/class
和/sys/block
。如果它不存在,您始终需要扫描所有三个地方,因为只要设备仍然可以通过相同的子系统名称访问,内核就可以自由地将子系统从一个地方移动到另一个地方。假设
/sys/class/<subsystem>
和/sys/bus/<subsystem>
,或者/sys/block
和/sys/class/block
是不可互换的是应用程序中的一个 bug。
- 块
位于
/sys/class/block
或/sys/subsystem/block
的转换后的块子系统将在同一级别包含磁盘和分区的链接,而不是在层次结构中。假设块子系统仅包含磁盘而不是同一扁平列表中的分区设备是应用程序中的一个 bug。
- “device”-link 和 <subsystem>:<kernel name>-links
永远不要依赖 “device”-link。“device”-link 是旧布局的解决方法,在这种布局中,类设备不是像总线设备一样在
/sys/devices/
中创建的。如果设备目录的链接解析未在/sys/devices/
中结束,则可以使用 “device”-link 在/sys/devices/
中查找父设备。这是 “device”-link 的唯一有效用途;它绝不能作为元素出现在任何路径中。假设/sys/devices/
中的设备存在 “device”-link 是应用程序中的一个 bug。访问/sys/class/net/eth0/device
是应用程序中的一个 bug。永远不要依赖于返回到
/sys/class
目录的类特定的链接。这些链接也是一个解决方法,用于解决类设备不是在/sys/devices.
中创建的设计错误。如果设备目录不包含子设备的目录,则可以使用这些链接在/sys/class.
中查找子设备。这是这些链接的唯一有效用途;它们绝不能作为元素出现在任何路径中。假设/sys/devices
树中实际子设备目录的设备存在这些链接是应用程序中的一个 bug。计划在所有类设备目录都位于
/sys/devices.
中时删除所有这些链接。
- 设备链中设备的位置可能会改变。
永远不要依赖于 devpath 中的特定父设备位置或父设备链。内核可以自由地将设备插入链中。您必须始终通过其子系统值请求您正在寻找的父设备。您需要向上遍历链,直到找到与预期子系统匹配的设备。依赖于父设备的特定位置或使用
../
访问父链的相对路径是应用程序中的一个 bug。
- 在读取和写入 sysfs 设备属性文件时,避免依赖
尽可能避免依赖于特定的错误代码。 这最大限度地减少了与内核中错误处理实现的耦合。
通常,读取或写入 sysfs 设备属性失败应尽可能传播错误。 常见错误包括但不限于:
-EIO
:不支持读取或存储操作,通常由 sysfs 系统本身返回,如果读取或存储指针为NULL
。-ENXIO
:读取或存储操作失败如果没有充分的理由,错误代码不会更改,如果对错误代码的更改导致用户空间中断,则会修复它,否则会恢复有问题的更改。
但是,用户空间应用程序可以预期,在给定属性的上下文中,在没有版本属性更改的情况下,属性文件的格式和内容保持一致。