一.数据结构设计
0.需要被管理的实体实际上很杂,包括设备,驱动,总线,类型,块设备,电源等等...迫切需要统一管理.
1.kobject代表每一个被管理实体,很显然的,这些实体可以带有一个或者多个属性.
2.这些属性由attribute表示,被管理的实体不同,可能还会互相嵌套,因此很难给出一个明确的attribute的定义,因此使用了list_head的设计方式,将它仅仅作为一个锚点,真实的数据存在于它附近的内存区域,通过container_of宏来得到.(之可以这么做,得益于冯诺依曼机器的连续存储)
3.另外,kobject也是一个锚点,并不携带真实数据,因此kobject和attribute之间也不便直接建立关系,而是通过kobj_type结构体解除耦合的.
4.为了将被管理实体归类,设计了kset数据结构,管理一类kobject
5.kset同时也是一个kobject,这就实现了一个组合模式.kobject的精化最终在这里体现.
二.用什么方式表现
1.kobject将所有被管理实体组织成一个树型结构,因此任意可以表示树型结构的方式都可以采用.
2.linux并不像windows导出很多操作接口(比如注册表,文件等),它基本只导出文件接口,也就是一个vfs接口,同时linux的文件系统组织是树型的,且实现了mount扩展机制,将不同类型的文件系统子树嫁接在根的任意子节点(需要是目录)上.
3.很方便为kobject实现一个文件系统,然后mount到某一处.
4.这个文件系统类型就是sysfs,一般处于/目录下的/sysfs目录中.
三.实现
1.kobject的定义:
struct kobject {
const char *name; //名称
struct list_head entry; //
struct kobject *parent; //kobject组成链表,便于查找
struct kset *kset; //此kobj所属的kset
struct kobj_type *ktype; //kobj_type解耦了kobj和attr
struct sysfs_dirent *sd; //sysfs中的组织结构
struct kref kref; //引用计数
...
};
2.kobj_type的定义:
struct kobj_type {
void (*release)(struct kobject *kobj);
struct sysfs_ops *sysfs_ops; //该kobj_type所属的kobject的所有attribute的总的store和show方法
struct attribute **default_attrs; //此type的属性们
};
3.kset的定义:
struct kset {
struct list_head list; //属于此kset的kobj们
...
struct kobject kobj; //kset本身也是一个kobject,实现一个类别
struct kset_uevent_ops *uevent_ops; //实现向用户态的通知机制
};
4.真实attribute的定义:
struct edac_pci_dev_attribute {
struct attribute attr; //所属的attribute结构锚点
void *value; //真实的,单独的attribute的值
ssize_t(*show) (void *, char *); //真实的,单独的attribute的show
ssize_t(*store) (void *, const char *, size_t);//真实的,单独的attribute的store
};
5.每一个kobject在sysfs中都实现为一个目录,kobject是树型的,该树和sysfs中的目录树真切地对应.
6.一个kobject的每一个attribute在sysfs中都实现为该kobject对应目录下的一个文件,所有的attribute统一由该kobject的kobj_type管理.
7.sysfs文件系统中每一个文件代表它所属目录的kobject的一个属性,拥有读/写方法,即show/store.
8.所有处于同一目录下的attribute的show/store统一由该目录所属kobject的kobj_type的show/store来分发,比如对于/sys/devices目录:
8.1.在注册一个顶层设备(比如总线等)时,均会将该device结构体的kobj的ktype初始化为device_ktype:
static struct kobj_type device_ktype = {
.releas |