关于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)( 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); } |
此处仅仅讲解了一些静态数据的操作函数,相应的动态数据操作类似,仅仅是数据不再是静态生命,而是动态创建。
注:在内核中经常可以看到某些函数参数和返回值相同,不光类型,也包括值,这样的做法是为了保证代码调用上的一致性,并没有什么特别作用。