概述
一. kobject介绍
kobject结构首先是在2.5.45内核版本引入的,开始设计的目的是用于管理对象的引用计数,
现在主要用来关联设备模型和设备模型的sysfs接口。因为kobject通常隐藏在更高层的结构体中,
开发驱动的人员很少直接接触kobject,但是理解了kobject,对于设备模型的框架理解是非常有帮助的。本文使用的内核是3.18.45。
二. kobject相关结构体介绍
1. kobject介绍
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct kernfs_node *sd;
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;
};
name :kobject的名称
entry :kobject可以内组织成一个链表形式
parent :kobject是以分级结构排列的,parent指针指向该kobject的上一级的kobject
kset :表示该kobject属于哪个kset
ktype :该kobject不在被引用的处理方式,在后面介绍struct kobj_type时介绍
sd :后面研究到了再补充。
kref :kobject的引用计数。
state_initialized :kobject是否初始化了
state_add_uevent_sent,state_remove_uevent_sent :和uevent相关
2. kset介绍
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
list :表示kset可以组织成一个链表形式
list_lock :操作kset链表时的需要自旋锁保证互斥
kobject :表示kset结构体中包含kobject结构
uevent_ops :表示kset的uevent的处理函数
3. ktype介绍
struct kobj_type {
void (*release)(struct kobject *kobj);
const struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};
release :表示kobject不再引用时,调用的释放资源的函数
sysfs_ops : 表示kobject在sysfs虚拟文件系统中的操作函数
default_attrs :后面研究到了再补充
kobj_ns_type_operations :后面研究到了再补充。namespace :后面研究到了再补充
总结:
1. kobject有一个name和kref字段,并且有一个父指针,用于kobject分级结构管理。
2. ktype用于当kobject的kref为0时,对kobject的处理方式。
3. kset字面意思是kobject的组合,list用于将一组kobject形成链表,便于管理。
kobject的结构图大致如下:
三. kset相关函数介绍
1. kset_create_and_add函数
static struct kset *kset_create(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int retval;
kset = kzalloc(sizeof(*kset), GFP_KERNEL); /* 创建内存空间,存储kset结构 */
if (!kset)
return NULL;
retval = kobject_set_name(&kset->kobj, "%s", name); /* 设置kset->kobj的name */
if (retval) {
kfree(kset);
return NULL;
}
kset->uevent_ops = uevent_ops; /* 设置uevent处理函数 */
kset->kobj.parent = parent_kobj; /* 指定kset->kobj的父kobj */
/*
* The kobject of this kset will have a type of kset_ktype and belong to
* no kset itself. That way we can properly free it when it is
* finished being used.
*/
kset->kobj.ktype = &kset_ktype; /* 设置ktype */
kset->kobj.kset = NULL; /* 指定kobj属于哪个kset,这里是NULL */
return kset;
}
static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref); /* kobj->kref初始化为1 */
INIT_LIST_HEAD(&kobj->entry); /* 初始化kobj->entry链表 */
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
kobj->state_initialized = 1; /* kobj的状态已初始化的标识 */
}
void kset_init(struct kset *k)
{
kobject_init_internal(&k->kobj);
INIT_LIST_HEAD(&k->list); /* 初始化kset的链表 */
spin_lock_init(&k->list_lock); /* 初始化链表自旋锁 */
}
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); /* kobj创建,则kobj的父kobj的kref要加1 */
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) { /* 判断kobj是否属于某个kset */
if (!parent) /* 如果kobj没有父kobj */
parent = kobject_get(&kobj->kset->kobj); /* kobj指向的kset的kobj作为父kobj,并且kref加1 */
kobj_kset_join(kobj);
kobj->parent = parent; /* kobj指向的kset的kobj作为kobj的父kobj */
}
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>");
error = create_dir(kobj);
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
/* be noisy on error issues */
if (error == -EEXIST)
WARN(1, "%s failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory.n",
__func__, kobject_name(kobj));
else
WARN(1, "%s failed for %s (error: %d parent: %s)n",
__func__, kobject_name(kobj), error,
parent ? kobject_name(parent) : "'none'");
} else
kobj->state_in_sysfs = 1;
return error;
}
int kset_register(struct kset *k)
{
int err;
if (!k)
return -EINVAL;
kset_init(k);
err = kobject_add_internal(&k->kobj);
if (err)
return err;
kobject_uevent(&k->kobj, KOBJ_ADD); /* kset->kobj注册会产生一个KOBJ_ADD的uevent事件 */
return 0;
}
struct kset *kset_create_and_add(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int error;
kset = kset_create(name, uevent_ops, parent_kobj); /* */
if (!kset)
return NULL;
error = kset_register(kset);
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
kset_create_and_add函数主要用来创建一个kset结构并且初始化结构体的参数,并关联到它的父结构体中。大致示意图如下
这里强调一些kobject_add_internal函数的作用,它用于将创建的kset的kobj与其指向的kset建立关联,如果创建的kset的kobj没有父kobj,但是指向一个kset,则将创建的kset的kobj加入到指向的kset的链表中,并且将指向的kset的kobj作为父kobj。示意图如下:
2. kset_release函数
static void kset_release(struct kobject *kobj)
{
struct kset *kset = container_of(kobj, struct kset, kobj);
pr_debug("kobject: '%s' (%p): %sn",
kobject_name(kobj), kobj, __func__);
kfree(kset);
}
使用container_of函数,可以通过kobj定位到它所在的kset,使用free函数回收kset的内存空间。
四. kobject相关函数介绍
1. kobject_init函数
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj) { /* 判断kobj是否为NULL */
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype) { /* 判断ktype是否为NULL */
err_str = "must have a ktype to be initialized properly!n";
goto error;
}
if (kobj->state_initialized) { /* 判断kobj是否被初始化过 */
/* do not error out as sometimes we can recover */
printk(KERN_ERR "kobject (%p): tried to init an initialized "
"object, something is seriously wrong.n", kobj);
dump_stack();
}
kobject_init_internal(kobj); /* 初始化kobj结构体,介绍kset时解析过 */
kobj->ktype = ktype;
return;
error:
printk(KERN_ERR "kobject (%p): %sn", kobj, err_str);
dump_stack();
}
kobject_init函数是对kobj指针指向的kobj结构成员进行初始化。
2. kobject_add函数
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
va_list vargs)
{
const char *old_name = kobj->name; /* 备份kobj的name */
char *s;
if (kobj->name && !fmt) /* kobj的name存在,fmt不合法时,直接返回 */
return 0;
kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs); /* 更新kobj的name */
if (!kobj->name) {
kobj->name = old_name;
return -ENOMEM;
}
/* ewww... some of these buggers have '/' in the name ... */
while ((s = strchr(kobj->name, '/'))) /* xx/yy ->xx!yy */
s[0] = '!';
kfree(old_name);
return 0;
}
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
const char *fmt, va_list vargs)
{
int retval;
retval = kobject_set_name_vargs(kobj, fmt, vargs); /* 设置kobj的name */
if (retval) {
printk(KERN_ERR "kobject: can not set name properly!n");
return retval;
}
kobj->parent = parent;
return kobject_add_internal(kobj);
}
int kobject_add(struct kobject *kobj, struct kobject *parent,
const char *fmt, ...)
{
va_list args;
int retval;
if (!kobj)
return -EINVAL;
if (!kobj->state_initialized) { /* kobject_add前需先初始化 */
printk(KERN_ERR "kobject '%s' (%p): tried to add an "
"uninitialized object, something is seriously wrong.n",
kobject_name(kobj), kobj);
dump_stack();
return -EINVAL;
}
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);
va_end(args);
return retval;
}
kobject_add主要是将kobj关联到其父kobj中,详细细节参考kset的介绍,区别在于kobj是否指向某一个kset。
3. kobject_get
struct kobject *kobject_get(struct kobject *kobj)
{
if (kobj)
kref_get(&kobj->kref);
return kobj;
}
kobject_get作用是将kobj的kref加1。
4. kobject_cleanup
static void kobject_cleanup(struct kobject *kobj)
{
struct kobj_type *t = get_ktype(kobj);
const char *name = kobj->name;
pr_debug("kobject: '%s' (%p): %s, parent %pn",
kobject_name(kobj), kobj, __func__, kobj->parent);
if (t && !t->release)
pr_debug("kobject: '%s' (%p): does not have a release() "
"function, it is broken and must be fixed.n",
kobject_name(kobj), kobj);
/* send "remove" if the caller did not do it but sent "add" */
if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
pr_debug("kobject: '%s' (%p): auto cleanup 'remove' eventn",
kobject_name(kobj), kobj);
kobject_uevent(kobj, KOBJ_REMOVE);
}
/* remove from sysfs if the caller did not do it */
if (kobj->state_in_sysfs) {
pr_debug("kobject: '%s' (%p): auto cleanup kobject_deln",
kobject_name(kobj), kobj);
kobject_del(kobj);
}
if (t && t->release) {
pr_debug("kobject: '%s' (%p): calling ktype releasen",
kobject_name(kobj), kobj);
t->release(kobj);
}
/* free name if we allocated it */
if (name) {
pr_debug("kobject: '%s': free namen", name);
kfree(name);
}
}
kobject_cleanup的作用是调用kobj的ktype中释放函数,并且发送uevent消息KOBJ_REMOVE
五. sysfs相关函数介绍
1. 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);
}
sysfs_create_file函数会在kobj->name名称的文件目录下创建文件,文件名称是attr->name。示例参考文章最后的代码举例。
2. sysfs_create_link
/**
* sysfs_create_link - create symlink between two objects.
* @kobj: object whose directory we're creating the link in.
* @target: object we're pointing to.
* @name: name of the symlink.
*/
int sysfs_create_link(struct kobject *kobj, struct kobject *target,
const char *name)
{
return sysfs_do_create_link(kobj, target, name, 1);
}
sysfs_create_link函数会在kobj->name名称的文件目录下创建一个软链接文件,文件名是第三个参数name,该文件链接到target->name的目录文件。示例参考文章最后的代码举例。
六. 总结
代码举例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>
struct kset *kobject_test_kset;
struct kset *device_kset;
struct kset *driver_kset;
struct kobject *dev1_kobj;
struct kobject *dev2_kobj;
struct kobject *drv1_kobj;
struct kobject *drv2_kobj;
struct attribute dev1_attr = {
.name = "dev1"
};
struct attribute dev2_attr = {
.name = "dev2"
};
struct attribute drv1_attr = {
.name = "drv1"
};
static int kobject_test_init(void)
{
kobject_test_kset = kset_create_and_add("kobkect_test", NULL, NULL);
device_kset = kset_create_and_add("device", NULL, &kobject_test_kset->kobj);
driver_kset = kset_create_and_add("driver", NULL, &kobject_test_kset->kobj);
dev1_kobj = kobject_create_and_add("dev1", &device_kset->kobj);
dev2_kobj = kobject_create_and_add("dev2", &device_kset->kobj);
drv1_kobj = kobject_create_and_add("drv1", &driver_kset->kobj);
drv2_kobj = kobject_create_and_add("drv2", &driver_kset->kobj);
sysfs_create_file(dev1_kobj, &dev1_attr);
sysfs_create_file(dev2_kobj, &dev2_attr);
sysfs_create_file(drv1_kobj, &drv1_attr);
sysfs_create_link(drv2_kobj, drv1_kobj, "drv2");
return 0;
}
void kobject_test_exit(void)
{
kobject_put(dev1_kobj);
kobject_put(dev2_kobj);
kobject_put(drv1_kobj);
kobject_put(drv2_kobj);
kset_unregister(device_kset);
kset_unregister(driver_kset);
kset_unregister(kobject_test_kset);
return;
}
代码效果:
/ # ls -l /sys/
total 0
drwxr-xr-x 2 root root 0 Jan 1 08:01 block
drwxr-xr-x 12 root root 0 Jan 1 08:01 bus
drwxr-xr-x 19 root root 0 Jan 1 08:00 class
drwxr-xr-x 4 root root 0 Jan 1 08:00 dev
drwxr-xr-x 17 root root 0 Jan 1 08:00 devices
drwxr-xr-x 3 root root 0 Jan 1 08:01 firmware
drwxr-xr-x 2 root root 0 Jan 1 08:01 fs
drwxr-xr-x 5 root root 0 Jan 1 08:01 kernel
drwxr-xr-x 4 root root 0 Jan 1 08:01 kobkect_test
drwxr-xr-x 24 root root 0 Jan 1 08:00 module
/ # ls -l /sys/kobkect_test/
total 0
drwxr-xr-x 4 root root 0 Jan 1 08:01 device
drwxr-xr-x 4 root root 0 Jan 1 08:01 driver
/ # ls -l /sys/kobkect_test/device/
total 0
drwxr-xr-x 2 root root 0 Jan 1 08:01 dev1
drwxr-xr-x 2 root root 0 Jan 1 08:01 dev2
/ # ls -l /sys/kobkect_test/device/dev1/
total 0
---------- 1 root root 4096 Jan 1 08:16 dev1
/ # ls -l /sys/kobkect_test/device/dev2/
total 0
---------- 1 root root 4096 Jan 1 08:16 dev2
/ # ls -l /sys/kobkect_test/driver/drv1/
total 0
---------- 1 root root 4096 Jan 1 08:17 drv1
/ # ls -l /sys/kobkect_test/driver/drv2/
total 0
lrwxrwxrwx 1 root root 0 Jan 1 08:17 drv2 -> ../drv1
kobject通过层级结构管理内核中的设备模型,对它的结构了解非常重要,后面会结合驱动模型一起分析
最后
以上就是顺利皮皮虾为你收集整理的设备模型管理对象kobject分析的全部内容,希望文章能够帮你解决设备模型管理对象kobject分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复