Kernel 设备模型基础框架kobject
Linux设备模型的基础框架是基于 kobject, kset 和 kobj_type 三个基础数据结构实现的。这篇主要分析这三个基础数据结构的作用,以及相互之间的关系。
1,kobject:
struct kobject {
const char *name; // 该kobject的名字,用于 sysfs 文件系统下的文件夹名字
struct list_head entry; // 同类型 kobject 链表节点
struct kobject *parent; // 指向父节点 kset 的 kobject
struct kset *kset; // 同类型kobject的集合
struct kobj_type *ktype; // kobject的属性操作方法,以及 release 方法
struct kernfs_node *sd; /* sysfs directory entry */ // 该 kobject 在sysfs文件系统下的节点
struct kref kref; // 引用计数
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
kobject 是最基础的数据结构,从上述字段定义中,可以看出这个结构包含如下功能:
(1)引用计数功能。一个kobject可能代表一个总线,设备或驱动等,这些实例在内核空间可能会被多个调度实体或对象指针引用,因此用一个引用计数结构 kref 来记录当前有多少对象引用该 kobject,当 kref 的引用计数减为0时,内核接口自动调用用户指定的release接口销毁该kobject对象。kref 数据结构的本质就是一个atomic类型的对象,内核提供了 kref_get() 和 kref_put() 两个接口用于对引用计数自增和自减:
struct kref {
refcount_t refcount;
};
typedef struct refcount_struct {
atomic_t refs; // 本质上就是一个 atomic 类型的字段
} refcount_t;
接口:
static inline void kref_get(struct kref *kref)
{
refcount_inc(&kref->refcount); // kref 自增
}
static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
{
if (refcount_dec_and_test(&kref->refcount)) { // kref 自减
release(kref); // 如果减完之后为0,释放该 kref 对象
return 1;
}
return 0;
}
(2)链表组织结构功能。多个kobject对象链接在一个kset下,形成一个循环双向链表。字段entry是双向链表节点,kset指向该kobject所属的kset,parent一般指向kset中的kobject。
(3)sysfs接口。一个kobject表示sysfs文件系统中的一个目录,方便用户在用户态访问内核态数据结构。字段sd表示该kobject在sysfs中的入口项,name表示kobject表示的目录名称,ktype表示该目录的操作接口,包含kobject对象的release接口,以及该目录下属性文件的读写接口。
2,kset:
struct kset {
struct list_head list; // 用于连接该kset下所有kobject的链表节点
spinlock_t list_lock;
struct kobject kobj; // 一个kset本质上也是一个 kobject
const struct kset_uevent_ops *uevent_ops; // 内核事件上报用户态接口,一般用于驱动的热插拔事件上报
} __randomize_layout;
一个kset表示所有同类型的kobject的集合。kset内部通过包含一个kobject,用来同其下挂的所有kobject组成一个双向循环链表。同时其下挂的所有kobject的parent都指向kset中包含的这个kobject。uevent_ops是内核事件上报用户态机制,多用于设备和驱动的热插拔事件上报。
3,kobj_type:
struct kobj_type {
void (*release)(struct kobject *kobj); // 同类型kobject对象的释放接口
const struct sysfs_ops *sysfs_ops; // kobject属性文件的读写接口
struct attribute **default_attrs; // kobject的属性
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};
一个kobj_type主要用来定义kobject的属性文件的读写接口,以及kobject对象的释放操作。
2,通过上述分析,我们可以画出 kobject,kset 和 kobj_type之间的关系:
3,总结一下:kobject/kset通常用于其他对象结构的内置结构,如设备和驱动数据结构通常都包含一个kobject结构,实现引用计数,设备层次结构和sysfs操作等。
转载于:https://my.oschina.net/yepanl/blog/3051355