关于kref的操作函数
初始化
void
kref_init(struct
kref
*kref){atomic_set(&kref->refcount,
1); |
注意smp_mb以及smp_mb_*的目的是保证在多核SMP机器上的一致性,初始化后引用计数为1。
递增引用计数
void
kref_get(struct
kref *kref){ WARN_ON(!atomic_read(&kref->refcount)); atomic_inc(&kref->refcount); smp_mb__after_atomic_inc();} |
递减引用计数
int
kref_put(struct
kref *kref, void(*release)(structkref
*kref)){ WARN_ON(release
== NULL); WARN_ON(release
== (void(*)(structkref
*))kfree); if(atomic_dec_and_test(&kref->refcount))
{ release(kref); return1; } return0;} |
kref_put使用了回调函数机制。如果引用计数递减后为0,将调用函数release来执行一些释放操作。函数kref_sub与本函数类似,只是kref_sub中引用计数可以减小指定的值,不再局限于1。
int
kref_sub(struct
kref
*kref, unsigned intcount, void(*release)(structkref
*kref)){ WARN_ON(release
== NULL); WARN_ON(release
== (void(*)(structkref
*))kfree); if(atomic_sub_and_test((int)
count, &kref->refcount)) { release(kref); return1; } return0;} |
关于kobject的函数
初始化
-
该函数首先检测参数的有效性,然后检测该kobject是否已经初始化,然后调用函数kobject_init_internal,最后设置
voidkobject_init(structkobject *kobj,structkobj_type *ktype){char*err_str;if(!kobj) {err_str ="invalid kobject pointer!";gotoerror;}if(!ktype) {err_str ="must have a ktype to be initialized properly!\n";gotoerror;}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;//内核中经常使用goto语句进行错误处理error:printk(KERN_ERR"kobject (%p): %s\n", kobj, err_str);dump_stack();}EXPORT_SYMBOL(kobject_init);
kobj和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_internal的主要工作就是初始化引用计数,链表元素以及各种状态标识。
添加,即将kobject加入驱动模型系统中进行管理
int
kobject_add(structkobject
*kobj, structkobject
*parent, constchar*fmt,
...){ va_listargs; intretval; 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); returnretval;}EXPORT_SYMBOL(kobject_add); |
该函数也仅是进行了参数验证之后,就调用函数kobject_add_varg执行真正的具体工作。
staticintkobject_add_varg(structkobject
*kobj, structkobject
*parent, constchar*fmt,
va_listvargs){ intretval; retval
= kobject_set_name_vargs(kobj, fmt, vargs); if(retval)
{ printk(KERN_ERR"kobject:
can not set name properly!\n"); returnretval; } kobj->parent
= parent; returnkobject_add_internal(kobj);} |
这个函数先是设置了kobject的名字,最后建立kobj及其父节点之间的映射关系。
intkobject_set_name_vargs(structkobject
*kobj, constchar*fmt, va_listvargs){ constchar*old_name
= kobj->name; char*s; if(kobj->name
&& !fmt) return0; kobj->name
= kvasprintf(GFP_KERNEL, fmt, vargs); if(!kobj->name) return-ENOMEM; /*
ewww... some of these buggers have '/' in the name ... */ /*
因为kobject如果通过sysfs导出到用户空间都对应一个目录,所以名称中不能包含‘/’字符 */ while((s
= strchr(kobj->name,'/'))) s[0]
= '!'; kfree(old_name); return0;} |
删除,即从驱动设备模型系统中去掉本kobject。
voidkobject_del(structkobject
*kobj){ if(!kobj) return; sysfs_remove_dir(kobj); kobj->state_in_sysfs
= 0; kobj_kset_leave(kobj); kobject_put(kobj->parent); kobj->parent
= NULL;} |
该函数首先从sysfs中去掉响应的目录项,然后从所属kset中去掉本kobject,并修改父节点引用计数。
staticvoidkobj_kset_leave(structkobject
*kobj){ if(!kobj->kset) return; spin_lock(&kobj->kset->list_lock); list_del_init(&kobj->entry); spin_unlock(&kobj->kset->list_lock); kset_put(kobj->kset);} |
在本函数中,将本kobject从kset的链表中摘下,调用kset_put函数(下面会有介绍)。
函数kobject_get用于递增kobject引用计数。
structkobject
*kobject_get(structkobject
*kobj){ if(kobj) kref_get(&kobj->kref); returnkobj;} |
对应的,函数kobject_put用于递增kobject引用计数,如果kobject引用计数为0,则调用kobject_release。
voidkobject_put(structkobject
*kobj){if(kobj)
{if(!kobj->state_initialized)WARN(1,
KERN_WARNING "kobject:
'%s' (%p): is not ""initialized,
yet kobject_put() is being ""called.\n",
kobject_name(kobj), kobj);kref_put(&kobj->kref,
kobject_release);}} |
以下函数用于删除时的清理工作。
staticvoid
kobject_release(structkref
*kref){ kobject_cleanup(container_of(kref,structkobject,
kref));}staticvoidkobject_cleanup(structkobject
*kobj){ structkobj_type
*t = get_ktype(kobj); constchar*name
= kobj->name; pr_debug("kobject:
'%s' (%p): %s\n", kobject_name(kobj),
kobj, __func__); 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' event\n", 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_del\n", kobject_name(kobj),
kobj); kobject_del(kobj); } if(t
&& t->release) { pr_debug("kobject:
'%s' (%p): calling ktype release\n", kobject_name(kobj),
kobj); t->release(kobj); } /*
free name if we allocated it */ if(name)
{ pr_debug("kobject:
'%s': free name\n",
name); kfree(name); }} |
有关kset的函数操作
初始化
voidkset_init(structkset
*k){ kobject_init_internal(&k->kobj); INIT_LIST_HEAD(&k->list); spin_lock_init(&k->list_lock);} |
本函数中初始化kset结构体内嵌的kobject,然后初始化链表以及自旋锁。由此可以看出,通过内嵌方式,可以实现面向对象中的继承机制。
注册
intkset_register(structkset
*k){ interr; if(!k) return-EINVAL; kset_init(k); err
= kobject_add_internal(&k->kobj); if(err) returnerr; kobject_uevent(&k->kobj,
KOBJ_ADD); return0;} |
所谓注册,无非是将内嵌的kobject加入设备模型系统中,当然,还要想用户空间到处uevent事件。此处的kobject_add_internal值得一看,从这个函数中可以看出kobject父子节点以及所属kset之间的关系规则。
static
int kobject_add_internal(structkobject
*kobj){ interror
= 0; structkobject
*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->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; returnerror;} |
由函数中可以看出,如果kobject的所属kset设定,而其父节点没有设定,则将本kobject加入kset,并将kset作为作为本kobject的父节点。
注销
voidkset_unregister(structkset
*k){ if(!k) return; kobject_put(&k->kobj);} |
仅仅是减少内嵌kobject对象的引用计数
kobject和kset
将某一kobject加入kset
staticvoidkobj_kset_join(structkobject
*kobj){ if(!kobj->kset) return; kset_get(kobj->kset); spin_lock(&kobj->kset->list_lock); list_add_tail(&kobj->entry,
&kobj->kset->list); spin_unlock(&kobj->kset->list_lock);} |
将某一Kobject从kset中移除
staticvoidkobj_kset_leave(structkobject
*kobj){ if(!kobj->kset) return; spin_lock(&kobj->kset->list_lock); list_del_init(&kobj->entry); spin_unlock(&kobj->kset->list_lock); kset_put(kobj->kset);} |
此处仅仅讲解了一些静态数据的操作函数,相应的动态数据操作类似,仅仅是数据不再是静态生命,而是动态创建。
注:在内核中经常可以看到某些函数参数和返回值相同,不光类型,也包括值,这样的做法是为了保证代码调用上的一致性,并没有什么特别作用。

本文详细介绍了Linux内核中Kobject与Kset的基本操作,包括初始化、添加、删除等函数的实现原理及应用场景。重点讲解了这些操作如何帮助管理内核中的对象。
1262

被折叠的 条评论
为什么被折叠?



