Linux 内核用 kobject 来表示一个内核对象,它在源码中的定义为:
struct kobject {
// 用来表示该内核对象的名称。如果该内核对象加入系统,那么它的 name 将会出现在
// sysfs 文件系统中(表现形式是一个新的目录名)
const char *name;
struct list_head entry; // 用来将一系列的内核对象构成链表
// 指向该内核对象的上层节点。通过引入该成员构建内核对象之间的层次化关系
struct kobject *parent;
// 当前内核对象所属的 kset 对象的指针。 kset 对象代表一个 subsystem,其中容纳了一系
// 列同类型的 kobject 对象
struct kset *kset;
// 定义了该内核对象的一组 sysfs 文件系统相关的操作函数和属性
// 内核通过 ktype 成员将 kobject 对象的 sysfs 文件操作与其属性文件关联起来
struct kobj_type *ktype;
// 用来表示该内核对象在 sysfs 文件系统中对应的目录项的实例
struct kernfs_node *sd; /* sysfs directory entry */
// 其核心数据是一原子型变量,用来表示内核对象的引用计数。
// 内核通过该成员追踪内核对象的生命周期
struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
unsigned int state_initialized:1; // 表示该 kobject 所代表的内核对象初始化的状态
unsigned int state_in_sysfs:1; // 表示该 kobject 所代表的内核对象有没有在 sysfs 文件中建立一个入口点
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
// 如果该 kobject 对象隶属于某一 kset, 那么它的状态变化可以导致其所在的 kset 对象向
// 用户空间发送 event 消息。成员 uevent_suppress 用来表示当该 kobject 状态发生变化时,是
// 否让其所在的 kset 向用户空间发送 event 消息。
unsigned int uevent_suppress:1;
};
kobject 对象上的一些常用的操作函数:
kobject_set_name
看着复杂,其实就是赋值kobject->name
// 为一个kobject设置名字
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
{
va_list vargs;
int retval;
va_start(vargs, fmt);
retval = kobject_set_name_vargs(kobj, fmt, vargs);
va_end(vargs);
return retval;
}
kobject_init
初始化一个内核对象的 kobject 结构
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
...
kobject_init_internal(kobj);
kobj->ktype = ktype; // 设置ktype
return;
}
// 真正的初始化工作发生在 kobject_init_internal 中
static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref); // 将 kobject 的引用计数 refcount 初始化为 1
INIT_LIST_HEAD(&kobj->entry);
kobj->state_in_sysfs = 0; // 表示该内核对象尚未出现在 sysfs 文件树中
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
kobj->state_initialized = 1; // 置为 1 表示该内核对象已被初始化
}
kobject_add
主要功能有两个,一是建立 kobject 对象间的层次关系,二是在 sysfs 文件系统中建立一个目录。
int kobject_add(struct kobject *kobj, struct kobject *parent,
const char *fmt, ...)
{
va_list args;
int retval;
...
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);
va_end(args);
return retval;
}
在kobject_add_varg函数中调用kobject_add_internal完成目录创建:
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
if (!kobj->name || !kobj->name[0]) {
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!\n", kobj);
return -EINVAL;
}
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj); // 将 kobj 加入到所属 kset 链表的末尾
// 把该 kobj->parent 或者 kset 中的 kobject 成员作为 kobj 的 parent
kobj->parent = parent;
}
// 在 kobj 没有所属的 kset 的情况下
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
// 在 sysfs 文件系统中为指定的 kobject 创建一个目录,并对其进行初始化和配置
error = create_dir(kobj);
if (error) {
...
} else
kobj->state_in_sysfs = 1;
return error;
}
kobject_create
分配并初始化一个 kobject 对象,这里会传入默认的ktype对象dynamic_kobj_ktype
struct kobject *kobject_create(void)
{
struct kobject *kobj;
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
if (!kobj)
return NULL;
kobject_init(kobj, &dynamic_kobj_ktype);
return kobj;
}
为一个 kobject 对象创建一个属性文件使用的函数为 sysfs_create_file
static inline int __must_check sysfs_create_file(struct kobject *kobj,
const struct attribute *attr)
{
return sysfs_create_file_ns(kobj, attr, NULL);
}
int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
const void *ns)
{
BUG_ON(!kobj || !kobj->sd || !attr);
return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, ns);
}
在内核中 struct kobj_type的定义为:
struct kobj_type {
void (*release)(struct kobject *kobj);
// 定义了一组针对 struct attribute 对象的操作函数的集合
const struct sysfs_ops *sysfs_ops;
// kobject 内核对象定义的属性成员
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};
成员 sysfs_ops 是一 struct sysfs_ops 类型的指针, struct sysfs_ops 和struct attribute的定义为:
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
struct attribute {
const char *name;
umode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
bool ignore_lockdep:1;
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};