关于kref的操作函数
初始化
void
kref_init(
struct
kref *kref)
{
atomic_set(&kref->refcount, 1);
smp_mb();
}
|
注意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)(
struct
kref *kref))
{
WARN_ON(release == NULL);
WARN_ON(release == (
void
(*)(
struct
kref *))kfree);
if
(atomic_dec_and_test(&kref->refcount)) {
release(kref);
return
1;
}
return
0;
}
|
kref_put使用了回调函数机制。如果引用计数递减后为0,将调用函数release来执行一些释放操作。函数kref_sub与本函数类似,只是kref_sub中引用计数可以减小指定的值,不再局限于1。
int
kref_sub(
struct
kref *kref, unsigned
int
count,
void
(*release)(
struct
kref *kref))
{
WARN_ON(release == NULL);
WARN_ON(release == (
void
(*)(
struct
kref *))kfree);
if
(atomic_sub_and_test((
int
) count, &kref->refcount)) {
release(kref);
return
1;
}
return
0;
}
|
关于kobject的函数
初始化
-
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
;
//内核中经常使用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(
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;
}
EXPORT_SYMBOL(kobject_add);
|
该函数也仅是进行了参数验证之后,就调用函数kobject_add_varg执行真正的具体工作。
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);
if
(retval) {
printk(KERN_ERR
"kobject: can not set name properly!\n"
);
return
retval;
}
kobj->parent = parent;
return
kobject_add_internal(kobj);
}
|
这个函数先是设置了kobject的名字,最后建立kobj及其父节点之间的映射关系。
int
kobject_set_name_vargs(
struct
kobject *kobj,
const
char
*fmt,
va_list
vargs)
{
const
char
*old_name = kobj->name;
char
*s;
if
(kobj->name && !fmt)
return
0;
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);
return
0;
}
|
删除,即从驱动设备模型系统中去掉本kobject。
void
kobject_del(
struct
kobject *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,并修改父节点引用计数。
static
void
kobj_kset_leave(
struct
kobject *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引用计数。
struct
kobject *kobject_get(
struct
kobject *kobj)
{
if
(kobj)
kref_get(&kobj->kref);
return
kobj;
}
|
对应的,函数kobject_put用于递增kobject引用计数,如果kobject引用计数为0,则调用kobject_release。
void
kobject_put(
struct
kobject *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);
}
}
|
以下函数用于删除时的清理工作。
static
void
kobject_release(
struct
kref *kref)
{
kobject_cleanup(container_of(kref,
struct
kobject, kref));
}
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\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的函数操作
初始化
void
kset_init(
struct
kset *k)
{
kobject_init_internal(&k->kobj);
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
|
本函数中初始化kset结构体内嵌的kobject,然后初始化链表以及自旋锁。由此可以看出,通过内嵌方式,可以实现面向对象中的继承机制。
注册
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);
return
0;
}
|
所谓注册,无非是将内嵌的kobject加入设备模型系统中,当然,还要想用户空间到处uevent事件。此处的kobject_add_internal值得一看,从这个函数中可以看出kobject父子节点以及所属kset之间的关系规则。
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->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;
}
|
由函数中可以看出,如果kobject的所属kset设定,而其父节点没有设定,则将本kobject加入kset,并将kset作为作为本kobject的父节点。
注销
void
kset_unregister(
struct
kset *k)
{
if
(!k)
return
;
kobject_put(&k->kobj);
}
|
仅仅是减少内嵌kobject对象的引用计数
kobject和kset
将某一kobject加入kset
static
void
kobj_kset_join(
struct
kobject *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中移除
static
void
kobj_kset_leave(
struct
kobject *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);
}
|
此处仅仅讲解了一些静态数据的操作函数,相应的动态数据操作类似,仅仅是数据不再是静态生命,而是动态创建。
注:在内核中经常可以看到某些函数参数和返回值相同,不光类型,也包括值,这样的做法是为了保证代码调用上的一致性,并没有什么特别作用。