Linux设备模型之kobject
每个在内核中注册的kobject都对应于sysfs文件系统中的一个目录。所以要了解sysfs接口必须了解kobject。
随着Linux内核的发展壮大,其支持的设备也越来越多,但一直没有一个很好的方法来管理慢慢增多的设备驱动。为了能够在内核中提供统一的机制来对设备进行分类,同时在更高的功能层面上描述这些设备,并使得这些设备对用户空间可见。从2.6开始,Linux内核引入一个新的设备模型来对系统结构做一般性的抽象描述,可以用于支持不同的任务需求,并提供了用户空间访问的接口。
对于驱动程序的作者来说,一般是不需要深入了解Linux设备模型的细节,而只需要理解设备模型的基本架构,懂得怎么使用设备模型提供的接口即可。因为Linux设备模型的代码已经处理了大部分模型相关的内容,并且目前看来,处理的还不错。但是,整体来说,理解Linux设备模型的内在实现原理对于学习内核驱动程序或者自己实现驱动程序大有好处,它可以让你对整体的把握,从一个宏观的角度来看问题。
本文主要介绍Linux设备模型中的基础数据结构kobject
kobject简介
kobject是Linux设备模型的基础结构,其地位类似于面向对象中的基类,通过派生出其他的类来丰富Linux设备模型的结构,如device、kset等。具体方法就是将kobject结构嵌入到上层的数据结构中,这样如果使用了该上层结构,只要访问kboject成员就可以获得kboject结构。同样,若知道kobject结构的指针,可以通过container_of宏来找回包含该kobject的结构。
目前为止,Kobject主要提供如下功能:
(1)通过parent指针,可以将所有Kobject以层次结构的形式组合起来。
(2)使用一个引用计数(reference count),来记录Kobject被引用的次数,并在引用次数变为0时把它释放(这是Kobject诞生时的唯一功能)。
(3)和sysfs虚拟文件系统配合,将每一个Kobject及其特性,以文件的形式,开放到用户空间(有关sysfs)。
注1:在Linux中,Kobject几乎不会单独存在。它的主要功能,就是内嵌在一个大型的数据结构中,为这个数据结构提供一些底层的功能实现。
注2:Linux driver开发者,很少会直接使用Kobject以及它提供的接口,而是使用构建在Kobject之上的设备模型接口。
至于kset,其实可以看成是kobject的集合,它也可以当成kobject来使用,下面来看看这两个结构体的内容:
struct kset {
/*链表,记录所有连入这个kset的kobject*/
struct list_head list;
/*kset要在文件系统中生成一个目录,同样需要包含一个kobj结构体,以插入内核树中*/
struct kobject kobj;
...
} __randomize_layout;
struct kobject {
const char *name;
/*当前kobj的父节点,在文件系统中的表现就是父目录*/
struct kobject *parent;
/*kobj属于的kset*/
struct kset *kset;
/*kobj的类型描述,最主要的是其中的属性描述,包含其读写方式*/
struct kobj_type *ktype;
/*当前kobj的引用,只有当引用为0时才能被删除*/
struct kref kref;
...
};
虽然linux基于C语言开发,但是其面向对象的思想无处不在,同时我们可以将kobject结构体看成是一个基类,提供基础的功能,而其他更为复杂的结构继承自这个结构体,延伸出不同的属性。
如下是struct device结构嵌入kobject结构的简单例子
struct device {
…
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
…
void (*release)(struct device *dev);
};
kobject结构在sysfs中的入口是一个目录,因此添加一个kobject的动作也会导致在sysfs中新建一个对应kobject的目录,目录名是kobject.name。该入口目录位于kobject的parent指针的目录当中,若parent指针为空,则将parent设置为该kobject中的kset对应的kobject(&kobj->kset->kobj)。如果parent指针和kset都是NULL,此时sysfs的入口目录将会在顶层目录下(/sys)被创建,不过不建议这么做。
kobject初始化
按照LDD3-ch14的建议,需要对kobject做清零初始化,然后再使用,否则可能会出现一些奇怪的错误,通常使用memset实现。
kobject常用的操作函数如下:
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...)
struct kobject *kobject_create(void)
struct kobject *kobject_create_and_add(const char *name, struct kobject *paren