之前https://mp.csdn.net/mdeditor/84722837#
这个博客里面介绍了关于kobject,set,ktype三个结构体之间的关系以及作用,可以做为参考,下面介绍一下这三个结构体相关的函数的使用以及作用;
static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
kobj->state_initialized = 1;
}
kobject_init_internetl函数介绍:
函数功能:
1. 初始化使用计数,使使用计数计为1;
2. 初始化链表操作
函数参数:
struct kobject * kobj,要初始化的对象;
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj) {
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype) {
err_str = "must have a ktype to be initialized properly!\n";
goto error;
}
if (kobj->state_initialized) {
/* 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->ktype = ktype;
return;
error:
printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
dump_stack();
}
kobj_init函数介绍如下:
函数参数:
struct kobject* kobj要初始化的kobject实例
struct kobj_type * ktype要初始化kobject是什么ktype,本函数中直接赋予kobj->ktype
函数功能:
1.先判断kobject->state_initialized是否已经被初始化了,如果已经被初始化,则发生一个内核的panic
2.(在kobject_init_internel中)初始化kobject实例,主要负责引用计数初始化以及kobject.entry链表初始化;然后把kobject->state_initialized置为1,表示已经被初始化了
3.把ktype指针赋予kobj->ktype;
kobject_add函数如下:
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) {
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函数介绍如下:
函数参数:
struct kobject* kboj要增加的kobject实例;
struct kobject* parent要增加的kobject的parent指针指向;
const char * fmt , va_list vargs; 要增加的kobject名字;
函数功能:
1.先判断kobj->state_initialized是否已经被初始化了,1表示已经初始化,0表示没有被初始化;
2.把const char * fmt, va_list vargs组合成一个字符串,并且把kobject->name指向这个字符串;
3.如果kobject->kset!= NULL,在kset目录下创建kobject->name文件夹;如果为空,则在/sys/目录下创建文件夹;
4.在kobject->name目录下创建kobject->ktype->default_attrs文件;
其中3.4步骤交与kobject_add_vargs和kobject_add_internel函数;
kobject_add_vargs和kobect_add_internel函数原型如下:
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
const char *fmt, va_list vargs)
{
int retval;
/**kobj->name赋予名字*/
retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
printk(KERN_ERR "kobject: can not set name properly!\n");
return retval;
}
kobj->parent = parent;//把kobj->parent赋予parent指针
return kobject_add_internal(kobj);//增加文件以及文件夹;
}
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的引用计数
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->parent = parent;
}
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)
printk(KERN_ERR "%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
printk(KERN_ERR "%s failed for %s (%d)\n",
__func__, kobject_name(kobj), error);
dump_stack();
} else
kobj->state_in_sysfs = 1;
return error;}
以上操作全是对于struct kobject函数增加到内核里面的操作,总体概括如下:
1. kobject_init可以初始化一个Kobject,主要初始化kref,entry(链表操作),state_initialized。没有对于/sys/文件夹做任何操作;
2. kobject_add主要是对于/sys/文件夹下的操作以及kobject->parent逻辑关系还有kobject->name的操作;
3. 以上操作可以总结,先使用kobject_init初始化再使用kobject_add函数增加逻辑关系(kset,parent)和向用户空间增加文件操作;
4. 第三条操作可以使用kobject_create_and_add一条增加;
对于以上操作的逆操作可以使用kobject_del函数和kobject_put共同完成,原型如下:
注意:如果只使用kobject_del函数来释放,可能会有问题,因为初始化的时候对于kobject->kref有置1操作,所有需要使用kobject_put来完成对于kobject的释放操作,这样kobject才会释放完成;
void kobject_del(struct kobject *kobj)
{
if (!kobj)
return;
/***移除文件/sys/xxxx
设置state_in_sysfs为0,
**/
sysfs_remove_dir(kobj);
kobj->state_in_sysfs = 0;
kobj_kset_leave(kobj);
kobject_put(kobj->parent);
kobj->parent = NULL;
}