2021.07.25 技術シェア
【技术浅谈】Linux设备模型(上)

简介


Linux设备模型是指Linux系统中设备、总线、驱动的系统结构抽象,它的意义在于为了系统地管理所有设备。


整个linux的设备模型是一个面向对象(Object Oriented)的体系结构。由于在linux底层是用面向过程的C语言实现,所以在linux中定义了kobject结构,使其嵌入到对象结构中来实现继承的效果,这个kobject属于最基础的结构,它在作用上相当于面向对象中的基类,由多个kobject对象组成的集合便成为了kset,也可以说是对象的容器。任何一个设备模型如总线,设备,驱动都属于一个kobject 。


kobjects与ksets实现层次树的底层骨架,进一步地,通过封装这些底层结构来实现上层的设备驱动模型。这就是我们要学习的总线、设备和驱动。在linux内核中,它们对应的是bus_type、device和device_driver数据结构。所以,这些数据结构如何联系及工作是我们学习的重点。


设备模型的简易架构图如下:


图片


 

学习步骤


⑴学习底层数据结构:kobject、kset


⑵学习linux设备模型层次关系:bus_type、device、device_driver


⑶简单实例分析:设备驱动注册源码的简单分析


⑷应用分析:面向对象的思想在linux设备模型中的应用分析


 

内核对象机制―关键数据结构

sysfs文件系统


sysfs文件系统是一个类似于proc文件系统的特殊文件系统,用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息。其顶层目录主要有:


⑴block目录:包含所有的块设备
⑵devices目录:包含系统所有的设备,并根据设备挂接的总线类型组织层次结构


⑶bus目录:包含系统中所有的总线类型
⑷drivers目录:包括内核中所有已注册的设备驱动程序
⑸class目录:系统中的设备类型(如网卡设备,声卡设备等)


 

kobject浅析


kobject是Linux 2.6引入的新的设备管理机制,在内核中由struct kobject表示。通过这个数据结构使所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux 2.6设备模型的核心结构,它与sysfs文件系统紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。


kobject结构定义为:


struct kobject {
char * k_name;    //指向设备名称的指针
char name[KOBJ_NAME_LEN];    //设备名称
struct kref kref;    //对象引用计数
struct list_head entry;    //挂接到所在kset中去的单元
struct kobject * parent;    //指向父对象的指针
struct kset * kset;    //所属kset的指针
struct kobj_type * ktype;    //指向其对象类型描述符的指针
struct dentry * dentry; 


//sysfs文件系统中与该对象对应的文件节点路径指针
};


其中的kref域表示该对象引用的计数,内核通过kref实现对象引用计数管理,内核提供两个函数kobject_get()、kobject_put()分别用于增加和减少引用计数,当引用计数为0时,所有该对象使用的资源将被释放。ktype域是一个指向kobj_type结构的指针,表示该对象的类型。


 

kset浅析


kset是具有相同类型的kobject的集合。kobject通常通过kset组织成层次化的结构。所有属于一个kset的对象(kobject)的parent都指向该kset的kobj。同时这个对象都连接到kset的list表上。同时位于kset层次之上的是subsys,在最新的内核中已经取消subsys,因为它本质上也就是一个ksets。kset有一套类似kobject的操作,实现上只是进一步调用其自身kobj的相应操作,毕竟kset本质上也是一个kobject。 


kset结构定义如下:


struct kset {
struct subsystem * subsys;    //所在的subsystem的指针
struct kobj_type * ktype;    //指向该kset对象类型描述符的指针
struct list_head list;    //用于连接该kset中所有kobject的链表头                            struct kobject kobj;    //嵌入的kobject
struct kset_hotplug_ops * hotplug_ops;   //指向热插拔操作表的指针    


};


包含在kset中的所有kobject被组织成一个双向循环链表,list域正是该链表的头。ktype域指向一个kobj_type结构,被该kset中的所有kobject共享,表示这些对象的类型。kset数据结构还内嵌了一个kobject对象(由kobj域表示),所有属于这个kset 的kobject对象的parent域均指向这个内嵌的对象。此外,kset还依赖于kobj维护引用计数:kset的引用计数实际上就是内嵌的kobject对象的引用计数。kset的简易工作原理如下:


图片


 

kobj_type浅析


最后,属于同一个集合的对象可以拥有共同的属性:ktype


struct kobj_type {


void (*release)(struct kobject *);    //释放资源


struct sysfs_ops * sysfs_ops;    //指向sysfs操作表和属性列表


struct attribute ** default_attrs;


             };


所谓的属性更具体一点说就是一些键值对。


kobj_type数据结构包含三个域:一个release方法用于释放kobject占用的资源;一个sysfs_ops指针指向sysfs操作表和一个sysfs文件系统缺省属性列表。sysfs操作表包括两个函数store()和show()。当用户态读取属性时,show()函数被调用,该函数编码指定属性值存入buffer中返回给用户态;而store()函数用于存储用户态传入的属性值。


如此 ,kobjects与ksets就实现了层次树的底层骨架。进一步地,通过封装这些底层结构来实现上层的设备驱动模型。


 

subsystem子系统


subsystem是一系列kset的集合,描述系统中某一类设备子系统,如block_subsys表示所有的块设备,对应于sysfs文件系统中的block目录。类似的,devices_subsys对应于sysfs中的devices目录,描述系统中所有的设备。subsystem由struct subsystem数据结构描述,定义为:
struct subsystem {
struct kset kset;    //内嵌的kset对象
struct rw_semaphore rwsem;    //互斥访问信号量


};


每个kset必须属于某个subsystem,通过设置kset结构中的subsys域指向指定      的subsystem可以将一个kset加入到该subsystem中。所有挂接到同一subsystem的 kset共享同一个rwsem信号量,用于同步访问kset中的链表。


本次先给大家简单介绍了内核对象机制与关键数据结构,下节课将为大家介绍常用函数api。


 


图片