Linux设备驱动模型体系十分庞大,在不涉及细节的情况下建立顶层图景比较困难,我们采用自底向上的分析方法,首先分析关键的数据结构,然后再建立关键数据结构的关系。
在阅读Linux内核源代码时(不仅仅对linux源码适用),通过核心数据结构,即可理解某个模块大部分逻辑,使用面向对象思想的设备模型部分尤为明显。这种思维方法值得刻意地锻炼。(以下内容参考http://www.wowotech.NET/sort/device_model,加入自己的理解并针对4.1内核修改)
LDDM的底层实现:kobject,kset和kobj_type
Linux设备模型的核心是使用Bus、Class、Device、Driver四个核心数据结构,将大量的、不同功能的硬件设备(以及驱动该硬件设备的方法),以树状结构的形式,进行归纳、抽象,从而方便kernel的统一管理。
而硬件设备的数量、种类是非常多的,这就决定了kernel中将会有大量的有关设备模型的数据结构。这些数据结构一定有一些共同的功能,需要抽象出来统一实现,否则就会不可避免的产生冗余代码。这就是kobject诞生的背景。
通过上面的描述,如果用面向对象的设计方法类比的话,kobjet实际上是整个LDDM的基类!!!。
就好比java的object类是所有类的基类,你在写java的时候基本不会用到object类,而是用它派生出的类。同样,kobject在Linux中,kobject几乎不会单独存在。它的主要功能,就是内嵌在一个大型的数据结构中(类似继承),为这个数据结构提供一些底层的功能实现。Linux driver开发者,很少会直接使用kobject以及它提供的接口,而是使用构建在kobject之上的设备模型接口。
kobject是基本数据类型,每个kobject都会在"/sys/“文件系统中以目录的形式出现。
kobj_type代表kobject(严格地讲,是包含了kobject的数据结构)的属性操作集合(由于通用性,多个kobject可能共用同一个属性操作集,因此把ktype独立出来了)。
kset是一个特殊的kobject(因此它也会在"/sys/“文件系统中以目录的形式出现),它用来集合相似的kobject(这些kobject可以是相同属性的,也可以不同属性的)。
kobject
name,该kobject的名称,同时也是sysfs中的目录名称。
entry,用于将kobject加入到kset中的list_head。
parent,指向parent kobject,以此形成层次结构(在sysfs就表现为目录结构)。
kset,该kobject属于的kset。可以为NULL。如果存在,且没有指定parent,则会把kset作为parent。
ktype,该kobject属于的kobj_type。每个kobject必须有一个ktype,否则kernel会提示错误。
sd,该kobject在sysfs中的表示。
kref,为一个可用于原子操作的引用计数。
state_initialized,指示该kobject是否已经初始化,以在kobject的init,put,add等操作时进行异常校验。
state_in_sysfs,指示该kobject是否已在sysfs中呈现,以便在自动注销时从sysfs中移除。
state_add_uevent_sent/state_remove_uevent_sent,记录是否已经向用户空间发送ADD uevent,如果有,且没有发送remove uevent,则在自动注销时,补发REMOVE uevent,以便让用户空间正确处理。
uevent_suppress,如果该字段为1,则表示忽略所有上报的uevent事件。
kset
list/list_lock,用于保存该kset下所有的kobject的链表。
kobj,该kset自己的kobject(kset是一个特殊的kobject,也会在sysfs中以目录的形式体现)。
uevent_ops,该kset的uevent操作函数集。当任何kobject需要上报uevent时,都要调用它所从属的kset的uevent_ops,添加环境变量,或者过滤event(kset可以决定哪些event可以上报)。因此,如果一个kobject不属于任何kset时,是不允许发送uevent的。
kobj_type
release,通过该回调函数,可以将包含该种类型kobject的数据结构的内存空间释放掉。
sysfs_ops,该种类型的kobject的sysfs文件系统接口。
default_attrs,该种类型的kobject的atrribute列表(所谓attribute,就是sysfs文件系统中的一个文件)。将会在kobject添加到内核时,一并注册到sysfs中。
child_ns_type/namespace,和文件系统(sysfs)的命名空间有关,这里不再详细说明。
kobject、kset和kobj_type的关系
kset是kobject的容器,kobject和kobj_type是组合关系。
LDDM层次结构在底层的实现及与sysfs的联系
内核使用kobject族将各个对象连接起来组成一个分层的体系结构,也就是LDDM的分层体系结构。由于程序员很少直接操作kobject族,而是通过将kobject嵌入到数据结构中发挥作用,所以,更准确的说是更高层的数据结构(bus_type,device,device_driver,class等)通过kobject族形成LDDM所设计的层次结构。如下图所示:
前面讲过,sysfs展示设备驱动模型个组件的层次关系,所以,sysfs的层次结构和kobject族的层次关系是一一对应的,或者说kobject族是sysfs的底层实现。kobjcet族与sysfs的对应关系如下表所示:
kobject族或其成员 | sysfs对应表现形式 |
kset | sysfs中的一个目录(一定出现在sysfs中) |
kobject | sysfs中的一个目录(不一定出现在sysfs中,kset的kobject链表中的kobject一定出现在sysfs中) |
kobject.name | sysfs中的目录名 |
kobj_type.defauts_attr | sysfs中的一个文件 |
kobj_type.defauts_attr.name | sysfs中的文件名 |
通过上述图和表可以推测出sysfs的底层表现形式,例如:
/sys/bus对应kset
/sys/bus下的子目录,如ac97,是有代表/sys/bus的kset中的链表链接起来的kobject
/sys/bus/ac97还包含子目录,如ac97包含子目录devices,上述kobject又被包含在代表本级目录的kset中,形成了子目录结构。
用kobject族核心类表示这个关系,如下图所示: