使用 /sys 文件系统访问 Linux 内核
2009-05-17 22:36
316 查看
导言:Linux 2.6驱动模型初看起来的复杂,估计让我们很多人生畏了,但,既然是对原来模型的改进,这种统一的模型自然有其独特的一面。去年暑假,对Linux驱动模型进行了一些的分析,似乎摸着其脉络,但又感觉没有找到入口和出口,于是也就搁置了,看到这篇文章,再次引起了兴趣,并知晓了更多的来去缘由,在此转载~~
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
|
2009 年 1 月 08 日sysfs 是 Linux 内核中设计较新的一种虚拟的基于内存的文件系统,它的作用与 proc 有些类似,但除了与 proc 相同的具有查看和设定内核参数功能之外,还有为 Linux 统一设备模型作为管理之用。相比于 proc 文件系统,使用 sysfs 导出内核数据的方式更为统一,并且组织的方式更好,它的设计从 proc 中吸取了很多教训。本文就 sysfs 的挂载点 /sys 目录结构、其与 Linux 统一设备模型的关系、常见属性文件的用法等方面对 sysfs 作入门介绍,并且就内核编程方面,以具体的例子来展示如何添加 sysfs 支持。
/proc/scsi/scsi,它是可读可写的,(其文件权限被错误地标记为了 0444 !,这是内核的一个BUG),并且读写格式不一样,代表不同的操作,应用程序中读到了这个文件的内容一般还需要进行字符串解析,而在写入时需要先用字符串格式化按指定的格式写入字符串进行操作;相比而言, sysfs 的设计原则是一个属性文件只做一件事情, sysfs 属性文件一般只有一个值,直接读取或写入。整个 /proc/scsi目录在2.6内核中已被标记为过时(LEGACY),它的功能已经被相应的 /sys 属性文件所完全取代。新设计的内核机制应该尽量使用 sysfs 机制,而将 proc 保留给纯净的“进程文件系统”。
清单 1. 与 /sys 文件系统的一次交互(视内核版本号和外接设备的不同,在您的系统上执行这些命令的结果可能与此有所不同)
/sys/devices下是所有设备的真实对象,包括如视频卡和以太网卡等真实的设备,也包括 ACPI 等不那么显而易见的真实设备、还有 tty, bonding 等纯粹虚拟的设备;在其它目录如 class, bus 等中则在分类的目录中含有大量对 devices 中真实对象引用的符号链接文件; 清单1 中在 /sys 根目录下顶层目录的意义如下: 表 1. /sys 下的目录结构
清单 2. 查看 /sys/devices/ 的目录结构
清单 3. 查看 /sys/devices/pci0000:00/ 的目录结构
清单 4. 查看 /sys/devices/pci0000:00/ 的目录结构
图 1. sysfs 目录层次图 其中涉及到 ksets, kobjects, attrs 等很多术语,这就不得不提到 Linux 统一设备模型。
表 2. Linux 统一设备模型的基本结构
kset: 它用来对同类型对象提供一个包装集合,在内核数据结构上它也是由内嵌一个 kboject 实现,因而它同时也是一个 kobject (面向对象 OOP 概念中的继承关系) ,具有 kobject 的全部功能;
涉及到文件系统实现来说, sysfs 是一种基于 ramfs 实现的内存文件系统,与其它同样以 ramfs 实现的内存文件系统(configfs,debugfs,tmpfs,...)类似, sysfs 也是直接以 VFS 中的 struct inode 和 struct dentry 等 VFS 层次的结构体直接实现文件系统中的各种对象;同时在每个文件系统的私有数据 (如 dentry->d_fsdata 等位置) 上,使用了称为 struct sysfs_dirent的结构用于表示 /sys 中的每一个目录项。
在部分 kset 下有二级或更深层次的 kset; 每个 kset 目录下再包含着一个或多个 kobject,这表示一个集合所包含的 kobject 结构体; 在 kobject 下有属性(attrs)文件和属性组(attr_group),属性组就是组织属性的一个目录,它们一起向用户层提供了表示和操作这个 kobject 的属性特征的接口; 在 kobject 下还有一些符号链接文件,指向其它的 kobject,这些符号链接文件用于组织上面所说的 device, driver, bus_type, class, module 之间的关系; 不同类型如设备类型的、设备驱动类型的 kobject 都有不同的属性,不同驱动程序支持的 sysfs 接口也有不同的属性文件;而相同类型的设备上有很多相同的属性文件; 注意,此表内容是按照最新开发中的 2.6.28 内核的更新组织的,在附录资源如 LDD3 等位置中有提到 sysfs 中曾有一种管理对象称为 subsys (子系统对象),在最新的内核中经过重构认为它是不需要的,它的功能完全可以由 kset 代替,也就是说 sysfs 中只需要一种管理结构是 kset,一种代表具体对象的结构是 kobject,在 kobject 下再用属性文件表示这个对象所具有的属性;
使用 enable 这个可写属性可以禁用或启用这个 PCI 设备,设备的过程很直观,写入1代表启用,写入0则代表禁用; subsystem 和 driver 符号链接文件分别指向对应的 sysfs 位置;(这里缺少 driver 符号链接说明这个设备当前未使用内核级的驱动程序) resource0, resource0_wc, resource1, resource2 等是从"PCI 配置空间"解析出来的资源定义段落分别生成的,它们是 PCI 总线驱动在 PCI 设备初始化阶段加上去的,都是二进制属性,但没有实现读写接口,只支持 mmap 内存映射接口,尝试进行读写会提示 IO 错误,其中 _wc 后缀表示 "合并式写入(write combined)" ,它们用于作应用程序的内存映射,就可以访问对应的 PCI 设备上相应的内存资源段落; 有了 PCI 核心对 sysfs 的完善支持,每个设备甚至不用单独的驱动程序,如这里的 "0000:01:00.0" 不需要一个内核级的驱动程序,有了 PCI 核心对该设备的配置空间发现机制,可以自动发现它的各个不同段落的资源属性,在 Xorg 应用程序中可以直接以 "/usr/lib/xorg/modules/drivers/sis_drv.so" 这个用户空间的驱动程序对其进行映射,就可以直接操作此视频卡了;有了这一个 PCI 设备的示例可以知道,有了一个 PCI 设备的 /sys/devices/ 设备对象,去访问它的各项属性和设置属性都非常简单。使用 uevent在 sysfs 下的很多 kobject 下都有 uevent 属性,它主要用于内核与 udev (自动设备发现程序)之间的一个通信接口;从 udev 本身与内核的通信接口 netlink 协议套接字来说,它并不需要知道设备的 uevent 属性文件,但多了 uevent 这样一个接口,可用于 udevmonitor 通过内核向 udevd (udev 后台程序)发送消息,也可用于检查设备本身所支持的 netlink 消息上的环境变量,这个特性一般用于开发人员调试 udev 规则文件, udevtrigger 这个调试工具本身就是以写各设备的 uevent 属性文件实现的。这些 uevent 属性文件一般都是可写的,其中 /sys/devices/ 树下的很多 uevent 属性在较新内核下还支持可读:
对 bind 属性写入总线号码(bus_id)即是强制绑定; 注意,它要求的写入的是总线号码,对应于PCI设备的总线号码是按照 "domain(4位):bus(2位):slot(2位):function号(不限)" 的方式组织,是可以从其设备 kobject 节点上找到,而其它类型的总线有各自不同的规则;请特别注意: 在这一个例子中, "echo 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/unbind" 这第一个写入命令以 "No such device" 为错误退出,而后续的 "echo -n" 命令则可以成功。这是因为内核在对总线号码进行匹配时过于严格了,通常的 "echo" 命令写入一个字符串会以一个换行符结束输出,内核所接收到的是带有这个换行符的 bus_id 字符串,将它与内核数据结构中的真正的 bus_id 字符串相比较,当然不能找到;所幸的是,这个问题在最新的 2.6.28 开发中的内核上已已经解决,它将这个比较函数改为一个特殊实现的字符串比较,自动忽略结尾处的换行符,在 2.6.28-rc6 内核上测试,不带"-n"参数的 echo 命令已经可以写入成功。而 new_id 属性文件也可以以另一种途径解决新的设备号问题:它是一个只写的驱动属性,可用于向其中写新的设备号。它支持写入 2至7个十六进制整形参数,分别代表 vendor, device, subvendor, subdevice, class, class_mask, driver_data 最少为 2个是因为一个 PCI设备主要以厂商号(vendor)和设备号(device)所唯一标定,其它 5个参数如果不输入则缺省值为 PCI_ANY_ID(0xffff)。
其它一些可读属性用于读取这个 SCSI 控制器的一些当前值; 其中的 scan 属性文件在调试一些 SCSI 硬件驱动时很有用,它是只写的,可以写入三个至四个以空格分开的整数,用于分别指定对应的 host, channel, id, lun 进行重新搜索。且这个 scan 属性支持以"-"作为通配符,如以下命令可以执行让整个 scsi_host 进行重新搜索,这个功能用于调试某些对热挺拔实现不完善的 SCSI 驱动程序很有用:
drivers/scsi/scsi_sysfs.c中:
注册 proc 接口,接受用户的 read/write/ioctl 操作;同样的,一个 proc 项通常使用其 read/write/ioctl 接口,它所存在的问题与上面的虚拟字符设备的的问题相似; 注册 sysfs 属性; 最重要的是,添加虚拟字符设备支持和注册 proc 接口支持这两者所需要增加的代码量都并不少,最好的方法还是使用 sysfs 属性支持,一切在用户层是可见的透明,且增加的代码量是最少的,可维护性也最好;方法就是使用 <include/linux/device.h> 头文件提供的这四个宏,分别应用于总线/类别/驱动/设备四种内核数据结构对象上:
struct bin_attribute中内嵌一个 struct attribute结构体对象,因此具有普通属性的所有功能特征; 二进制属性上多一个 size 用来描述此二进制文件的大小,而普通属性文件的大小总是 4096, 准确地说,应该是一个内存页的大小,因为从当前 sysfs 内核实现来说,它分配一个内存页面来作为 (buf/count) 的缓冲区; 二进制属性比普通属性多内存映射(mmap)接口的支持; 编程示例,对 LDD3 一书中的 lddbus 驱动程序的 sysfs 改进首先,这个程序本身是针对当时作者写书的年代的内核(2.6.11)而编写的,在当前的 Fedora10 系统 (2.6.27.5-117.fc10.i686) 上甚至无法编译编译通过;因此首先需要将它移植过来至少达到可运行状态;附件的压缩包中含有修改过的 lddbus, sculld 的源代码和修改过程的四个patch:第一个 0001-ldd3-examples-build-on-fedora-10-2.6.27.5-117.fc10.i.patch 是将 lddbus 和 sculld 移植到 Fedora10 内核上可运行,这其中主要是一此内核 API 的变化; 第二个 0002-port-dmem-proc-entry-to-use-sysfs-entry.patch 演示了怎样将原有的 proc 接口改进成为 sysfs 属性接口的,从这个 patch 中可以看到删除的代码多而新增加的代码少,这说明对于相同的功能,使用 sysfs 编程接口的代码量更少,而且 sysfs 代码看起来也比 proc 更为整洁:打印每个设备的调试信息可以做成每个设备上分别有自己的接口,而不是统一的一个 proc 接口;设备属性文件最终出现的位置如 "/sys/devices/ldd0/sculld0/dmem";
第四个 0004-port-qset-get-set-ioctl-to-use-sysfs-entry.patch 演示了怎样把基于 ioctl 的操作接口改进成为基于 sysfs 接口,由于原来的 ioctl 接口设置和获取 qset 信息是表示整个驱动模块级的变量,它用来控制整个驱动程序而非驱动所支持的单个的设备,因此这个 qset 属性使用 DRIVER_ATTR 来添加更为合适;
参考资料学习 “使用 /proc 文件系统来访问 Linux 内核的内容”(developerWorks 中国,2006 年 4 月)介绍了通过 /proc 来访问Linux内核的方法,包括怎样在自己编写的内核模块中,给用户提供/proc访问接口的方法。 “The Driver Model Core, Part I”(LinuxJournal文章, June 1st, 2003 by Greg Kroah-Hartman in Software)。 “Linux设备驱动第3版”(LnuxWeeklyNews, 由Jonathan Corbet, Alessandro Rubini, 和 Greg Kroah-Hartman 共同完成于2003年)其中第14章(Chapter 14: The Linux Device Model)系统地阐述了Linux设备模型,其中包括Linux设备模型与sysfs文件系统的关系。 “Linux设备模型”(2003年 Linux Conference Australia)。 “The sysfs Filesystem, OLS'05”(2005年 Ottawa Linux Symposium),论文下载自 kernel.org。 “Sysfs, From Wikipedia”。 “kobjects and sysfs, From Linux Weekly News, 2003”。 “The zen of kobjects, From Linux Weekly News, 2003”。 请参考阅读 Linux 内核代码, Linux 设备模型代码位于 drivers/base/,而 sysfs 代码位于 fs/sysfs/。 在 developerWorks 中国网站 Linux 专区 中学习更多 Linux 方面的知识。 获得产品和技术 下载 IBM 软件试用版,体验强大的 DB2®,Lotus®,Rational®,Tivoli® 和 WebSphere® 软件。 讨论 查看 developerWorks博客的最新信息。 关于作者
|
相关文章推荐
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核:比/proc 更为理想的访问内核数据的途径
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核:比/proc 更为理想的访问内核数据的途径
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核
- 使用 /sys 文件系统访问 Linux 内核